Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gre: Add netlink interface

This patch adds a netlink interface that will eventually displace
the existing ioctl interface. It utilises the elegant rtnl_link_ops
mechanism.

This also means that user-space no longer needs to rely on the
tunnel interface being of type GRE to identify GRE tunnels. The
identification can now occur using rtnl_link_ops.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
c19e654d 42aa9162

+262 -4
+19
include/linux/if_tunnel.h
··· 2 2 #define _IF_TUNNEL_H_ 3 3 4 4 #include <linux/types.h> 5 + #include <linux/ip.h> 5 6 6 7 #define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0) 7 8 #define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) ··· 47 46 48 47 /* PRL flags */ 49 48 #define PRL_DEFAULT 0x0001 49 + 50 + enum 51 + { 52 + IFLA_GRE_UNSPEC, 53 + IFLA_GRE_LINK, 54 + IFLA_GRE_IFLAGS, 55 + IFLA_GRE_OFLAGS, 56 + IFLA_GRE_IKEY, 57 + IFLA_GRE_OKEY, 58 + IFLA_GRE_LOCAL, 59 + IFLA_GRE_REMOTE, 60 + IFLA_GRE_TTL, 61 + IFLA_GRE_TOS, 62 + IFLA_GRE_PMTUDISC, 63 + __IFLA_GRE_MAX, 64 + }; 65 + 66 + #define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1) 50 67 51 68 #endif /* _IF_TUNNEL_H_ */
+243 -4
net/ipv4/ip_gre.c
··· 41 41 #include <net/xfrm.h> 42 42 #include <net/net_namespace.h> 43 43 #include <net/netns/generic.h> 44 + #include <net/rtnetlink.h> 44 45 45 46 #ifdef CONFIG_IPV6 46 47 #include <net/ipv6.h> ··· 118 117 Alexey Kuznetsov. 119 118 */ 120 119 120 + static struct rtnl_link_ops ipgre_link_ops __read_mostly; 121 121 static int ipgre_tunnel_init(struct net_device *dev); 122 122 static void ipgre_tunnel_setup(struct net_device *dev); 123 123 static int ipgre_tunnel_bind_dev(struct net_device *dev); ··· 288 286 goto failed_free; 289 287 } 290 288 291 - dev->init = ipgre_tunnel_init; 292 289 nt = netdev_priv(dev); 293 290 nt->parms = *parms; 291 + dev->rtnl_link_ops = &ipgre_link_ops; 294 292 295 293 dev->mtu = ipgre_tunnel_bind_dev(dev); 296 294 ··· 1089 1087 1090 1088 static void ipgre_tunnel_setup(struct net_device *dev) 1091 1089 { 1090 + dev->init = ipgre_tunnel_init; 1092 1091 dev->uninit = ipgre_tunnel_uninit; 1093 1092 dev->destructor = free_netdev; 1094 1093 dev->hard_start_xmit = ipgre_tunnel_xmit; ··· 1199 1196 1200 1197 ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init; 1201 1198 dev_net_set(ign->fb_tunnel_dev, net); 1199 + ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops; 1202 1200 1203 1201 if ((err = register_netdev(ign->fb_tunnel_dev))) 1204 1202 goto err_reg_dev; ··· 1232 1228 .exit = ipgre_exit_net, 1233 1229 }; 1234 1230 1231 + static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) 1232 + { 1233 + __be16 flags; 1234 + 1235 + if (!data) 1236 + return 0; 1237 + 1238 + flags = 0; 1239 + if (data[IFLA_GRE_IFLAGS]) 1240 + flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); 1241 + if (data[IFLA_GRE_OFLAGS]) 1242 + flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); 1243 + if (flags & (GRE_VERSION|GRE_ROUTING)) 1244 + return -EINVAL; 1245 + 1246 + return 0; 1247 + } 1248 + 1249 + static void ipgre_netlink_parms(struct nlattr *data[], 1250 + struct ip_tunnel_parm *parms) 1251 + { 1252 + memset(parms, 0, sizeof(parms)); 1253 + 1254 + parms->iph.protocol = IPPROTO_GRE; 1255 + 1256 + if (!data) 1257 + return; 1258 + 1259 + if (data[IFLA_GRE_LINK]) 1260 + parms->link = nla_get_u32(data[IFLA_GRE_LINK]); 1261 + 1262 + if (data[IFLA_GRE_IFLAGS]) 1263 + parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]); 1264 + 1265 + if (data[IFLA_GRE_OFLAGS]) 1266 + parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]); 1267 + 1268 + if (data[IFLA_GRE_IKEY]) 1269 + parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); 1270 + 1271 + if (data[IFLA_GRE_OKEY]) 1272 + parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); 1273 + 1274 + if (data[IFLA_GRE_LOCAL]) 1275 + memcpy(&parms->iph.saddr, nla_data(data[IFLA_GRE_LOCAL]), 4); 1276 + 1277 + if (data[IFLA_GRE_REMOTE]) 1278 + memcpy(&parms->iph.daddr, nla_data(data[IFLA_GRE_REMOTE]), 4); 1279 + 1280 + if (data[IFLA_GRE_TTL]) 1281 + parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]); 1282 + 1283 + if (data[IFLA_GRE_TOS]) 1284 + parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]); 1285 + 1286 + if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) 1287 + parms->iph.frag_off = htons(IP_DF); 1288 + } 1289 + 1290 + static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[], 1291 + struct nlattr *data[]) 1292 + { 1293 + struct ip_tunnel *nt; 1294 + struct net *net = dev_net(dev); 1295 + struct ipgre_net *ign = net_generic(net, ipgre_net_id); 1296 + int mtu; 1297 + int err; 1298 + 1299 + nt = netdev_priv(dev); 1300 + ipgre_netlink_parms(data, &nt->parms); 1301 + 1302 + if (ipgre_tunnel_locate(net, &nt->parms, 0)) 1303 + return -EEXIST; 1304 + 1305 + mtu = ipgre_tunnel_bind_dev(dev); 1306 + if (!tb[IFLA_MTU]) 1307 + dev->mtu = mtu; 1308 + 1309 + err = register_netdevice(dev); 1310 + if (err) 1311 + goto out; 1312 + 1313 + dev_hold(dev); 1314 + ipgre_tunnel_link(ign, nt); 1315 + 1316 + out: 1317 + return err; 1318 + } 1319 + 1320 + static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], 1321 + struct nlattr *data[]) 1322 + { 1323 + struct ip_tunnel *t, *nt; 1324 + struct net *net = dev_net(dev); 1325 + struct ipgre_net *ign = net_generic(net, ipgre_net_id); 1326 + struct ip_tunnel_parm p; 1327 + int mtu; 1328 + 1329 + if (dev == ign->fb_tunnel_dev) 1330 + return -EINVAL; 1331 + 1332 + nt = netdev_priv(dev); 1333 + ipgre_netlink_parms(data, &p); 1334 + 1335 + t = ipgre_tunnel_locate(net, &p, 0); 1336 + 1337 + if (t) { 1338 + if (t->dev != dev) 1339 + return -EEXIST; 1340 + } else { 1341 + unsigned nflags = 0; 1342 + 1343 + t = nt; 1344 + 1345 + if (ipv4_is_multicast(p.iph.daddr)) 1346 + nflags = IFF_BROADCAST; 1347 + else if (p.iph.daddr) 1348 + nflags = IFF_POINTOPOINT; 1349 + 1350 + if ((dev->flags ^ nflags) & 1351 + (IFF_POINTOPOINT | IFF_BROADCAST)) 1352 + return -EINVAL; 1353 + 1354 + ipgre_tunnel_unlink(ign, t); 1355 + t->parms.iph.saddr = p.iph.saddr; 1356 + t->parms.iph.daddr = p.iph.daddr; 1357 + t->parms.i_key = p.i_key; 1358 + memcpy(dev->dev_addr, &p.iph.saddr, 4); 1359 + memcpy(dev->broadcast, &p.iph.daddr, 4); 1360 + ipgre_tunnel_link(ign, t); 1361 + netdev_state_change(dev); 1362 + } 1363 + 1364 + t->parms.o_key = p.o_key; 1365 + t->parms.iph.ttl = p.iph.ttl; 1366 + t->parms.iph.tos = p.iph.tos; 1367 + t->parms.iph.frag_off = p.iph.frag_off; 1368 + 1369 + if (t->parms.link != p.link) { 1370 + t->parms.link = p.link; 1371 + mtu = ipgre_tunnel_bind_dev(dev); 1372 + if (!tb[IFLA_MTU]) 1373 + dev->mtu = mtu; 1374 + netdev_state_change(dev); 1375 + } 1376 + 1377 + return 0; 1378 + } 1379 + 1380 + static size_t ipgre_get_size(const struct net_device *dev) 1381 + { 1382 + return 1383 + /* IFLA_GRE_LINK */ 1384 + nla_total_size(4) + 1385 + /* IFLA_GRE_IFLAGS */ 1386 + nla_total_size(2) + 1387 + /* IFLA_GRE_OFLAGS */ 1388 + nla_total_size(2) + 1389 + /* IFLA_GRE_IKEY */ 1390 + nla_total_size(4) + 1391 + /* IFLA_GRE_OKEY */ 1392 + nla_total_size(4) + 1393 + /* IFLA_GRE_LOCAL */ 1394 + nla_total_size(4) + 1395 + /* IFLA_GRE_REMOTE */ 1396 + nla_total_size(4) + 1397 + /* IFLA_GRE_TTL */ 1398 + nla_total_size(1) + 1399 + /* IFLA_GRE_TOS */ 1400 + nla_total_size(1) + 1401 + /* IFLA_GRE_PMTUDISC */ 1402 + nla_total_size(1) + 1403 + 0; 1404 + } 1405 + 1406 + static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) 1407 + { 1408 + struct ip_tunnel *t = netdev_priv(dev); 1409 + struct ip_tunnel_parm *p = &t->parms; 1410 + 1411 + NLA_PUT_U32(skb, IFLA_GRE_LINK, p->link); 1412 + NLA_PUT_BE16(skb, IFLA_GRE_IFLAGS, p->i_flags); 1413 + NLA_PUT_BE16(skb, IFLA_GRE_OFLAGS, p->o_flags); 1414 + NLA_PUT_BE32(skb, IFLA_GRE_IFLAGS, p->i_flags); 1415 + NLA_PUT_BE32(skb, IFLA_GRE_OFLAGS, p->o_flags); 1416 + NLA_PUT(skb, IFLA_GRE_LOCAL, 4, &p->iph.saddr); 1417 + NLA_PUT(skb, IFLA_GRE_REMOTE, 4, &p->iph.daddr); 1418 + NLA_PUT_U8(skb, IFLA_GRE_TTL, p->iph.ttl); 1419 + NLA_PUT_U8(skb, IFLA_GRE_TOS, p->iph.tos); 1420 + NLA_PUT_U8(skb, IFLA_GRE_PMTUDISC, !!(p->iph.frag_off & htons(IP_DF))); 1421 + 1422 + return 0; 1423 + 1424 + nla_put_failure: 1425 + return -EMSGSIZE; 1426 + } 1427 + 1428 + static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { 1429 + [IFLA_GRE_LINK] = { .type = NLA_U32 }, 1430 + [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, 1431 + [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, 1432 + [IFLA_GRE_IKEY] = { .type = NLA_U32 }, 1433 + [IFLA_GRE_OKEY] = { .type = NLA_U32 }, 1434 + [IFLA_GRE_LOCAL] = { .len = 4 }, 1435 + [IFLA_GRE_REMOTE] = { .len = 4 }, 1436 + [IFLA_GRE_TTL] = { .type = NLA_U8 }, 1437 + [IFLA_GRE_TOS] = { .type = NLA_U8 }, 1438 + [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, 1439 + }; 1440 + 1441 + static struct rtnl_link_ops ipgre_link_ops __read_mostly = { 1442 + .kind = "gre", 1443 + .maxtype = IFLA_GRE_MAX, 1444 + .policy = ipgre_policy, 1445 + .priv_size = sizeof(struct ip_tunnel), 1446 + .setup = ipgre_tunnel_setup, 1447 + .validate = ipgre_tunnel_validate, 1448 + .newlink = ipgre_newlink, 1449 + .changelink = ipgre_changelink, 1450 + .get_size = ipgre_get_size, 1451 + .fill_info = ipgre_fill_info, 1452 + }; 1453 + 1235 1454 /* 1236 1455 * And now the modules code and kernel interface. 1237 1456 */ ··· 1472 1245 1473 1246 err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops); 1474 1247 if (err < 0) 1475 - inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); 1248 + goto gen_device_failed; 1476 1249 1250 + err = rtnl_link_register(&ipgre_link_ops); 1251 + if (err < 0) 1252 + goto rtnl_link_failed; 1253 + 1254 + out: 1477 1255 return err; 1256 + 1257 + rtnl_link_failed: 1258 + unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); 1259 + gen_device_failed: 1260 + inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); 1261 + goto out; 1478 1262 } 1479 1263 1480 1264 static void __exit ipgre_fini(void) 1481 1265 { 1266 + rtnl_link_unregister(&ipgre_link_ops); 1267 + unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); 1482 1268 if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) 1483 1269 printk(KERN_INFO "ipgre close: can't remove protocol\n"); 1484 - 1485 - unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); 1486 1270 } 1487 1271 1488 1272 module_init(ipgre_init); 1489 1273 module_exit(ipgre_fini); 1490 1274 MODULE_LICENSE("GPL"); 1275 + MODULE_ALIAS("rtnl-link-gre");