Skip to contentSkip to conversation

MIB: add struct net to UDP accounting macros

PATCH Applied Pavel Emelyanov 5 participants 11 messages Jul 4, 2008 – Jul 10, 2008

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

cover MIB: add struct net to UDP accounting macros

This is the first small set of MIB statistics netnsization. The easiest case is UDP stats, so I started with this one. If this set is accepted, I will go on step-by-step with adding struct net to all the other stats' accounting macros, then SNMP_XXX ones and finish with a set than will put the stats on the struct net and fix appropriate proc files.

#1 lore raw

PATCH 1/4 MIB: add struct net to UDP_INC_STATS_USER

Nothing special - all the places already have a struct sock at hands, so use the sock_net() net.

---
 include/net/udp.h |    2 +-
 net/ipv4/udp.c    |   11 +++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)
include/net/udp.h +1 -1
index 7a86848..1331909 100644
@@ -158,7 +158,7 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
 /*
  * 	SNMP statistics for UDP and UDP-Lite
  */
-#define UDP_INC_STATS_USER(field, is_udplite)			       do {   \
+#define UDP_INC_STATS_USER(net, field, is_udplite)	      do { (void)net; \
 	if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field);       \
 	else		SNMP_INC_STATS_USER(udp_statistics, field);  }  while(0)
 #define UDP_INC_STATS_BH(field, is_udplite) 			       do  {  \
net/ipv4/udp.c +7 -4
index 3bbf6fb..c97da53 100644
@@ -526,7 +526,8 @@ out:
 	up->len = 0;
 	up->pending = 0;
 	if (!err)
-		UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite);
+		UDP_INC_STATS_USER(sock_net(sk),
+				UDP_MIB_OUTDATAGRAMS, is_udplite);
 	return err;
 }
 
@@ -725,7 +726,8 @@ out:
 	 * seems like overkill.
 	 */
 	if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
-		UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite);
+		UDP_INC_STATS_USER(sock_net(sk),
+				UDP_MIB_SNDBUFERRORS, is_udplite);
 	}
 	return err;
 
@@ -888,7 +890,8 @@ try_again:
 		goto out_free;
 
 	if (!peeked)
-		UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
+		UDP_INC_STATS_USER(sock_net(sk),
+				UDP_MIB_INDATAGRAMS, is_udplite);
 
 	sock_recv_timestamp(msg, sk, skb);
 
@@ -917,7 +920,7 @@ out:
 csum_copy_err:
 	lock_sock(sk);
 	if (!skb_kill_datagram(sk, skb, flags))
-		UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
+		UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
 	release_sock(sk);
 
 	if (noblock)
Signature · 1 line
1.5.3.4
#2 lore raw

PATCH 2/4 MIB: add struct net to UDP_INC_STATS_BH

In reply to Pavel Emelyanov

Two special cases here - one is rxrpc - I put init_net there explicitly, since we haven't touched this part yet. The second place is in __udp4_lib_rcv - we already have a struct net there, but I have to move its initialization above to make it ready at the "drop" label.

---
 include/net/udp.h    |    6 +++---
 net/ipv4/udp.c       |   18 ++++++++++--------
 net/rxrpc/ar-input.c |    5 +++--
 3 files changed, 16 insertions(+), 13 deletions(-)
include/net/udp.h +3 -3
index 1331909..7b18cfb 100644
@@ -161,7 +161,7 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
 #define UDP_INC_STATS_USER(net, field, is_udplite)	      do { (void)net; \
 	if (is_udplite) SNMP_INC_STATS_USER(udplite_statistics, field);       \
 	else		SNMP_INC_STATS_USER(udp_statistics, field);  }  while(0)
-#define UDP_INC_STATS_BH(field, is_udplite) 			       do  {  \
+#define UDP_INC_STATS_BH(net, field, is_udplite) 	      do { (void)net; \
 	if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field);         \
 	else		SNMP_INC_STATS_BH(udp_statistics, field);    }  while(0)
 
