Skip to content

Commit 374edea

Browse files
committed
Merge branch 'ip6_gre-Fixes-in-headroom-handling'
Petr Machata says: ==================== net: ip6_gre: Fixes in headroom handling This series mends some problems in headroom management in ip6_gre module. The current code base has the following three closely-related problems: - ip6gretap tunnels neglect to ensure there's enough writable headroom before pushing GRE headers. - ip6erspan does this, but assumes that dev->needed_headroom is primed. But that doesn't happen until ip6_tnl_xmit() is called later. Thus for the first packet, ip6erspan actually behaves like ip6gretap above. - ip6erspan shares some of the code with ip6gretap, including calculations of needed header length. While there is custom ERSPAN-specific code for calculating the headroom, the computed values are overwritten by the ip6gretap code. The first two issues lead to a kernel panic in situations where a packet is mirrored from a veth device to the device in question. They are fixed, respectively, in patches rib#1 and rib#2, which include the full panic trace and a reproducer. The rest of the patchset deals with the last issue. In patches rib#3 to rib#6, several functions are split up into reusable parts. Finally in patch rib#7 these blocks are used to compose ERSPAN-specific callbacks where necessary to fix the hlen calculation. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 02f99df + 2d66503 commit 374edea

File tree

1 file changed

+145
-39
lines changed

1 file changed

+145
-39
lines changed

net/ipv6/ip6_gre.c

Lines changed: 145 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ static int ip6gre_tunnel_init(struct net_device *dev);
8181
static void ip6gre_tunnel_setup(struct net_device *dev);
8282
static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t);
8383
static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu);
84+
static void ip6erspan_tnl_link_config(struct ip6_tnl *t, int set_mtu);
8485

8586
/* Tunnel hash table */
8687

@@ -698,6 +699,9 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
698699
else
699700
fl6->daddr = tunnel->parms.raddr;
700701

702+
if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
703+
return -ENOMEM;
704+
701705
/* Push GRE header. */
702706
protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
703707

@@ -908,7 +912,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
908912
truncate = true;
909913
}
910914

911-
if (skb_cow_head(skb, dev->needed_headroom))
915+
if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen))
912916
goto tx_err;
913917

914918
t->parms.o_flags &= ~TUNNEL_KEY;
@@ -1022,12 +1026,11 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
10221026
return NETDEV_TX_OK;
10231027
}
10241028

1025-
static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
1029+
static void ip6gre_tnl_link_config_common(struct ip6_tnl *t)
10261030
{
10271031
struct net_device *dev = t->dev;
10281032
struct __ip6_tnl_parm *p = &t->parms;
10291033
struct flowi6 *fl6 = &t->fl.u.ip6;
1030-
int t_hlen;
10311034

10321035
if (dev->type != ARPHRD_ETHER) {
10331036
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
@@ -1054,12 +1057,13 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
10541057
dev->flags |= IFF_POINTOPOINT;
10551058
else
10561059
dev->flags &= ~IFF_POINTOPOINT;
1060+
}
10571061

1058-
t->tun_hlen = gre_calc_hlen(t->parms.o_flags);
1059-
1060-
t->hlen = t->encap_hlen + t->tun_hlen;
1061-
1062-
t_hlen = t->hlen + sizeof(struct ipv6hdr);
1062+
static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu,
1063+
int t_hlen)
1064+
{
1065+
const struct __ip6_tnl_parm *p = &t->parms;
1066+
struct net_device *dev = t->dev;
10631067

10641068
if (p->flags & IP6_TNL_F_CAP_XMIT) {
10651069
int strict = (ipv6_addr_type(&p->raddr) &
@@ -1091,8 +1095,26 @@ static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
10911095
}
10921096
}
10931097

1094-
static int ip6gre_tnl_change(struct ip6_tnl *t,
1095-
const struct __ip6_tnl_parm *p, int set_mtu)
1098+
static int ip6gre_calc_hlen(struct ip6_tnl *tunnel)
1099+
{
1100+
int t_hlen;
1101+
1102+
tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
1103+
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
1104+
1105+
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
1106+
tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
1107+
return t_hlen;
1108+
}
1109+
1110+
static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
1111+
{
1112+
ip6gre_tnl_link_config_common(t);
1113+
ip6gre_tnl_link_config_route(t, set_mtu, ip6gre_calc_hlen(t));
1114+
}
1115+
1116+
static void ip6gre_tnl_copy_tnl_parm(struct ip6_tnl *t,
1117+
const struct __ip6_tnl_parm *p)
10961118
{
10971119
t->parms.laddr = p->laddr;
10981120
t->parms.raddr = p->raddr;
@@ -1108,6 +1130,12 @@ static int ip6gre_tnl_change(struct ip6_tnl *t,
11081130
t->parms.o_flags = p->o_flags;
11091131
t->parms.fwmark = p->fwmark;
11101132
dst_cache_reset(&t->dst_cache);
1133+
}
1134+
1135+
static int ip6gre_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
1136+
int set_mtu)
1137+
{
1138+
ip6gre_tnl_copy_tnl_parm(t, p);
11111139
ip6gre_tnl_link_config(t, set_mtu);
11121140
return 0;
11131141
}
@@ -1384,11 +1412,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
13841412
return ret;
13851413
}
13861414

