diff options
author | Denis V. Lunev <den@openvz.org> | 2007-11-20 01:26:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:54:25 -0500 |
commit | 97c53cacf00d1f5aa04adabfebcc806ca8b22b10 (patch) | |
tree | 6b7223df312aa27a5017c4d7c4d1e500a33ed8d8 /net/core | |
parent | b854272b3c732316676e9128f7b9e6f1e1ff88b0 (diff) |
[NET]: Make rtnetlink infrastructure network namespace aware (v3)
After this patch none of the netlink callback support anything
except the initial network namespace but the rtnetlink infrastructure
now handles multiple network namespaces.
Changes from v2:
- IPv6 addrlabel processing
Changes from v1:
- no need for special rtnl_unlock handling
- fixed IPv6 ndisc
Signed-off-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/fib_rules.c | 4 | ||||
-rw-r--r-- | net/core/neighbour.c | 4 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 63 |
3 files changed, 56 insertions, 15 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 3b20b6f0982e..0af0538343da 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -599,10 +599,10 @@ static void notify_rule_change(int event, struct fib_rule *rule, | |||
599 | kfree_skb(skb); | 599 | kfree_skb(skb); |
600 | goto errout; | 600 | goto errout; |
601 | } | 601 | } |
602 | err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL); | 602 | err = rtnl_notify(skb, &init_net, pid, ops->nlgroup, nlh, GFP_KERNEL); |
603 | errout: | 603 | errout: |
604 | if (err < 0) | 604 | if (err < 0) |
605 | rtnl_set_sk_err(ops->nlgroup, err); | 605 | rtnl_set_sk_err(&init_net, ops->nlgroup, err); |
606 | } | 606 | } |
607 | 607 | ||
608 | static void attach_rules(struct list_head *rules, struct net_device *dev) | 608 | static void attach_rules(struct list_head *rules, struct net_device *dev) |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 29f0a4d2008f..a8b72c1c7c8a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -2467,10 +2467,10 @@ static void __neigh_notify(struct neighbour *n, int type, int flags) | |||
2467 | kfree_skb(skb); | 2467 | kfree_skb(skb); |
2468 | goto errout; | 2468 | goto errout; |
2469 | } | 2469 | } |
2470 | err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); | 2470 | err = rtnl_notify(skb, &init_net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); |
2471 | errout: | 2471 | errout: |
2472 | if (err < 0) | 2472 | if (err < 0) |
2473 | rtnl_set_sk_err(RTNLGRP_NEIGH, err); | 2473 | rtnl_set_sk_err(&init_net, RTNLGRP_NEIGH, err); |
2474 | } | 2474 | } |
2475 | 2475 | ||
2476 | #ifdef CONFIG_ARPD | 2476 | #ifdef CONFIG_ARPD |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4edc3dac4ccd..9efaf35934f4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -60,7 +60,6 @@ struct rtnl_link | |||
60 | }; | 60 | }; |
61 | 61 | ||
62 | static DEFINE_MUTEX(rtnl_mutex); | 62 | static DEFINE_MUTEX(rtnl_mutex); |
63 | static struct sock *rtnl; | ||
64 | 63 | ||
65 | void rtnl_lock(void) | 64 | void rtnl_lock(void) |
66 | { | 65 | { |
@@ -458,8 +457,9 @@ size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size) | |||
458 | return ret; | 457 | return ret; |
459 | } | 458 | } |
460 | 459 | ||
461 | int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) | 460 | int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo) |
462 | { | 461 | { |
462 | struct sock *rtnl = net->rtnl; | ||
463 | int err = 0; | 463 | int err = 0; |
464 | 464 | ||
465 | NETLINK_CB(skb).dst_group = group; | 465 | NETLINK_CB(skb).dst_group = group; |
@@ -471,14 +471,17 @@ int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) | |||
471 | return err; | 471 | return err; |
472 | } | 472 | } |
473 | 473 | ||
474 | int rtnl_unicast(struct sk_buff *skb, u32 pid) | 474 | int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid) |
475 | { | 475 | { |
476 | struct sock *rtnl = net->rtnl; | ||
477 | |||
476 | return nlmsg_unicast(rtnl, skb, pid); | 478 | return nlmsg_unicast(rtnl, skb, pid); |
477 | } | 479 | } |
478 | 480 | ||
479 | int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, | 481 | int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, |
480 | struct nlmsghdr *nlh, gfp_t flags) | 482 | struct nlmsghdr *nlh, gfp_t flags) |
481 | { | 483 | { |
484 | struct sock *rtnl = net->rtnl; | ||
482 | int report = 0; | 485 | int report = 0; |
483 | 486 | ||
484 | if (nlh) | 487 | if (nlh) |
@@ -487,8 +490,10 @@ int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, | |||
487 | return nlmsg_notify(rtnl, skb, pid, group, report, flags); | 490 | return nlmsg_notify(rtnl, skb, pid, group, report, flags); |
488 | } | 491 | } |
489 | 492 | ||
490 | void rtnl_set_sk_err(u32 group, int error) | 493 | void rtnl_set_sk_err(struct net *net, u32 group, int error) |
491 | { | 494 | { |
495 | struct sock *rtnl = net->rtnl; | ||
496 | |||
492 | netlink_set_err(rtnl, 0, group, error); | 497 | netlink_set_err(rtnl, 0, group, error); |
493 | } | 498 | } |
494 | 499 | ||
@@ -1201,7 +1206,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
1201 | kfree_skb(nskb); | 1206 | kfree_skb(nskb); |
1202 | goto errout; | 1207 | goto errout; |
1203 | } | 1208 | } |
1204 | err = rtnl_unicast(nskb, NETLINK_CB(skb).pid); | 1209 | err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid); |
1205 | errout: | 1210 | errout: |
1206 | dev_put(dev); | 1211 | dev_put(dev); |
1207 | 1212 | ||
@@ -1252,10 +1257,10 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | |||
1252 | kfree_skb(skb); | 1257 | kfree_skb(skb); |
1253 | goto errout; | 1258 | goto errout; |
1254 | } | 1259 | } |
1255 | err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); | 1260 | err = rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); |
1256 | errout: | 1261 | errout: |
1257 | if (err < 0) | 1262 | if (err < 0) |
1258 | rtnl_set_sk_err(RTNLGRP_LINK, err); | 1263 | rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err); |
1259 | } | 1264 | } |
1260 | 1265 | ||
1261 | /* Protected by RTNL sempahore. */ | 1266 | /* Protected by RTNL sempahore. */ |
@@ -1266,6 +1271,7 @@ static int rtattr_max; | |||
1266 | 1271 | ||
1267 | static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 1272 | static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
1268 | { | 1273 | { |
1274 | struct net *net = skb->sk->sk_net; | ||
1269 | rtnl_doit_func doit; | 1275 | rtnl_doit_func doit; |
1270 | int sz_idx, kind; | 1276 | int sz_idx, kind; |
1271 | int min_len; | 1277 | int min_len; |
@@ -1294,6 +1300,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1294 | return -EPERM; | 1300 | return -EPERM; |
1295 | 1301 | ||
1296 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { | 1302 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
1303 | struct sock *rtnl; | ||
1297 | rtnl_dumpit_func dumpit; | 1304 | rtnl_dumpit_func dumpit; |
1298 | 1305 | ||
1299 | dumpit = rtnl_get_dumpit(family, type); | 1306 | dumpit = rtnl_get_dumpit(family, type); |
@@ -1301,6 +1308,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1301 | return -EOPNOTSUPP; | 1308 | return -EOPNOTSUPP; |
1302 | 1309 | ||
1303 | __rtnl_unlock(); | 1310 | __rtnl_unlock(); |
1311 | rtnl = net->rtnl; | ||
1304 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); | 1312 | err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); |
1305 | rtnl_lock(); | 1313 | rtnl_lock(); |
1306 | return err; | 1314 | return err; |
@@ -1373,6 +1381,40 @@ static struct notifier_block rtnetlink_dev_notifier = { | |||
1373 | .notifier_call = rtnetlink_event, | 1381 | .notifier_call = rtnetlink_event, |
1374 | }; | 1382 | }; |
1375 | 1383 | ||
1384 | |||
1385 | static int rtnetlink_net_init(struct net *net) | ||
1386 | { | ||
1387 | struct sock *sk; | ||
1388 | sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, | ||
1389 | rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); | ||
1390 | if (!sk) | ||
1391 | return -ENOMEM; | ||
1392 | |||
1393 | /* Don't hold an extra reference on the namespace */ | ||
1394 | put_net(sk->sk_net); | ||
1395 | net->rtnl = sk; | ||
1396 | return 0; | ||
1397 | } | ||
1398 | |||
1399 | static void rtnetlink_net_exit(struct net *net) | ||
1400 | { | ||
1401 | struct sock *sk = net->rtnl; | ||
1402 | if (sk) { | ||
1403 | /* At the last minute lie and say this is a socket for the | ||
1404 | * initial network namespace. So the socket will be safe to | ||
1405 | * free. | ||
1406 | */ | ||
1407 | sk->sk_net = get_net(&init_net); | ||
1408 | sock_put(sk); | ||
1409 | net->rtnl = NULL; | ||
1410 | } | ||
1411 | } | ||
1412 | |||
1413 | static struct pernet_operations rtnetlink_net_ops = { | ||
1414 | .init = rtnetlink_net_init, | ||
1415 | .exit = rtnetlink_net_exit, | ||
1416 | }; | ||
1417 | |||
1376 | void __init rtnetlink_init(void) | 1418 | void __init rtnetlink_init(void) |
1377 | { | 1419 | { |
1378 | int i; | 1420 | int i; |
@@ -1385,10 +1427,9 @@ void __init rtnetlink_init(void) | |||
1385 | if (!rta_buf) | 1427 | if (!rta_buf) |
1386 | panic("rtnetlink_init: cannot allocate rta_buf\n"); | 1428 | panic("rtnetlink_init: cannot allocate rta_buf\n"); |
1387 | 1429 | ||
1388 | rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX, | 1430 | if (register_pernet_subsys(&rtnetlink_net_ops)) |
1389 | rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); | ||
1390 | if (rtnl == NULL) | ||
1391 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); | 1431 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); |
1432 | |||
1392 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); | 1433 | netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); |
1393 | register_netdevice_notifier(&rtnetlink_dev_notifier); | 1434 | register_netdevice_notifier(&rtnetlink_dev_notifier); |
1394 | 1435 | ||