@@ -176,12 +176,12 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
 #define UDPX_INC_STATS_BH(sk, field) \
 	do { \
 		if ((sk)->sk_family == AF_INET) \
-			UDP_INC_STATS_BH(field, 0); \
+			UDP_INC_STATS_BH(sock_net(sk), field, 0); \
 		else \
 			UDP6_INC_STATS_BH(field, 0); \
 	} while (0);
 #else
-#define UDPX_INC_STATS_BH(sk, field) UDP_INC_STATS_BH(field, 0)
+#define UDPX_INC_STATS_BH(sk, field) UDP_INC_STATS_BH(sock_net(sk), field, 0)
 #endif
 
 /* /proc */
net/ipv4/udp.c +10 -8
index c97da53..7187121 100644
@@ -991,7 +991,8 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 
 			ret = (*up->encap_rcv)(sk, skb);
 			if (ret <= 0) {
-				UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS,
+				UDP_INC_STATS_BH(sock_net(sk),
+						 UDP_MIB_INDATAGRAMS,
 						 is_udplite);
 				return -ret;
 			}
@@ -1044,7 +1045,8 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
 		/* Note that an ENOMEM error is charged twice */
 		if (rc == -ENOMEM) {
-			UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite);
+			UDP_INC_STATS_BH(sock_net(sk),
+					UDP_MIB_RCVBUFERRORS, is_udplite);
 			atomic_inc(&sk->sk_drops);
 		}
 		goto drop;
@@ -1053,7 +1055,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 	return 0;
 
 drop:
-	UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
+	UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
 	kfree_skb(skb);
 	return -1;
 }
@@ -1161,7 +1163,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	struct rtable *rt = (struct rtable*)skb->dst;
 	__be32 saddr = ip_hdr(skb)->saddr;
 	__be32 daddr = ip_hdr(skb)->daddr;
-	struct net *net;
+	struct net *net = dev_net(skb->dev);
 
 	/*
 	 *  Validate the packet.
@@ -1183,7 +1185,6 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	if (udp4_csum_init(skb, uh, proto))
 		goto csum_error;
 
-	net = dev_net(skb->dev);
 	if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
 		return __udp4_lib_mcast_deliver(net, skb, uh,
 				saddr, daddr, udptable);
@@ -1217,7 +1218,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	if (udp_lib_checksum_complete(skb))
 		goto csum_error;
 
-	UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
+	UDP_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 
 	/*
@@ -1251,7 +1252,7 @@ csum_error:
 		       ntohs(uh->dest),
 		       ulen);
 drop:
-	UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
+	UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
 	kfree_skb(skb);
 	return 0;
 }
@@ -1458,7 +1459,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
 		spin_lock_bh(&rcvq->lock);
 		while ((skb = skb_peek(rcvq)) != NULL &&
 		       udp_lib_checksum_complete(skb)) {
-			UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite);
+			UDP_INC_STATS_BH(sock_net(sk),
+					UDP_MIB_INERRORS, is_lite);
 			__skb_unlink(skb, rcvq);
 			kfree_skb(skb);
 		}
net/rxrpc/ar-input.c +3 -2
index f8a699e..f98c802 100644
@@ -21,6 +21,7 @@
 #include <net/af_rxrpc.h>
 #include <net/ip.h>
 #include <net/udp.h>
+#include <net/net_namespace.h>
 #include "ar-internal.h"
 
 unsigned long rxrpc_ack_timeout = 1;
@@ -708,12 +709,12 @@ void rxrpc_data_ready(struct sock *sk, int count)
 	if (skb_checksum_complete(skb)) {
 		rxrpc_free_skb(skb);
 		rxrpc_put_local(local);
-		UDP_INC_STATS_BH(UDP_MIB_INERRORS, 0);
+		UDP_INC_STATS_BH(&init_net, UDP_MIB_INERRORS, 0);
 		_leave(" [CSUM failed]");
 		return;
 	}
 
-	UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, 0);
+	UDP_INC_STATS_BH(&init_net, UDP_MIB_INDATAGRAMS, 0);
 
 	/* the socket buffer we have is owned by UDP, with UDP's data all over
 	 * it, but we really want our own */
Signature · 1 line
1.5.3.4
#3 lore raw

PATCH 3/4 MIB: add struct net to UDP6_INC_STATS_USER