1387-
tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
1388-
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
1389-
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
1390-
1391-
dev->hard_header_len = LL_MAX_HEADER + t_hlen;
1415+
t_hlen = ip6gre_calc_hlen(tunnel);
13921416
dev->mtu = ETH_DATA_LEN - t_hlen;
13931417
if (dev->type == ARPHRD_ETHER)
13941418
dev->mtu -= ETH_HLEN;
@@ -1731,6 +1755,19 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = {
17311755
.ndo_get_iflink = ip6_tnl_get_iflink,
17321756
};
17331757

1758+
static int ip6erspan_calc_hlen(struct ip6_tnl *tunnel)
1759+
{
1760+
int t_hlen;
1761+
1762+
tunnel->tun_hlen = 8;
1763+
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1764+
erspan_hdr_len(tunnel->parms.erspan_ver);
1765+
1766+
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
1767+
tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
1768+
return t_hlen;
1769+
}
1770+
17341771
static int ip6erspan_tap_init(struct net_device *dev)
17351772
{
17361773
struct ip6_tnl *tunnel;
@@ -1754,20 +1791,15 @@ static int ip6erspan_tap_init(struct net_device *dev)
17541791
return ret;
17551792
}
17561793

1757-
tunnel->tun_hlen = 8;
1758-
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
1759-
erspan_hdr_len(tunnel->parms.erspan_ver);
1760-
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
1761-
1762-
dev->hard_header_len = LL_MAX_HEADER + t_hlen;
1794+
t_hlen = ip6erspan_calc_hlen(tunnel);
17631795
dev->mtu = ETH_DATA_LEN - t_hlen;
17641796
if (dev->type == ARPHRD_ETHER)
17651797
dev->mtu -= ETH_HLEN;
17661798
if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
17671799
dev->mtu -= 8;
17681800

17691801
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
1770-
ip6gre_tnl_link_config(tunnel, 1);
1802+
ip6erspan_tnl_link_config(tunnel, 1);
17711803

17721804
return 0;
17731805
}
@@ -1838,9 +1870,9 @@ static bool ip6gre_netlink_encap_parms(struct nlattr *data[],
18381870
return ret;
18391871
}
18401872

1841-
static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
1842-
struct nlattr *tb[], struct nlattr *data[],
1843-
struct netlink_ext_ack *extack)
1873+
static int ip6gre_newlink_common(struct net *src_net, struct net_device *dev,
1874+
struct nlattr *tb[], struct nlattr *data[],
1875+
struct netlink_ext_ack *extack)
18441876
{
18451877
struct ip6_tnl *nt;
18461878
struct net *net = dev_net(dev);
@@ -1877,49 +1909,76 @@ static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
18771909
if (err)
18781910
goto out;
18791911

1880-
ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
1881-
18821912
if (tb[IFLA_MTU])
18831913
ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
18841914

18851915
dev_hold(dev);
1886-
ip6gre_tunnel_link(ign, nt);
18871916

18881917
out:
18891918
return err;
18901919
}
18911920

