aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/net_namespace.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index ce780c722e48..9d1a4cac83b6 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -15,6 +15,10 @@
15#include <linux/file.h> 15#include <linux/file.h>
16#include <linux/export.h> 16#include <linux/export.h>
17#include <linux/user_namespace.h> 17#include <linux/user_namespace.h>
18#include <linux/net_namespace.h>
19#include <linux/rtnetlink.h>
20#include <net/sock.h>
21#include <net/netlink.h>
18#include <net/net_namespace.h> 22#include <net/net_namespace.h>
19#include <net/netns/generic.h> 23#include <net/netns/generic.h>
20 24
@@ -144,6 +148,77 @@ static void ops_free_list(const struct pernet_operations *ops,
144 } 148 }
145} 149}
146 150
151static int alloc_netid(struct net *net, struct net *peer, int reqid)
152{
153 int min = 0, max = 0;
154
155 ASSERT_RTNL();
156
157 if (reqid >= 0) {
158 min = reqid;
159 max = reqid + 1;
160 }
161
162 return idr_alloc(&net->netns_ids, peer, min, max, GFP_KERNEL);
163}
164
165/* This function is used by idr_for_each(). If net is equal to peer, the
166 * function returns the id so that idr_for_each() stops. Because we cannot
167 * returns the id 0 (idr_for_each() will not stop), we return the magic value
168 * NET_ID_ZERO (-1) for it.
169 */
170#define NET_ID_ZERO -1
171static int net_eq_idr(int id, void *net, void *peer)
172{
173 if (net_eq(net, peer))
174 return id ? : NET_ID_ZERO;
175 return 0;
176}
177
178static int __peernet2id(struct net *net, struct net *peer, bool alloc)
179{
180 int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
181
182 ASSERT_RTNL();
183
184 /* Magic value for id 0. */
185 if (id == NET_ID_ZERO)
186 return 0;
187 if (id > 0)
188 return id;
189
190 if (alloc)
191 return alloc_netid(net, peer, -1);
192
193 return -ENOENT;
194}
195
196/* This function returns the id of a peer netns. If no id is assigned, one will
197 * be allocated and returned.
198 */
199int peernet2id(struct net *net, struct net *peer)
200{
201 int id = __peernet2id(net, peer, true);
202
203 return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED;
204}
205
206struct net *get_net_ns_by_id(struct net *net, int id)
207{
208 struct net *peer;
209
210 if (id < 0)
211 return NULL;
212
213 rcu_read_lock();
214 peer = idr_find(&net->netns_ids, id);
215 if (peer)
216 get_net(peer);
217 rcu_read_unlock();
218
219 return peer;
220}
221
147/* 222/*
148 * setup_net runs the initializers for the network namespace object. 223 * setup_net runs the initializers for the network namespace object.
149 */ 224 */
@@ -158,6 +233,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
158 atomic_set(&net->passive, 1); 233 atomic_set(&net->passive, 1);
159 net->dev_base_seq = 1; 234 net->dev_base_seq = 1;
160 net->user_ns = user_ns; 235 net->user_ns = user_ns;
236 idr_init(&net->netns_ids);
161 237
162#ifdef NETNS_REFCNT_DEBUG 238#ifdef NETNS_REFCNT_DEBUG
163 atomic_set(&net->use_count, 0); 239 atomic_set(&net->use_count, 0);
@@ -288,6 +364,14 @@ static void cleanup_net(struct work_struct *work)
288 list_for_each_entry(net, &net_kill_list, cleanup_list) { 364 list_for_each_entry(net, &net_kill_list, cleanup_list) {
289 list_del_rcu(&net->list); 365 list_del_rcu(&net->list);
290 list_add_tail(&net->exit_list, &net_exit_list); 366 list_add_tail(&net->exit_list, &net_exit_list);
367 for_each_net(tmp) {
368 int id = __peernet2id(tmp, net, false);
369
370 if (id >= 0)
371 idr_remove(&tmp->netns_ids, id);
372 }
373 idr_destroy(&net->netns_ids);
374
291 } 375 }
292 rtnl_unlock(); 376 rtnl_unlock();
293 377
@@ -402,6 +486,130 @@ static struct pernet_operations __net_initdata net_ns_ops = {
402 .exit = net_ns_net_exit, 486 .exit = net_ns_net_exit,
403}; 487};
404 488
489static struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
490 [NETNSA_NONE] = { .type = NLA_UNSPEC },
491 [NETNSA_NSID] = { .type = NLA_S32 },
492 [NETNSA_PID] = { .type = NLA_U32 },
493 [NETNSA_FD] = { .type = NLA_U32 },
494};
495
496static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh)
497{
498 struct net *net = sock_net(skb->sk);
499 struct nlattr *tb[NETNSA_MAX + 1];
500 struct net *peer;
501 int nsid, err;
502
503 err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
504 rtnl_net_policy);
505 if (err < 0)
506 return err;
507 if (!tb[NETNSA_NSID])
508 return -EINVAL;
509 nsid = nla_get_s32(tb[NETNSA_NSID]);
510
511 if (tb[NETNSA_PID])
512 peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID]));
513 else if (tb[NETNSA_FD])
514 peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
515 else
516 return -EINVAL;
517 if (IS_ERR(peer))
518 return PTR_ERR(peer);
519
520 if (__peernet2id(net, peer, false) >= 0) {
521 err = -EEXIST;
522 goto out;
523 }
524
525 err = alloc_netid(net, peer, nsid);
526 if (err > 0)
527 err = 0;
528out:
529 put_net(peer);
530 return err;
531}
532
533static int rtnl_net_get_size(void)
534{
535 return NLMSG_ALIGN(sizeof(struct rtgenmsg))
536 + nla_total_size(sizeof(s32)) /* NETNSA_NSID */
537 ;
538}
539
540static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
541 int cmd, struct net *net, struct net *peer)
542{
543 struct nlmsghdr *nlh;
544 struct rtgenmsg *rth;
545 int id;
546
547 ASSERT_RTNL();
548
549 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rth), flags);
550 if (!nlh)
551 return -EMSGSIZE;
552
553 rth = nlmsg_data(nlh);
554 rth->rtgen_family = AF_UNSPEC;
555
556 id = __peernet2id(net, peer, false);
557 if (id < 0)
558 id = NETNSA_NSID_NOT_ASSIGNED;
559 if (nla_put_s32(skb, NETNSA_NSID, id))
560 goto nla_put_failure;
561
562 nlmsg_end(skb, nlh);
563 return 0;
564
565nla_put_failure:
566 nlmsg_cancel(skb, nlh);
567 return -EMSGSIZE;
568}
569
570static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh)
571{
572 struct net *net = sock_net(skb->sk);
573 struct nlattr *tb[NETNSA_MAX + 1];
574 struct sk_buff *msg;
575 int err = -ENOBUFS;
576 struct net *peer;
577
578 err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
579 rtnl_net_policy);
580 if (err < 0)
581 return err;
582 if (tb[NETNSA_PID])
583 peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID]));
584 else if (tb[NETNSA_FD])
585 peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD]));
586 else
587 return -EINVAL;
588
589 if (IS_ERR(peer))
590 return PTR_ERR(peer);
591
592 msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
593 if (!msg) {
594 err = -ENOMEM;
595 goto out;
596 }
597
598 err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
599 RTM_GETNSID, net, peer);
600 if (err < 0)
601 goto err_out;
602
603 err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid);
604 goto out;
605
606err_out:
607 nlmsg_free(msg);
608out:
609 put_net(peer);
610 return err;
611}
612
405static int __init net_ns_init(void) 613static int __init net_ns_init(void)
406{ 614{
407 struct net_generic *ng; 615 struct net_generic *ng;
@@ -435,6 +643,9 @@ static int __init net_ns_init(void)
435 643
436 register_pernet_subsys(&net_ns_ops); 644 register_pernet_subsys(&net_ns_ops);
437 645
646 rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, NULL);
647 rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, NULL, NULL);
648
438 return 0; 649 return 0;
439} 650}
440 651