In reply to Pavel Emelyanov

As simple as the patch #1 in this set.

---
 include/net/udp.h |    2 +-
 net/ipv6/udp.c    |   11 +++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)
include/net/udp.h +1 -1
index 7b18cfb..bb5b9ec 100644
@@ -168,7 +168,7 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
 #define UDP6_INC_STATS_BH(field, is_udplite) 			      do  {  \
 	if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field);         \
 	else		SNMP_INC_STATS_BH(udp_stats_in6, field);    } while(0)
-#define UDP6_INC_STATS_USER(field, is_udplite)			       do {    \
+#define UDP6_INC_STATS_USER(net, field, is_udplite)	    do { (void)net;    \
 	if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field);         \
 	else		SNMP_INC_STATS_USER(udp_stats_in6, field);    } while(0)
 
net/ipv6/udp.c +7 -4
index f91e1df..833f715 100644
@@ -166,7 +166,8 @@ try_again:
 		goto out_free;
 
 	if (!peeked)
-		UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
+		UDP6_INC_STATS_USER(sock_net(sk),
+				UDP_MIB_INDATAGRAMS, is_udplite);
 
 	sock_recv_timestamp(msg, sk, skb);
 
@@ -213,7 +214,7 @@ out:
 csum_copy_err:
 	lock_sock(sk);
 	if (!skb_kill_datagram(sk, skb, flags))
-		UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
+		UDP6_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
 	release_sock(sk);
 
 	if (flags & MSG_DONTWAIT)
@@ -591,7 +592,8 @@ out:
 	up->len = 0;
 	up->pending = 0;
 	if (!err)
-		UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite);
+		UDP6_INC_STATS_USER(sock_net(sk),
+				UDP_MIB_OUTDATAGRAMS, is_udplite);
 	return err;
 }
 
@@ -873,7 +875,8 @@ out:
 	 * seems like overkill.
 	 */
 	if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
-		UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite);
+		UDP6_INC_STATS_USER(sock_net(sk),
+				UDP_MIB_SNDBUFERRORS, is_udplite);
 	}
 	return err;
 
Signature · 1 line
1.5.3.4
#4 lore raw

PATCH 4/4 MIB: add struct net to UDP6_INC_STATS_BH

In reply to Pavel Emelyanov
---
 include/net/udp.h |    4 ++--
 net/ipv6/udp.c    |   13 +++++++------
 2 files changed, 9 insertions(+), 8 deletions(-)
include/net/udp.h +2 -2
index bb5b9ec..3e55159 100644
@@ -165,7 +165,7 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
 	if (is_udplite) SNMP_INC_STATS_BH(udplite_statistics, field);         \
 	else		SNMP_INC_STATS_BH(udp_statistics, field);    }  while(0)
 
-#define UDP6_INC_STATS_BH(field, is_udplite) 			      do  {  \
+#define UDP6_INC_STATS_BH(net, field, is_udplite) 	    do { (void)net;  \
 	if (is_udplite) SNMP_INC_STATS_BH(udplite_stats_in6, field);         \
 	else		SNMP_INC_STATS_BH(udp_stats_in6, field);    } while(0)
 #define UDP6_INC_STATS_USER(net, field, is_udplite)	    do { (void)net;    \
@@ -178,7 +178,7 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
 		if ((sk)->sk_family == AF_INET) \
 			UDP_INC_STATS_BH(sock_net(sk), field, 0); \
 		else \
-			UDP6_INC_STATS_BH(field, 0); \
+			UDP6_INC_STATS_BH(sock_net(sk), field, 0); \
 	} while (0);
 #else
 #define UDPX_INC_STATS_BH(sk, field) UDP_INC_STATS_BH(sock_net(sk), field, 0)
net/ipv6/udp.c +7 -6
index 833f715..d1477b3 100644
@@ -299,7 +299,8 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
 		/* Note that an ENOMEM error is charged twice */
 		if (rc == -ENOMEM) {
-			UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite);
+			UDP6_INC_STATS_BH(sock_net(sk),
+					UDP_MIB_RCVBUFERRORS, is_udplite);
 			atomic_inc(&sk->sk_drops);
 		}
 		goto drop;