1892-
static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
1893-
struct nlattr *data[],
1894-
struct netlink_ext_ack *extack)
1921+
static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
1922+
struct nlattr *tb[], struct nlattr *data[],
1923+
struct netlink_ext_ack *extack)
1924+
{
1925+
int err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
1926+
struct ip6_tnl *nt = netdev_priv(dev);
1927+
struct net *net = dev_net(dev);
1928+
1929+
if (!err) {
1930+
ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
1931+
ip6gre_tunnel_link(net_generic(net, ip6gre_net_id), nt);
1932+
}
1933+
return err;
1934+
}
1935+
1936+
static struct ip6_tnl *
1937+
ip6gre_changelink_common(struct net_device *dev, struct nlattr *tb[],
1938+
struct nlattr *data[], struct __ip6_tnl_parm *p_p,
1939+
struct netlink_ext_ack *extack)
18951940
{
18961941
struct ip6_tnl *t, *nt = netdev_priv(dev);
18971942
struct net *net = nt->net;
18981943
struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
1899-
struct __ip6_tnl_parm p;
19001944
struct ip_tunnel_encap ipencap;
19011945

19021946
if (dev == ign->fb_tunnel_dev)
1903-
return -EINVAL;
1947+
return ERR_PTR(-EINVAL);
19041948

19051949
if (ip6gre_netlink_encap_parms(data, &ipencap)) {
19061950
int err = ip6_tnl_encap_setup(nt, &ipencap);
19071951

19081952
if (err < 0)
1909-
return err;
1953+
return ERR_PTR(err);
19101954
}
19111955

1912-
ip6gre_netlink_parms(data, &p);
1956+
ip6gre_netlink_parms(data, p_p);
19131957

1914-
t = ip6gre_tunnel_locate(net, &p, 0);
1958+
t = ip6gre_tunnel_locate(net, p_p, 0);
19151959

19161960
if (t) {
19171961
if (t->dev != dev)
1918-
return -EEXIST;
1962+
return ERR_PTR(-EEXIST);
19191963
} else {
19201964
t = nt;
19211965
}
19221966

1967+
return t;
1968+
}
1969+
1970+
static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
1971+
struct nlattr *data[],
1972+
struct netlink_ext_ack *extack)
1973+
{
1974+
struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
1975+
struct __ip6_tnl_parm p;
1976+
struct ip6_tnl *t;
1977+
1978+
t = ip6gre_changelink_common(dev, tb, data, &p, extack);
1979+
if (IS_ERR(t))
1980+
return PTR_ERR(t);
1981+
19231982
ip6gre_tunnel_unlink(ign, t);
19241983
ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
19251984
ip6gre_tunnel_link(ign, t);
@@ -2071,6 +2130,53 @@ static void ip6erspan_tap_setup(struct net_device *dev)
20712130
netif_keep_dst(dev);
20722131
}
20732132

2133+
static int ip6erspan_newlink(struct net *src_net, struct net_device *dev,
2134+
struct nlattr *tb[], struct nlattr *data[],
2135+
struct netlink_ext_ack *extack)
2136+
{
2137+
int err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
2138+
struct ip6_tnl *nt = netdev_priv(dev);
2139+
struct net *net = dev_net(dev);
2140+
2141+
if (!err) {
2142+
ip6erspan_tnl_link_config(nt, !tb[IFLA_MTU]);
2143+
ip6gre_tunnel_link(net_generic(net, ip6gre_net_id), nt);
2144+
}
2145+
return err;
2146+
}
2147+
2148+
static void ip6erspan_tnl_link_config(struct ip6_tnl *t, int set_mtu)
2149+
{
2150+
ip6gre_tnl_link_config_common(t);
2151+
ip6gre_tnl_link_config_route(t, set_mtu, ip6erspan_calc_hlen(t));
2152+
}
2153+
2154+
static int ip6erspan_tnl_change(struct ip6_tnl *t,
2155+
const struct __ip6_tnl_parm *p, int set_mtu)
2156+
{
2157+
ip6gre_tnl_copy_tnl_parm(t, p);
2158+
ip6erspan_tnl_link_config(t, set_mtu);
2159+
return 0;
2160+
}
2161+
2162+
static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
2163+
struct nlattr *data[],
2164+
struct netlink_ext_ack *extack)
2165+
{
2166+
struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
2167+
struct __ip6_tnl_parm p;
2168+
struct ip6_tnl *t;
2169+
2170+
t = ip6gre_changelink_common(dev, tb, data, &p, extack);
2171+
if (IS_ERR(t))
2172+
return PTR_ERR(t);
2173+
2174+
ip6gre_tunnel_unlink(ign, t);
2175+
ip6erspan_tnl_change(t, &p, !tb[IFLA_MTU]);
2176+
ip6gre_tunnel_link(ign, t);
2177+
return 0;
2178+
}
2179+
20742180
static struct rtnl_link_ops ip6gre_link_ops __read_mostly = {
20752181
.kind = "ip6gre",
20762182
.maxtype = IFLA_GRE_MAX,
@@ -2107,8 +2213,8 @@ static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly = {
21072213
.priv_size = sizeof(struct ip6_tnl),
21082214
.setup = ip6erspan_tap_setup,
21092215
.validate = ip6erspan_tap_validate,
2110-
.newlink = ip6gre_newlink,
2111-
.changelink = ip6gre_changelink,
2216+
.newlink = ip6erspan_newlink,
2217+
.changelink = ip6erspan_changelink,
21122218
.get_size = ip6gre_get_size,
21132219
.fill_info = ip6gre_fill_info,
21142220
.get_link_net = ip6_tnl_get_link_net,

0 commit comments

Comments
 (0)