Skip to content

Commit e1f8f78

Browse files
pmachatadavem330
authored andcommitted
net: ip_gre: Separate ERSPAN newlink / changelink callbacks
ERSPAN shares most of the code path with GRE and gretap code. While that helps keep the code compact, it is also error prone. Currently a broken userspace can turn a gretap tunnel into a de facto ERSPAN one by passing IFLA_GRE_ERSPAN_VER. There has been a similar issue in ip6gretap in the past. To prevent these problems in future, split the newlink and changelink code paths. Split the ERSPAN code out of ipgre_netlink_parms() into a new function erspan_netlink_parms(). Extract a piece of common logic from ipgre_newlink() and ipgre_changelink() into ipgre_newlink_encap_setup(). Add erspan_newlink() and erspan_changelink(). Fixes: 84e54fe ("gre: introduce native tunnel support for ERSPAN") Signed-off-by: Petr Machata <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 46ea929 commit e1f8f78

File tree

1 file changed

+85
-18
lines changed

1 file changed

+85
-18
lines changed

net/ipv4/ip_gre.c

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,22 @@ static int ipgre_netlink_parms(struct net_device *dev,
11531153
if (data[IFLA_GRE_FWMARK])
11541154
*fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
11551155

1156+
return 0;
1157+
}
1158+
1159+
static int erspan_netlink_parms(struct net_device *dev,
1160+
struct nlattr *data[],
1161+
struct nlattr *tb[],
1162+
struct ip_tunnel_parm *parms,
1163+
__u32 *fwmark)
1164+
{
1165+
struct ip_tunnel *t = netdev_priv(dev);
1166+
int err;
1167+
1168+
err = ipgre_netlink_parms(dev, data, tb, parms, fwmark);
1169+
if (err)
1170+
return err;
1171+
11561172
if (data[IFLA_GRE_ERSPAN_VER]) {
11571173
t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
11581174

@@ -1276,45 +1292,70 @@ static void ipgre_tap_setup(struct net_device *dev)
12761292
ip_tunnel_setup(dev, gre_tap_net_id);
12771293
}
12781294

1279-
static int ipgre_newlink(struct net *src_net, struct net_device *dev,
1280-
struct nlattr *tb[], struct nlattr *data[],
1281-
struct netlink_ext_ack *extack)
1295+
static int
1296+
ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[])
12821297
{
1283-
struct ip_tunnel_parm p;
12841298
struct ip_tunnel_encap ipencap;
1285-
__u32 fwmark = 0;
1286-
int err;
12871299

12881300
if (ipgre_netlink_encap_parms(data, &ipencap)) {
12891301
struct ip_tunnel *t = netdev_priv(dev);
1290-
err = ip_tunnel_encap_setup(t, &ipencap);
1302+
int err = ip_tunnel_encap_setup(t, &ipencap);
12911303

12921304
if (err < 0)
12931305
return err;
12941306
}
12951307

1308+
return 0;
1309+
}
1310+
1311+
static int ipgre_newlink(struct net *src_net, struct net_device *dev,
1312+
struct nlattr *tb[], struct nlattr *data[],
1313+
struct netlink_ext_ack *extack)
1314+
{
1315+
struct ip_tunnel_parm p;
1316+
__u32 fwmark = 0;
1317+
int err;
1318+
1319+
err = ipgre_newlink_encap_setup(dev, data);
1320+
if (err)
1321+
return err;
1322+
12961323
err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
12971324
if (err < 0)
12981325
return err;
12991326
return ip_tunnel_newlink(dev, tb, &p, fwmark);
13001327
}
13011328

1329+
static int erspan_newlink(struct net *src_net, struct net_device *dev,
1330+
struct nlattr *tb[], struct nlattr *data[],
1331+
struct netlink_ext_ack *extack)
1332+
{
1333+
struct ip_tunnel_parm p;
1334+
__u32 fwmark = 0;
1335+
int err;
1336+
1337+
err = ipgre_newlink_encap_setup(dev, data);
1338+
if (err)
1339+
return err;
1340+
1341+
err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1342+
if (err)
1343+
return err;
1344+
return ip_tunnel_newlink(dev, tb, &p, fwmark);
1345+
}
1346+
13021347
static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
13031348
struct nlattr *data[],
13041349
struct netlink_ext_ack *extack)
13051350
{
13061351
struct ip_tunnel *t = netdev_priv(dev);
1307-
struct ip_tunnel_encap ipencap;
13081352
__u32 fwmark = t->fwmark;
13091353
struct ip_tunnel_parm p;
13101354
int err;
13111355

1312-
if (ipgre_netlink_encap_parms(data, &ipencap)) {
1313-
err = ip_tunnel_encap_setup(t, &ipencap);
1314-
1315-
if (err < 0)
1316-
return err;
1317-
}
1356+
err = ipgre_newlink_encap_setup(dev, data);
1357+
if (err)
1358+
return err;
13181359

13191360
err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
13201361
if (err < 0)
@@ -1327,8 +1368,34 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
13271368
t->parms.i_flags = p.i_flags;
13281369
t->parms.o_flags = p.o_flags;
13291370

1330-
if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
1331-
ipgre_link_update(dev, !tb[IFLA_MTU]);
1371+
ipgre_link_update(dev, !tb[IFLA_MTU]);
1372+
1373+
return 0;
1374+
}
1375+
1376+
static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
1377+
struct nlattr *data[],
1378+
struct netlink_ext_ack *extack)
1379+
{
1380+
struct ip_tunnel *t = netdev_priv(dev);
1381+
__u32 fwmark = t->fwmark;
1382+
struct ip_tunnel_parm p;
1383+
int err;
1384+
1385+
err = ipgre_newlink_encap_setup(dev, data);
1386+
if (err)
1387+
return err;
1388+
1389+
err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
1390+
if (err < 0)
1391+
return err;
1392+
1393+
err = ip_tunnel_changelink(dev, tb, &p, fwmark);
1394+
if (err < 0)
1395+
return err;
1396+
1397+
t->parms.i_flags = p.i_flags;
1398+
t->parms.o_flags = p.o_flags;
13321399

13331400
return 0;
13341401
}
@@ -1519,8 +1586,8 @@ static struct rtnl_link_ops erspan_link_ops __read_mostly = {
15191586
.priv_size = sizeof(struct ip_tunnel),
15201587
.setup = erspan_setup,
15211588
.validate = erspan_validate,
1522-
.newlink = ipgre_newlink,
1523-
.changelink = ipgre_changelink,
1589+
.newlink = erspan_newlink,
1590+
.changelink = erspan_changelink,
15241591
.dellink = ip_tunnel_dellink,
15251592
.get_size = ipgre_get_size,
15261593
.fill_info = ipgre_fill_info,

0 commit comments

Comments
 (0)