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