aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--include/net/net_namespace.h4
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/net_namespace.h23
-rw-r--r--include/uapi/linux/rtnetlink.h5
-rw-r--r--net/core/net_namespace.c211
6 files changed, 245 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9de900572633..9b91d9f0257e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6578,6 +6578,7 @@ F: include/linux/netdevice.h
6578F: include/uapi/linux/in.h 6578F: include/uapi/linux/in.h
6579F: include/uapi/linux/net.h 6579F: include/uapi/linux/net.h
6580F: include/uapi/linux/netdevice.h 6580F: include/uapi/linux/netdevice.h
6581F: include/uapi/linux/net_namespace.h
6581F: tools/net/ 6582F: tools/net/
6582F: tools/testing/selftests/net/ 6583F: tools/testing/selftests/net/
6583F: lib/random32.c 6584F: lib/random32.c
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 2e8756b8c775..36faf4990c4b 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -60,6 +60,7 @@ struct net {
60 struct list_head exit_list; /* Use only net_mutex */ 60 struct list_head exit_list; /* Use only net_mutex */
61 61
62 struct user_namespace *user_ns; /* Owning user namespace */ 62 struct user_namespace *user_ns; /* Owning user namespace */
63 struct idr netns_ids;
63 64
64 struct ns_common ns; 65 struct ns_common ns;
65 66
@@ -290,6 +291,9 @@ static inline struct net *read_pnet(struct net * const *pnet)
290#define __net_initconst __initconst 291#define __net_initconst __initconst
291#endif 292#endif
292 293
294int peernet2id(struct net *net, struct net *peer);
295struct net *get_net_ns_by_id(struct net *net, int id);
296
293struct pernet_operations { 297struct pernet_operations {
294 struct list_head list; 298 struct list_head list;
295 int (*init)(struct net *net); 299 int (*init)(struct net *net);
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 00b100023c47..14b7b6e44c77 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -283,6 +283,7 @@ header-y += net.h
283header-y += netlink_diag.h 283header-y += netlink_diag.h
284header-y += netlink.h 284header-y += netlink.h
285header-y += netrom.h 285header-y += netrom.h
286header-y += net_namespace.h
286header-y += net_tstamp.h 287header-y += net_tstamp.h
287header-y += nfc.h 288header-y += nfc.h
288header-y += nfs2.h 289header-y += nfs2.h
diff --git a/include/uapi/linux/net_namespace.h b/include/uapi/linux/net_namespace.h
new file mode 100644
index 000000000000..778cd2c3ebf4
--- /dev/null
+++ b/include/uapi/linux/net_namespace.h
@@ -0,0 +1,23 @@
1/* Copyright (c) 2015 6WIND S.A.
2 * Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 */
8#ifndef _UAPI_LINUX_NET_NAMESPACE_H_
9#define _UAPI_LINUX_NET_NAMESPACE_H_
10
11/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
12enum {
13 NETNSA_NONE,
14#define NETNSA_NSID_NOT_ASSIGNED -1
15 NETNSA_NSID,
16 NETNSA_PID,
17 NETNSA_FD,
18 __NETNSA_MAX,
19};
20
21#define NETNSA_MAX (__NETNSA_MAX - 1)
22
23#endif /* _UAPI_LINUX_NET_NAMESPACE_H_ */
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index a1d18593f41e..5cc5d66bf519 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -132,6 +132,11 @@ enum {
132 RTM_GETMDB = 86, 132 RTM_GETMDB = 86,
133#define RTM_GETMDB RTM_GETMDB 133#define RTM_GETMDB RTM_GETMDB
134 134
135 RTM_NEWNSID = 88,
136#define RTM_NEWNSID RTM_NEWNSID
137 RTM_GETNSID = 90,
138#define RTM_GETNSID RTM_GETNSID
139
135 __RTM_MAX, 140 __RTM_MAX,
136#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) 141#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
137}; 142};
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