All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] genetlink: make netns aware
@ 2009-06-17 19:33 Johannes Berg
  2009-06-17 21:19 ` Eric W. Biederman
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Johannes Berg @ 2009-06-17 19:33 UTC (permalink / raw)
  To: Netdev; +Cc: Thomas Graf, Eric W. Biederman, Alexey Dobriyan

This makes generic netlink network namespace aware.
No actual generic netlink families are made namespace
aware, they need to be checked one by one and then
set the family->netnsok member to true.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
I created this patch against wireless-testing and added the one hunk
that was necessary against net-next (ieee80215 stack) to the end of the
patch manually. As a result, there's one hunk in here that cannot apply
against net-next currently because it's not in there yet. I can also
send a patch w/o that hunk, if preferred.

 drivers/acpi/event.c           |    2 
 fs/dlm/netlink.c               |    2 
 fs/quota/dquot.c               |    2 
 include/net/genetlink.h        |   20 +++--
 include/net/net_namespace.h    |    2 
 kernel/taskstats.c             |    4 -
 net/core/drop_monitor.c        |    2 
 net/irda/irnetlink.c           |    2 
 net/netfilter/ipvs/ip_vs_ctl.c |    2 
 net/netlink/genetlink.c        |  143 ++++++++++++++++++++++++++++++-----------
 net/tipc/netlink.c             |    2 
 net/wimax/op-msg.c             |    2 
 net/wimax/stack.c              |    2 
 net/wireless/nl80211.c         |   34 ++++-----
 net/ieee802154/netlink.c       |    3 +--
 15 files changed, 151 insertions(+), 73 deletions(-)

--- wireless-testing.orig/include/net/genetlink.h	2009-06-17 20:36:46.000000000 +0200
+++ wireless-testing/include/net/genetlink.h	2009-06-17 21:04:04.000000000 +0200
@@ -3,6 +3,7 @@
 
 #include <linux/genetlink.h>
 #include <net/netlink.h>
+#include <net/net_namespace.h>
 
 /**
  * struct genl_multicast_group - generic netlink multicast group
@@ -27,6 +28,8 @@ struct genl_multicast_group
  * @name: name of family
  * @version: protocol version
  * @maxattr: maximum number of attributes supported
+ * @netnsok: set to true if the family can handle network
+ *	namespaces and should be presented in all of them
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
@@ -39,6 +42,7 @@ struct genl_family
 	char			name[GENL_NAMSIZ];
 	unsigned int		version;
 	unsigned int		maxattr;
+	bool			netnsok;
 	struct nlattr **	attrbuf;	/* private */
 	struct list_head	ops_list;	/* private */
 	struct list_head	family_list;	/* private */
@@ -62,6 +66,7 @@ struct genl_info
 	struct genlmsghdr *	genlhdr;
 	void *			userhdr;
 	struct nlattr **	attrs;
+	struct net *		net;
 };
 
 /**
@@ -96,8 +101,6 @@ extern int genl_register_mc_group(struct
 extern void genl_unregister_mc_group(struct genl_family *family,
 				     struct genl_multicast_group *grp);
 
-extern struct sock *genl_sock;
-
 /**
  * genlmsg_put - Add generic netlink header to netlink message
  * @skb: socket buffer holding the message
@@ -174,10 +177,11 @@ static inline void genlmsg_cancel(struct
  * @group: multicast group id
  * @flags: allocation flags
  */
-static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
-				    unsigned int group, gfp_t flags)
+static inline int genlmsg_multicast(struct net *net, struct sk_buff *skb,
+				    u32 pid, unsigned int group,
+				    gfp_t flags)
 {
-	return nlmsg_multicast(genl_sock, skb, pid, group, flags);
+	return nlmsg_multicast(net->genl_sock, skb, pid, group, flags);
 }
 
 /**
@@ -185,9 +189,9 @@ static inline int genlmsg_multicast(stru
  * @skb: netlink message as socket buffer
  * @pid: netlink pid of the destination socket
  */
-static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
+static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid)
 {
-	return nlmsg_unicast(genl_sock, skb, pid);
+	return nlmsg_unicast(net->genl_sock, skb, pid);
 }
 
 /**
@@ -197,7 +201,7 @@ static inline int genlmsg_unicast(struct
  */
 static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
 {
-	return genlmsg_unicast(skb, info->snd_pid);
+	return genlmsg_unicast(info->net, skb, info->snd_pid);
 }
 
 /**
--- wireless-testing.orig/include/net/net_namespace.h	2009-06-17 20:36:59.000000000 +0200
+++ wireless-testing/include/net/net_namespace.h	2009-06-17 21:05:52.000000000 +0200
@@ -26,6 +26,7 @@ struct net_device;
 struct sock;
 struct ctl_table_header;
 struct net_generic;
+struct sock;
 
 struct net {
 	atomic_t		count;		/* To decided when the network
@@ -63,6 +64,7 @@ struct net {
 	struct netns_packet	packet;
 	struct netns_unix	unx;
 	struct netns_ipv4	ipv4;
+	struct sock		*genl_sock;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	struct netns_ipv6	ipv6;
 #endif
--- wireless-testing.orig/net/netlink/genetlink.c	2009-06-17 20:36:51.000000000 +0200
+++ wireless-testing/net/netlink/genetlink.c	2009-06-17 21:21:55.000000000 +0200
@@ -18,8 +18,6 @@
 #include <net/sock.h>
 #include <net/genetlink.h>
 
-struct sock *genl_sock = NULL;
-
 static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 
 static inline void genl_lock(void)
@@ -175,10 +173,28 @@ int genl_register_mc_group(struct genl_f
 		mc_groups_longs++;
 	}
 
-	err = netlink_change_ngroups(genl_sock,
-				     mc_groups_longs * BITS_PER_LONG);
-	if (err)
-		goto out;
+	if (family->netnsok) {
+		struct net *net;
+
+		for_each_net(net) {
+			err = netlink_change_ngroups(net->genl_sock,
+					mc_groups_longs * BITS_PER_LONG);
+			if (err) {
+				/*
+				 * No need to roll back can only fail
+				 * if memory allocation fails and then
+				 * the number of groups is larger for
+				 * some sockets which is ok.
+				 */
+				goto out;
+			}
+		}
+	} else {
+		err = netlink_change_ngroups(init_net.genl_sock,
+					     mc_groups_longs * BITS_PER_LONG);
+		if (err)
+			goto out;
+	}
 
 	grp->id = id;
 	set_bit(id, mc_groups);
@@ -195,8 +211,12 @@ EXPORT_SYMBOL(genl_register_mc_group);
 static void __genl_unregister_mc_group(struct genl_family *family,
 				       struct genl_multicast_group *grp)
 {
+	struct net *net;
 	BUG_ON(grp->family != family);
-	netlink_clear_multicast_users(genl_sock, grp->id);
+
+	for_each_net(net)
+		netlink_clear_multicast_users(net->genl_sock, grp->id);
+
 	clear_bit(grp->id, mc_groups);
 	list_del(&grp->list);
 	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
@@ -421,6 +441,7 @@ static int genl_rcv_msg(struct sk_buff *
 {
 	struct genl_ops *ops;
 	struct genl_family *family;
+	struct net *net = sock_net(skb->sk);
 	struct genl_info info;
 	struct genlmsghdr *hdr = nlmsg_data(nlh);
 	int hdrlen, err;
@@ -429,6 +450,10 @@ static int genl_rcv_msg(struct sk_buff *
 	if (family == NULL)
 		return -ENOENT;
 
+	/* this family doesn't exist in this netns */
+	if (!family->netnsok && net != &init_net)
+		return -ENOENT;
+
 	hdrlen = GENL_HDRLEN + family->hdrsize;
 	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
 		return -EINVAL;
@@ -446,7 +471,7 @@ static int genl_rcv_msg(struct sk_buff *
 			return -EOPNOTSUPP;
 
 		genl_unlock();
-		err = netlink_dump_start(genl_sock, skb, nlh,
+		err = netlink_dump_start(net->genl_sock, skb, nlh,
 					 ops->dumpit, ops->done);
 		genl_lock();
 		return err;
@@ -468,6 +493,7 @@ static int genl_rcv_msg(struct sk_buff *
 	info.genlhdr = nlmsg_data(nlh);
 	info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
 	info.attrs = family->attrbuf;
+	info.net = net;
 
 	return ops->doit(skb, &info);
 }
@@ -488,6 +514,7 @@ static struct genl_family genl_ctrl = {
 	.name = "nlctrl",
 	.version = 0x2,
 	.maxattr = CTRL_ATTR_MAX,
+	.netnsok = true,
 };
 
 static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
@@ -604,6 +631,7 @@ static int ctrl_dumpfamily(struct sk_buf
 
 	int i, n = 0;
 	struct genl_family *rt;
+	struct net *net = sock_net(skb->sk);
 	int chains_to_skip = cb->args[0];
 	int fams_to_skip = cb->args[1];
 
@@ -612,6 +640,8 @@ static int ctrl_dumpfamily(struct sk_buf
 			continue;
 		n = 0;
 		list_for_each_entry(rt, genl_family_chain(i), family_list) {
+			if (!rt->netnsok && net != &init_net)
+				continue;
 			if (++n < fams_to_skip)
 				continue;
 			if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
@@ -683,6 +713,7 @@ static int ctrl_getfamily(struct sk_buff
 	if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
 		u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
 		res = genl_family_find_byid(id);
+		err = -ENOENT;
 	}
 
 	if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
@@ -690,49 +721,67 @@ static int ctrl_getfamily(struct sk_buff
 
 		name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
 		res = genl_family_find_byname(name);
+		err = -ENOENT;
 	}
 
-	if (res == NULL) {
-		err = -ENOENT;
-		goto errout;
+	if (res == NULL)
+		return err;
+
+	if (!res->netnsok && info->net != &init_net) {
+		/* family doesn't exist here */
+		return -ENOENT;
 	}
 
 	msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
 				    CTRL_CMD_NEWFAMILY);
-	if (IS_ERR(msg)) {
-		err = PTR_ERR(msg);
-		goto errout;
-	}
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
 
-	err = genlmsg_reply(msg, info);
-errout:
-	return err;
+	return genlmsg_reply(msg, info);
 }
 
 static int genl_ctrl_event(int event, void *data)
 {
-	struct sk_buff *msg;
+	struct net *net;
+	struct sk_buff *msg, *skb;
+	struct genl_family *family;
+	struct genl_multicast_group *grp;
 
-	if (genl_sock == NULL)
+	/* genl is still initialising */
+	if (!init_net.genl_sock)
 		return 0;
 
 	switch (event) {
 	case CTRL_CMD_NEWFAMILY:
 	case CTRL_CMD_DELFAMILY:
-		msg = ctrl_build_family_msg(data, 0, 0, event);
-		if (IS_ERR(msg))
-			return PTR_ERR(msg);
-
-		genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+		family = data;
+		msg = ctrl_build_family_msg(family, 0, 0, event);
 		break;
 	case CTRL_CMD_NEWMCAST_GRP:
 	case CTRL_CMD_DELMCAST_GRP:
+		grp = data;
+		family = grp->family;
 		msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
-		if (IS_ERR(msg))
-			return PTR_ERR(msg);
-
-		genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
 		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	if (!family->netnsok)
+		genlmsg_multicast(&init_net, msg, 0,
+				  GENL_ID_CTRL, GFP_KERNEL);
+	else {
+		for_each_net(net) {
+			skb = skb_clone(msg, GFP_KERNEL);
+			if (!skb)
+				continue;
+			genlmsg_multicast(net, skb, 0, GENL_ID_CTRL,
+					  GFP_KERNEL);
+		}
+		kfree_skb(msg);
 	}
 
 	return 0;
@@ -749,6 +798,33 @@ static struct genl_multicast_group notif
 	.name		= "notify",
 };
 
+static int __net_init genl_pernet_init(struct net *net)
+{
+	/* we'll bump the group number right afterwards */
+	net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0,
+					       genl_rcv, &genl_mutex,
+					       THIS_MODULE);
+
+	if (!net->genl_sock && net == &init_net)
+		panic("GENL: Cannot initialize generic netlink\n");
+
+	if (!net->genl_sock)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void __net_exit genl_pernet_exit(struct net *net)
+{
+	netlink_kernel_release(net->genl_sock);
+	net->genl_sock = NULL;
+}
+
+static struct pernet_operations genl_pernet_ops = {
+	.init = genl_pernet_init,
+	.exit = genl_pernet_exit,
+};
+
 static int __init genl_init(void)
 {
 	int i, err;
@@ -766,11 +842,9 @@ static int __init genl_init(void)
 
 	netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
 
-	/* we'll bump the group number right afterwards */
-	genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0,
-					  genl_rcv, &genl_mutex, THIS_MODULE);
-	if (genl_sock == NULL)
-		panic("GENL: Cannot initialize generic netlink\n");
+	err = register_pernet_subsys(&genl_pernet_ops);
+	if (err)
+		goto errout_register;
 
 	err = genl_register_mc_group(&genl_ctrl, &notify_grp);
 	if (err < 0)
@@ -786,7 +860,6 @@ errout:
 
 subsys_initcall(genl_init);
 
-EXPORT_SYMBOL(genl_sock);
 EXPORT_SYMBOL(genl_register_ops);
 EXPORT_SYMBOL(genl_unregister_ops);
 EXPORT_SYMBOL(genl_register_family);
--- wireless-testing.orig/drivers/acpi/event.c	2009-04-09 10:00:06.000000000 +0200
+++ wireless-testing/drivers/acpi/event.c	2009-06-17 21:02:28.000000000 +0200
@@ -235,7 +235,7 @@ int acpi_bus_generate_netlink_event(cons
 		return result;
 	}
 
-	genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&init_net, skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
 	return 0;
 }
 
--- wireless-testing.orig/fs/dlm/netlink.c	2009-01-13 15:05:18.000000000 +0100
+++ wireless-testing/fs/dlm/netlink.c	2009-06-17 21:02:28.000000000 +0200
@@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb
 		return rv;
 	}
 
-	return genlmsg_unicast(skb, listener_nlpid);
+	return genlmsg_unicast(&init_net, skb, listener_nlpid);
 }
 
 static int user_cmd(struct sk_buff *skb, struct genl_info *info)
--- wireless-testing.orig/fs/quota/dquot.c	2009-04-09 10:00:33.000000000 +0200
+++ wireless-testing/fs/quota/dquot.c	2009-06-17 21:02:28.000000000 +0200
@@ -1130,7 +1130,7 @@ static void send_warning(const struct dq
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
 
-	genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS);
+	genlmsg_multicast(&init_net, skb, 0, quota_genl_family.id, GFP_NOFS);
 	return;
 attr_err_out:
 	printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
--- wireless-testing.orig/kernel/taskstats.c	2009-01-13 15:05:23.000000000 +0100
+++ wireless-testing/kernel/taskstats.c	2009-06-17 21:02:28.000000000 +0200
@@ -120,7 +120,7 @@ static int send_reply(struct sk_buff *sk
 		return rc;
 	}
 
-	return genlmsg_unicast(skb, pid);
+	return genlmsg_unicast(&init_net, skb, pid);
 }
 
 /*
@@ -150,7 +150,7 @@ static void send_cpu_listeners(struct sk
 			if (!skb_next)
 				break;
 		}
-		rc = genlmsg_unicast(skb_cur, s->pid);
+		rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
 		if (rc == -ECONNREFUSED) {
 			s->valid = 0;
 			delcount++;
--- wireless-testing.orig/net/core/drop_monitor.c	2009-04-09 10:00:38.000000000 +0200
+++ wireless-testing/net/core/drop_monitor.c	2009-06-17 21:02:28.000000000 +0200
@@ -94,7 +94,7 @@ static void send_dm_alert(struct work_st
 	/*
 	 * Ship it!
 	 */
-	genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
+	genlmsg_multicast(&init_net, skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
 
 }
 
--- wireless-testing.orig/net/irda/irnetlink.c	2008-12-19 00:28:09.000000000 +0100
+++ wireless-testing/net/irda/irnetlink.c	2009-06-17 21:02:28.000000000 +0200
@@ -115,7 +115,7 @@ static int irda_nl_get_mode(struct sk_bu
 
 	genlmsg_end(msg, hdr);
 
-	return genlmsg_unicast(msg, info->snd_pid);
+	return genlmsg_unicast(&init_net, msg, info->snd_pid);
 
  err_out:
 	nlmsg_free(msg);
--- wireless-testing.orig/net/netfilter/ipvs/ip_vs_ctl.c	2009-01-13 15:05:25.000000000 +0100
+++ wireless-testing/net/netfilter/ipvs/ip_vs_ctl.c	2009-06-17 21:02:28.000000000 +0200
@@ -3231,7 +3231,7 @@ static int ip_vs_genl_get_cmd(struct sk_
 	}
 
 	genlmsg_end(msg, reply);
-	ret = genlmsg_unicast(msg, info->snd_pid);
+	ret = genlmsg_unicast(&init_net, msg, info->snd_pid);
 	goto out;
 
 nla_put_failure:
--- wireless-testing.orig/net/tipc/netlink.c	2008-12-19 00:28:09.000000000 +0100
+++ wireless-testing/net/tipc/netlink.c	2009-06-17 21:02:28.000000000 +0200
@@ -62,7 +62,7 @@ static int handle_cmd(struct sk_buff *sk
 		rep_nlh = nlmsg_hdr(rep_buf);
 		memcpy(rep_nlh, req_nlh, hdr_space);
 		rep_nlh->nlmsg_len = rep_buf->len;
-		genlmsg_unicast(rep_buf, NETLINK_CB(skb).pid);
+		genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid);
 	}
 
 	return 0;
--- wireless-testing.orig/net/wimax/op-msg.c	2009-05-18 12:02:06.000000000 +0200
+++ wireless-testing/net/wimax/op-msg.c	2009-06-17 21:02:28.000000000 +0200
@@ -266,7 +266,7 @@ int wimax_msg_send(struct wimax_dev *wim
 
 	d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
 	d_dump(2, dev, msg, size);
-	genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
 	d_printf(1, dev, "CTX: genl multicast done\n");
 	return 0;
 }
--- wireless-testing.orig/net/wimax/stack.c	2009-05-18 12:02:06.000000000 +0200
+++ wireless-testing/net/wimax/stack.c	2009-06-17 21:02:28.000000000 +0200
@@ -168,7 +168,7 @@ int wimax_gnl_re_state_change_send(
 		goto out;
 	}
 	genlmsg_end(report_skb, header);
-	genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
 out:
 	d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
 		wimax_dev, report_skb, result);
--- wireless-testing.orig/net/wireless/nl80211.c	2009-06-17 20:25:59.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-06-17 21:10:32.000000000 +0200
@@ -398,7 +398,7 @@ static int nl80211_get_wiphy(struct sk_b
 
 	cfg80211_put_dev(dev);
 
-	return genlmsg_unicast(msg, info->snd_pid);
+	return genlmsg_unicast(&init_net, msg, info->snd_pid);
 
  out_free:
 	nlmsg_free(msg);
@@ -723,7 +723,7 @@ static int nl80211_get_interface(struct 
 	dev_put(netdev);
 	cfg80211_put_dev(dev);
 
-	return genlmsg_unicast(msg, info->snd_pid);
+	return genlmsg_unicast(&init_net, msg, info->snd_pid);
 
  out_free:
 	nlmsg_free(msg);
@@ -1014,7 +1014,7 @@ static int nl80211_get_key(struct sk_buf
 		goto nla_put_failure;
 
 	genlmsg_end(msg, hdr);
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_unicast(&init_net, msg, info->snd_pid);
 	goto out;
 
  nla_put_failure:
@@ -1602,7 +1602,7 @@ static int nl80211_get_station(struct sk
 				 dev, mac_addr, &sinfo) < 0)
 		goto out_free;
 
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_unicast(&init_net, msg, info->snd_pid);
 	goto out;
 
  out_free:
@@ -2006,7 +2006,7 @@ static int nl80211_get_mpath(struct sk_b
 				 dev, dst, next_hop, &pinfo) < 0)
 		goto out_free;
 
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_unicast(&init_net, msg, info->snd_pid);
 	goto out;
 
  out_free:
@@ -2355,7 +2355,7 @@ static int nl80211_get_mesh_params(struc
 			cur_params.dot11MeshHWMPnetDiameterTraversalTime);
 	nla_nest_end(msg, pinfoattr);
 	genlmsg_end(msg, hdr);
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_unicast(&init_net, msg, info->snd_pid);
 	goto out;
 
  nla_put_failure:
@@ -2543,7 +2543,7 @@ static int nl80211_get_reg(struct sk_buf
 	nla_nest_end(msg, nl_reg_rules);
 
 	genlmsg_end(msg, hdr);
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_unicast(&init_net, msg, info->snd_pid);
 	goto out;
 
 nla_put_failure:
@@ -3594,7 +3594,7 @@ void nl80211_notify_dev_rename(struct cf
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
 }
 
 static int nl80211_add_scan_req(struct sk_buff *msg,
@@ -3669,7 +3669,7 @@ void nl80211_send_scan_start(struct cfg8
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
 void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
@@ -3687,7 +3687,7 @@ void nl80211_send_scan_done(struct cfg80
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
 void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
@@ -3705,7 +3705,7 @@ void nl80211_send_scan_aborted(struct cf
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
 /*
@@ -3754,7 +3754,7 @@ void nl80211_send_reg_change_event(struc
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
 
 	return;
 
@@ -3790,7 +3790,7 @@ static void nl80211_send_mlme_event(stru
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
 	return;
 
  nla_put_failure:
@@ -3854,7 +3854,7 @@ static void nl80211_send_mlme_timeout(st
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
 	return;
 
  nla_put_failure:
@@ -3901,7 +3901,7 @@ void nl80211_send_ibss_bssid(struct cfg8
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_mlme_mcgrp.id, gfp);
 	return;
 
  nla_put_failure:
@@ -3941,7 +3941,7 @@ void nl80211_michael_mic_failure(struct 
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
 	return;
 
  nla_put_failure:
@@ -3994,7 +3994,7 @@ void nl80211_send_beacon_hint_event(stru
 		return;
 	}
 
-	genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&init_net, msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
 
 	return;
 
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -76,8 +76,7 @@ static int ieee802154_nl_finish(struct sk_buff *msg)
 	if (!genlmsg_end(msg, hdr))
 		goto out;
 
-	return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id,
-			GFP_ATOMIC);
+	return genlmsg_multicast(&init_net, msg, 0, ieee802154_coord_mcgrp.id, GFP_ATOMIC);
 out:
 	nlmsg_free(msg);
 	return -ENOBUFS;



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-17 19:33 [PATCH] genetlink: make netns aware Johannes Berg
@ 2009-06-17 21:19 ` Eric W. Biederman
  2009-06-17 21:37   ` Johannes Berg
  2009-06-17 21:26 ` Johannes Berg
  2009-06-18  2:10 ` Brian Haley
  2 siblings, 1 reply; 10+ messages in thread
From: Eric W. Biederman @ 2009-06-17 21:19 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Netdev, Thomas Graf, Eric W. Biederman, Alexey Dobriyan

Johannes Berg <johannes@sipsolutions.net> writes:

> This makes generic netlink network namespace aware.
> No actual generic netlink families are made namespace
> aware, they need to be checked one by one and then
> set the family->netnsok member to true.

Nothing at first glance looks wrong.

Most of these genetlink things are network related so making it
network namespace aware makes sense.

My impression had been that genetlink was mostly not network related
and I would have to solve the other hard problem of how to filter
sockets based on other namespaces.  I guess that can be delayed for
a while longer.

Eric

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-17 19:33 [PATCH] genetlink: make netns aware Johannes Berg
  2009-06-17 21:19 ` Eric W. Biederman
