diff options
author | David S. Miller <davem@davemloft.net> | 2015-04-07 17:29:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-04-07 17:29:47 -0400 |
commit | 26ba9e8c3f455b1328d805937a320719cb152e80 (patch) | |
tree | 2c9faf03479b4aaefe193c47b2c66061e95ddfcd | |
parent | e0e8db2f89bac4529fa12dde2595d6295e313952 (diff) | |
parent | a143c40c32bb8a6d6a556920646021d7e96d1f91 (diff) |
Merge branch 'netns-next'
Nicolas Dichtel says:
====================
netns: enhance netlink interface for nsid
The first patch is a small cleanup. The second patch implements notifications
for netns id events. And the last one allows to dump existing netns id from
userland.
iproute2 patches are available, I can send them on demand.
v2: drop the first patch (the fix is now in net-next)
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/uapi/linux/rtnetlink.h | 4 | ||||
-rw-r--r-- | net/core/net_namespace.c | 103 |
2 files changed, 97 insertions, 10 deletions
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index bea910f924dd..974db03f7b1a 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h | |||
@@ -134,6 +134,8 @@ enum { | |||
134 | 134 | ||
135 | RTM_NEWNSID = 88, | 135 | RTM_NEWNSID = 88, |
136 | #define RTM_NEWNSID RTM_NEWNSID | 136 | #define RTM_NEWNSID RTM_NEWNSID |
137 | RTM_DELNSID = 89, | ||
138 | #define RTM_DELNSID RTM_DELNSID | ||
137 | RTM_GETNSID = 90, | 139 | RTM_GETNSID = 90, |
138 | #define RTM_GETNSID RTM_GETNSID | 140 | #define RTM_GETNSID RTM_GETNSID |
139 | 141 | ||
@@ -635,6 +637,8 @@ enum rtnetlink_groups { | |||
635 | #define RTNLGRP_MDB RTNLGRP_MDB | 637 | #define RTNLGRP_MDB RTNLGRP_MDB |
636 | RTNLGRP_MPLS_ROUTE, | 638 | RTNLGRP_MPLS_ROUTE, |
637 | #define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE | 639 | #define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE |
640 | RTNLGRP_NSID, | ||
641 | #define RTNLGRP_NSID RTNLGRP_NSID | ||
638 | __RTNLGRP_MAX | 642 | __RTNLGRP_MAX |
639 | }; | 643 | }; |
640 | #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) | 644 | #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index e7345d9031df..a3abb719221f 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -148,9 +148,11 @@ static void ops_free_list(const struct pernet_operations *ops, | |||
148 | } | 148 | } |
149 | } | 149 | } |
150 | 150 | ||
151 | static void rtnl_net_notifyid(struct net *net, struct net *peer, int cmd, | ||
152 | int id); | ||
151 | static int alloc_netid(struct net *net, struct net *peer, int reqid) | 153 | static int alloc_netid(struct net *net, struct net *peer, int reqid) |
152 | { | 154 | { |
153 | int min = 0, max = 0; | 155 | int min = 0, max = 0, id; |
154 | 156 | ||
155 | ASSERT_RTNL(); | 157 | ASSERT_RTNL(); |
156 | 158 | ||
@@ -159,7 +161,11 @@ static int alloc_netid(struct net *net, struct net *peer, int reqid) | |||
159 | max = reqid + 1; | 161 | max = reqid + 1; |
160 | } | 162 | } |
161 | 163 | ||
162 | return idr_alloc(&net->netns_ids, peer, min, max, GFP_KERNEL); | 164 | id = idr_alloc(&net->netns_ids, peer, min, max, GFP_KERNEL); |
165 | if (id >= 0) | ||
166 | rtnl_net_notifyid(net, peer, RTM_NEWNSID, id); | ||
167 | |||
168 | return id; | ||
163 | } | 169 | } |
164 | 170 | ||
165 | /* This function is used by idr_for_each(). If net is equal to peer, the | 171 | /* This function is used by idr_for_each(). If net is equal to peer, the |
@@ -359,8 +365,10 @@ static void cleanup_net(struct work_struct *work) | |||
359 | for_each_net(tmp) { | 365 | for_each_net(tmp) { |
360 | int id = __peernet2id(tmp, net, false); | 366 | int id = __peernet2id(tmp, net, false); |
361 | 367 | ||
362 | if (id >= 0) | 368 | if (id >= 0) { |
369 | rtnl_net_notifyid(tmp, net, RTM_DELNSID, id); | ||
363 | idr_remove(&tmp->netns_ids, id); | 370 | idr_remove(&tmp->netns_ids, id); |
371 | } | ||
364 | } | 372 | } |
365 | idr_destroy(&net->netns_ids); | 373 | idr_destroy(&net->netns_ids); |
366 | 374 | ||
@@ -531,7 +539,8 @@ static int rtnl_net_get_size(void) | |||
531 | } | 539 | } |
532 | 540 | ||
533 | static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags, | 541 | static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags, |
534 | int cmd, struct net *net, struct net *peer) | 542 | int cmd, struct net *net, struct net *peer, |
543 | int nsid) | ||
535 | { | 544 | { |
536 | struct nlmsghdr *nlh; | 545 | struct nlmsghdr *nlh; |
537 | struct rtgenmsg *rth; | 546 | struct rtgenmsg *rth; |
@@ -546,9 +555,13 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags, | |||
546 | rth = nlmsg_data(nlh); | 555 | rth = nlmsg_data(nlh); |
547 | rth->rtgen_family = AF_UNSPEC; | 556 | rth->rtgen_family = AF_UNSPEC; |
548 | 557 | ||
549 | id = __peernet2id(net, peer, false); | 558 | if (nsid >= 0) { |
550 | if (id < 0) | 559 | id = nsid; |
551 | id = NETNSA_NSID_NOT_ASSIGNED; | 560 | } else { |
561 | id = __peernet2id(net, peer, false); | ||
562 | if (id < 0) | ||
563 | id = NETNSA_NSID_NOT_ASSIGNED; | ||
564 | } | ||
552 | if (nla_put_s32(skb, NETNSA_NSID, id)) | 565 | if (nla_put_s32(skb, NETNSA_NSID, id)) |
553 | goto nla_put_failure; | 566 | goto nla_put_failure; |
554 | 567 | ||
@@ -565,8 +578,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
565 | struct net *net = sock_net(skb->sk); | 578 | struct net *net = sock_net(skb->sk); |
566 | struct nlattr *tb[NETNSA_MAX + 1]; | 579 | struct nlattr *tb[NETNSA_MAX + 1]; |
567 | struct sk_buff *msg; | 580 | struct sk_buff *msg; |
568 | int err = -ENOBUFS; | ||
569 | struct net *peer; | 581 | struct net *peer; |
582 | int err; | ||
570 | 583 | ||
571 | err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, | 584 | err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, |
572 | rtnl_net_policy); | 585 | rtnl_net_policy); |
@@ -589,7 +602,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
589 | } | 602 | } |
590 | 603 | ||
591 | err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, | 604 | err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, |
592 | RTM_GETNSID, net, peer); | 605 | RTM_GETNSID, net, peer, -1); |
593 | if (err < 0) | 606 | if (err < 0) |
594 | goto err_out; | 607 | goto err_out; |
595 | 608 | ||
@@ -603,6 +616,75 @@ out: | |||
603 | return err; | 616 | return err; |
604 | } | 617 | } |
605 | 618 | ||
619 | struct rtnl_net_dump_cb { | ||
620 | struct net *net; | ||
621 | struct sk_buff *skb; | ||
622 | struct netlink_callback *cb; | ||
623 | int idx; | ||
624 | int s_idx; | ||
625 | }; | ||
626 | |||
627 | static int rtnl_net_dumpid_one(int id, void *peer, void *data) | ||
628 | { | ||
629 | struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data; | ||
630 | int ret; | ||
631 | |||
632 | if (net_cb->idx < net_cb->s_idx) | ||
633 | goto cont; | ||
634 | |||
635 | ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid, | ||
636 | net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
637 | RTM_NEWNSID, net_cb->net, peer, id); | ||
638 | if (ret < 0) | ||
639 | return ret; | ||
640 | |||
641 | cont: | ||
642 | net_cb->idx++; | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) | ||
647 | { | ||
648 | struct net *net = sock_net(skb->sk); | ||
649 | struct rtnl_net_dump_cb net_cb = { | ||
650 | .net = net, | ||
651 | .skb = skb, | ||
652 | .cb = cb, | ||
653 | .idx = 0, | ||
654 | .s_idx = cb->args[0], | ||
655 | }; | ||
656 | |||
657 | ASSERT_RTNL(); | ||
658 | |||
659 | idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); | ||
660 | |||
661 | cb->args[0] = net_cb.idx; | ||
662 | return skb->len; | ||
663 | } | ||
664 | |||
665 | static void rtnl_net_notifyid(struct net *net, struct net *peer, int cmd, | ||
666 | int id) | ||
667 | { | ||
668 | struct sk_buff *msg; | ||
669 | int err = -ENOMEM; | ||
670 | |||
671 | msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); | ||
672 | if (!msg) | ||
673 | goto out; | ||
674 | |||
675 | err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, peer, id); | ||
676 | if (err < 0) | ||
677 | goto err_out; | ||
678 | |||
679 | rtnl_notify(msg, net, 0, RTNLGRP_NSID, NULL, 0); | ||
680 | return; | ||
681 | |||
682 | err_out: | ||
683 | nlmsg_free(msg); | ||
684 | out: | ||
685 | rtnl_set_sk_err(net, RTNLGRP_NSID, err); | ||
686 | } | ||
687 | |||
606 | static int __init net_ns_init(void) | 688 | static int __init net_ns_init(void) |
607 | { | 689 | { |
608 | struct net_generic *ng; | 690 | struct net_generic *ng; |
@@ -637,7 +719,8 @@ static int __init net_ns_init(void) | |||
637 | register_pernet_subsys(&net_ns_ops); | 719 | register_pernet_subsys(&net_ns_ops); |
638 | 720 | ||
639 | rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, NULL); | 721 | rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, NULL); |
640 | rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, NULL, NULL); | 722 | rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid, |
723 | NULL); | ||
641 | 724 | ||
642 | return 0; | 725 | return 0; |
643 | } | 726 | } |