@@ -307,7 +308,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 
 	return 0;
 drop:
-	UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
+	UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
 	kfree_skb(skb);
 	return -1;
 }
@@ -439,7 +440,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	struct net_device *dev = skb->dev;
 	struct in6_addr *saddr, *daddr;
 	u32 ulen = 0;
-	struct net *net;
+	struct net *net = dev_net(skb->dev);
 
 	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 		goto short_packet;
@@ -474,7 +475,6 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	if (udp6_csum_init(skb, uh, proto))
 		goto discard;
 
-	net = dev_net(skb->dev);
 	/*
 	 *	Multicast receive code
 	 */
@@ -497,7 +497,8 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 
 		if (udp_lib_checksum_complete(skb))
 			goto discard;
-		UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
+		UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS,
+				proto == IPPROTO_UDPLITE);
 
 		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
 
@@ -522,7 +523,7 @@ short_packet:
 		       ulen, skb->len);
 
 discard:
-	UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
+	UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
 	kfree_skb(skb);
 	return 0;
 }
Signature · 1 line
1.5.3.4
maintainer Applied
#5 lore raw
In reply to Pavel Emelyanov

From: Pavel Emelyanov <[email protected]>
Date: Fri, 04 Jul 2008 15:58:44 +0400

Quoted 8 lines

This is the first small set of MIB statistics netnsization. The easiest case is UDP stats, so I started with this one. If this set is accepted, I will go on step-by-step with adding struct net to all the other stats' accounting macros, then SNMP_XXX ones and finish with a set than will put the stats on the struct net and fix appropriate proc files.

Applied, thanks Pavel.

Are we going to provide some way for an administrator to fetch stats from the perspective of all namespaces? I know the idea is seperation with this stuff, but admins are going to want something like that.

#6 lore raw
Quoted 12 lines · David Miller

From: Pavel Emelyanov <[email protected]>
Date: Fri, 04 Jul 2008 15:58:44 +0400

Quoted 8 lines

This is the first small set of MIB statistics netnsization. The easiest case is UDP stats, so I started with this one. If this set is accepted, I will go on step-by-step with adding struct net to all the other stats' accounting macros, then SNMP_XXX ones and finish with a set than will put the stats on the struct net and fix appropriate proc files.

Quoted 6 lines

Applied, thanks Pavel.

Are we going to provide some way for an administrator to fetch stats from the perspective of all namespaces? I know the idea is seperation with this stuff, but admins are going to want something like that.

Well, if we want to get the stats for each namespace separately, then this ability is already present. Since this statistics is shown via the /proc/net files and the /proc/net itself is seen via the /proc/<pid>/net, then we can walk the init-s of all the containers in the system and dump this info.

The problem that is to be solved with this approach is how to get these init-s :) But since finding any namespace by some task living in it is a common practice now (netdev moving, sys_hijack) this one will be solved.

BTW, are there some plans about implementing some netlink-based fetcher of this statistics? If so, then I think it's worth making this engine namespaces aware from the very beginning.

Thanks,
Pavel

maintainer
#7 lore raw

From: Pavel Emelyanov <[email protected]>
Date: Mon, 07 Jul 2008 12:13:27 +0400

Quoted 3 lines

BTW, are there some plans about implementing some netlink-based fetcher of this statistics? If so, then I think it's worth making this engine namespaces aware from the very beginning.

I'm not aware of any, or whether that would make any sense.

Thomas?

#8 lore raw

* David Miller <[email protected]> 2008-07-07 01:47

Quoted 8 lines

From: Pavel Emelyanov <[email protected]>
Date: Mon, 07 Jul 2008 12:13:27 +0400

Quoted 3 lines

BTW, are there some plans about implementing some netlink-based fetcher of this statistics? If so, then I think it's worth making this engine namespaces aware from the very beginning.

I'm not aware of any, or whether that would make any sense.

There have been plans but none was brave enough so far.

#9 lore raw
In reply to Pavel Emelyanov
Quoted 23 lines · Pavel Emelyanov
Quoted 7 lines · David Miller