@ 2009-06-17 21:26 ` Johannes Berg
  2009-06-18  2:10 ` Brian Haley
  2 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2009-06-17 21:26 UTC (permalink / raw)
  To: Netdev; +Cc: Thomas Graf, Eric W. Biederman, Alexey Dobriyan

[-- Attachment #1: Type: text/plain, Size: 329 bytes --]

On Wed, 2009-06-17 at 21:34 +0200, Johannes Berg wrote:
> This makes generic netlink network namespace aware.
> No actual generic netlink families are made namespace
> aware, they need to be checked one by one and then
> set the family->netnsok member to true.

This needs locking fixes too, of course. Sorry.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-17 21:19 ` Eric W. Biederman
@ 2009-06-17 21:37   ` Johannes Berg
  2009-06-17 21:49     ` Eric W. Biederman
  0 siblings, 1 reply; 10+ messages in thread
From: Johannes Berg @ 2009-06-17 21:37 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Netdev, Thomas Graf, Eric W. Biederman, Alexey Dobriyan

[-- Attachment #1: Type: text/plain, Size: 945 bytes --]

On Wed, 2009-06-17 at 14:19 -0700, Eric W. Biederman wrote:

> Nothing at first glance looks wrong.

Will review locking :) Not sure I hold enough locks at the correct
places here.

> Most of these genetlink things are network related so making it
> network namespace aware makes sense.

Well, some are non-network, and some are network, like nl80211. My goal
is this patch:
http://johannes.sipsolutions.net/patches/kernel/all/LATEST/016-cfg80211-netns.patch

It already kinda works, but has bugs like not going back to init_net if
the ns a wiphy is in exits, and some more like that.

> My impression had been that genetlink was mostly not network related
> and I would have to solve the other hard problem of how to filter
> sockets based on other namespaces.  I guess that can be delayed for
> a while longer.

Ah, well, I was thinking that the generic netlink family code would have
to take care of that.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-17 21:37   ` Johannes Berg
@ 2009-06-17 21:49     ` Eric W. Biederman
  2009-06-17 21:54       ` Johannes Berg
  0 siblings, 1 reply; 10+ messages in thread
From: Eric W. Biederman @ 2009-06-17 21:49 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Netdev, Thomas Graf, Eric W. Biederman, Alexey Dobriyan

Johannes Berg <johannes@sipsolutions.net> writes:

> On Wed, 2009-06-17 at 14:19 -0700, Eric W. Biederman wrote:
>
>> Nothing at first glance looks wrong.
>
> Will review locking :) Not sure I hold enough locks at the correct
> places here.

