Re: VRF-like use of Network Namespaces

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

[this is related to the use of Eric Biederman's new set of patches for named
netns / netns switching]

ok so I successfully modified /sbin/ip. I can now:
- add/del a new netns by name: "ip netns {addns,delns} ns_name"
-> The namespace files are mounted on /var/run/netns/ns_name (so you have to
mkdir /var/run/netns/ for this to work).
- list netns: "ip netns show"
- use /sbin/ip in any named netns: "ip -netns ns_name link show"

(rough patch against current git tree attached)

I want now to move devices across namespaces using their filesystem names
(instead of using PIDs...). I'm not sure I can do it in userspace with the
current code yet, can I ?
I saw there was a rtnetlink attribute to set the netns of a device but it
uses the PID of a namespace owner to do so... within 'ip' i can refer to
only one namespace (i.e. the one that 'ip' task_struct->ns_proxy currently
points to), so I won't be able to move an interface from outside my
namespace to my namespace...
I hope my explanation is clear and that this will get some interest... :)

BTW is this the right ML to post this on ?

Thanks,

Mathieu.

On Tue, Jun 8, 2010 at 11:48 PM, Mathieu Peresse
<mathieu.peresse@xxxxxxxxx>wrote:

> I want to be able to type say: "ip vrf add vrf_name" to create a persisting
> network namespace, and then be able to add a net device to this namespace
> "ip link add dev tun0 vrf vrf_name" and then add a route to a subnet in this
> namespace using e.g. "ip route add 192.168.1.0/24 dev tun0 vrf vrf_name"
>
> I believe i can patch iproute2 (providing the 'ip' config utility) to use
> setns() and unshare() to add new namespaces and configure interfaces and
> routing in namespace ?
>
> I will look more into it tomorrow :)
>
> Thanks a lot for this awesome work anyways !
>
> mathieu.
>
>
> On Tue, Jun 8, 2010 at 11:06 PM, Daniel Lezcano <daniel.lezcano@xxxxxxx>wrote:
>
>> On 06/08/2010 07:12 PM, Mathieu Peresse wrote:
>>
>>> Looks good, thanks ! Has anyone worked to make 'ip' use these facilities
>>> ?
>>>
>>> If I understand correctly, from a network resource configuration
>>> perspective:
>>>
>>> - Creating a persisting namespace ('VRF') is equivalent to: create a
>>> namespace (using clone()),  which creates a proc entry for that
>>> namespace,
>>> and then bind mount the file so that it stays open.
>>>
>>>
>>
>> From the same process, unshare (using unshare()), open /proc/self/ns/net,
>> store the fd, unshare again, open /proc/self/ns/net, store the fd, ...
>> A single process handles by this way several network namespaces.
>>
>> To switch from one namespace to another, just use the setns syscall.
>>
>> Well this is one example to use it, AFAIK you are looking for this very
>> specific usage no ?
>>
>> Thanks
>>  -- Daniel
>>
>>
>>
>
>
> --
> a+
> mathieu
>



-- 
a+
mathieu
diff -pruN iproute2/ip/ip.c iproute2_netns/ip/ip.c
--- iproute2/ip/ip.c	2010-06-11 16:21:25.948671592 +0200
+++ iproute2_netns/ip/ip.c	2010-06-11 16:19:45.684672493 +0200
@@ -42,11 +42,11 @@ static void usage(void)
 "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
 "       ip [ -force ] -batch filename\n"
 "where  OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
-"                   tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm }\n"
+"                   tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm | netns }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
 "                    -o[neline] | -t[imestamp] | -b[atch] [filename] |\n"
-"                    -rc[vbuf] [size]}\n");
+"                    -rc[vbuf] [size] | -[n]etns netnsname}\n");
 	exit(-1);
 }
 
@@ -75,6 +75,7 @@ static const struct cmd {
 	{ "tap",	do_iptuntap },
 	{ "monitor",	do_ipmonitor },
 	{ "xfrm",	do_xfrm },
+	{ "netns",	do_ipnetns },
 	{ "mroute",	do_multiroute },
 	{ "mrule",	do_multirule },
 	{ "help",	do_help },
@@ -225,6 +226,27 @@ int main(int argc, char **argv)
 				exit(-1);
 			}
 			rcvbuf = size;
