summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ip/ipnetns.c62
-rw-r--r--man/man8/ip-netns.810
2 files changed, 57 insertions, 15 deletions
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 03879b49..430d8844 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -28,6 +28,7 @@ static int usage(void)
{
fprintf(stderr, "Usage: ip netns list\n");
fprintf(stderr, " ip netns add NAME\n");
+ fprintf(stderr, " ip netns attach NAME PID\n");
fprintf(stderr, " ip netns set NAME NETNSID\n");
fprintf(stderr, " ip [-all] netns delete [NAME]\n");
fprintf(stderr, " ip netns identify [PID]\n");
@@ -632,24 +633,40 @@ static int create_netns_dir(void)
return 0;
}
-static int netns_add(int argc, char **argv)
+static int netns_add(int argc, char **argv, bool create)
{
/* This function creates a new network namespace and
* a new mount namespace and bind them into a well known
* location in the filesystem based on the name provided.
*
+ * If create is true, a new namespace will be created,
+ * otherwise an existing one will be attached to the file.
+ *
* The mount namespace is created so that any necessary
* userspace tweaks like remounting /sys, or bind mounting
- * a new /etc/resolv.conf can be shared between uers.
+ * a new /etc/resolv.conf can be shared between users.
*/
- char netns_path[PATH_MAX];
+ char netns_path[PATH_MAX], proc_path[PATH_MAX];
const char *name;
+ pid_t pid;
int fd;
int made_netns_run_dir_mount = 0;
- if (argc < 1) {
- fprintf(stderr, "No netns name specified\n");
- return -1;
+ if (create) {
+ if (argc < 1) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+ } else {
+ if (argc < 2) {
+ fprintf(stderr, "No netns name and PID specified\n");
+ return -1;
+ }
+
+ if (get_s32(&pid, argv[1], 0) || !pid) {
+ fprintf(stderr, "Invalid PID: %s\n", argv[1]);
+ return -1;
+ }
}
name = argv[0];
@@ -689,21 +706,33 @@ static int netns_add(int argc, char **argv)
return -1;
}
close(fd);
- if (unshare(CLONE_NEWNET) < 0) {
- fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
- name, strerror(errno));
- goto out_delete;
+
+ if (create) {
+ if (unshare(CLONE_NEWNET) < 0) {
+ fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
+ name, strerror(errno));
+ goto out_delete;
+ }
+
+ strcpy(proc_path, "/proc/self/ns/net");
+ } else {
+ snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
}
/* Bind the netns last so I can watch for it */
- if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
- fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
- netns_path, strerror(errno));
+ if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
+ fprintf(stderr, "Bind %s -> %s failed: %s\n",
+ proc_path, netns_path, strerror(errno));
goto out_delete;
}
return 0;
out_delete:
- netns_delete(argc, argv);
+ if (create) {
+ netns_delete(argc, argv);
+ } else if (unlink(netns_path) < 0) {
+ fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
+ netns_path, strerror(errno));
+ }
return -1;
}
@@ -846,7 +875,7 @@ int do_netns(int argc, char **argv)
return usage();
if (matches(*argv, "add") == 0)
- return netns_add(argc-1, argv+1);
+ return netns_add(argc-1, argv+1, true);
if (matches(*argv, "set") == 0)
return netns_set(argc-1, argv+1);
@@ -866,6 +895,9 @@ int do_netns(int argc, char **argv)
if (matches(*argv, "monitor") == 0)
return netns_monitor(argc-1, argv+1);
+ if (matches(*argv, "attach") == 0)
+ return netns_add(argc-1, argv+1, false);
+
fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
exit(-1);
}
diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8
index d539f18b..39a10e76 100644
--- a/man/man8/ip-netns.8
+++ b/man/man8/ip-netns.8
@@ -20,6 +20,10 @@ ip-netns \- process network namespace management
.I NETNSNAME
.ti -8
+.B ip netns attach
+.I NETNSNAME PID
+
+.ti -8
.B ip [-all] netns del
.RI "[ " NETNSNAME " ]"
@@ -90,6 +94,12 @@ If NAME is available in /var/run/netns/ this command creates a new
network namespace and assigns NAME.
.TP
+.B ip netns attach NAME PID - create a new named network namespace
+.sp
+If NAME is available in /var/run/netns/ this command attaches the network
+namespace of the process PID to NAME as if it were created with ip netns.
+
+.TP
.B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s)
.sp
If NAME is present in /var/run/netns it is umounted and the mount