From: Pavel Emelyanov <[email protected]>
Date: Fri, 04 Jul 2008 15:58:44 +0400

Quoted 4 lines

This is the first small set of MIB statistics netnsization. The easiest
case is UDP stats, so I started with this one. If this set is accepted,
I will go on step-by-step with adding struct net to all the other stats' accounting macros, then SNMP_XXX ones and finish with a set than will put the stats on the struct net and fix appropriate proc files.

Quoted 8 lines
Quoted 2 lines

Applied, thanks Pavel.

Are we going to provide some way for an administrator to fetch stats from the perspective of all namespaces? I know the idea is seperation with this stuff, but admins are going to want something like that.

Well, if we want to get the stats for each namespace separately, then this ability is already present. Since this statistics is shown via the /proc/net files and the /proc/net itself is seen via the /proc/<pid>/net, then we can walk the init-s of all the containers in the system and dump this info.

Quoted 7 lines

The problem that is to be solved with this approach is how to get these init-s :) But since finding any namespace by some task living in it is a common practice now (netdev moving, sys_hijack) this one will be solved.

BTW, are there some plans about implementing some netlink-based fetcher of this statistics? If so, then I think it's worth making this engine namespaces aware from the very beginning.

Shouldn't be interesting to handle the network namespaces directly with the iproute command ?

* ip netns add <name>
* ip netns del <name>
* ip netns <oldname> set name <newname>
* ip netns show

When a network namespace is created via clone|unshare, the name is automatically the pid of the creator.

In order to track the namespace, we can add an entry in /proc/net (aka /proc/<pid>/net) named "name" which contains the name of the namespace. I heard Eric is thinking about a netnsfs.

From a larger perspective, the iproute command with a new "netns" subcommand can be enhanced to have more features, for example the freeze and resume for the network.

* ip netns set down <name>
* ip netns set up <name>

So having the netns binded, we can plug the known subcommand (link, ip, ...) with the netns features. For examples:

* ip addr add 1.2.3.4/24 dev eth0 netns foo

#10 lore raw

Global namespace naming, and monitoring.

Quoted 9 lines · Daniel Lezcano
Quoted 9 lines

Well, if we want to get the stats for each namespace separately, then this ability is already present. Since this statistics is shown via the /proc/net files and the /proc/net itself is seen via the /proc/<pid>/net, then we can walk the init-s of all the containers in the system and dump this info.

The problem that is to be solved with this approach is how to get these init-s :) But since finding any namespace by some task living in it is a common practice now (netdev moving, sys_hijack) this one will be solved.

Yes. Finding the which the a single process in each namespace to look at (the init-s) is something we have yet to refine.

The model for multiple namespace monitoring is definitely having filesystems mounted that we can look at to get all of the information we care about. /proc does a lot of this today, and with some cleanups it should be able to display per namespace sysctls and a few other goodies.

...

There is one class of user that we have yet to find a good solution for. The people who want to use isolated network stacks within a single application. Usually because there are duplicate routes between the stacks. In that case indirect through processes falls down, as does being able to create a socket in one namespace.

My latest brainstorm comes from asking how the problem would have been solved in plan9. The idea is to create a filesystem we can mount that holds a reference to a netns (netnsfs). Using a mounted filesystem like that is a bit heavy weight, but just referring to it's the root directory is enough to give us a name in the mount namespace. The auto unmount and consequent release of the network namespace when the mount namespace goes away is attractive.

Quoted 7 lines

Shouldn't be interesting to handle the network namespaces directly with the iproute command ?

* ip netns add <name>
* ip netns del <name>
* ip netns <oldname> set name <newname>
* ip netns show

Ugh. You have to be really careful with proposal like this to ensure that they wind up in some namespace. Otherwise you have created a new global namespace, and have made nesting of containers much harder to implement.

Quoted 4 lines

So having the netns binded, we can plug the known subcommand (link, ip, ...) with the netns features. For examples:

* ip addr add 1.2.3.4/24 dev eth0 netns foo

The only thing limiting that today is that we need someway to get a netlink socket on the namespace in question. Get me in a perverse mood and I will grab the netlink socket from one of the init-s with ptrace.

Eric