+		} else if (matches(opt, "-netns") == 0) {
+			int nsfd;
+			char netns_path[255];
+			argc--;
+			argv++;
+			if (strlen(argv[1]) > NETNS_STR_MAXLEN) {
+				fprintf(stderr, "Invalid netns name.\n");
+				exit(-1);
+			}
+			strcpy(netns_path, NETNS_DIR);
+			strcat(netns_path, argv[1]);
+			if ((nsfd = open(netns_path, O_RDONLY)) < 0) {
+					fprintf(stderr, "Could not open netns file.\n");
+					exit(-1);
+			}
+			/* Change namespace for iface configuration */
+			if (setns(0, nsfd) < 0) {
+				fprintf(stderr, "setns() failed: %s\n",
+						strerror(errno));
+				exit(-1);
+			}
 		} else if (matches(opt, "-help") == 0) {
 			usage();
 		} else {
diff -pruN iproute2/ip/ip_common.h iproute2_netns/ip/ip_common.h
--- iproute2/ip/ip_common.h	2010-06-11 16:21:25.948671592 +0200
+++ iproute2_netns/ip/ip_common.h	2010-06-11 16:20:14.900724958 +0200
@@ -39,6 +39,7 @@ extern int do_multiaddr(int argc, char *
 extern int do_multiroute(int argc, char **argv);
 extern int do_multirule(int argc, char **argv);
 extern int do_xfrm(int argc, char **argv);
+extern int do_ipnetns(int argc, char **argv);
 
 static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
 {
@@ -65,6 +66,51 @@ struct link_util
 
 struct link_util *get_link_kind(const char *kind);
 
+
+/* ip netns stuff */
+#define NETNS_STR_MAXLEN 16
+#define MY_NS_PROC_FILE "/proc/self/ns/net"
+#define NETNS_DIR	"/var/run/netns/"
+
+#ifndef _syscall0
+#include <unistd.h>
+#define _syscall0(type,name) \
+	type name(void) \
+{\
+	        return syscall(__NR_##name);\
+}
+#endif
+
+#ifndef _syscall1
+#include <unistd.h>
+#define _syscall1(type,name,type1,arg1, type2, arg2) \
+	type name(type1 arg1, type2 arg2) \
+{\
+	        return syscall(__NR_##name, arg1, arg2);\
+}
+#endif
+
+#ifndef HAVE_SETNS
+
+#if __i386__
+#    define __NR_setns 338
+#elif __x86_64__
+#    define __NR_setns 300 
+#else
+#    error "Architecture not supported"
+#endif
+
+#endif /* HAVE_SETNS */
+
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET		0x20000000
+#endif
+
+#ifndef setns 
+static inline _syscall1 (int,  setns, unsigned int, nstype, int, fd)
+#endif
+
+
 #ifndef	INFINITY_LIFE_TIME
 #define     INFINITY_LIFE_TIME      0xFFFFFFFFU
 #endif
diff -pruN iproute2/ip/iplink.c iproute2_netns/ip/iplink.c
--- iproute2/ip/iplink.c	2010-06-11 16:21:25.948671592 +0200
+++ iproute2_netns/ip/iplink.c	2010-06-11 16:19:16.232663973 +0200
@@ -28,6 +28,10 @@
 #include <sys/ioctl.h>
 #include <linux/sockios.h>
 
+#include <libgen.h>
+#include <sched.h>
+#include <linux/unistd.h>
+
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
diff -pruN iproute2/ip/ipnetns.c iproute2_netns/ip/ipnetns.c
--- iproute2/ip/ipnetns.c	1970-01-01 01:00:00.000000000 +0100
+++ iproute2_netns/ip/ipnetns.c	2010-06-11 16:19:16.232663973 +0200
@@ -0,0 +1,190 @@
+/*
+ * ipnetns.c		"ip netns".
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	James R. Leu <jleu@xxxxxxxxxxxxxx>
+ * 		Mathieu Peresse <mperesse@xxxxxxxxxxxx>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "utils.h"
+#include "ip_common.h"
+
+#define NETNS_ADDNS 1
+#define NETNS_DELNS 2 
+#define NETNS_ADDIF 3
+#define NETNS_DELIF 4 
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: ip netns [ add | remove ] NETNS_NAME\n");
+	fprintf(stderr, "       ip netns show\n");
+	exit(-1);
+}
+
+static int do_netns_show(char *path)
+{
+	DIR *mydir = NULL;
+        struct dirent *entry = NULL;
+
+
+	if ((mydir = opendir(path)) == NULL) {
+		fprintf(stderr, "Could not open dir: %s\n", strerror(errno));
+		return -1;
+	}
+
+	while((entry = readdir(mydir))) 
+	{
+		if ((strcmp(entry->d_name, "..") != 0) && 
+				(strcmp(entry->d_name, ".") != 0)) 
+			fprintf(stderr, "%s\n", entry->d_name);
+	}
+
+	closedir(mydir);
+	return 0;
+}
+
+static int ipnetns_mvdev(char *dev, char *netns)
+{
+       struct rtnl_handle rth;
+       struct {
+               struct nlmsghdr         n;
+               struct ifinfomsg        r;
+               char                    buf[16];
+       } req;
+       int pid = getpid();
+                                                                               
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_type = RTM_SETLINK;
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+
+       if (rtnl_open(&rth, 0) < 0)
+               return 1;
+
+       ll_init_map(&rth);
+
+       req.r.ifi_family = AF_UNSPEC;
+       req.r.ifi_index = ll_name_to_index(dev);
+       addattr_l(&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4);
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+               return 2;
+
+       return (0);
+}
+
+int ipnetns_modify(int cmd, char netns[NETNS_STR_MAXLEN])
+{
+
+	char netns_path[255] = NETNS_DIR;
+	unsigned long flags = CLONE_NEWNET;
+	int fd;
+	
+	strncat(netns_path, netns, sizeof(netns)); 
+
+	switch (cmd) 
+	{
+	/* add new namespace */
+	case NETNS_ADDNS:
+		if (unshare(flags) < 0) {
+			fprintf(stderr, "unshare() failed: %s",
+					strerror(errno));
+			return -1;
+		}
+		/*check netns doesn't already exists */
+		if ((fd = open(netns_path, O_RDONLY)) > 0) {
+			fprintf(stderr, "netns already exists.\n");
+			close(fd);
+			return -1;
+		}
+		/* create file for netns */
+		if ((fd = open(netns_path, O_CREAT, S_IRUSR)) < 0) {
+			fprintf(stderr, "could not create file.\n");
+			return -1;
+		}
+		close(fd);
+		if(mount(MY_NS_PROC_FILE, netns_path, "proc", MS_BIND, NULL) < 0) {
+			fprintf(stderr, "bind mount failed: %s\n",
+					strerror(errno));
+			return -1;
+		}
+		break;
+	/* del */
+	case NETNS_DELNS:
+		if(umount(netns_path) < 0) {
+			fprintf(stderr, "umount failed: %s\n", strerror(errno));
+			return -1;
+		}
+		if(remove(netns_path) < 0) {
+			fprintf(stderr, "remove failed: %s\n", strerror(errno));
+			return -1;
+		}
+		break;
+	/* add new interface in the current namespace 
+	 * (can be explicitely specified by -netns switch)*/
+	case NETNS_ADDIF:
+		break;
+	/* del */
+	case NETNS_DELIF:
+		break;
+	}
+
+	return 0;
+}
+
+
+
+
+
+int do_ipnetns(int argc, char **argv)
+{
+	if (argc > 0) {
+		if (matches(*argv, "show") == 0)
+			return do_netns_show(NETNS_DIR);
+		if (matches(*argv, "help") == 0)
+			usage();
+		if (matches(*argv, "addns") == 0) {
+		        NEXT_ARG();
+			if (strlen(*argv) > NETNS_STR_MAXLEN)
+			        invarg("Invalid \"netns\" value (must be < 16 chars)\n", *argv);
+			return ipnetns_modify(NETNS_ADDNS, *argv);
+		}
+		if (matches(*argv, "remove") == 0 ||
+		    matches(*argv, "delete") == 0 ||
+		    matches(*argv, "delns") == 0) {
+		        NEXT_ARG();
+			if (strlen(*argv) > NETNS_STR_MAXLEN)
+			        invarg("Invalid \"netns\" value (must be < 16 chars)\n", *argv);
+			return ipnetns_modify(NETNS_DELNS, *argv);
+		}
+	} else
+	        return do_netns_show(NETNS_DIR);
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
+	exit(-1);
+}
diff -pruN iproute2/ip/Makefile iproute2_netns/ip/Makefile
--- iproute2/ip/Makefile	2010-06-11 16:21:25.948671592 +0200
+++ iproute2_netns/ip/Makefile	2010-06-11 16:19:16.232663973 +0200
@@ -3,7 +3,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o ipr
     ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o \
     ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
     iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
-    iplink_macvlan.o
+    iplink_macvlan.o ipnetns.o
 
 RTMONOBJ=rtmon.o
 
_______________________________________________
Containers mailing list
Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/containers

[Index of Archives]     [Cgroups]     [Netdev]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux