Skip to contentSkip to conversation

netns: make IPv6 multicast forwarding per-namespace

PATCH In review Benjamin Thery 2 participants 11 messages Dec 8, 2008 – Dec 9, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover netns: make IPv6 multicast forwarding per-namespace

This patchset introduces the support for network namespaces in IPv6 multicast forwarding code (net/ipv6/ip6mr.c).

The first patches in the series moves global data from ip6mr.c into struct netns_ipv6 to prepare netns support. Data are still referenced in init_net only. One of these patches makes the related /proc entries per-namespace.

The last patch does the main job and enables the network namespace support by replacing all the init_net references with the proper net retrieved from sockets or net devices.

The patchset applies on top of net-next-2.6

Regards,
Benjamin

#1 lore raw

PATCH 1/8 netns: ip6mr: allocate mroute6_socket per-namespace.

Preliminary work to make IPv6 multicast forwarding netns-aware.

Make IPv6 multicast forwarding mroute6_socket per-namespace, moves it into struct netns_ipv6.

At the moment, mroute6_socket is only referenced in init_net.

---
 include/linux/mroute6.h  |    8 ++++++--
 include/net/netns/ipv6.h |    3 +++
 net/ipv6/ip6_output.c    |    3 ++-
 net/ipv6/ip6mr.c         |   22 ++++++++++------------
 4 files changed, 21 insertions(+), 15 deletions(-)
include/linux/mroute6.h +6 -2
index 6f4c180..2cd9901 100644
@@ -117,6 +117,7 @@ struct sioc_mif_req6
 
 #include <linux/pim.h>
 #include <linux/skbuff.h>	/* for struct sk_buff_head */
+#include <net/net_namespace.h>
 
 #ifdef CONFIG_IPV6_MROUTE
 static inline int ip6_mroute_opt(int opt)
@@ -232,10 +233,13 @@ struct rtmsg;
 extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
 
 #ifdef CONFIG_IPV6_MROUTE
-extern struct sock *mroute6_socket;
+static inline struct sock *mroute6_socket(struct net *net)
+{
+	return net->ipv6.mroute6_sk;
+}
 extern int ip6mr_sk_done(struct sock *sk);
 #else
-#define mroute6_socket NULL
+static inline struct sock *mroute6_socket(struct net *net) { return NULL; }
 static inline int ip6mr_sk_done(struct sock *sk) { return 0; }
 #endif
 #endif
include/net/netns/ipv6.h +3 -0
index 2932721..8a0a67d 100644
@@ -55,5 +55,8 @@ struct netns_ipv6 {
 	struct sock             *ndisc_sk;
 	struct sock             *tcp_sk;
 	struct sock             *igmp_sk;
+#ifdef CONFIG_IPV6_MROUTE
+	struct sock		*mroute6_sk;
+#endif
 };
 #endif
net/ipv6/ip6_output.c +2 -1
index 7d92fd9..4b15938 100644
@@ -137,7 +137,8 @@ static int ip6_output2(struct sk_buff *skb)
 		struct inet6_dev *idev = ip6_dst_idev(skb->dst);
 
 		if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
-		    ((mroute6_socket && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
+		    ((mroute6_socket(dev_net(dev)) &&
+		     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
 		     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
 					 &ipv6_hdr(skb)->saddr))) {
 			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
net/ipv6/ip6mr.c +10 -12
index d1008e6..02163db 100644
@@ -49,9 +49,6 @@
 #include <net/addrconf.h>
 #include <linux/netfilter_ipv6.h>
 
-struct sock *mroute6_socket;
-
-
 /* Big lock, protecting vif table, mrt cache and mroute socket state.
    Note that the changes are semaphored via rtnl_lock.
  */
@@ -820,7 +817,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert)
 	skb_pull(skb, sizeof(struct ipv6hdr));
 	}
 
-	if (mroute6_socket == NULL) {
+	if (init_net.ipv6.mroute6_sk == NULL) {
 		kfree_skb(skb);
 		return -EINVAL;
 	}
@@ -828,7 +825,8 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert)
 	/*
 	 *	Deliver to user space multicast routing algorithms
 	 */
