]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
lib: Add netns_switch func for change network namespace
authorVadim Kochan <vadim4j@gmail.com>
Wed, 24 Dec 2014 21:04:08 +0000 (23:04 +0200)
committerStephen Hemminger <shemming@brocade.com>
Sat, 27 Dec 2014 18:22:27 +0000 (10:22 -0800)
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 <vadim4j@gmail.com>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
include/namespace.h [new file with mode: 0644]
ip/ipnetns.c
lib/Makefile
lib/namespace.c [new file with mode: 0644]

diff --git a/include/namespace.h b/include/namespace.h
new file mode 100644 (file)
index 0000000..2f13e65
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __NAMESPACE_H__
+#define __NAMESPACE_H__ 1
+
+#include <sched.h>
+#include <sys/mount.h>
+#include <errno.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 */
+
+extern int netns_switch(char *netns);
+
+#endif /* __NAMESPACE_H__ */
index 1c8aa029073eda73a6093ff1c806b061a1ced64e..519d5183626c015ab845d3f375f82c858fd3bf09 100644 (file)
 
 #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);
 
index a42b88599d4ea3265e868bcb04868e571ff192bf..66f89f1d36dbf07e892df72fec5a002a8be0c704 100644 (file)
@@ -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 (file)
index 0000000..1554ce0
--- /dev/null
@@ -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 <fcntl.h>
+#include <dirent.h>
+
+#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;
+}