Skip to contentSkip to conversation

netns: Add network namespace argument in rt6_fill_node() and ipv6_dev_get_saddr()

PATCH In review Brian Haley 6 participants 8 messages Aug 14, 2008 – Aug 18, 2008 1 message not in the archive

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

PATCH 2/2 netns: Add network namespace argument in rt6_fill_node() and ipv6_dev_get_saddr()

Add network namespace argument to rt6_fill_node() and ipv6_dev_get_saddr(). This required adding a namespace pointer in the IPv6 fib dump callback routine.

-Brian

---

include/net/addrconf.h +2 -1
index 06b2814..c216de5 100644
@@ -80,7 +80,8 @@ extern struct inet6_ifaddr      *ipv6_get_ifaddr(struct net *net,
 						 struct net_device *dev,
 						 int strict);
 
-extern int			ipv6_dev_get_saddr(struct net_device *dev, 
+extern int			ipv6_dev_get_saddr(struct net *net,
+					       struct net_device *dev,
 					       const struct in6_addr *daddr,
 					       unsigned int srcprefs,
 					       struct in6_addr *saddr);
include/net/ip6_route.h +1 -0
index bc391ba..5f53db7 100644
@@ -107,6 +107,7 @@ struct rt6_rtnl_dump_arg
 {
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
+	struct net *net;
 };
 
 extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
net/ipv6/addrconf.c +4 -2
index a7842c5..dea420a 100644
@@ -1106,17 +1106,19 @@ out:
 	return ret;
 }
 
-int ipv6_dev_get_saddr(struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
 		       const struct in6_addr *daddr, unsigned int prefs,
 		       struct in6_addr *saddr)
 {
 	struct ipv6_saddr_score scores[2],
 				*score = &scores[0], *hiscore = &scores[1];
-	struct net *net = dev_net(dst_dev);
 	struct ipv6_saddr_dst dst;
 	struct net_device *dev;
 	int dst_type;
 
+	if (!net)
+		net = dev_net(dst_dev);
+
 	dst_type = __ipv6_addr_type(daddr);
 	dst.addr = daddr;
 	dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
net/ipv6/fib6_rules.c +2 -1
index 8d05527..f5de3f9 100644
@@ -93,7 +93,8 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 			if (flags & RT6_LOOKUP_F_SRCPREF_COA)
 				srcprefs |= IPV6_PREFER_SRC_COA;
 
-			if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+			if (ipv6_dev_get_saddr(net,
+					       ip6_dst_idev(&rt->u.dst)->dev,
 					       &flp->fl6_dst, srcprefs,
 					       &saddr))
 				goto again;
net/ipv6/ip6_fib.c +1 -0
index 52dddc2..29c7c99 100644
@@ -378,6 +378,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
 	arg.skb = skb;
 	arg.cb = cb;
+	arg.net = net;
 	w->args = &arg;
 
 	for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
net/ipv6/ip6_output.c +1 -1
index a4402de..0e844c2 100644
@@ -934,7 +934,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 		goto out_err_release;
 
 	if (ipv6_addr_any(&fl->fl6_src)) {
-		err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
 					 &fl->fl6_dst,
 					 sk ? inet6_sk(sk)->srcprefs : 0,
 					 &fl->fl6_src);
net/ipv6/ndisc.c +1 -1
index beb48e3..f1c62ba 100644
@@ -549,7 +549,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 			override = 0;
 		in6_ifa_put(ifp);
 	} else {
-		if (ipv6_dev_get_saddr(dev, daddr,
+		if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
 				       inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
 				       &tmpaddr))
 			return;
net/ipv6/route.c +7 -5
index 41b165f..9af6115 100644
@@ -2106,7 +2106,8 @@ static inline size_t rt6_nlmsg_size(void)
 	       + nla_total_size(sizeof(struct rta_cacheinfo));
 }
 
-static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+static int rt6_fill_node(struct net *net,
+			 struct sk_buff *skb, struct rt6_info *rt,
 			 struct in6_addr *dst, struct in6_addr *src,
 			 int iif, int type, u32 pid, u32 seq,
 			 int prefix, int nowait, unsigned int flags)
@@ -2189,7 +2190,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
 	} else if (dst) {
 		struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst);
 		struct in6_addr saddr_buf;