grr. At first glance NOTHING looks wrong.
I have a bad habit of skipping the most important word in my sentences
sometimes.

>> Most of these genetlink things are network related so making it
>> network namespace aware makes sense.
>
> Well, some are non-network, and some are network, like nl80211. My goal
> is this patch:
> http://johannes.sipsolutions.net/patches/kernel/all/LATEST/016-cfg80211-netns.patch
>
> It already kinda works, but has bugs like not going back to init_net if
> the ns a wiphy is in exits, and some more like that.
>
>> My impression had been that genetlink was mostly not network related
>> and I would have to solve the other hard problem of how to filter
>> sockets based on other namespaces.  I guess that can be delayed for
>> a while longer.
>
> Ah, well, I was thinking that the generic netlink family code would have
> to take care of that.

Probably.  As even genetlink has those kinds of users.  The kernel
receive path is easy now.  Yeah for synchronous processing. It is
which socket do you transmit on that is interesting.

Eric

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-17 21:49     ` Eric W. Biederman
@ 2009-06-17 21:54       ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2009-06-17 21:54 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Netdev, Thomas Graf, Eric W. Biederman, Alexey Dobriyan

[-- Attachment #1: Type: text/plain, Size: 1454 bytes --]

On Wed, 2009-06-17 at 14:49 -0700, Eric W. Biederman wrote:
> Johannes Berg <johannes@sipsolutions.net> writes:
> 
> > On Wed, 2009-06-17 at 14:19 -0700, Eric W. Biederman wrote:
> >
> >> Nothing at first glance looks wrong.
> >
> > Will review locking :) Not sure I hold enough locks at the correct
> > places here.
> 
> grr. At first glance NOTHING looks wrong.
> I have a bad habit of skipping the most important word in my sentences
> sometimes.

My autocorrection kicked in and did actually read "nothing looks wrong",
but locking is still wrong :)

> Probably.  As even genetlink has those kinds of users.  The kernel
> receive path is easy now.  Yeah for synchronous processing. It is
> which socket do you transmit on that is interesting.

Indeed. But genlmsg_reply() will automatically reply to the correct
netns now, so no big deal there. Multicast is more interesting, one
thing I may need to figure out is multicasting to _all_ namespaces.
Actually, hmm, let me change the API so that genlmsg_multicast() sends
to all network namespaces, and genmlsg_multicast_ns() sends to just a
specific netns.

I'm thinking that most genl users should enable netns but not do
anything different, so their services can be used regardless of what
netns the tool using them lives in, since many genl services don't
actually care about networking. Those that do, like nl80211, will have
to be updated differently.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-17 19:33 [PATCH] genetlink: make netns aware Johannes Berg
  2009-06-17 21:19 ` Eric W. Biederman
  2009-06-17 21:26 ` Johannes Berg
@ 2009-06-18  2:10 ` Brian Haley
  2009-06-18  2:16   ` Johannes Berg
  2 siblings, 1 reply; 10+ messages in thread
From: Brian Haley @ 2009-06-18  2:10 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Netdev, Thomas Graf, Eric W. Biederman, Alexey Dobriyan

Johannes Berg wrote:
> This makes generic netlink network namespace aware.
> No actual generic netlink families are made namespace
> aware, they need to be checked one by one and then
> set the family->netnsok member to true.
> 
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
...
> --- wireless-testing.orig/include/net/net_namespace.h	2009-06-17 20:36:59.000000000 +0200
> +++ wireless-testing/include/net/net_namespace.h	2009-06-17 21:05:52.000000000 +0200
> @@ -26,6 +26,7 @@ struct net_device;
>  struct sock;
>  struct ctl_table_header;
>  struct net_generic;
> +struct sock;
>  
>  struct net {
>  	atomic_t		count;		/* To decided when the network
> @@ -63,6 +64,7 @@ struct net {
>  	struct netns_packet	packet;
>  	struct netns_unix	unx;
>  	struct netns_ipv4	ipv4;
> +	struct sock		*genl_sock;
>  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
>  	struct netns_ipv6	ipv6;
>  #endif

Maybe you want to move *genl_sock up near the *rtnl sock?  Just seemed
strange to be stuck in the middle here to me.

> @@ -429,6 +450,10 @@ static int genl_rcv_msg(struct sk_buff *
>  	if (family == NULL)
>  		return -ENOENT;
>  
> +	/* this family doesn't exist in this netns */
> +	if (!family->netnsok && net != &init_net)
> +		return -ENOENT;

I know there's a net_eq() inline that exists, and actually becomes a no-op
when namespaces aren't built-in, so it might be worthwhile to change it
throughout, even if the rest of networking isn't consistent in using it.

-Brian

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-18  2:10 ` Brian Haley
@ 2009-06-18  2:16   ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2009-06-18  2:16 UTC (permalink / raw)
  To: Brian Haley; +Cc: Netdev, Thomas Graf, Eric W. Biederman, Alexey Dobriyan

