From: Vadim Kochan Date: Wed, 24 Dec 2014 21:04:08 +0000 (+0200) Subject: lib: Add netns_switch func for change network namespace X-Git-Tag: v3.19.0~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb67e4498aec35eb16eaf894329f85b6316dabe8;p=thirdparty%2Fiproute2.git lib: Add netns_switch func for change network namespace New netns_switch func moved to the lib/namespace.c from ip/ipnetns.c so it can be used from the other tools for fast switching network namespace. Signed-off-by: Vadim Kochan Signed-off-by: Jiri Pirko --- diff --git a/include/namespace.h b/include/namespace.h new file mode 100644 index 000000000..2f13e6594 --- /dev/null +++ b/include/namespace.h @@ -0,0 +1,46 @@ +#ifndef __NAMESPACE_H__ +#define __NAMESPACE_H__ 1 + +#include +#include +#include + +#define NETNS_RUN_DIR "/var/run/netns" +#define NETNS_ETC_DIR "/etc/netns" + +#ifndef CLONE_NEWNET +#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ +#endif + +#ifndef MNT_DETACH +#define MNT_DETACH 0x00000002 /* Just detach from the tree */ +#endif /* MNT_DETACH */ + +/* sys/mount.h may be out too old to have these */ +#ifndef MS_REC +#define MS_REC 16384 +#endif + +#ifndef MS_SLAVE +#define MS_SLAVE (1 << 19) +#endif + +#ifndef MS_SHARED +#define MS_SHARED (1 << 20) +#endif + +#ifndef HAVE_SETNS +static int setns(int fd, int nstype) +{ +#ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif /* HAVE_SETNS */ + +extern int netns_switch(char *netns); + +#endif /* __NAMESPACE_H__ */ diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 1c8aa0290..519d51836 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -17,42 +17,7 @@ #include "utils.h" #include "ip_common.h" - -#define NETNS_RUN_DIR "/var/run/netns" -#define NETNS_ETC_DIR "/etc/netns" - -#ifndef CLONE_NEWNET -#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ -#endif - -#ifndef MNT_DETACH -#define MNT_DETACH 0x00000002 /* Just detach from the tree */ -#endif /* MNT_DETACH */ - -/* sys/mount.h may be out too old to have these */ -#ifndef MS_REC -#define MS_REC 16384 -#endif - -#ifndef MS_SLAVE -#define MS_SLAVE (1 << 19) -#endif - -#ifndef MS_SHARED -#define MS_SHARED (1 << 20) -#endif - -#ifndef HAVE_SETNS -static int setns(int fd, int nstype) -{ -#ifdef __NR_setns - return syscall(__NR_setns, fd, nstype); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif /* HAVE_SETNS */ +#include "namespace.h" static int usage(void) { @@ -101,42 +66,12 @@ static int netns_list(int argc, char **argv) return 0; } -static void bind_etc(const char *name) -{ - char etc_netns_path[MAXPATHLEN]; - char netns_name[MAXPATHLEN]; - char etc_name[MAXPATHLEN]; - struct dirent *entry; - DIR *dir; - - snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name); - dir = opendir(etc_netns_path); - if (!dir) - return; - - while ((entry = readdir(dir)) != NULL) { - if (strcmp(entry->d_name, ".") == 0) - continue; - if (strcmp(entry->d_name, "..") == 0) - continue; - snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name); - snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name); - if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) { - fprintf(stderr, "Bind %s -> %s failed: %s\n", - netns_name, etc_name, strerror(errno)); - } - } - closedir(dir); -} - static int netns_exec(int argc, char **argv) { /* Setup the proper environment for apps that are not netns * aware, and execute a program in that environment. */ - const char *name, *cmd; - char net_path[MAXPATHLEN]; - int netns; + const char *cmd; if (argc < 1) { fprintf(stderr, "No netns name specified\n"); @@ -146,45 +81,10 @@ static int netns_exec(int argc, char **argv) fprintf(stderr, "No command specified\n"); return -1; } - - name = argv[0]; cmd = argv[1]; - snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name); - netns = open(net_path, O_RDONLY | O_CLOEXEC); - if (netns < 0) { - fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", - name, strerror(errno)); - return -1; - } - - if (setns(netns, CLONE_NEWNET) < 0) { - fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n", - name, strerror(errno)); - return -1; - } - if (unshare(CLONE_NEWNS) < 0) { - fprintf(stderr, "unshare failed: %s\n", strerror(errno)); - return -1; - } - /* Don't let any mounts propagate back to the parent */ - if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) { - fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n", - strerror(errno)); + if (netns_switch(argv[0])) return -1; - } - /* Mount a version of /sys that describes the network namespace */ - if (umount2("/sys", MNT_DETACH) < 0) { - fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); - return -1; - } - if (mount(name, "/sys", "sysfs", 0, NULL) < 0) { - fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno)); - return -1; - } - - /* Setup bind mounts for config files in /etc */ - bind_etc(name); fflush(stdout); diff --git a/lib/Makefile b/lib/Makefile index a42b88599..66f89f1d3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,8 +1,12 @@ include ../Config +ifeq ($(IP_CONFIG_SETNS),y) + CFLAGS += -DHAVE_SETNS +endif + CFLAGS += -fPIC -UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o +UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o NLOBJ=libgenl.o ll_map.o libnetlink.o diff --git a/lib/namespace.c b/lib/namespace.c new file mode 100644 index 000000000..1554ce084 --- /dev/null +++ b/lib/namespace.c @@ -0,0 +1,86 @@ +/* + * namespace.c + * + * 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. + */ + +#include +#include + +#include "utils.h" +#include "namespace.h" + +static void bind_etc(const char *name) +{ + char etc_netns_path[MAXPATHLEN]; + char netns_name[MAXPATHLEN]; + char etc_name[MAXPATHLEN]; + struct dirent *entry; + DIR *dir; + + snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name); + dir = opendir(etc_netns_path); + if (!dir) + return; + + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name); + snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name); + if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) { + fprintf(stderr, "Bind %s -> %s failed: %s\n", + netns_name, etc_name, strerror(errno)); + } + } + closedir(dir); +} + +int netns_switch(char *name) +{ + char net_path[MAXPATHLEN]; + int netns; + + snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name); + netns = open(net_path, O_RDONLY | O_CLOEXEC); + if (netns < 0) { + fprintf(stderr, "Cannot open network namespace \"%s\": %s\n", + name, strerror(errno)); + return -1; + } + + if (setns(netns, CLONE_NEWNET) < 0) { + fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n", + name, strerror(errno)); + return -1; + } + + if (unshare(CLONE_NEWNS) < 0) { + fprintf(stderr, "unshare failed: %s\n", strerror(errno)); + return -1; + } + /* Don't let any mounts propagate back to the parent */ + if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) { + fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n", + strerror(errno)); + return -1; + } + /* Mount a version of /sys that describes the network namespace */ + if (umount2("/sys", MNT_DETACH) < 0) { + fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); + return -1; + } + if (mount(name, "/sys", "sysfs", 0, NULL) < 0) { + fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno)); + return -1; + } + + /* Setup bind mounts for config files in /etc */ + bind_etc(name); + return 0; +}