Commit 85aa84d3c5877ee999546729892ae6c5dbaeac3c
Committed by
Greg Kroah-Hartman
1 parent
62e3ffa4ea
net: ip_gre: Separate ERSPAN newlink / changelink callbacks
[ Upstream commit e1f8f78ffe9854308b9e12a73ebe4e909074fc33 ] 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: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Signed-off-by: Petr Machata <petrm@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 85 additions and 18 deletions Side-by-side Diff
net/ipv4/ip_gre.c
... | ... | @@ -1149,6 +1149,22 @@ |
1149 | 1149 | if (data[IFLA_GRE_FWMARK]) |
1150 | 1150 | *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]); |
1151 | 1151 | |
1152 | + return 0; | |
1153 | +} | |
1154 | + | |
1155 | +static int erspan_netlink_parms(struct net_device *dev, | |
1156 | + struct nlattr *data[], | |
1157 | + struct nlattr *tb[], | |
1158 | + struct ip_tunnel_parm *parms, | |
1159 | + __u32 *fwmark) | |
1160 | +{ | |
1161 | + struct ip_tunnel *t = netdev_priv(dev); | |
1162 | + int err; | |
1163 | + | |
1164 | + err = ipgre_netlink_parms(dev, data, tb, parms, fwmark); | |
1165 | + if (err) | |
1166 | + return err; | |
1167 | + | |
1152 | 1168 | if (data[IFLA_GRE_ERSPAN_VER]) { |
1153 | 1169 | t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); |
1154 | 1170 | |
1155 | 1171 | |
1156 | 1172 | |
1157 | 1173 | |
1158 | 1174 | |
1159 | 1175 | |
1160 | 1176 | |
1161 | 1177 | |
1162 | 1178 | |
... | ... | @@ -1272,46 +1288,71 @@ |
1272 | 1288 | ip_tunnel_setup(dev, gre_tap_net_id); |
1273 | 1289 | } |
1274 | 1290 | |
1275 | -static int ipgre_newlink(struct net *src_net, struct net_device *dev, | |
1276 | - struct nlattr *tb[], struct nlattr *data[], | |
1277 | - struct netlink_ext_ack *extack) | |
1291 | +static int | |
1292 | +ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[]) | |
1278 | 1293 | { |
1279 | - struct ip_tunnel_parm p; | |
1280 | 1294 | struct ip_tunnel_encap ipencap; |
1281 | - __u32 fwmark = 0; | |
1282 | - int err; | |
1283 | 1295 | |
1284 | 1296 | if (ipgre_netlink_encap_parms(data, &ipencap)) { |
1285 | 1297 | struct ip_tunnel *t = netdev_priv(dev); |
1286 | - err = ip_tunnel_encap_setup(t, &ipencap); | |
1298 | + int err = ip_tunnel_encap_setup(t, &ipencap); | |
1287 | 1299 | |
1288 | 1300 | if (err < 0) |
1289 | 1301 | return err; |
1290 | 1302 | } |
1291 | 1303 | |
1304 | + return 0; | |
1305 | +} | |
1306 | + | |
1307 | +static int ipgre_newlink(struct net *src_net, struct net_device *dev, | |
1308 | + struct nlattr *tb[], struct nlattr *data[], | |
1309 | + struct netlink_ext_ack *extack) | |
1310 | +{ | |
1311 | + struct ip_tunnel_parm p; | |
1312 | + __u32 fwmark = 0; | |
1313 | + int err; | |
1314 | + | |
1315 | + err = ipgre_newlink_encap_setup(dev, data); | |
1316 | + if (err) | |
1317 | + return err; | |
1318 | + | |
1292 | 1319 | err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark); |
1293 | 1320 | if (err < 0) |
1294 | 1321 | return err; |
1295 | 1322 | return ip_tunnel_newlink(dev, tb, &p, fwmark); |
1296 | 1323 | } |
1297 | 1324 | |
1325 | +static int erspan_newlink(struct net *src_net, struct net_device *dev, | |
1326 | + struct nlattr *tb[], struct nlattr *data[], | |
1327 | + struct netlink_ext_ack *extack) | |
1328 | +{ | |
1329 | + struct ip_tunnel_parm p; | |
1330 | + __u32 fwmark = 0; | |
1331 | + int err; | |
1332 | + | |
1333 | + err = ipgre_newlink_encap_setup(dev, data); | |
1334 | + if (err) | |
1335 | + return err; | |
1336 | + | |
1337 | + err = erspan_netlink_parms(dev, data, tb, &p, &fwmark); | |
1338 | + if (err) | |
1339 | + return err; | |
1340 | + return ip_tunnel_newlink(dev, tb, &p, fwmark); | |
1341 | +} | |
1342 | + | |
1298 | 1343 | static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], |
1299 | 1344 | struct nlattr *data[], |
1300 | 1345 | struct netlink_ext_ack *extack) |
1301 | 1346 | { |
1302 | 1347 | struct ip_tunnel *t = netdev_priv(dev); |
1303 | - struct ip_tunnel_encap ipencap; | |
1304 | 1348 | __u32 fwmark = t->fwmark; |
1305 | 1349 | struct ip_tunnel_parm p; |
1306 | 1350 | int err; |
1307 | 1351 | |
1308 | - if (ipgre_netlink_encap_parms(data, &ipencap)) { | |
1309 | - err = ip_tunnel_encap_setup(t, &ipencap); | |
1352 | + err = ipgre_newlink_encap_setup(dev, data); | |
1353 | + if (err) | |
1354 | + return err; | |
1310 | 1355 | |
1311 | - if (err < 0) | |
1312 | - return err; | |
1313 | - } | |
1314 | - | |
1315 | 1356 | err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark); |
1316 | 1357 | if (err < 0) |
1317 | 1358 | return err; |
1318 | 1359 | |
... | ... | @@ -1323,12 +1364,38 @@ |
1323 | 1364 | t->parms.i_flags = p.i_flags; |
1324 | 1365 | t->parms.o_flags = p.o_flags; |
1325 | 1366 | |
1326 | - if (strcmp(dev->rtnl_link_ops->kind, "erspan")) | |
1327 | - ipgre_link_update(dev, !tb[IFLA_MTU]); | |
1367 | + ipgre_link_update(dev, !tb[IFLA_MTU]); | |
1328 | 1368 | |
1329 | 1369 | return 0; |
1330 | 1370 | } |
1331 | 1371 | |
1372 | +static int erspan_changelink(struct net_device *dev, struct nlattr *tb[], | |
1373 | + struct nlattr *data[], | |
1374 | + struct netlink_ext_ack *extack) | |
1375 | +{ | |
1376 | + struct ip_tunnel *t = netdev_priv(dev); | |
1377 | + __u32 fwmark = t->fwmark; | |
1378 | + struct ip_tunnel_parm p; | |
1379 | + int err; | |
1380 | + | |
1381 | + err = ipgre_newlink_encap_setup(dev, data); | |
1382 | + if (err) | |
1383 | + return err; | |
1384 | + | |
1385 | + err = erspan_netlink_parms(dev, data, tb, &p, &fwmark); | |
1386 | + if (err < 0) | |
1387 | + return err; | |
1388 | + | |
1389 | + err = ip_tunnel_changelink(dev, tb, &p, fwmark); | |
1390 | + if (err < 0) | |
1391 | + return err; | |
1392 | + | |
1393 | + t->parms.i_flags = p.i_flags; | |
1394 | + t->parms.o_flags = p.o_flags; | |
1395 | + | |
1396 | + return 0; | |
1397 | +} | |
1398 | + | |
1332 | 1399 | static size_t ipgre_get_size(const struct net_device *dev) |
1333 | 1400 | { |
1334 | 1401 | return |
... | ... | @@ -1515,8 +1582,8 @@ |
1515 | 1582 | .priv_size = sizeof(struct ip_tunnel), |
1516 | 1583 | .setup = erspan_setup, |
1517 | 1584 | .validate = erspan_validate, |
1518 | - .newlink = ipgre_newlink, | |
1519 | - .changelink = ipgre_changelink, | |
1585 | + .newlink = erspan_newlink, | |
1586 | + .changelink = erspan_changelink, | |
1520 | 1587 | .dellink = ip_tunnel_dellink, |
1521 | 1588 | .get_size = ipgre_get_size, |
1522 | 1589 | .fill_info = ipgre_fill_info, |