[-- Attachment #1: Type: text/plain, Size: 1796 bytes --]

On Wed, 2009-06-17 at 22:10 -0400, Brian Haley wrote:
> Johannes Berg wrote:
> > This makes generic netlink network namespace aware.
> > No actual generic netlink families are made namespace
> > aware, they need to be checked one by one and then
> > set the family->netnsok member to true.
> > 
> > Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
> ...
> > --- wireless-testing.orig/include/net/net_namespace.h	2009-06-17 20:36:59.000000000 +0200
> > +++ wireless-testing/include/net/net_namespace.h	2009-06-17 21:05:52.000000000 +0200
> > @@ -26,6 +26,7 @@ struct net_device;
> >  struct sock;
> >  struct ctl_table_header;
> >  struct net_generic;
> > +struct sock;
> >  
> >  struct net {
> >  	atomic_t		count;		/* To decided when the network
> > @@ -63,6 +64,7 @@ struct net {
> >  	struct netns_packet	packet;
> >  	struct netns_unix	unx;
> >  	struct netns_ipv4	ipv4;
> > +	struct sock		*genl_sock;
> >  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> >  	struct netns_ipv6	ipv6;
> >  #endif
> 
> Maybe you want to move *genl_sock up near the *rtnl sock?  Just seemed
> strange to be stuck in the middle here to me.

Heh I dunno, doesn't matter to me. I just didn't want to stick it at the
end because I'd stuck wext there.

> > @@ -429,6 +450,10 @@ static int genl_rcv_msg(struct sk_buff *
> >  	if (family == NULL)
> >  		return -ENOENT;
> >  
> > +	/* this family doesn't exist in this netns */
> > +	if (!family->netnsok && net != &init_net)
> > +		return -ENOENT;
> 
> I know there's a net_eq() inline that exists, and actually becomes a no-op
> when namespaces aren't built-in, so it might be worthwhile to change it
> throughout, even if the rest of networking isn't consistent in using it.

Good catch.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] genetlink: make netns aware
  2009-06-18 11:16 Johannes Berg
@ 2009-06-19  1:12 ` Johannes Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Johannes Berg @ 2009-06-19  1:12 UTC (permalink / raw)
  To: Netdev; +Cc: Thomas Graf, Eric W. Biederman

[-- Attachment #1: Type: text/plain, Size: 773 bytes --]

On Thu, 2009-06-18 at 13:17 +0200, Johannes Berg wrote:
> This makes generic netlink network namespace aware.

Please drop this patch, it has a deadlock bug.

> +int genlmsg_multicast(struct sk_buff *skb, u32 pid,
> +		      unsigned int group, gfp_t flags)
> +{
> +	int ret;
> +
> +	if (flags & GFP_ATOMIC) {
> +		rcu_read_lock();
> +		ret = genlmsg_mcast(skb, pid, group, flags);
> +		rcu_read_unlock();
> +	} else {
> +		rtnl_lock();
> +		ret = genlmsg_mcast(skb, pid, group, flags);
> +		rtnl_unlock();
> +	}
> +
> +	return ret;
> +}

It used to be possible to call genlmsg_multicast() under rtnl, which
will now obviously deadlock unless you also make it GFP_ATOMIC... I'm
inclined to always use RCU here to solve that, comments?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] genetlink: make netns aware
@ 2009-06-18 11:16 Johannes Berg
  2009-06-19  1:12 ` Johannes Berg
  0 siblings, 1 reply; 10+ messages in thread
From: Johannes Berg @ 2009-06-18 11:16 UTC (permalink / raw)
  To: Netdev; +Cc: Thomas Graf, Eric W. Biederman

This makes generic netlink network namespace aware. No
generic netlink families except for the controller family
are made namespace aware, they need to be checked one by
one and then set the family->netnsok member to true.

The function genlmsg_multicast() is changed to multicast
the message in all namespaces, this is correct for all
generic netlink families that do not care about the net
namespace at all -- which will probably be a significant
amount but they still need to be fixed up.

A new function genlmsg_multicast_netns() is introduced to
allow sending a multicast message in a given namespace,
for example when it applies to an object that lives in
that namespace.

The current state is that generic netlink is available
only in init_net, where after this patch families can
easily decide whether or not they should be available in
all net namespaces or not. Many families that use genl
for something unrelated to networking should probably be
available in all network namespaces, hence the multicast
behaviour mentioned above.

Note that this doesn't touch on the checkpoint/restart
problem where network namespaces could be used, genl
families and multicast groups are numbered globally and
I see no easy way of changing that, especially since it
must be possible to multicast to all network namespaces
for those families that do not care about netns.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 fs/dlm/netlink.c               |    2 
 include/net/genetlink.h        |   32 ++++--
 include/net/net_namespace.h    |    2 
 kernel/taskstats.c             |   10 +-
 net/irda/irnetlink.c           |    2 
 net/netfilter/ipvs/ip_vs_ctl.c |    2 
 net/netlink/genetlink.c        |  195 ++++++++++++++++++++++++++++++++---------
 net/tipc/netlink.c             |    2 
 net/wireless/nl80211.c         |   14 +-
 9 files changed, 196 insertions(+), 65 deletions(-)

--- wireless-testing.orig/include/net/genetlink.h	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/include/net/genetlink.h	2009-06-18 03:48:13.000000000 +0200
@@ -3,6 +3,7 @@
 
 #include <linux/genetlink.h>
 #include <net/netlink.h>
+#include <net/net_namespace.h>
 
 /**
  * struct genl_multicast_group - generic netlink multicast group
@@ -27,6 +28,8 @@ struct genl_multicast_group
  * @name: name of family
  * @version: protocol version
  * @maxattr: maximum number of attributes supported
+ * @netnsok: set to true if the family can handle network
+ *	namespaces and should be presented in all of them
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
@@ -39,6 +42,7 @@ struct genl_family
 	char			name[GENL_NAMSIZ];
 	unsigned int		version;
 	unsigned int		maxattr;
+	bool			netnsok;
 	struct nlattr **	attrbuf;	/* private */
 	struct list_head	ops_list;	/* private */
 	struct list_head	family_list;	/* private */
@@ -62,6 +66,7 @@ struct genl_info
 	struct genlmsghdr *	genlhdr;
 	void *			userhdr;
 	struct nlattr **	attrs;
+	struct net *		net;
 };
 
 /**
@@ -96,8 +101,6 @@ extern int genl_register_mc_group(struct
 extern void genl_unregister_mc_group(struct genl_family *family,
 				     struct genl_multicast_group *grp);
 
-extern struct sock *genl_sock;
-
 /**
  * genlmsg_put - Add generic netlink header to netlink message
  * @skb: socket buffer holding the message
@@ -168,16 +171,27 @@ static inline void genlmsg_cancel(struct
 }
 
 /**
- * genlmsg_multicast - multicast a netlink message
+ * genlmsg_multicast - multicast a netlink message to all network namespaces
+ * @skb: netlink message as socket buffer
+ * @pid: own netlink pid to avoid sending to yourself
+ * @group: multicast group id
+ * @flags: allocation flags
+ */
+int genlmsg_multicast(struct sk_buff *skb, u32 pid,
+		      unsigned int group, gfp_t flags);
+
+/**
+ * genlmsg_multicast_netns - multicast a netlink message to a specific netns
+ * @net: the net namespace
  * @skb: netlink message as socket buffer
  * @pid: own netlink pid to avoid sending to yourself
  * @group: multicast group id
  * @flags: allocation flags
  */