-	if ((ret = sock_queue_rcv_skb(mroute6_socket, skb)) < 0) {
+	ret = sock_queue_rcv_skb(init_net.ipv6.mroute6_sk, skb);
+	if (ret < 0) {
 		if (net_ratelimit())
 			printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n");
 		kfree_skb(skb);
@@ -1145,8 +1143,8 @@ static int ip6mr_sk_init(struct sock *sk)
 
 	rtnl_lock();
 	write_lock_bh(&mrt_lock);
-	if (likely(mroute6_socket == NULL))
-		mroute6_socket = sk;
+	if (likely(init_net.ipv6.mroute6_sk == NULL))
+		init_net.ipv6.mroute6_sk = sk;
 	else
 		err = -EADDRINUSE;
 	write_unlock_bh(&mrt_lock);
@@ -1161,9 +1159,9 @@ int ip6mr_sk_done(struct sock *sk)
 	int err = 0;
 
 	rtnl_lock();
-	if (sk == mroute6_socket) {
+	if (sk == init_net.ipv6.mroute6_sk) {
 		write_lock_bh(&mrt_lock);
-		mroute6_socket = NULL;
+		init_net.ipv6.mroute6_sk = NULL;
 		write_unlock_bh(&mrt_lock);
 
 		mroute_clean_tables(sk);
@@ -1189,7 +1187,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
 	mifi_t mifi;
 
 	if (optname != MRT6_INIT) {
-		if (sk != mroute6_socket && !capable(CAP_NET_ADMIN))
+		if (sk != init_net.ipv6.mroute6_sk && !capable(CAP_NET_ADMIN))
 			return -EACCES;
 	}
 
@@ -1214,7 +1212,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
 		if (vif.mif6c_mifi >= MAXMIFS)
 			return -ENFILE;
 		rtnl_lock();
-		ret = mif6_add(&vif, sk == mroute6_socket);
+		ret = mif6_add(&vif, sk == init_net.ipv6.mroute6_sk);
 		rtnl_unlock();
 		return ret;
 
@@ -1242,7 +1240,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
 		if (optname == MRT6_DEL_MFC)
 			ret = ip6mr_mfc_delete(&mfc);
 		else
-			ret = ip6mr_mfc_add(&mfc, sk == mroute6_socket);
+			ret = ip6mr_mfc_add(&mfc, sk == init_net.ipv6.mroute6_sk);
 		rtnl_unlock();
 		return ret;
 
#2 lore raw

PATCH 2/8 netns: ip6mr: dynamically allocates vif6_table

In reply to Benjamin Thery

Preliminary work to make IPv6 multicast forwarding netns-aware.

Dynamically allocates interface table vif6_table and moves it to struct netns_ipv6, and updates MIF_EXISTS() macro.

At the moment, vif6_table is only referenced in init_net.

---
 include/net/netns/ipv6.h |    2 +
 net/ipv6/ip6mr.c         |  107 +++++++++++++++++++++++++++++-----------------
 2 files changed, 70 insertions(+), 39 deletions(-)
include/net/netns/ipv6.h +2 -0
index 8a0a67d..4ab0cb0 100644
@@ -57,6 +57,8 @@ struct netns_ipv6 {
 	struct sock             *igmp_sk;
 #ifdef CONFIG_IPV6_MROUTE
 	struct sock		*mroute6_sk;
+	struct mif_device	*vif6_table;
+	int			maxvif;
 #endif
 };
 #endif
net/ipv6/ip6mr.c +68 -39

266 lines not on this page · raw message

#3 lore raw

PATCH 3/8 netns: ip6mr: Dynamically allocates mfc6_cache_array

In reply to Benjamin Thery

Preliminary work to make IPv6 multicast forwarding netns-aware.

Dynamically allocates IPv6 multicast forwarding cache, mfc6_cache_array, and moves it to struct netns_ipv6.

At the moment, mfc6_cache_array is only referenced in init_net.

Replace 'ARRAY_SIZE(mfc6_cache_array)' with mfc6_cache_array size: MFC6_LINES.

---
 include/net/netns/ipv6.h |    1 +
 net/ipv6/ip6mr.c         |   47 ++++++++++++++++++++++++++++++---------------
 2 files changed, 32 insertions(+), 16 deletions(-)
include/net/netns/ipv6.h +1 -0
index 4ab0cb0..14c1bbe 100644
@@ -57,6 +57,7 @@ struct netns_ipv6 {
 	struct sock             *igmp_sk;
 #ifdef CONFIG_IPV6_MROUTE
 	struct sock		*mroute6_sk;
+	struct mfc6_cache	**mfc6_cache_array;
 	struct mif_device	*vif6_table;
 	int			maxvif;
 #endif
net/ipv6/ip6mr.c +31 -16

117 lines not on this page · raw message

#4 lore raw

PATCH 4/8 netns: ip6mr: Declare mroute_do_assert and mroute_do_pim per-namespace

In reply to Benjamin Thery

Preliminary work to make IPv6 multicast forwarding netns-aware.

Declare IPv6 multicast forwarding variables 'mroute_do_assert' and 'mroute_do_pim' per-namespace in struct netns_ipv6.

At the moment, these variables are only referenced in init_net.

---
 include/net/netns/ipv6.h |    2 ++
 net/ipv6/ip6mr.c         |   26 ++++++++++----------------
 2 files changed, 12 insertions(+), 16 deletions(-)
include/net/netns/ipv6.h +2 -0
index 14c1bbe..b17e522 100644
@@ -60,6 +60,8 @@ struct netns_ipv6 {
 	struct mfc6_cache	**mfc6_cache_array;
 	struct mif_device	*vif6_table;
 	int			maxvif;
+	int			mroute_do_assert;
+	int			mroute_do_pim;
 #endif
 };
 #endif
net/ipv6/ip6mr.c +10 -16
index 565e81e..94a3133 100644
@@ -61,13 +61,6 @@ static DEFINE_RWLOCK(mrt_lock);
 
 #define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL)
 
-static int mroute_do_assert;				/* Set in PIM assert	*/
-#ifdef CONFIG_IPV6_PIMSM_V2
-static int mroute_do_pim;
-#else
-#define mroute_do_pim 0
-#endif
-
 static struct mfc6_cache *mfc_unres_queue;		/* Queue of unresolved entries */
 static atomic_t cache_resolve_queue_len;		/* Size of unresolved	*/
 
@@ -1296,7 +1289,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
 		int v;
 		if (get_user(v, (int __user *)optval))
 			return -EFAULT;
-		mroute_do_assert = !!v;
+		init_net.ipv6.mroute_do_assert = !!v;
 		return 0;
 	}
 
@@ -1309,10 +1302,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
 		v = !!v;
 		rtnl_lock();
 		ret = 0;
-		if (v != mroute_do_pim) {
-			mroute_do_pim = v;
-			mroute_do_assert = v;
-			if (mroute_do_pim)
+		if (v != init_net.ipv6.mroute_do_pim) {
+			init_net.ipv6.mroute_do_pim = v;
+			init_net.ipv6.mroute_do_assert = v;
+			if (init_net.ipv6.mroute_do_pim)
 				ret = inet6_add_protocol(&pim6_protocol,
 							 IPPROTO_PIM);
 			else
@@ -1351,11 +1344,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
 		break;
 #ifdef CONFIG_IPV6_PIMSM_V2
 	case MRT6_PIM:
-		val = mroute_do_pim;
+		val = init_net.ipv6.mroute_do_pim;
 		break;
 #endif
 	case MRT6_ASSERT:
-		val = mroute_do_assert;
+		val = init_net.ipv6.mroute_do_assert;
 		break;
 	default:
 		return -ENOPROTOOPT;
@@ -1543,13 +1536,14 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
 		cache->mfc_un.res.wrong_if++;
 		true_vifi = ip6mr_find_vif(skb->dev);
 
-		if (true_vifi >= 0 && mroute_do_assert &&
+		if (true_vifi >= 0 && init_net.ipv6.mroute_do_assert &&
 		    /* pimsm uses asserts, when switching from RPT to SPT,
 		       so that we cannot check that packet arrived on an oif.
 		       It is bad, but otherwise we would need to move pretty
 		       large chunk of pimd to kernel. Ough... --ANK
 		     */
-		    (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) &&
+		    (init_net.ipv6.mroute_do_pim ||
+		     cache->mfc_un.res.ttls[true_vifi] < 255) &&
 		    time_after(jiffies,
 			       cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
 			cache->mfc_un.res.last_assert = jiffies;
#5 lore raw

PATCH 5/8 netns: ip6mr: store netns in struct mfc6_cache

In reply to Benjamin Thery

This patch stores into struct mfc6_cache the network namespace each mfc6_cache belongs to. The new member is mfc6_net.

mfc6_net is assigned at cache allocation and doesn't change during the rest of the cache entry life.

This will help to retrieve the current netns around the IPv6 multicast forwarding code.

At the moment, all mfc6_cache are allocated in init_net.

Changelog:
==========
* Use write_pnet()/read_pnet() to set and get mfc6_net.

---
 include/linux/mroute6.h |   15 +++++++++++++++
 net/ipv6/ip6mr.c        |   28 +++++++++++++++++++---------
 2 files changed, 34 insertions(+), 9 deletions(-)
include/linux/mroute6.h +15 -0
index 2cd9901..15d85fe 100644
@@ -188,6 +188,9 @@ struct mif_device
 struct mfc6_cache
 {
 	struct mfc6_cache *next;		/* Next entry on cache line 	*/
+#ifdef CONFIG_NET_NS
+	struct net *mfc6_net;
+#endif
 	struct in6_addr mf6c_mcastgrp;			/* Group the entry belongs to 	*/
 	struct in6_addr mf6c_origin;			/* Source of packet 		*/
 	mifi_t mf6c_parent;			/* Source interface		*/
@@ -210,6 +213,18 @@ struct mfc6_cache
 	} mfc_un;
 };
 
+static inline
+struct net *mfc6_net(const struct mfc6_cache *mfc)
+{
+	return read_pnet(&mfc->mfc6_net);
+}
+
+static inline
+void mfc6_net_set(struct mfc6_cache *mfc, struct net *net)
+{
+	write_pnet(&mfc->mfc6_net, hold_net(net));
+}
+
 #define MFC_STATIC		1
 #define MFC_NOTIFY		2
 
net/ipv6/ip6mr.c +19 -9
index 94a3133..1583202 100644
@@ -498,6 +498,14 @@ static int mif6_delete(int vifi)
 	return 0;
 }
 
+static inline void ip6mr_cache_free(struct mfc6_cache *c)
+{
+#ifdef CONFIG_NET_NS
+	release_net(c->mfc6_net);
+#endif
+	kmem_cache_free(mrt_cachep, c);
+}
+
 /* Destroy an unresolved cache entry, killing queued skbs
    and reporting error to netlink readers.
  */
@@ -520,7 +528,7 @@ static void ip6mr_destroy_unres(struct mfc6_cache *c)
 			kfree_skb(skb);
 	}
 
-	kmem_cache_free(mrt_cachep, c);
+	ip6mr_cache_free(c);
 }
 
 
@@ -677,22 +685,24 @@ static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_a
 /*
  *	Allocate a multicast cache entry
  */
-static struct mfc6_cache *ip6mr_cache_alloc(void)
+static struct mfc6_cache *ip6mr_cache_alloc(struct net *net)
 {
 	struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
 	if (c == NULL)
 		return NULL;
 	c->mfc_un.res.minvif = MAXMIFS;
+	mfc6_net_set(c, net);
 	return c;
 }
 
-static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
+static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
 {
 	struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
 	if (c == NULL)
 		return NULL;
 	skb_queue_head_init(&c->mfc_un.unres.unresolved);
 	c->mfc_un.unres.expires = jiffies + 10 * HZ;
+	mfc6_net_set(c, net);
 	return c;
 }
 
@@ -848,7 +858,7 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb)
 		 */
 
 		if (atomic_read(&cache_resolve_queue_len) >= 10 ||
-		    (c = ip6mr_cache_alloc_unres()) == NULL) {
+		    (c = ip6mr_cache_alloc_unres(&init_net)) == NULL) {
 			spin_unlock_bh(&mfc_unres_lock);
 
 			kfree_skb(skb);
@@ -871,7 +881,7 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb)
 			 */
 			spin_unlock_bh(&mfc_unres_lock);
 
-			kmem_cache_free(mrt_cachep, c);
+			ip6mr_cache_free(c);
 			kfree_skb(skb);
 			return err;
 		}
@@ -917,7 +927,7 @@ static int ip6mr_mfc_delete(struct mf6cctl *mfc)
 			*cp = c->next;
 			write_unlock_bh(&mrt_lock);
 
-			kmem_cache_free(mrt_cachep, c);
+			ip6mr_cache_free(c);
 			return 0;
 		}
 	}
@@ -1081,7 +1091,7 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
 	if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
 		return -EINVAL;
 
-	c = ip6mr_cache_alloc();
+	c = ip6mr_cache_alloc(&init_net);
 	if (c == NULL)
 		return -ENOMEM;
 
@@ -1116,7 +1126,7 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
 
 	if (uc) {
 		ip6mr_cache_resolve(uc, c);
-		kmem_cache_free(mrt_cachep, uc);
+		ip6mr_cache_free(uc);
 	}
 	return 0;
 }
@@ -1153,7 +1163,7 @@ static void mroute_clean_tables(struct sock *sk)
 			*cp = c->next;
 			write_unlock_bh(&mrt_lock);
 
-			kmem_cache_free(mrt_cachep, c);
+			ip6mr_cache_free(c);
 		}
 	}
 
#6 lore raw

PATCH 6/8 netns: ip6mr: declare reg_vif_num per-namespace

In reply to Benjamin Thery

Preliminary work to make IPv6 multicast forwarding netns-aware.

Declare variable 'reg_vif_num' per-namespace, moves into struct netns_ipv6.

At the moment, this variable is only referenced in init_net.

---
 include/net/netns/ipv6.h |    3 +++
 net/ipv6/ip6mr.c         |   19 +++++++++++--------
 2 files changed, 14 insertions(+), 8 deletions(-)
include/net/netns/ipv6.h +3 -0
index b17e522..c0e3189 100644
@@ -62,6 +62,9 @@ struct netns_ipv6 {
 	int			maxvif;
 	int			mroute_do_assert;
 	int			mroute_do_pim;
+#ifdef CONFIG_IPV6_PIMSM_V2
+	int			mroute_reg_vif_num;
+#endif
 #endif
 };
 #endif
net/ipv6/ip6mr.c +11 -8
index 1583202..b9f03f7 100644
@@ -334,13 +334,13 @@ static struct file_operations ip6mr_mfc_fops = {
 #endif
 
 #ifdef CONFIG_IPV6_PIMSM_V2
-static int reg_vif_num = -1;
 
 static int pim6_rcv(struct sk_buff *skb)
 {
 	struct pimreghdr *pim;
 	struct ipv6hdr   *encap;
 	struct net_device  *reg_dev = NULL;
+	int reg_vif_num = init_net.ipv6.mroute_reg_vif_num;
 
 	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
 		goto drop;
@@ -402,7 +402,7 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
 	read_lock(&mrt_lock);
 	dev->stats.tx_bytes += skb->len;
 	dev->stats.tx_packets++;
-	ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
+	ip6mr_cache_report(skb, init_net.ipv6.mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
 	read_unlock(&mrt_lock);
 	kfree_skb(skb);
 	return 0;
@@ -474,8 +474,8 @@ static int mif6_delete(int vifi)
 	}
 
 #ifdef CONFIG_IPV6_PIMSM_V2
-	if (vifi == reg_vif_num)
-		reg_vif_num = -1;
+	if (vifi == init_net.ipv6.mroute_reg_vif_num)
+		init_net.ipv6.mroute_reg_vif_num = -1;
 #endif
 
 	if (vifi + 1 == init_net.ipv6.maxvif) {
@@ -613,7 +613,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock)
 		 * Special Purpose VIF in PIM
 		 * All the packets will be sent to the daemon
 		 */
-		if (reg_vif_num >= 0)
+		if (init_net.ipv6.mroute_reg_vif_num >= 0)
 			return -EADDRINUSE;
 		dev = ip6mr_reg_vif();
 		if (!dev)
@@ -661,7 +661,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock)
 	v->dev = dev;
 #ifdef CONFIG_IPV6_PIMSM_V2
 	if (v->flags & MIFF_REGISTER)
-		reg_vif_num = vifi;
+		init_net.ipv6.mroute_reg_vif_num = vifi;
 #endif
 	if (vifi + 1 > init_net.ipv6.maxvif)
 		init_net.ipv6.maxvif = vifi + 1;
@@ -780,7 +780,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert)
 		msg = (struct mrt6msg *)skb_transport_header(skb);
 		msg->im6_mbz = 0;
 		msg->im6_msgtype = MRT6MSG_WHOLEPKT;
