[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20190124155053.7795-1-mcroce@redhat.com>
Date: Thu, 24 Jan 2019 16:50:53 +0100
From: Matteo Croce <mcroce@...hat.com>
To: netdev@...r.kernel.org
Cc: David Ahern <dsahern@...il.com>,
Stephen Hemminger <sthemmin@...rosoft.com>
Subject: [PATCH iproute2-next] netns: add subcommand to attach an existing network namespace
ip tracks namespaces with dummy files in /var/run/netns/, but can't see
namespaces created with other tools.
Creating the dummy file and bind mounting the correct procfs entry will
make ip aware of that namespace.
Add an ip netns subcommand to automate this task.
Signed-off-by: Matteo Croce <mcroce@...hat.com>
---
ip/ipnetns.c | 84 +++++++++++++++++++++++++++++++++++++++++++++
man/man8/ip-netns.8 | 10 ++++++
2 files changed, 94 insertions(+)
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 03879b49..86b1a36b 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");
@@ -811,6 +812,86 @@ static int netns_monitor(int argc, char **argv)
return 0;
}
+static int netns_attach(int argc, char **argv)
+{
+ /* This function bind mounts an existing network namespace to a
+ * well known location in the filesystem based on the name provided.
+ * If everything succeeds, the result is the same as netns_add.
+ *
+ * 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 users.
+ */
+ char netns_path[PATH_MAX], proc_path[PATH_MAX];
+ const char *name;
+ int fd;
+ pid_t pid;
+ int made_netns_run_dir_mount = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, "No netns name and PID specified\n");
+ return -1;
+ }
+ name = argv[0];
+
+ if (get_s32(&pid, argv[1], 0) || !pid) {
+ fprintf(stderr, "Invalid PID: %s\n", argv[1]);
+ return -1;
+ }
+
+ snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
+
+ if (create_netns_dir())
+ return -1;
+
+ /* Make it possible for network namespace mounts to propagate between
+ * mount namespaces. This makes it likely that a unmounting a network
+ * namespace file in one namespace will unmount the network namespace
+ * file in all namespaces allowing the network namespace to be freed
+ * sooner.
+ */
+ while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
+ /* Fail unless we need to make the mount point */
+ if (errno != EINVAL || made_netns_run_dir_mount) {
+ fprintf(stderr, "mount --make-shared %s failed: %s\n",
+ NETNS_RUN_DIR, strerror(errno));
+ return -1;
+ }
+
+ /* Upgrade NETNS_RUN_DIR to a mount point */
+ if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
+ fprintf(stderr, "mount --bind %s %s failed: %s\n",
+ NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
+ return -1;
+ }
+ made_netns_run_dir_mount = 1;
+ }
+
+ /* Create the filesystem state */
+ fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
+ netns_path, strerror(errno));
+ return -1;
+ }
+ close(fd);
+
+ snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
+
+ /* Bind the netns last so I can watch for it */
+ 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:
+ if (unlink(netns_path) < 0)
+ fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
+ netns_path, strerror(errno));
+ return -1;
+}
+
static int invalid_name(const char *name)
{
return !*name || strlen(name) > NAME_MAX ||
@@ -866,6 +947,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_attach(argc-1, argv+1);
+
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
@@ -19,6 +19,10 @@ ip-netns \- process network namespace management
.B ip netns add
.I NETNSNAME
+.ti -8
+.B ip netns attach
+.I NETNSNAME PID
+
.ti -8
.B ip [-all] netns del
.RI "[ " NETNSNAME " ]"
@@ -89,6 +93,12 @@ This command displays all of the network namespaces in /var/run/netns
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
--
2.20.1
Powered by blists - more mailing lists