diff --git a/include/namespace.h b/include/namespace.h index e47f9b5d..89cdda11 100644 --- a/include/namespace.h +++ b/include/namespace.h @@ -49,6 +49,8 @@ static inline int setns(int fd, int nstype) } #endif /* HAVE_SETNS */ +void netns_save(void); +void netns_restore(void); int netns_switch(char *netns); int netns_get_fd(const char *netns); int netns_foreach(int (*func)(char *nsname, void *arg), void *arg); diff --git a/ip/ip.c b/ip/ip.c index e4131714..d64d43e1 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -158,6 +158,7 @@ static int batch(const char *name) if (!force) break; } + netns_restore(); } if (line) free(line); diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 52aefacf..e4788e75 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -707,6 +707,7 @@ static int netns_add(int argc, char **argv, bool create) close(fd); if (create) { + netns_save(); if (unshare(CLONE_NEWNET) < 0) { fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n", name, strerror(errno)); diff --git a/lib/namespace.c b/lib/namespace.c index 06ae0a48..a2aea57a 100644 --- a/lib/namespace.c +++ b/lib/namespace.c @@ -15,6 +15,35 @@ #include "utils.h" #include "namespace.h" +static int saved_netns = -1; + +/* Obtain a FD for the current namespace, so we can reenter it later */ +void netns_save(void) +{ + if (saved_netns != -1) + return; + + saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC); + if (saved_netns == -1) { + perror("Cannot open init namespace"); + exit(1); + } +} + +void netns_restore(void) +{ + if (saved_netns == -1) + return; + + if (setns(saved_netns, CLONE_NEWNET)) { + perror("setns"); + exit(1); + } + + close(saved_netns); + saved_netns = -1; +} + static void bind_etc(const char *name) { char etc_netns_path[sizeof(NETNS_ETC_DIR) + NAME_MAX]; @@ -61,6 +90,8 @@ int netns_switch(char *name) return -1; } + netns_save(); + if (setns(netns, CLONE_NEWNET) < 0) { fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n", name, strerror(errno));