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.pere...@gmail.com>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.lezc...@free.fr>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 <j...@mindspring.com>
+ * Mathieu Peresse <mpere...@corp.free.fr>
+ *
+ */
+
+#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
contain...@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
_______________________________________________
Devel mailing list
Devel@openvz.org
https://openvz.org/mailman/listinfo/devel