* [RFC PATCH net-next 1/5] netns: allocate an unique id to identify a netns
2012-12-12 17:24 [RFC PATCH net-next 0/5] Ease netns management by userland Nicolas Dichtel
@ 2012-12-12 17:24 ` Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 2/5] netns: allow to dump netns with netlink Nicolas Dichtel
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dichtel @ 2012-12-12 17:24 UTC (permalink / raw)
To: netdev; +Cc: davem, ebiederm, aatteka, Nicolas Dichtel
This patch simply adds a field nsindex, which will contain a unique index.
The goal is to prepare the monitoring of netns activities with rtnelink and to
ease netns management by userland apps.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/net/net_namespace.h | 1 +
net/core/net_namespace.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index c5a43f5..5db7a1b 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -55,6 +55,7 @@ struct net {
struct list_head exit_list; /* Use only net_mutex */
struct user_namespace *user_ns; /* Owning user namespace */
+ int nsindex; /* index to identify this ns */
struct proc_dir_entry *proc_net;
struct proc_dir_entry *proc_net_stat;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 6456439..f5267e4 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -27,6 +27,7 @@ static DEFINE_MUTEX(net_mutex);
LIST_HEAD(net_namespace_list);
EXPORT_SYMBOL_GPL(net_namespace_list);
+static DEFINE_IDA(net_namespace_ids);
struct net init_net = {
.dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head),
@@ -157,6 +158,15 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
atomic_set(&net->passive, 1);
net->dev_base_seq = 1;
net->user_ns = user_ns;
+again:
+ error = ida_get_new_above(&net_namespace_ids, 1, &net->nsindex);
+ if (error < 0) {
+ if (error == -EAGAIN) {
+ ida_pre_get(&net_namespace_ids, GFP_KERNEL);
+ goto again;
+ }
+ return error;
+ }
#ifdef NETNS_REFCNT_DEBUG
atomic_set(&net->use_count, 0);
@@ -171,6 +181,7 @@ out:
return error;
out_undo:
+ ida_remove(&net_namespace_ids, net->nsindex);
/* Walk through the list backwards calling the exit functions
* for the pernet modules whose init functions did not fail.
*/
@@ -297,6 +308,11 @@ static void cleanup_net(struct work_struct *work)
*/
synchronize_rcu();
+ list_for_each_entry(net, &net_exit_list, exit_list) {
+ /* Free the index */
+ ida_remove(&net_namespace_ids, net->nsindex);
+ }
+
/* Run all of the network namespace exit methods */
list_for_each_entry_reverse(ops, &pernet_list, list)
ops_exit_list(ops, &net_exit_list);
--
1.8.0.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH net-next 2/5] netns: allow to dump netns with netlink
2012-12-12 17:24 [RFC PATCH net-next 0/5] Ease netns management by userland Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 1/5] netns: allocate an unique id to identify a netns Nicolas Dichtel
@ 2012-12-12 17:24 ` Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 3/5] dev/netns: allow to get netns from nsindex in rtnl msg Nicolas Dichtel
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dichtel @ 2012-12-12 17:24 UTC (permalink / raw)
To: netdev; +Cc: davem, ebiederm, aatteka, Nicolas Dichtel
This patch adds the basic support of netlink for netns. The user can dump all
existing netns and get associated nsindex.
He also can get nsindex associated to a pid or fd.
To initialize genetlink family for netns, there is a problem of chicken and
eggs. genetlink init is done after init_net is created, hence when init_net is
created, we cannot call genl_register_family_with_ops(). It's why I put the
init part in genetlink module.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/net/net_namespace.h | 1 +
include/uapi/linux/netns.h | 27 ++++++++
net/core/net_namespace.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
net/netlink/genetlink.c | 4 ++
4 files changed, 189 insertions(+)
create mode 100644 include/uapi/linux/netns.h
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 5db7a1b..c373f2e 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -306,6 +306,7 @@ extern int register_pernet_subsys(struct pernet_operations *);
extern void unregister_pernet_subsys(struct pernet_operations *);
extern int register_pernet_device(struct pernet_operations *);
extern void unregister_pernet_device(struct pernet_operations *);
+extern int netns_genl_register(void);
struct ctl_table;
struct ctl_table_header;
diff --git a/include/uapi/linux/netns.h b/include/uapi/linux/netns.h
new file mode 100644
index 0000000..e1c1da3
--- /dev/null
+++ b/include/uapi/linux/netns.h
@@ -0,0 +1,27 @@
+#ifndef _UAPI_LINUX_NETNS_H_
+#define _UAPI_LINUX_NETNS_H_
+
+/* Generic netlink messages */
+
+#define NETNS_GENL_NAME "netns"
+#define NETNS_GENL_VERSION 0x1
+
+/* Commands */
+enum {
+ NETNS_CMD_NOOP,
+ NETNS_CMD_GET,
+ __NETNS_CMD_MAX,
+};
+#define NETNS_CMD_MAX (__NETNS_CMD_MAX - 1)
+
+/* Attributes */
+enum {
+ NETNSA_NONE,
+ NETNSA_NSINDEX,
+ NETNSA_PID,
+ NETNSA_FD,
+ __NETNSA_MAX,
+};
+#define NETNSA_MAX (__NETNSA_MAX - 1)
+
+#endif /* _UAPI_LINUX_NETNS_H_ */
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f5267e4..2ae22b0 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -14,6 +14,8 @@
#include <linux/file.h>
#include <linux/export.h>
#include <linux/user_namespace.h>
+#include <linux/netns.h>
+#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -397,6 +399,161 @@ struct net *get_net_ns_by_pid(pid_t pid)
}
EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
+static struct genl_family netns_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = NETNS_GENL_NAME,
+ .version = NETNS_GENL_VERSION,
+ .hdrsize = 0,
+ .maxattr = NETNSA_MAX,
+ .netnsok = true,
+};
+
+static struct nla_policy netns_nl_policy[NETNSA_MAX + 1] = {
+ [NETNSA_NONE] = { .type = NLA_UNSPEC, },
+ [NETNSA_NSINDEX] = { .type = NLA_U32, },
+ [NETNSA_PID] = { .type = NLA_U32 },
+ [NETNSA_FD] = { .type = NLA_U32 },
+};
+
+static int netns_nl_get_size(void)
+{
+ return nla_total_size(sizeof(u32)) /* NETNSA_NSINDEX */
+ ;
+}
+
+static int netns_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sk_buff *msg;
+ void *hdr;
+ int ret = -ENOBUFS;
+
+ msg = genlmsg_new(netns_nl_get_size(), GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+ &netns_nl_family, 0, NETNS_CMD_NOOP);
+ if (!hdr) {
+ ret = -EMSGSIZE;
+ goto err_out;
+ }
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid);
+
+err_out:
+ nlmsg_free(msg);
+
+out:
+ return ret;
+}
+
+static int netns_nl_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
+ int cmd, struct net *net)
+{
+ void *hdr;
+
+ hdr = genlmsg_put(skb, portid, seq, &netns_nl_family, flags, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (nla_put_u32(skb, NETNSA_NSINDEX, net->nsindex))
+ goto nla_put_failure;
+
+ return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+ genlmsg_cancel(skb, hdr);
+ return -EMSGSIZE;
+}
+
+static int netns_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net *net = genl_info_net(info);
+ struct sk_buff *msg;
+ int err = -ENOBUFS;
+
+ if (info->attrs[NETNSA_PID])
+ net = get_net_ns_by_pid(nla_get_u32(info->attrs[NETNSA_PID]));
+ else if (info->attrs[NETNSA_FD])
+ net = get_net_ns_by_fd(nla_get_u32(info->attrs[NETNSA_FD]));
+ else
+ get_net(net);
+
+ msg = genlmsg_new(netns_nl_get_size(), GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = netns_nl_fill(msg, info->snd_portid, info->snd_seq,
+ NLM_F_ACK, NETNS_CMD_GET, net);
+ if (err < 0)
+ goto err_out;
+
+ err = genlmsg_unicast(genl_info_net(info), msg, info->snd_portid);
+ goto out;
+
+err_out:
+ nlmsg_free(msg);
+
+out:
+ put_net(net);
+ return err;
+}
+
+static int netns_nl_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int i = 0, s_i = cb->args[0];
+ struct net *net;
+
+ rtnl_lock();
+ for_each_net(net) {
+ if (i < s_i) {
+ i++;
+ continue;
+ }
+
+ if (netns_nl_fill(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ NETNS_CMD_GET, net) <= 0)
+ goto out;
+
+ i++;
+ }
+
+out:
+ cb->args[0] = i;
+ rtnl_unlock();
+
+ return skb->len;
+}
+
+static struct genl_ops netns_nl_ops[] = {
+ {
+ .cmd = NETNS_CMD_NOOP,
+ .policy = netns_nl_policy,
+ .doit = netns_nl_cmd_noop,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NETNS_CMD_GET,
+ .policy = netns_nl_policy,
+ .doit = netns_nl_cmd_get,
+ .dumpit = netns_nl_cmd_dump,
+ .flags = GENL_ADMIN_PERM,
+ },
+};
+
+int netns_genl_register(void)
+{
+ return genl_register_family_with_ops(&netns_nl_family, netns_nl_ops,
+ ARRAY_SIZE(netns_nl_ops));
+}
+
static int __init net_ns_init(void)
{
struct net_generic *ng;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f2aabb6..6d25ddb 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -963,6 +963,10 @@ static int __init genl_init(void)
if (err < 0)
goto problem;
+ err = netns_genl_register();
+ if (err < 0)
+ goto problem;
+
return 0;
problem:
--
1.8.0.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH net-next 3/5] dev/netns: allow to get netns from nsindex in rtnl msg
2012-12-12 17:24 [RFC PATCH net-next 0/5] Ease netns management by userland Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 1/5] netns: allocate an unique id to identify a netns Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 2/5] netns: allow to dump netns with netlink Nicolas Dichtel
@ 2012-12-12 17:24 ` Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 4/5] netns: advertise netns activity with netlink Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 5/5] net/sock: add support of SO_NETNS Nicolas Dichtel
4 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dichtel @ 2012-12-12 17:24 UTC (permalink / raw)
To: netdev; +Cc: davem, ebiederm, aatteka, Nicolas Dichtel
This patch allows to move a netdevice to another netns by giving the nsindex.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/net/net_namespace.h | 1 +
include/uapi/linux/if_link.h | 1 +
net/core/net_namespace.c | 14 ++++++++++++++
net/core/rtnetlink.c | 7 ++++++-
4 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index c373f2e..68e7a36 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -151,6 +151,7 @@ extern struct list_head net_namespace_list;
extern struct net *get_net_ns_by_pid(pid_t pid);
extern struct net *get_net_ns_by_fd(int pid);
+extern struct net *get_net_ns_by_nsindex(int nsindex);
#ifdef CONFIG_NET_NS
extern void __put_net(struct net *net);
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 60f3b6b..6720a47 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -142,6 +142,7 @@ enum {
#define IFLA_PROMISCUITY IFLA_PROMISCUITY
IFLA_NUM_TX_QUEUES,
IFLA_NUM_RX_QUEUES,
+ IFLA_NET_NS_INDEX,
__IFLA_MAX
};
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 2ae22b0..18fc62f 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -399,6 +399,20 @@ struct net *get_net_ns_by_pid(pid_t pid)
}
EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
+struct net *get_net_ns_by_nsindex(int nsindex)
+{
+ struct net *net;
+
+ ASSERT_RTNL();
+ for_each_net(net)
+ if (net->nsindex == nsindex) {
+ get_net(net);
+ break;
+ }
+ return net;
+}
+EXPORT_SYMBOL_GPL(get_net_ns_by_nsindex);
+
static struct genl_family netns_nl_family = {
.id = GENL_ID_GENERATE,
.name = NETNS_GENL_NAME,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1868625..e22954a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1115,6 +1115,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_LINKINFO] = { .type = NLA_NESTED },
[IFLA_NET_NS_PID] = { .type = NLA_U32 },
[IFLA_NET_NS_FD] = { .type = NLA_U32 },
+ [IFLA_NET_NS_INDEX] = { .type = NLA_U32 },
[IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 },
[IFLA_VFINFO_LIST] = {. type = NLA_NESTED },
[IFLA_VF_PORTS] = { .type = NLA_NESTED },
@@ -1171,6 +1172,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
else if (tb[IFLA_NET_NS_FD])
net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
+ else if (tb[IFLA_NET_NS_INDEX])
+ net = get_net_ns_by_nsindex(nla_get_u32(tb[IFLA_NET_NS_INDEX]));
else
net = get_net(src_net);
return net;
@@ -1310,7 +1313,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
int send_addr_notify = 0;
int err;
- if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
+ if (tb[IFLA_NET_NS_PID] ||
+ tb[IFLA_NET_NS_FD] ||
+ tb[IFLA_NET_NS_INDEX]) {
struct net *net = rtnl_link_get_net(dev_net(dev), tb);
if (IS_ERR(net)) {
err = PTR_ERR(net);
--
1.8.0.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH net-next 4/5] netns: advertise netns activity with netlink
2012-12-12 17:24 [RFC PATCH net-next 0/5] Ease netns management by userland Nicolas Dichtel
` (2 preceding siblings ...)
2012-12-12 17:24 ` [RFC PATCH net-next 3/5] dev/netns: allow to get netns from nsindex in rtnl msg Nicolas Dichtel
@ 2012-12-12 17:24 ` Nicolas Dichtel
2012-12-12 17:24 ` [RFC PATCH net-next 5/5] net/sock: add support of SO_NETNS Nicolas Dichtel
4 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dichtel @ 2012-12-12 17:24 UTC (permalink / raw)
To: netdev; +Cc: davem, ebiederm, aatteka, Nicolas Dichtel
Goal of this patch is to send netlink messages when netns are crated/deleted.
This is useful for daemon that wants to manage all netns with only one running
instance.
Note that until that netns_nl_event_mcgrp group is not registered, we cannot
send event.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/uapi/linux/netns.h | 4 ++++
net/core/net_namespace.c | 38 +++++++++++++++++++++++++++++++++++++-
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/netns.h b/include/uapi/linux/netns.h
index e1c1da3..e14d90b 100644
--- a/include/uapi/linux/netns.h
+++ b/include/uapi/linux/netns.h
@@ -6,10 +6,14 @@
#define NETNS_GENL_NAME "netns"
#define NETNS_GENL_VERSION 0x1
+#define NETNS_GENL_MCAST_EVENT_NAME "events"
+
/* Commands */
enum {
NETNS_CMD_NOOP,
NETNS_CMD_GET,
+ NETNS_CMD_NEW,
+ NETNS_CMD_DEL,
__NETNS_CMD_MAX,
};
#define NETNS_CMD_MAX (__NETNS_CMD_MAX - 1)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 18fc62f..da92ecb 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -40,6 +40,8 @@ EXPORT_SYMBOL(init_net);
static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS;
+static int netns_nl_event(struct net *net, int cmd);
+
static struct net_generic *net_alloc_generic(void)
{
struct net_generic *ng;
@@ -179,6 +181,7 @@ again:
if (error < 0)
goto out_undo;
}
+ netns_nl_event(net, NETNS_CMD_NEW);
out:
return error;
@@ -311,6 +314,7 @@ static void cleanup_net(struct work_struct *work)
synchronize_rcu();
list_for_each_entry(net, &net_exit_list, exit_list) {
+ netns_nl_event(net, NETNS_CMD_DEL);
/* Free the index */
ida_remove(&net_namespace_ids, net->nsindex);
}
@@ -413,6 +417,10 @@ struct net *get_net_ns_by_nsindex(int nsindex)
}
EXPORT_SYMBOL_GPL(get_net_ns_by_nsindex);
+static struct genl_multicast_group netns_nl_event_mcgrp = {
+ .name = NETNS_GENL_MCAST_EVENT_NAME,
+};
+
static struct genl_family netns_nl_family = {
.id = GENL_ID_GENERATE,
.name = NETNS_GENL_NAME,
@@ -562,10 +570,38 @@ static struct genl_ops netns_nl_ops[] = {
},
};
+static int netns_nl_event(struct net *net, int cmd)
+{
+ struct sk_buff *msg;
+ int err = -ENOBUFS;
+
+ /* Check that gennl infra is ready */
+ if (!netns_nl_event_mcgrp.id)
+ return -ENOENT;
+
+ msg = genlmsg_new(netns_nl_get_size(), GFP_ATOMIC);
+ if (!msg)
+ return -ENOMEM;
+
+ err = netns_nl_fill(msg, 0, 0, 0, cmd, net);
+ if (err < 0) {
+ nlmsg_free(msg);
+ return err;
+ }
+
+ return genlmsg_multicast(msg, 0, netns_nl_event_mcgrp.id, GFP_ATOMIC);
+}
+
int netns_genl_register(void)
{
- return genl_register_family_with_ops(&netns_nl_family, netns_nl_ops,
+ int err;
+
+ err = genl_register_family_with_ops(&netns_nl_family, netns_nl_ops,
ARRAY_SIZE(netns_nl_ops));
+ if (err < 0)
+ return err;
+
+ return genl_register_mc_group(&netns_nl_family, &netns_nl_event_mcgrp);
}
static int __init net_ns_init(void)
--
1.8.0.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH net-next 5/5] net/sock: add support of SO_NETNS
2012-12-12 17:24 [RFC PATCH net-next 0/5] Ease netns management by userland Nicolas Dichtel
` (3 preceding siblings ...)
2012-12-12 17:24 ` [RFC PATCH net-next 4/5] netns: advertise netns activity with netlink Nicolas Dichtel
@ 2012-12-12 17:24 ` Nicolas Dichtel
4 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dichtel @ 2012-12-12 17:24 UTC (permalink / raw)
To: netdev; +Cc: davem, ebiederm, aatteka, Nicolas Dichtel
This new setsockopt() option allows user to change netns of a socket. It
should be done enough early, before any bind(), etc.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
arch/alpha/include/asm/socket.h | 2 ++
arch/avr32/include/uapi/asm/socket.h | 2 ++
arch/frv/include/uapi/asm/socket.h | 2 ++
arch/h8300/include/asm/socket.h | 2 ++
arch/ia64/include/uapi/asm/socket.h | 2 ++
arch/m32r/include/asm/socket.h | 2 ++
arch/m68k/include/uapi/asm/socket.h | 2 ++
arch/mips/include/uapi/asm/socket.h | 2 ++
arch/mn10300/include/uapi/asm/socket.h | 2 ++
arch/parisc/include/uapi/asm/socket.h | 2 ++
arch/powerpc/include/uapi/asm/socket.h | 2 ++
arch/s390/include/uapi/asm/socket.h | 2 ++
arch/sparc/include/uapi/asm/socket.h | 2 ++
arch/xtensa/include/uapi/asm/socket.h | 2 ++
include/uapi/asm-generic/socket.h | 2 ++
net/core/sock.c | 28 ++++++++++++++++++++++++++++
16 files changed, 58 insertions(+)
diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h
index 0087d05..13aa509 100644
--- a/arch/alpha/include/asm/socket.h
+++ b/arch/alpha/include/asm/socket.h
@@ -77,6 +77,8 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#ifdef __KERNEL__
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 486df68..39cc927 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* __ASM_AVR32_SOCKET_H */
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index 871f89b..ac7eef6 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -70,5 +70,7 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h
index 90a2e57..4d2a4e8 100644
--- a/arch/h8300/include/asm/socket.h
+++ b/arch/h8300/include/asm/socket.h
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index 23d6759..ed4534b 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -79,4 +79,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h
index 5e7088a..37d0eb0 100644
--- a/arch/m32r/include/asm/socket.h
+++ b/arch/m32r/include/asm/socket.h
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/m68k/include/uapi/asm/socket.h b/arch/m68k/include/uapi/asm/socket.h
index 285da3b..e79aad8 100644
--- a/arch/m68k/include/uapi/asm/socket.h
+++ b/arch/m68k/include/uapi/asm/socket.h
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 17307ab..356f943 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -90,5 +90,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index af5366b..b899cf8 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index d9ff473..8503329 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -69,6 +69,8 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 0x4024
+#define SO_NETNS 0x4025
+
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index eb0b186..1a520ff 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -77,4 +77,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 436d07c..cbdda59 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -76,4 +76,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index c83a937..c1c2853 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -66,6 +66,8 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 0x0027
+#define SO_NETNS 0x0028
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h
index 38079be..a8f956d 100644
--- a/arch/xtensa/include/uapi/asm/socket.h
+++ b/arch/xtensa/include/uapi/asm/socket.h
@@ -81,4 +81,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* _XTENSA_SOCKET_H */
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 2d32d07..08c108c 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -73,4 +73,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_NETNS 44
+
#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/net/core/sock.c b/net/core/sock.c
index a692ef4..7ec288f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -895,6 +895,30 @@ set_rcvbuf:
sock_valbool_flag(sk, SOCK_NOFCS, valbool);
break;
+ case SO_NETNS:
+#ifdef CONFIG_NET_NS
+ if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
+ ret = -EPERM;
+ else if (sk->sk_state != TCP_CLOSE)
+ ret = -EBUSY; /* Too late to change netns */
+ else {
+ struct net *net = get_net_ns_by_nsindex(val);
+
+ if (net) {
+ /* We can not use sk_change_net() because sk
+ * will not be released with
+ * sk_release_kernel(). Let do it manually.
+ */
+ put_net(sock_net(sk));
+ sock_net_set(sk, net);
+ } else
+ ret = -EINVAL;
+ }
+#else
+ ret = -EOPNOTSUPP;
+#endif
+ break;
+
default:
ret = -ENOPROTOOPT;
break;
@@ -1140,6 +1164,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
goto lenout;
+ case SO_NETNS:
+ v.val = sock_net(sk)->nsindex;
+ break;
+
default:
return -ENOPROTOOPT;
}
--
1.8.0.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC PATCH net-next 2/5] netns: allow to dump netns with netlink
2012-12-12 17:17 [RFC PATCH net-next 0/5] Ease netns management for userland Nicolas Dichtel
@ 2012-12-12 17:17 ` Nicolas Dichtel
0 siblings, 0 replies; 7+ messages in thread
From: Nicolas Dichtel @ 2012-12-12 17:17 UTC (permalink / raw)
To: netdev; +Cc: davem, ebiederm, aatteka, Nicolas Dichtel
This patch adds the basic support of netlink for netns. The user can dump all
existing netns and get associated nsindex.
He also can get nsindex associated to a pid or fd.
To initialize genetlink family for netns, there is a problem of chicken and
eggs. genetlink init is done after init_net is created, hence when init_net is
created, we cannot call genl_register_family_with_ops(). It's why I put the
init part in genetlink module.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
include/net/net_namespace.h | 1 +
include/uapi/linux/netns.h | 27 ++++++++
net/core/net_namespace.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
net/netlink/genetlink.c | 4 ++
4 files changed, 189 insertions(+)
create mode 100644 include/uapi/linux/netns.h
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 5db7a1b..c373f2e 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -306,6 +306,7 @@ extern int register_pernet_subsys(struct pernet_operations *);
extern void unregister_pernet_subsys(struct pernet_operations *);
extern int register_pernet_device(struct pernet_operations *);
extern void unregister_pernet_device(struct pernet_operations *);
+extern int netns_genl_register(void);
struct ctl_table;
struct ctl_table_header;
diff --git a/include/uapi/linux/netns.h b/include/uapi/linux/netns.h
new file mode 100644
index 0000000..e1c1da3
--- /dev/null
+++ b/include/uapi/linux/netns.h
@@ -0,0 +1,27 @@
+#ifndef _UAPI_LINUX_NETNS_H_
+#define _UAPI_LINUX_NETNS_H_
+
+/* Generic netlink messages */
+
+#define NETNS_GENL_NAME "netns"
+#define NETNS_GENL_VERSION 0x1
+
+/* Commands */
+enum {
+ NETNS_CMD_NOOP,
+ NETNS_CMD_GET,
+ __NETNS_CMD_MAX,
+};
+#define NETNS_CMD_MAX (__NETNS_CMD_MAX - 1)
+
+/* Attributes */
+enum {
+ NETNSA_NONE,
+ NETNSA_NSINDEX,
+ NETNSA_PID,
+ NETNSA_FD,
+ __NETNSA_MAX,
+};
+#define NETNSA_MAX (__NETNSA_MAX - 1)
+
+#endif /* _UAPI_LINUX_NETNS_H_ */
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f5267e4..2ae22b0 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -14,6 +14,8 @@
#include <linux/file.h>
#include <linux/export.h>
#include <linux/user_namespace.h>
+#include <linux/netns.h>
+#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -397,6 +399,161 @@ struct net *get_net_ns_by_pid(pid_t pid)
}
EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
+static struct genl_family netns_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = NETNS_GENL_NAME,
+ .version = NETNS_GENL_VERSION,
+ .hdrsize = 0,
+ .maxattr = NETNSA_MAX,
+ .netnsok = true,
+};
+
+static struct nla_policy netns_nl_policy[NETNSA_MAX + 1] = {
+ [NETNSA_NONE] = { .type = NLA_UNSPEC, },
+ [NETNSA_NSINDEX] = { .type = NLA_U32, },
+ [NETNSA_PID] = { .type = NLA_U32 },
+ [NETNSA_FD] = { .type = NLA_U32 },
+};
+
+static int netns_nl_get_size(void)
+{
+ return nla_total_size(sizeof(u32)) /* NETNSA_NSINDEX */
+ ;
+}
+
+static int netns_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sk_buff *msg;
+ void *hdr;
+ int ret = -ENOBUFS;
+
+ msg = genlmsg_new(netns_nl_get_size(), GFP_KERNEL);
+ if (!msg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+ &netns_nl_family, 0, NETNS_CMD_NOOP);
+ if (!hdr) {
+ ret = -EMSGSIZE;
+ goto err_out;
+ }
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid);
+
+err_out:
+ nlmsg_free(msg);
+
+out:
+ return ret;
+}
+
+static int netns_nl_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags,
+ int cmd, struct net *net)
+{
+ void *hdr;
+
+ hdr = genlmsg_put(skb, portid, seq, &netns_nl_family, flags, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (nla_put_u32(skb, NETNSA_NSINDEX, net->nsindex))
+ goto nla_put_failure;
+
+ return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+ genlmsg_cancel(skb, hdr);
+ return -EMSGSIZE;
+}
+
+static int netns_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net *net = genl_info_net(info);
+ struct sk_buff *msg;
+ int err = -ENOBUFS;
+
+ if (info->attrs[NETNSA_PID])
+ net = get_net_ns_by_pid(nla_get_u32(info->attrs[NETNSA_PID]));
+ else if (info->attrs[NETNSA_FD])
+ net = get_net_ns_by_fd(nla_get_u32(info->attrs[NETNSA_FD]));
+ else
+ get_net(net);
+
+ msg = genlmsg_new(netns_nl_get_size(), GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = netns_nl_fill(msg, info->snd_portid, info->snd_seq,
+ NLM_F_ACK, NETNS_CMD_GET, net);
+ if (err < 0)
+ goto err_out;
+
+ err = genlmsg_unicast(genl_info_net(info), msg, info->snd_portid);
+ goto out;
+
+err_out:
+ nlmsg_free(msg);
+
+out:
+ put_net(net);
+ return err;
+}
+
+static int netns_nl_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int i = 0, s_i = cb->args[0];
+ struct net *net;
+
+ rtnl_lock();
+ for_each_net(net) {
+ if (i < s_i) {
+ i++;
+ continue;
+ }
+
+ if (netns_nl_fill(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ NETNS_CMD_GET, net) <= 0)
+ goto out;
+
+ i++;
+ }
+
+out:
+ cb->args[0] = i;
+ rtnl_unlock();
+
+ return skb->len;
+}
+
+static struct genl_ops netns_nl_ops[] = {
+ {
+ .cmd = NETNS_CMD_NOOP,
+ .policy = netns_nl_policy,
+ .doit = netns_nl_cmd_noop,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NETNS_CMD_GET,
+ .policy = netns_nl_policy,
+ .doit = netns_nl_cmd_get,
+ .dumpit = netns_nl_cmd_dump,
+ .flags = GENL_ADMIN_PERM,
+ },
+};
+
+int netns_genl_register(void)
+{
+ return genl_register_family_with_ops(&netns_nl_family, netns_nl_ops,
+ ARRAY_SIZE(netns_nl_ops));
+}
+
static int __init net_ns_init(void)
{
struct net_generic *ng;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f2aabb6..6d25ddb 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -963,6 +963,10 @@ static int __init genl_init(void)
if (err < 0)
goto problem;
+ err = netns_genl_register();
+ if (err < 0)
+ goto problem;
+
return 0;
problem:
--
1.8.0.1
^ permalink raw reply related [flat|nested] 7+ messages in thread