-static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
-				    unsigned int group, gfp_t flags)
+static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
+					  u32 pid, unsigned int group, gfp_t flags)
 {
-	return nlmsg_multicast(genl_sock, skb, pid, group, flags);
+	return nlmsg_multicast(net->genl_sock, skb, pid, group, flags);
 }
 
 /**
@@ -185,9 +199,9 @@ static inline int genlmsg_multicast(stru
  * @skb: netlink message as socket buffer
  * @pid: netlink pid of the destination socket
  */
-static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
+static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid)
 {
-	return nlmsg_unicast(genl_sock, skb, pid);
+	return nlmsg_unicast(net->genl_sock, skb, pid);
 }
 
 /**
@@ -197,7 +211,7 @@ static inline int genlmsg_unicast(struct
  */
 static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
 {
-	return genlmsg_unicast(skb, info->snd_pid);
+	return genlmsg_unicast(info->net, skb, info->snd_pid);
 }
 
 /**
--- wireless-testing.orig/net/netlink/genetlink.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/net/netlink/genetlink.c	2009-06-18 04:18:22.000000000 +0200
@@ -15,11 +15,10 @@
 #include <linux/skbuff.h>
 #include <linux/mutex.h>
 #include <linux/bitmap.h>
+#include <linux/rtnetlink.h>
 #include <net/sock.h>
 #include <net/genetlink.h>
 
-struct sock *genl_sock = NULL;
-
 static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 
 static inline void genl_lock(void)
@@ -175,10 +174,30 @@ int genl_register_mc_group(struct genl_f
 		mc_groups_longs++;
 	}
 
-	err = netlink_change_ngroups(genl_sock,
-				     mc_groups_longs * BITS_PER_LONG);
-	if (err)
-		goto out;
+	if (family->netnsok) {
+		struct net *net;
+
+		rtnl_lock();
+		for_each_net(net) {
+			err = netlink_change_ngroups(net->genl_sock,
+					mc_groups_longs * BITS_PER_LONG);
+			if (err) {
+				/*
+				 * No need to roll back can only fail
+				 * if memory allocation fails and then
+				 * the number of groups is larger for
+				 * some sockets which is ok.
+				 */
+				goto out;
+			}
+		}
+		rtnl_unlock();
+	} else {
+		err = netlink_change_ngroups(init_net.genl_sock,
+					     mc_groups_longs * BITS_PER_LONG);
+		if (err)
+			goto out;
+	}
 
 	grp->id = id;
 	set_bit(id, mc_groups);
