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