-		msg->im6_mif = reg_vif_num;
+		msg->im6_mif = init_net.ipv6.mroute_reg_vif_num;
 		msg->im6_pad = 0;
 		ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
 		ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
@@ -966,7 +966,6 @@ static struct notifier_block ip6_mr_notifier = {
 static int __net_init ip6mr_net_init(struct net *net)
 {
 	int err = 0;
-
 	net->ipv6.vif6_table = kcalloc(MAXMIFS, sizeof(struct mif_device),
 				       GFP_KERNEL);
 	if (!net->ipv6.vif6_table) {
@@ -982,6 +981,10 @@ static int __net_init ip6mr_net_init(struct net *net)
 		err = -ENOMEM;
 		goto fail_mfc6_cache;
 	}
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+	net->ipv6.mroute_reg_vif_num = -1;
+#endif
 	return 0;
 
 fail_mfc6_cache:
#7 lore raw

PATCH 7/8 netns: ip6mr: declare ip6mr /proc/net entries per-namespace

In reply to Benjamin Thery

Declare IPv6 multicast forwarding /proc/net entries per-namespace:
/proc/net/ip6_mr_vif
/proc/net/ip6_mr_cache

---
 net/ipv6/ip6mr.c |  104 ++++++++++++++++++++++++++++++-----------------------
 1 files changed, 59 insertions(+), 45 deletions(-)
net/ipv6/ip6mr.c +59 -45
index b9f03f7..ad540a0 100644
@@ -91,19 +91,21 @@ static struct timer_list ipmr_expire_timer;
 #ifdef CONFIG_PROC_FS
 
 struct ipmr_mfc_iter {
+	struct seq_net_private p;
 	struct mfc6_cache **cache;
 	int ct;
 };
 
 
-static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
+static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
+					   struct ipmr_mfc_iter *it, loff_t pos)
 {
 	struct mfc6_cache *mfc;
 
-	it->cache = init_net.ipv6.mfc6_cache_array;
+	it->cache = net->ipv6.mfc6_cache_array;
 	read_lock(&mrt_lock);
 	for (it->ct = 0; it->ct < MFC6_LINES; it->ct++)
-		for (mfc = init_net.ipv6.mfc6_cache_array[it->ct];
+		for (mfc = net->ipv6.mfc6_cache_array[it->ct];
 		     mfc; mfc = mfc->next)
 			if (pos-- == 0)
 				return mfc;
@@ -128,17 +130,19 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos)
  */
 
 struct ipmr_vif_iter {
+	struct seq_net_private p;
 	int ct;
 };
 
-static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter,
+static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
+					    struct ipmr_vif_iter *iter,
 					    loff_t pos)
 {
-	for (iter->ct = 0; iter->ct < init_net.ipv6.maxvif; ++iter->ct) {
-		if (!MIF_EXISTS(&init_net, iter->ct))
+	for (iter->ct = 0; iter->ct < net->ipv6.maxvif; ++iter->ct) {
+		if (!MIF_EXISTS(net, iter->ct))
 			continue;
 		if (pos-- == 0)
-			return &init_net.ipv6.vif6_table[iter->ct];
+			return &net->ipv6.vif6_table[iter->ct];
 	}
 	return NULL;
 }
@@ -146,23 +150,26 @@ static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter,
 static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(mrt_lock)
 {
+	struct net *net = seq_file_net(seq);
+
 	read_lock(&mrt_lock);
-	return (*pos ? ip6mr_vif_seq_idx(seq->private, *pos - 1)
-		: SEQ_START_TOKEN);
+	return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
+		: SEQ_START_TOKEN;
 }
 
 static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct ipmr_vif_iter *iter = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	++*pos;
 	if (v == SEQ_START_TOKEN)
-		return ip6mr_vif_seq_idx(iter, 0);
+		return ip6mr_vif_seq_idx(net, iter, 0);
 
-	while (++iter->ct < init_net.ipv6.maxvif) {
-		if (!MIF_EXISTS(&init_net, iter->ct))
+	while (++iter->ct < net->ipv6.maxvif) {
+		if (!MIF_EXISTS(net, iter->ct))
 			continue;
-		return &init_net.ipv6.vif6_table[iter->ct];
+		return &net->ipv6.vif6_table[iter->ct];
 	}
 	return NULL;
 }
@@ -175,6 +182,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
 
 static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
 {
+	struct net *net = seq_file_net(seq);
+
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq,
 			 "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags\n");
@@ -184,7 +193,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
 
 		seq_printf(seq,
 			   "%2td %-10s %8ld %7ld  %8ld %7ld %05X\n",
-			   vif - init_net.ipv6.vif6_table,
+			   vif - net->ipv6.vif6_table,
 			   name, vif->bytes_in, vif->pkt_in,
 			   vif->bytes_out, vif->pkt_out,
 			   vif->flags);
@@ -201,8 +210,8 @@ static struct seq_operations ip6mr_vif_seq_ops = {
 
 static int ip6mr_vif_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ip6mr_vif_seq_ops,
-				sizeof(struct ipmr_vif_iter));
+	return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
+			    sizeof(struct ipmr_vif_iter));
 }
 
 static struct file_operations ip6mr_vif_fops = {
@@ -210,24 +219,27 @@ static struct file_operations ip6mr_vif_fops = {
 	.open    = ip6mr_vif_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 
 static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
 {
-	return (*pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1)
-		: SEQ_START_TOKEN);
+	struct net *net = seq_file_net(seq);
+
+	return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
+		: SEQ_START_TOKEN;
 }
 
 static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct mfc6_cache *mfc = v;
 	struct ipmr_mfc_iter *it = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	++*pos;
 
 	if (v == SEQ_START_TOKEN)
-		return ipmr_mfc_seq_idx(seq->private, 0);
+		return ipmr_mfc_seq_idx(net, seq->private, 0);
 
 	if (mfc->next)
 		return mfc->next;
@@ -235,10 +247,10 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 	if (it->cache == &mfc_unres_queue)
 		goto end_of_list;
 
-	BUG_ON(it->cache != init_net.ipv6.mfc6_cache_array);
+	BUG_ON(it->cache != net->ipv6.mfc6_cache_array);
 
 	while (++it->ct < MFC6_LINES) {
-		mfc = init_net.ipv6.mfc6_cache_array[it->ct];
+		mfc = net->ipv6.mfc6_cache_array[it->ct];
 		if (mfc)
 			return mfc;
 	}
@@ -263,16 +275,18 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
 {
 	struct ipmr_mfc_iter *it = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	if (it->cache == &mfc_unres_queue)
 		spin_unlock_bh(&mfc_unres_lock);
-	else if (it->cache == init_net.ipv6.mfc6_cache_array)
+	else if (it->cache == net->ipv6.mfc6_cache_array)
 		read_unlock(&mrt_lock);
 }
 
 static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
 {
 	int n;
+	struct net *net = seq_file_net(seq);
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq,
@@ -294,7 +308,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
 				   mfc->mfc_un.res.wrong_if);
 			for (n = mfc->mfc_un.res.minvif;
 			     n < mfc->mfc_un.res.maxvif; n++) {
-				if (MIF_EXISTS(&init_net, n) &&
+				if (MIF_EXISTS(net, n) &&
 				    mfc->mfc_un.res.ttls[n] < 255)
 					seq_printf(seq,
 						   " %2d:%-3d",
@@ -320,8 +334,8 @@ static struct seq_operations ipmr_mfc_seq_ops = {
 
 static int ipmr_mfc_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ipmr_mfc_seq_ops,
-				sizeof(struct ipmr_mfc_iter));
+	return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
+			    sizeof(struct ipmr_mfc_iter));
 }
 
 static struct file_operations ip6mr_mfc_fops = {
@@ -329,7 +343,7 @@ static struct file_operations ip6mr_mfc_fops = {
 	.open    = ipmr_mfc_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 #endif
 
@@ -985,8 +999,22 @@ static int __net_init ip6mr_net_init(struct net *net)
 #ifdef CONFIG_IPV6_PIMSM_V2
 	net->ipv6.mroute_reg_vif_num = -1;
 #endif
+
+#ifdef CONFIG_PROC_FS
+	err = -ENOMEM;
+	if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
+		goto proc_vif_fail;
+	if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops))
+		goto proc_cache_fail;
+#endif
 	return 0;
 
+#ifdef CONFIG_PROC_FS
+proc_cache_fail:
+	proc_net_remove(net, "ip6_mr_vif");
+proc_vif_fail:
+	kfree(net->ipv6.mfc6_cache_array);
+#endif
 fail_mfc6_cache:
 	kfree(net->ipv6.vif6_table);
 fail:
@@ -995,6 +1023,10 @@ fail:
 
 static void __net_exit ip6mr_net_exit(struct net *net)
 {
+#ifdef CONFIG_PROC_FS
+	proc_net_remove(net, "ip6_mr_cache");
+	proc_net_remove(net, "ip6_mr_vif");
+#endif
 	kfree(net->ipv6.mfc6_cache_array);
 	kfree(net->ipv6.vif6_table);
 }
@@ -1023,21 +1055,7 @@ int __init ip6_mr_init(void)
 	err = register_netdevice_notifier(&ip6_mr_notifier);
 	if (err)
 		goto reg_notif_fail;
-#ifdef CONFIG_PROC_FS
-	err = -ENOMEM;
-	if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
-		goto proc_vif_fail;
-	if (!proc_net_fops_create(&init_net, "ip6_mr_cache",
-				     0, &ip6mr_mfc_fops))
-		goto proc_cache_fail;
-#endif
 	return 0;
-#ifdef CONFIG_PROC_FS
-proc_cache_fail:
-	proc_net_remove(&init_net, "ip6_mr_vif");
-proc_vif_fail:
-	unregister_netdevice_notifier(&ip6_mr_notifier);
-#endif
 reg_notif_fail:
 	del_timer(&ipmr_expire_timer);
 	unregister_pernet_subsys(&ip6mr_net_ops);
@@ -1048,10 +1066,6 @@ reg_pernet_fail:
 
 void ip6_mr_cleanup(void)
 {
-#ifdef CONFIG_PROC_FS
-	proc_net_remove(&init_net, "ip6_mr_cache");
-	proc_net_remove(&init_net, "ip6_mr_vif");
-#endif
 	unregister_netdevice_notifier(&ip6_mr_notifier);
 	del_timer(&ipmr_expire_timer);
 	unregister_pernet_subsys(&ip6mr_net_ops);
#8 lore raw

PATCH 8/8 ipv6: netns: enable namespace support in ipv6 multicast forwarding code

In reply to Benjamin Thery

This last patch makes the appropriate changes to use and propagate the network namespace where needed in IPv6 multicast forwarding code.

This consists mainly in replacing all the remaining init_net occurences with current netns pointer retrieved from sockets, net devices or mfc6_caches depending on the routines' contexts.

Some routines receive a new 'struct net' parameter to propagate the netns:
* ip6mr_get_route
* ip6mr_cache_report
* ip6mr_cache_find
* ip6mr_cache_unresolved
* mif6_add/mif6_delete
* ip6mr_mfc_add/ip6mr_mfc_delete

All the IPv6 multicast forwarding variables moved to struct netns_ipv6 by the previous patches are now referenced in the correct namespace.

Changelog:
==========
* Take into account the net associated to mfc6_cache when matching entries in mfc_unres_queue list.
* Call mroute_clean_tables() in ip6mr_net_exit() to free memory allocated per-namespace.
* Call dev_net_set() in ip6mr_reg_vif() to initialize dev->nd_net correctly.

---
 include/linux/mroute6.h |    3 +-
 net/ipv6/ip6mr.c        |  235 ++++++++++++++++++++++++++---------------------
 net/ipv6/route.c        |    2 +-
 3 files changed, 133 insertions(+), 107 deletions(-)
include/linux/mroute6.h +2 -1
index 15d85fe..5375fac 100644
@@ -245,7 +245,8 @@ void mfc6_net_set(struct mfc6_cache *mfc, struct net *net)
 
 #ifdef __KERNEL__
 struct rtmsg;
-extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
+extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
+			   struct rtmsg *rtm, int nowait);
 
 #ifdef CONFIG_IPV6_MROUTE
 static inline struct sock *mroute6_socket(struct net *net)
net/ipv6/ip6mr.c +130 -105

695 lines not on this page · raw message

net/ipv6/route.c +1 -1
index 9da1ece..18c486c 100644
@@ -2194,7 +2194,7 @@ static int rt6_fill_node(struct net *net,
 	if (iif) {
 #ifdef CONFIG_IPV6_MROUTE
 		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
-			int err = ip6mr_get_route(skb, rtm, nowait);
+			int err = ip6mr_get_route(net, skb, rtm, nowait);
 			if (err <= 0) {
 				if (!nowait) {
 					if (err == 0)
#9 lore raw
In reply to Benjamin Thery

Dave,

While doing some more tests on the patchset I've realized that the queue of unresolved entries (mfc_unres_queue) should also be allocated per-netns (or at least counter cache_resolve_queue_len should be).

With the current patchset, the cache for unresolved entries is limited to 10 entries for all namespaces. D'oh.

I'm looking at this issue and will resend the patchset with the missing patch ASAP.

Benjamin

Quoted 18 lines · Benjamin Thery

This patchset introduces the support for network namespaces in IPv6 multicast forwarding code (net/ipv6/ip6mr.c).

The first patches in the series moves global data from ip6mr.c into struct netns_ipv6 to prepare netns support. Data are still referenced in init_net only. One of these patches makes the related /proc entries
per-namespace.

The last patch does the main job and enables the network namespace support by replacing all the init_net references with the proper net retrieved from sockets or net devices.

The patchset applies on top of net-next-2.6

Regards,
Benjamin

Signature · 3 lines
B e n j a m i n   T h e r y  - BULL/DT/Open Software R&D

   http://www.bull.com
maintainer
#10 lore raw

From: Benjamin Thery <[email protected]>
Date: Tue, 09 Dec 2008 17:56:03 +0100

Quoted 9 lines

While doing some more tests on the patchset I've realized that the queue of unresolved entries (mfc_unres_queue) should also be allocated per-netns (or at least counter cache_resolve_queue_len should be).

With the current patchset, the cache for unresolved entries is limited to 10 entries for all namespaces. D'oh.

I'm looking at this issue and will resend the patchset with the missing patch ASAP.

Okie dokie.