-		if (ipv6_dev_get_saddr(idev ? idev->dev : NULL,
+		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
 				       dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
@@ -2234,7 +2235,8 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
 	} else
 		prefix = 0;
 
-	return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
+	return rt6_fill_node(arg->net,
+		     arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
 		     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
 		     prefix, 0, NLM_F_MULTI);
 }
@@ -2300,7 +2302,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
 	skb->dst = &rt->u.dst;
 
-	err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
+	err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
 			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
 			    nlh->nlmsg_seq, 0, 0, 0);
 	if (err < 0) {
@@ -2327,7 +2329,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
 	if (skb == NULL)
 		goto errout;
 
-	err = rt6_fill_node(skb, rt, NULL, NULL, 0,
+	err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
 				event, info->pid, seq, 0, 0, 0);
 	if (err < 0) {
 		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
net/ipv6/xfrm6_policy.c +1 -1
index 8f1e054..5c36ef2 100644
@@ -57,7 +57,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
 	if (IS_ERR(dst))
 		return -EHOSTUNREACH;
 
-	ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+	ipv6_dev_get_saddr(NULL, ip6_dst_idev(dst)->dev,
 			   (struct in6_addr *)&daddr->a6, 0,
 			   (struct in6_addr *)&saddr->a6);
 	dst_release(dst);
net/sctp/ipv6.c +2 -1
index 483a01d..e0945d4 100644
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
 			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
 	if (!asoc) {
-		ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+		ipv6_dev_get_saddr(NULL,
+				   dst ? ip6_dst_idev(dst)->dev : NULL,
 				   &daddr->v6.sin6_addr,
 				   inet6_sk(&sk->inet.sk)->srcprefs,
 				   &saddr->v6.sin6_addr);
#1 lore raw

Hi Brian

Quoted 7 lines · Brian Haley

---

net/sctp/ipv6.c +0 -0
index 483a01d..e0945d4 100644

net/sctp/ipv6.c static void sctp_v6_get_saddr(struct sctp_sock *sk, · line 326

Quoted 9 lines
net/sctp/ipv6.c +2 -1
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
 			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
 	if (!asoc) {
-		ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+		ipv6_dev_get_saddr(NULL,
+				   dst ? ip6_dst_idev(dst)->dev : NULL,
 				   &daddr->v6.sin6_addr,
 				   inet6_sk(&sk->inet.sk)->srcprefs,
 				   &saddr->v6.sin6_addr);

I think this needs to use sock_net(sctp_opt2s(sk)) instead of NULL.

-vlad

#2 lore raw

Hi Vlad,

Quoted 12 lines · Vlad Yasevich

Hi Brian

Quoted 9 lines · Brian Haley

---

net/sctp/ipv6.c +0 -0
index 483a01d..e0945d4 100644
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
 			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
Quoted 10 lines

net/sctp/ipv6.c static void sctp_v6_get_saddr(struct sctp_sock *sk, · line 326

Quoted 7 lines
net/sctp/ipv6.c +2 -1
 	if (!asoc) {
-		ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+		ipv6_dev_get_saddr(NULL,
+				   dst ? ip6_dst_idev(dst)->dev : NULL,
 				   &daddr->v6.sin6_addr,
 				   inet6_sk(&sk->inet.sk)->srcprefs,
 				   &saddr->v6.sin6_addr);

I think this needs to use sock_net(sctp_opt2s(sk)) instead of NULL.

Thanks Vlad, I didn't see that. I noticed the xfrm code could pass non-NULL has well, I'll respin.

-Brian

#3 lore raw
Quoted 25 lines · Brian Haley

Hi Vlad,

Quoted 22 lines · Vlad Yasevich

Hi Brian

Quoted 7 lines · Brian Haley

---

net/sctp/ipv6.c +0 -0
index 483a01d..e0945d4 100644

net/sctp/ipv6.c static void sctp_v6_get_saddr(struct sctp_sock *sk, · line 326

Quoted 9 lines
net/sctp/ipv6.c +2 -1
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
               __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
     if (!asoc) {
-        ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+        ipv6_dev_get_saddr(NULL,
+                   dst ? ip6_dst_idev(dst)->dev : NULL,
                    &daddr->v6.sin6_addr,
                    inet6_sk(&sk->inet.sk)->srcprefs,
                    &saddr->v6.sin6_addr);

I think this needs to use sock_net(sctp_opt2s(sk)) instead of NULL.

that was supposed to read: sock_net(sctp_opt2sk(sk)

-vlad

#4 lore raw
In reply to Vlad Yasevich
Quoted 12 lines · Vlad Yasevich

Hi Brian

Quoted 9 lines · Brian Haley

---

net/sctp/ipv6.c +0 -0
index 483a01d..e0945d4 100644
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
 			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
Quoted 10 lines

net/sctp/ipv6.c static void sctp_v6_get_saddr(struct sctp_sock *sk, · line 326

Quoted 7 lines
net/sctp/ipv6.c +2 -1
 	if (!asoc) {
-		ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+		ipv6_dev_get_saddr(NULL,
+				   dst ? ip6_dst_idev(dst)->dev : NULL,
 				   &daddr->v6.sin6_addr,
 				   inet6_sk(&sk->inet.sk)->srcprefs,
 				   &saddr->v6.sin6_addr);

I think this needs to use sock_net(sctp_opt2s(sk)) instead of NULL.

this looks safe to me

#5 lore raw
In reply to Brian Haley
Quoted 8 lines · Brian Haley

Add network namespace argument to rt6_fill_node() and ipv6_dev_get_saddr(). This required adding a namespace pointer in the IPv6 fib dump callback routine.

-Brian

---

This patch is to fix a kernel panic in ipv6_dev_get_saddr.
That happens because the dev parameter can be null and we try to dereference dev->nd_net, right ?

The approach looks correct except with the network namespace passed as parameter, it must never be NULL.

Quoted 38 lines
include/net/addrconf.h +2 -1
index 06b2814..c216de5 100644
@@ -80,7 +80,8 @@ extern struct inet6_ifaddr      *ipv6_get_ifaddr(struct net *net,
 						 struct net_device *dev,
 						 int strict);
 
-extern int			ipv6_dev_get_saddr(struct net_device *dev, 
+extern int			ipv6_dev_get_saddr(struct net *net,
+					       struct net_device *dev,
 					       const struct in6_addr *daddr,
 					       unsigned int srcprefs,
 					       struct in6_addr *saddr);
include/net/ip6_route.h +1 -0
index bc391ba..5f53db7 100644
@@ -107,6 +107,7 @@ struct rt6_rtnl_dump_arg
 {
 	struct sk_buff *skb;
 	struct netlink_callback *cb;
+	struct net *net;
 };
 
 extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
net/ipv6/addrconf.c +1 -1
index a7842c5..dea420a 100644
@@ -1106,17 +1106,19 @@ out:
 	return ret;
 }
 
-int ipv6_dev_get_saddr(struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
 		       const struct in6_addr *daddr, unsigned int prefs,
 		       struct in6_addr *saddr)

net/ipv6/addrconf.c out: · line 1120

Quoted 10 lines
net/ipv6/addrconf.c +2 -1
 {
 	struct ipv6_saddr_score scores[2],
 				*score = &scores[0], *hiscore = &scores[1];
-	struct net *net = dev_net(dst_dev);
 	struct ipv6_saddr_dst dst;
 	struct net_device *dev;
 	int dst_type;
 
+	if (!net)
+		net = dev_net(dst_dev);

These lines are not needed, because the net parameter will be never NULL, see below.

Quoted 111 lines
net/ipv6/addrconf.c +0 -0
 	dst_type = __ipv6_addr_type(daddr);
 	dst.addr = daddr;
 	dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
net/ipv6/fib6_rules.c +2 -1
index 8d05527..f5de3f9 100644
@@ -93,7 +93,8 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 			if (flags & RT6_LOOKUP_F_SRCPREF_COA)
 				srcprefs |= IPV6_PREFER_SRC_COA;
 
-			if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+			if (ipv6_dev_get_saddr(net,
+					       ip6_dst_idev(&rt->u.dst)->dev,
 					       &flp->fl6_dst, srcprefs,
 					       &saddr))
 				goto again;
net/ipv6/ip6_fib.c +1 -0
index 52dddc2..29c7c99 100644
@@ -378,6 +378,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
 	arg.skb = skb;
 	arg.cb = cb;
+	arg.net = net;
 	w->args = &arg;
 
 	for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
net/ipv6/ip6_output.c +1 -1
index a4402de..0e844c2 100644
@@ -934,7 +934,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 		goto out_err_release;
 
 	if (ipv6_addr_any(&fl->fl6_src)) {
-		err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
 					 &fl->fl6_dst,
 					 sk ? inet6_sk(sk)->srcprefs : 0,
 					 &fl->fl6_src);
net/ipv6/ndisc.c +1 -1
index beb48e3..f1c62ba 100644
@@ -549,7 +549,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 			override = 0;
 		in6_ifa_put(ifp);
 	} else {
-		if (ipv6_dev_get_saddr(dev, daddr,
+		if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
 				       inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
 				       &tmpaddr))
 			return;
net/ipv6/route.c +7 -5
index 41b165f..9af6115 100644
@@ -2106,7 +2106,8 @@ static inline size_t rt6_nlmsg_size(void)
 	       + nla_total_size(sizeof(struct rta_cacheinfo));
 }
 
-static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+static int rt6_fill_node(struct net *net,
+			 struct sk_buff *skb, struct rt6_info *rt,
 			 struct in6_addr *dst, struct in6_addr *src,
 			 int iif, int type, u32 pid, u32 seq,
 			 int prefix, int nowait, unsigned int flags)
@@ -2189,7 +2190,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
 	} else if (dst) {
 		struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst);
 		struct in6_addr saddr_buf;
-		if (ipv6_dev_get_saddr(idev ? idev->dev : NULL,
+		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
 				       dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
@@ -2234,7 +2235,8 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
 	} else
 		prefix = 0;
 
-	return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
+	return rt6_fill_node(arg->net,
+		     arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
 		     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
 		     prefix, 0, NLM_F_MULTI);
 }
@@ -2300,7 +2302,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
 	skb->dst = &rt->u.dst;
 
-	err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
+	err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
 			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
 			    nlh->nlmsg_seq, 0, 0, 0);
 	if (err < 0) {
@@ -2327,7 +2329,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
 	if (skb == NULL)
 		goto errout;
 
-	err = rt6_fill_node(skb, rt, NULL, NULL, 0,
+	err = rt6_fill_node(net, skb, rt, NULL, NULL, 0,
 				event, info->pid, seq, 0, 0, 0);
 	if (err < 0) {
 		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
net/ipv6/xfrm6_policy.c +0 -0
index 8f1e054..5c36ef2 100644

net/ipv6/xfrm6_policy.c static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) · line 60

Quoted 5 lines
net/ipv6/xfrm6_policy.c +1 -1
@@ -57,7 +57,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
 	if (IS_ERR(dst))
 		return -EHOSTUNREACH;
 
-	ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+	ipv6_dev_get_saddr(NULL, ip6_dst_idev(dst)->dev,
	ipv6_dev_get_saddr(&init_net, ...

net/sctp/ipv6.c static void sctp_v6_get_saddr(struct sctp_sock *sk, · line 322

Quoted 13 lines
net/ipv6/xfrm6_policy.c +0 -0
 			   (struct in6_addr *)&daddr->a6, 0,
 			   (struct in6_addr *)&saddr->a6);
 	dst_release(dst);
net/sctp/ipv6.c +1 -1
index 483a01d..e0945d4 100644
@@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
 			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
 	if (!asoc) {
-		ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+		ipv6_dev_get_saddr(NULL,
		ipv6_dev_get_saddr(&init_net, ...

Using init_net instead of NULL makes sense for xfrm6 and sctp, because they are not yet supported by the namespaces :) Furthermore it is more practical to track the places where we have to take care of the namespaces.

Thanks.
-- Daniel

maintainer
#6 lore raw

From: Daniel Lezcano <[email protected]>
Date: Sun, 17 Aug 2008 00:47:12 +0200

Quoted 2 lines

The approach looks correct except with the network namespace passed as parameter, it must never be NULL.

You're reviewing the patches that Brian retracted, we added a different version of these fixes in the end.

A message that is not in the archive (sent off-list or not yet received): 20080817.153526.109132408.davem-fT/PcQaiUtIeIZ0/[email protected]

#8 lore raw
Quoted 8 lines · David Miller

From: Daniel Lezcano <dlezcano-NmTC/[email protected]>
Date: Sun, 17 Aug 2008 00:47:12 +0200

Quoted 2 lines

The approach looks correct except with the network namespace passed as parameter, it must never be NULL.

You're reviewing the patches that Brian retracted, we added a different version of these fixes in the end.

Yes thanks, I received the emails delayed, so I saw the first version and no reply to them, neither the V2.
The second version is much better.
Thanks Brian for fixing this :)

-- Daniel