@@ -195,8 +214,14 @@ EXPORT_SYMBOL(genl_register_mc_group);
 static void __genl_unregister_mc_group(struct genl_family *family,
 				       struct genl_multicast_group *grp)
 {
+	struct net *net;
 	BUG_ON(grp->family != family);
-	netlink_clear_multicast_users(genl_sock, grp->id);
+
+	rtnl_lock();
+	for_each_net(net)
+		netlink_clear_multicast_users(net->genl_sock, grp->id);
+	rtnl_unlock();
+
 	clear_bit(grp->id, mc_groups);
 	list_del(&grp->list);
 	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
@@ -421,6 +446,7 @@ static int genl_rcv_msg(struct sk_buff *
 {
 	struct genl_ops *ops;
 	struct genl_family *family;
+	struct net *net = sock_net(skb->sk);
 	struct genl_info info;
 	struct genlmsghdr *hdr = nlmsg_data(nlh);
 	int hdrlen, err;
@@ -429,6 +455,10 @@ static int genl_rcv_msg(struct sk_buff *
 	if (family == NULL)
 		return -ENOENT;
 
+	/* this family doesn't exist in this netns */
+	if (!family->netnsok && !net_eq(net, &init_net))
+		return -ENOENT;
+
 	hdrlen = GENL_HDRLEN + family->hdrsize;
 	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
 		return -EINVAL;
@@ -446,7 +476,7 @@ static int genl_rcv_msg(struct sk_buff *
 			return -EOPNOTSUPP;
 
 		genl_unlock();
-		err = netlink_dump_start(genl_sock, skb, nlh,
+		err = netlink_dump_start(net->genl_sock, skb, nlh,
 					 ops->dumpit, ops->done);
 		genl_lock();
 		return err;
@@ -468,6 +498,7 @@ static int genl_rcv_msg(struct sk_buff *
 	info.genlhdr = nlmsg_data(nlh);
 	info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
 	info.attrs = family->attrbuf;
+	info.net = net;
 
 	return ops->doit(skb, &info);
 }
@@ -488,6 +519,7 @@ static struct genl_family genl_ctrl = {
 	.name = "nlctrl",
 	.version = 0x2,
 	.maxattr = CTRL_ATTR_MAX,
+	.netnsok = true,
 };
 
 static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
@@ -604,6 +636,7 @@ static int ctrl_dumpfamily(struct sk_buf
 
 	int i, n = 0;
 	struct genl_family *rt;
+	struct net *net = sock_net(skb->sk);
 	int chains_to_skip = cb->args[0];
 	int fams_to_skip = cb->args[1];
 
@@ -612,6 +645,8 @@ static int ctrl_dumpfamily(struct sk_buf
 			continue;
 		n = 0;
 		list_for_each_entry(rt, genl_family_chain(i), family_list) {
+			if (!rt->netnsok && !net_eq(net, &init_net))
+				continue;
 			if (++n < fams_to_skip)
 				continue;
 			if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).pid,
@@ -683,6 +718,7 @@ static int ctrl_getfamily(struct sk_buff
 	if (info->attrs[CTRL_ATTR_FAMILY_ID]) {
 		u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]);
 		res = genl_family_find_byid(id);
+		err = -ENOENT;
 	}
 
 	if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
@@ -690,51 +726,60 @@ static int ctrl_getfamily(struct sk_buff
 
 		name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
 		res = genl_family_find_byname(name);
+		err = -ENOENT;
 	}
 
-	if (res == NULL) {
-		err = -ENOENT;
-		goto errout;
+	if (res == NULL)
+		return err;
+
+	if (!res->netnsok && !net_eq(info->net, &init_net)) {
+		/* family doesn't exist here */
+		return -ENOENT;
 	}
 
 	msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
 				    CTRL_CMD_NEWFAMILY);
-	if (IS_ERR(msg)) {
-		err = PTR_ERR(msg);
-		goto errout;
-	}
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
 
-	err = genlmsg_reply(msg, info);
-errout:
-	return err;
+	return genlmsg_reply(msg, info);
 }
 
 static int genl_ctrl_event(int event, void *data)
 {
 	struct sk_buff *msg;
+	struct genl_family *family;
+	struct genl_multicast_group *grp;
 
-	if (genl_sock == NULL)
+	/* genl is still initialising */
+	if (!init_net.genl_sock)
 		return 0;
 
 	switch (event) {
 	case CTRL_CMD_NEWFAMILY:
 	case CTRL_CMD_DELFAMILY:
-		msg = ctrl_build_family_msg(data, 0, 0, event);
-		if (IS_ERR(msg))
-			return PTR_ERR(msg);
-
-		genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+		family = data;
+		msg = ctrl_build_family_msg(family, 0, 0, event);
 		break;
 	case CTRL_CMD_NEWMCAST_GRP:
 	case CTRL_CMD_DELMCAST_GRP:
+		grp = data;
+		family = grp->family;
 		msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
-		if (IS_ERR(msg))
-			return PTR_ERR(msg);
-
-		genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
 		break;
+	default:
+		return -EINVAL;
 	}
 
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	if (!family->netnsok)
+		genlmsg_multicast_netns(&init_net, msg, 0,
+					GENL_ID_CTRL, GFP_KERNEL);
+	else
+		genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+
 	return 0;
 }
 
@@ -749,6 +794,33 @@ static struct genl_multicast_group notif
 	.name		= "notify",
 };
 
+static int __net_init genl_pernet_init(struct net *net)
+{
+	/* we'll bump the group number right afterwards */
+	net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0,
+					       genl_rcv, &genl_mutex,
+					       THIS_MODULE);
+
+	if (!net->genl_sock && net_eq(net, &init_net))
+		panic("GENL: Cannot initialize generic netlink\n");
+
+	if (!net->genl_sock)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void __net_exit genl_pernet_exit(struct net *net)
+{
+	netlink_kernel_release(net->genl_sock);
+	net->genl_sock = NULL;
+}
+
+static struct pernet_operations genl_pernet_ops = {
+	.init = genl_pernet_init,
+	.exit = genl_pernet_exit,
+};
+
 static int __init genl_init(void)
 {
 	int i, err;
@@ -758,36 +830,79 @@ static int __init genl_init(void)
 
 	err = genl_register_family(&genl_ctrl);
 	if (err < 0)
-		goto errout;
+		goto problem;
 
 	err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops);
 	if (err < 0)
-		goto errout_register;
+		goto problem;
 
 	netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
 
-	/* we'll bump the group number right afterwards */
-	genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0,
-					  genl_rcv, &genl_mutex, THIS_MODULE);
-	if (genl_sock == NULL)
-		panic("GENL: Cannot initialize generic netlink\n");
+	err = register_pernet_subsys(&genl_pernet_ops);
+	if (err)
+		goto problem;
 
 	err = genl_register_mc_group(&genl_ctrl, &notify_grp);
 	if (err < 0)
-		goto errout_register;
+		goto problem;
 
 	return 0;
 
-errout_register:
-	genl_unregister_family(&genl_ctrl);
-errout:
+problem:
 	panic("GENL: Cannot register controller: %d\n", err);
 }
 
 subsys_initcall(genl_init);
 
-EXPORT_SYMBOL(genl_sock);
 EXPORT_SYMBOL(genl_register_ops);
 EXPORT_SYMBOL(genl_unregister_ops);
 EXPORT_SYMBOL(genl_register_family);
 EXPORT_SYMBOL(genl_unregister_family);
+
+static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
+			 gfp_t flags)
+{
+	struct sk_buff *tmp;
+	struct net *net, *prev = NULL;
+	int err;
+
+	for_each_net_rcu(net) {
+		if (prev) {
+			tmp = skb_clone(skb, flags);
+			if (!tmp) {
+				err = -ENOMEM;
+				goto error;
+			}
+			err = nlmsg_multicast(prev->genl_sock, tmp,
+					      pid, group, flags);
+			if (err)
+				goto error;
+		}
+
+		prev = net;
+	}
+
+	return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags);
+ error:
+	kfree_skb(skb);
+	return err;
+}
+
+int genlmsg_multicast(struct sk_buff *skb, u32 pid,
+		      unsigned int group, gfp_t flags)
+{
+	int ret;
+
+	if (flags & GFP_ATOMIC) {
+		rcu_read_lock();
+		ret = genlmsg_mcast(skb, pid, group, flags);
+		rcu_read_unlock();
+	} else {
+		rtnl_lock();
+		ret = genlmsg_mcast(skb, pid, group, flags);
+		rtnl_unlock();
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(genlmsg_multicast);
--- wireless-testing.orig/fs/dlm/netlink.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/fs/dlm/netlink.c	2009-06-18 03:48:13.000000000 +0200
@@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb
 		return rv;
 	}
 
-	return genlmsg_unicast(skb, listener_nlpid);
+	return genlmsg_unicast(&init_net, skb, listener_nlpid);
 }
 
 static int user_cmd(struct sk_buff *skb, struct genl_info *info)
--- wireless-testing.orig/kernel/taskstats.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/kernel/taskstats.c	2009-06-18 03:48:13.000000000 +0200
@@ -108,7 +108,7 @@ static int prepare_reply(struct genl_inf
 /*
  * Send taskstats data in @skb to listener with nl_pid @pid
  */
-static int send_reply(struct sk_buff *skb, pid_t pid)
+static int send_reply(struct sk_buff *skb, struct genl_info *info)
 {
 	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
 	void *reply = genlmsg_data(genlhdr);
@@ -120,7 +120,7 @@ static int send_reply(struct sk_buff *sk
 		return rc;
 	}
 
-	return genlmsg_unicast(skb, pid);
+	return genlmsg_reply(skb, info);
 }
 
 /*
@@ -150,7 +150,7 @@ static void send_cpu_listeners(struct sk
 			if (!skb_next)
 				break;
 		}
-		rc = genlmsg_unicast(skb_cur, s->pid);
+		rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
 		if (rc == -ECONNREFUSED) {
 			s->valid = 0;
 			delcount++;
@@ -418,7 +418,7 @@ static int cgroupstats_user_cmd(struct s
 		goto err;
 	}
 
-	rc = send_reply(rep_skb, info->snd_pid);
+	rc = send_reply(rep_skb, info);
 
 err:
 	fput_light(file, fput_needed);
@@ -487,7 +487,7 @@ free_return_rc:
 	} else
 		goto err;
 
-	return send_reply(rep_skb, info->snd_pid);
+	return send_reply(rep_skb, info);
 err:
 	nlmsg_free(rep_skb);
 	return rc;
--- wireless-testing.orig/net/irda/irnetlink.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/net/irda/irnetlink.c	2009-06-18 03:48:13.000000000 +0200
@@ -115,7 +115,7 @@ static int irda_nl_get_mode(struct sk_bu
 
 	genlmsg_end(msg, hdr);
 
-	return genlmsg_unicast(msg, info->snd_pid);
+	return genlmsg_reply(msg, info);
 
  err_out:
 	nlmsg_free(msg);
--- wireless-testing.orig/net/netfilter/ipvs/ip_vs_ctl.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/net/netfilter/ipvs/ip_vs_ctl.c	2009-06-18 03:48:13.000000000 +0200
@@ -3231,7 +3231,7 @@ static int ip_vs_genl_get_cmd(struct sk_
 	}
 
 	genlmsg_end(msg, reply);
-	ret = genlmsg_unicast(msg, info->snd_pid);
+	ret = genlmsg_reply(msg, info);
 	goto out;
 
 nla_put_failure:
--- wireless-testing.orig/net/tipc/netlink.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/net/tipc/netlink.c	2009-06-18 03:48:13.000000000 +0200
@@ -62,7 +62,7 @@ static int handle_cmd(struct sk_buff *sk
 		rep_nlh = nlmsg_hdr(rep_buf);
 		memcpy(rep_nlh, req_nlh, hdr_space);
 		rep_nlh->nlmsg_len = rep_buf->len;
-		genlmsg_unicast(rep_buf, NETLINK_CB(skb).pid);
+		genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid);
 	}
 
 	return 0;
--- wireless-testing.orig/net/wireless/nl80211.c	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-06-18 04:16:38.000000000 +0200
@@ -398,7 +398,7 @@ static int nl80211_get_wiphy(struct sk_b
 
 	cfg80211_put_dev(dev);
 
-	return genlmsg_unicast(msg, info->snd_pid);
+	return genlmsg_reply(msg, info);
 
  out_free:
 	nlmsg_free(msg);
@@ -723,7 +723,7 @@ static int nl80211_get_interface(struct 
 	dev_put(netdev);
 	cfg80211_put_dev(dev);
 
-	return genlmsg_unicast(msg, info->snd_pid);
+	return genlmsg_reply(msg, info);
 
  out_free:
 	nlmsg_free(msg);
@@ -1014,7 +1014,7 @@ static int nl80211_get_key(struct sk_buf
 		goto nla_put_failure;
 
 	genlmsg_end(msg, hdr);
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_reply(msg, info);
 	goto out;
 
  nla_put_failure:
@@ -1602,7 +1602,7 @@ static int nl80211_get_station(struct sk
 				 dev, mac_addr, &sinfo) < 0)
 		goto out_free;
 
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_reply(msg, info);
 	goto out;
 
  out_free:
@@ -2009,7 +2009,7 @@ static int nl80211_get_mpath(struct sk_b
 				 dev, dst, next_hop, &pinfo) < 0)
 		goto out_free;
 
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_reply(msg, info);
 	goto out;
 
  out_free:
@@ -2358,7 +2358,7 @@ static int nl80211_get_mesh_params(struc
 			cur_params.dot11MeshHWMPnetDiameterTraversalTime);
 	nla_nest_end(msg, pinfoattr);
 	genlmsg_end(msg, hdr);
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_reply(msg, info);
 	goto out;
 
  nla_put_failure:
@@ -2546,7 +2546,7 @@ static int nl80211_get_reg(struct sk_buf
 	nla_nest_end(msg, nl_reg_rules);
 
 	genlmsg_end(msg, hdr);
-	err = genlmsg_unicast(msg, info->snd_pid);
+	err = genlmsg_reply(msg, info);
 	goto out;
 
 nla_put_failure:
--- wireless-testing.orig/include/net/net_namespace.h	2009-06-18 03:48:12.000000000 +0200
+++ wireless-testing/include/net/net_namespace.h	2009-06-18 04:17:00.000000000 +0200
@@ -26,6 +26,7 @@ struct net_device;
 struct sock;
 struct ctl_table_header;
 struct net_generic;
+struct sock;
 
 struct net {
 	atomic_t		count;		/* To decided when the network
@@ -57,6 +58,7 @@ struct net {
 	spinlock_t		rules_mod_lock;
 
 	struct sock 		*rtnl;			/* rtnetlink socket */
+	struct sock		*genl_sock;
 
 	struct netns_core	core;
 	struct netns_mib	mib;



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-06-19  1:12 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-17 19:33 [PATCH] genetlink: make netns aware Johannes Berg
2009-06-17 21:19 ` Eric W. Biederman
2009-06-17 21:37   ` Johannes Berg
2009-06-17 21:49     ` Eric W. Biederman
2009-06-17 21:54       ` Johannes Berg
2009-06-17 21:26 ` Johannes Berg
2009-06-18  2:10 ` Brian Haley
2009-06-18  2:16   ` Johannes Berg
2009-06-18 11:16 Johannes Berg
2009-06-19  1:12 ` Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.