All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting
@ 2017-02-16 16:58 David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 1/4] ip vrf: Handle vrf in a cgroup hierarchy David Ahern
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: David Ahern @ 2017-02-16 16:58 UTC (permalink / raw)
  To: netdev, stephen, luto; +Cc: David Ahern

More updates to ip vrf for 4.10. Major changes: handle vrf in an existing
cgroup hierarchy and handle vrf nesting in network namespaces.

Comparison of the netns in bpf code will be added once the kernel patch
is accepted.

David Ahern (4):
  ip vrf: Handle vrf in a cgroup hierarchy
  ip netns: refactor netns_identify
  ip vrf: Handle VRF nesting in namespace
  ip vrf: Detect invalid vrf name in pids command

 ip/ip_common.h |   1 +
 ip/ipnetns.c   |  47 +++++++-----
 ip/ipvrf.c     | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 227 insertions(+), 43 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH iproute2 1/4] ip vrf: Handle vrf in a cgroup hierarchy
  2017-02-16 16:58 [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting David Ahern
@ 2017-02-16 16:58 ` David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 2/4] ip netns: refactor netns_identify David Ahern
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: David Ahern @ 2017-02-16 16:58 UTC (permalink / raw)
  To: netdev, stephen, luto; +Cc: David Ahern

Add support for VRF in a pre-existing hierarchy. For example, if the
current process is running in CGRP/foo/bar, the 'ip vrf exec NAME CMD'
should run CMD in the cgroup CGRP/foo/bar/vrf/NAME.

When listing process ids in a VRF, search for the directory vrf/NAME
regardless of base path (foo/bar/vrf/NAME and vrf/NAME) are still
running against the same vrf NAME.

Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 ip/ipvrf.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 145 insertions(+), 28 deletions(-)

diff --git a/ip/ipvrf.c b/ip/ipvrf.c
index 8bd99d6251f2..8d61d0718c66 100644
--- a/ip/ipvrf.c
+++ b/ip/ipvrf.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <dirent.h>
 #include <errno.h>
 #include <limits.h>
 
@@ -40,6 +41,10 @@ static void usage(void)
 	exit(-1);
 }
 
+/*
+ * parse process based cgroup file looking for PATH/vrf/NAME where
+ * NAME is the name of the vrf the process is associated with
+ */
 static int vrf_identify(pid_t pid, char *name, size_t len)
 {
 	char path[PATH_MAX];
@@ -55,9 +60,13 @@ static int vrf_identify(pid_t pid, char *name, size_t len)
 	memset(name, 0, len);
 
 	while (fgets(buf, sizeof(buf), fp)) {
-		vrf = strstr(buf, "::/vrf/");
+		/* want the controller-less cgroup */
+		if (strstr(buf, "::/") == NULL)
+			continue;
+
+		vrf = strstr(buf, "/vrf/");
 		if (vrf) {
-			vrf += 7;  /* skip past "::/vrf/" */
+			vrf += 5;  /* skip past "/vrf/" */
 			end = strchr(vrf, '\n');
 			if (end)
 				*end = '\0';
@@ -97,50 +106,101 @@ static int ipvrf_identify(int argc, char **argv)
 	return rc;
 }
 
-static int ipvrf_pids(int argc, char **argv)
+/* read PATH/vrf/NAME/cgroup.procs file */
+static void read_cgroup_pids(const char *base_path, char *name)
 {
 	char path[PATH_MAX];
 	char buf[4096];
-	char *mnt, *vrf;
-	int fd, rc = -1;
 	ssize_t n;
+	int fd;
 
-	if (argc != 1) {
-		fprintf(stderr, "Invalid arguments\n");
-		return -1;
-	}
-
-	vrf = argv[0];
-
-	mnt = find_cgroup2_mount();
-	if (!mnt)
-		return -1;
+	if (snprintf(path, sizeof(path), "%s/vrf/%s%s",
+		     base_path, name, CGRP_PROC_FILE) >= sizeof(path))
+		return;
 
-	snprintf(path, sizeof(path), "%s/vrf/%s%s", mnt, vrf, CGRP_PROC_FILE);
-	free(mnt);
 	fd = open(path, O_RDONLY);
 	if (fd < 0)
-		return 0; /* no cgroup file, nothing to show */
+		return; /* no cgroup file, nothing to show */
 
+	/* dump contents (pids) of cgroup.procs */
 	while (1) {
 		n = read(fd, buf, sizeof(buf) - 1);
-		if (n < 0) {
-			fprintf(stderr,
-				"Failed to read cgroups file: %s\n",
-				strerror(errno));
+		if (n <= 0)
 			break;
-		} else if (n == 0) {
-			rc = 0;
-			break;
-		}
+
 		printf("%s", buf);
 	}
 
 	close(fd);
+}
+
+/* recurse path looking for PATH/vrf/NAME */
+static int recurse_dir(char *base_path, char *name)
+{
+	char path[PATH_MAX];
+	struct dirent *de;
+	struct stat fstat;
+	int rc;
+	DIR *d;
+
+	d = opendir(base_path);
+	if (!d)
+		return -1;
+
+	while ((de = readdir(d)) != NULL) {
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+			continue;
+
+		if (!strcmp(de->d_name, "vrf")) {
+			read_cgroup_pids(base_path, name);
+			continue;
+		}
+
+		/* is this a subdir that needs to be walked */
+		if (snprintf(path, sizeof(path), "%s/%s",
+			     base_path, de->d_name) >= sizeof(path))
+			continue;
+
+		if (lstat(path, &fstat) < 0)
+			continue;
+
+		if (S_ISDIR(fstat.st_mode)) {
+			rc = recurse_dir(path, name);
+			if (rc != 0)
+				goto out;
+		}
+	}
+
+	rc = 0;
+out:
+	closedir(d);
 
 	return rc;
 }
 
+static int ipvrf_pids(int argc, char **argv)
+{
+	char *mnt, *vrf;
+	int ret;
+
+	if (argc != 1) {
+		fprintf(stderr, "Invalid arguments\n");
+		return -1;
+	}
+
+	vrf = argv[0];
+
+	mnt = find_cgroup2_mount();
+	if (!mnt)
+		return -1;
+
+	ret = recurse_dir(mnt, vrf);
+
+	free(mnt);
+
+	return ret;
+}
+
 /* load BPF program to set sk_bound_dev_if for sockets */
 static char bpf_log_buf[256*1024];
 
@@ -203,9 +263,60 @@ static int vrf_configure_cgroup(const char *path, int ifindex)
 	return rc;
 }
 
+/* get base path for controller-less cgroup for a process.
+ * path returned does not include /vrf/NAME if it exists
+ */
+static int vrf_path(char *vpath, size_t len)
+{
+	char path[PATH_MAX];
+	char buf[4096];
+	char *vrf;
+	FILE *fp;
+
+	snprintf(path, sizeof(path), "/proc/%d/cgroup", getpid());
+	fp = fopen(path, "r");
+	if (!fp)
+		return -1;
+
+	vpath[0] = '\0';
+
+	while (fgets(buf, sizeof(buf), fp)) {
+		char *start, *nl;
+
+		start = strstr(buf, "::/");
+		if (!start)
+			continue;
+
+		/* advance past '::' */
+		start += 2;
+
+		nl = strchr(start, '\n');
+		if (nl)
+			*nl = '\0';
+
+		vrf = strstr(start, "/vrf");
+		if (vrf)
+			*vrf = '\0';
+
+		strncpy(vpath, start, len - 1);
+		vpath[len - 1] = '\0';
+
+		/* if vrf path is just / then return nothing */
+		if (!strcmp(vpath, "/"))
+			vpath[0] = '\0';
+
+		break;
+	}
+
+	fclose(fp);
+
+	return 0;
+}
+
 static int vrf_switch(const char *name)
 {
 	char path[PATH_MAX], *mnt, pid[16];
+	char vpath[PATH_MAX];
 	int ifindex = 0;
 	int rc = -1, len, fd = -1;
 
@@ -221,11 +332,17 @@ static int vrf_switch(const char *name)
 	if (!mnt)
 		return -1;
 
+	if (vrf_path(vpath, sizeof(vpath)) < 0) {
+		fprintf(stderr, "Failed to get base cgroup path: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
 	/* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
 	 * to the end of the path
 	 */
-	len = snprintf(path, sizeof(path) - sizeof(CGRP_PROC_FILE), "%s/vrf/%s",
-		       mnt, ifindex ? name : "");
+	len = snprintf(path, sizeof(path) - sizeof(CGRP_PROC_FILE),
+		       "%s%s/vrf/%s", mnt, vpath, ifindex ? name : "");
 	if (len > sizeof(path) - sizeof(CGRP_PROC_FILE)) {
 		fprintf(stderr, "Invalid path to cgroup2 mount\n");
 		goto out;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH iproute2 2/4] ip netns: refactor netns_identify
  2017-02-16 16:58 [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 1/4] ip vrf: Handle vrf in a cgroup hierarchy David Ahern
@ 2017-02-16 16:58 ` David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 3/4] ip vrf: Handle VRF nesting in namespace David Ahern
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: David Ahern @ 2017-02-16 16:58 UTC (permalink / raw)
  To: netdev, stephen, luto; +Cc: David Ahern

Move guts of netns_identify into a standalone function that returns
the netns name in a given buffer.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 ip/ip_common.h |  1 +
 ip/ipnetns.c   | 47 +++++++++++++++++++++++++++++++----------------
 2 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/ip/ip_common.h b/ip/ip_common.h
index ab6a83431fd6..e8642a184f39 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -59,6 +59,7 @@ int do_ipnetconf(int argc, char **argv);
 int do_iptoken(int argc, char **argv);
 int do_ipvrf(int argc, char **argv);
 void vrf_reset(void);
+int netns_identify_pid(const char *pidstr, char *name, int len);
 
 int iplink_get(unsigned int flags, char *name, __u32 filt_mask);
 
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 8201b94a1620..0b0378ab6560 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -468,28 +468,15 @@ static int netns_pids(int argc, char **argv)
 
 }
 
-static int netns_identify(int argc, char **argv)
+int netns_identify_pid(const char *pidstr, char *name, int len)
 {
-	const char *pidstr;
 	char net_path[PATH_MAX];
 	int netns;
 	struct stat netst;
 	DIR *dir;
 	struct dirent *entry;
 
-	if (argc < 1) {
-		pidstr = "self";
-	} else if (argc > 1) {
-		fprintf(stderr, "extra arguments specified\n");
-		return -1;
-	} else {
-		pidstr = argv[0];
-		if (!is_pid(pidstr)) {
-			fprintf(stderr, "Specified string '%s' is not a pid\n",
-					pidstr);
-			return -1;
-		}
-	}
+	name[0] = '\0';
 
 	snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
 	netns = open(net_path, O_RDONLY);
@@ -531,7 +518,8 @@ static int netns_identify(int argc, char **argv)
 
 		if ((st.st_dev == netst.st_dev) &&
 		    (st.st_ino == netst.st_ino)) {
-			printf("%s\n", entry->d_name);
+			strncpy(name, entry->d_name, len - 1);
+			name[len - 1] = '\0';
 		}
 	}
 	closedir(dir);
@@ -539,6 +527,33 @@ static int netns_identify(int argc, char **argv)
 
 }
 
+static int netns_identify(int argc, char **argv)
+{
+	const char *pidstr;
+	char name[256];
+	int rc;
+
+	if (argc < 1) {
+		pidstr = "self";
+	} else if (argc > 1) {
+		fprintf(stderr, "extra arguments specified\n");
+		return -1;
+	} else {
+		pidstr = argv[0];
+		if (!is_pid(pidstr)) {
+			fprintf(stderr, "Specified string '%s' is not a pid\n",
+					pidstr);
+			return -1;
+		}
+	}
+
+	rc = netns_identify_pid(pidstr, name, sizeof(name));
+	if (!rc)
+		printf("%s\n", name);
+
+	return rc;
+}
+
 static int on_netns_del(char *nsname, void *arg)
 {
 	char netns_path[PATH_MAX];
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH iproute2 3/4] ip vrf: Handle VRF nesting in namespace
  2017-02-16 16:58 [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 1/4] ip vrf: Handle vrf in a cgroup hierarchy David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 2/4] ip netns: refactor netns_identify David Ahern
@ 2017-02-16 16:58 ` David Ahern
  2017-02-16 16:58 ` [PATCH iproute2 4/4] ip vrf: Detect invalid vrf name in pids command David Ahern
  2017-02-19  0:11 ` [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting Stephen Hemminger
  4 siblings, 0 replies; 6+ messages in thread
From: David Ahern @ 2017-02-16 16:58 UTC (permalink / raw)
  To: netdev, stephen, luto; +Cc: David Ahern

Since cgroups are not namespace aware, the directory heirarchy used by
ip vrf should account for network namespaces. In this case, change the
path from CGRP/BASE/vrf/NAME to CGRP/BASE/NETNS/vrf/NAME where CGRP is
the cgroup2 mount path, BASE in any base heirarchy inherited before VRF
is applied and NAME is the VRF name.

The intent is as follows: a user logs into the box into some namespace
with a name known to iproute2. Some other policy may have put the
process into a BASE heirarchy. From there the user executes a task in
a VRF and in doing so the task heirarchy becomes CGRP/BASE/NETNS/vrf/NAME.
The namespace level is omitted for the default namespace.

Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 ip/ipvrf.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/ip/ipvrf.c b/ip/ipvrf.c
index 8d61d0718c66..cb7f9fa6d1db 100644
--- a/ip/ipvrf.c
+++ b/ip/ipvrf.c
@@ -134,8 +134,8 @@ static void read_cgroup_pids(const char *base_path, char *name)
 	close(fd);
 }
 
-/* recurse path looking for PATH/vrf/NAME */
-static int recurse_dir(char *base_path, char *name)
+/* recurse path looking for PATH[/NETNS]/vrf/NAME */
+static int recurse_dir(char *base_path, char *name, const char *netns)
 {
 	char path[PATH_MAX];
 	struct dirent *de;
@@ -152,7 +152,15 @@ static int recurse_dir(char *base_path, char *name)
 			continue;
 
 		if (!strcmp(de->d_name, "vrf")) {
-			read_cgroup_pids(base_path, name);
+			const char *pdir = strrchr(base_path, '/');
+
+			/* found a 'vrf' directory. if it is for the given
+			 * namespace then dump the cgroup pids
+			 */
+			if (*netns == '\0' ||
+			    (pdir && !strcmp(pdir+1, netns)))
+				read_cgroup_pids(base_path, name);
+
 			continue;
 		}
 
@@ -165,7 +173,7 @@ static int recurse_dir(char *base_path, char *name)
 			continue;
 
 		if (S_ISDIR(fstat.st_mode)) {
-			rc = recurse_dir(path, name);
+			rc = recurse_dir(path, name, netns);
 			if (rc != 0)
 				goto out;
 		}
@@ -178,10 +186,25 @@ static int recurse_dir(char *base_path, char *name)
 	return rc;
 }
 
+static int ipvrf_get_netns(char *netns, int len)
+{
+	if (netns_identify_pid("self", netns, len-3)) {
+		fprintf(stderr, "Failed to get name of network namespace: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
+	if (*netns != '\0')
+		strcat(netns, "-ns");
+
+	return 0;
+}
+
 static int ipvrf_pids(int argc, char **argv)
 {
 	char *mnt, *vrf;
-	int ret;
+	char netns[256];
+	int ret = -1;
 
 	if (argc != 1) {
 		fprintf(stderr, "Invalid arguments\n");
@@ -194,8 +217,12 @@ static int ipvrf_pids(int argc, char **argv)
 	if (!mnt)
 		return -1;
 
-	ret = recurse_dir(mnt, vrf);
+	if (ipvrf_get_netns(netns, sizeof(netns)) < 0)
+		goto out;
+
+	ret = recurse_dir(mnt, vrf, netns);
 
+out:
 	free(mnt);
 
 	return ret;
@@ -316,7 +343,7 @@ static int vrf_path(char *vpath, size_t len)
 static int vrf_switch(const char *name)
 {
 	char path[PATH_MAX], *mnt, pid[16];
-	char vpath[PATH_MAX];
+	char vpath[PATH_MAX], netns[256];
 	int ifindex = 0;
 	int rc = -1, len, fd = -1;
 
@@ -332,17 +359,37 @@ static int vrf_switch(const char *name)
 	if (!mnt)
 		return -1;
 
+	/* -1 on length to add '/' to the end */
+	if (ipvrf_get_netns(netns, sizeof(netns) - 1) < 0)
+		return -1;
+
 	if (vrf_path(vpath, sizeof(vpath)) < 0) {
 		fprintf(stderr, "Failed to get base cgroup path: %s\n",
 			strerror(errno));
 		return -1;
 	}
 
+	/* if path already ends in netns then don't add it again */
+	if (*netns != '\0') {
+		char *pdir = strrchr(vpath, '/');
+
+		if (!pdir)
+			pdir = vpath;
+		else
+			pdir++;
+
+		if (strcmp(pdir, netns) == 0)
+			*pdir = '\0';
+
+		strcat(netns, "/");
+	}
+
 	/* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
 	 * to the end of the path
 	 */
 	len = snprintf(path, sizeof(path) - sizeof(CGRP_PROC_FILE),
-		       "%s%s/vrf/%s", mnt, vpath, ifindex ? name : "");
+		       "%s%s/%svrf/%s",
+		       mnt, vpath, netns, ifindex ? name : "");
 	if (len > sizeof(path) - sizeof(CGRP_PROC_FILE)) {
 		fprintf(stderr, "Invalid path to cgroup2 mount\n");
 		goto out;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH iproute2 4/4] ip vrf: Detect invalid vrf name in pids command
  2017-02-16 16:58 [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting David Ahern
                   ` (2 preceding siblings ...)
  2017-02-16 16:58 ` [PATCH iproute2 3/4] ip vrf: Handle VRF nesting in namespace David Ahern
@ 2017-02-16 16:58 ` David Ahern
  2017-02-19  0:11 ` [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting Stephen Hemminger
  4 siblings, 0 replies; 6+ messages in thread
From: David Ahern @ 2017-02-16 16:58 UTC (permalink / raw)
  To: netdev, stephen, luto; +Cc: David Ahern

Verify VRF name is valid before attempting to read cgroups files.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 ip/ipvrf.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ip/ipvrf.c b/ip/ipvrf.c
index cb7f9fa6d1db..5e204a9ebbb1 100644
--- a/ip/ipvrf.c
+++ b/ip/ipvrf.c
@@ -212,6 +212,10 @@ static int ipvrf_pids(int argc, char **argv)
 	}
 
 	vrf = argv[0];
+	if (!name_is_vrf(vrf)) {
+		fprintf(stderr, "Invalid VRF name\n");
+		return -1;
+	}
 
 	mnt = find_cgroup2_mount();
 	if (!mnt)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting
  2017-02-16 16:58 [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting David Ahern
                   ` (3 preceding siblings ...)
  2017-02-16 16:58 ` [PATCH iproute2 4/4] ip vrf: Detect invalid vrf name in pids command David Ahern
@ 2017-02-19  0:11 ` Stephen Hemminger
  4 siblings, 0 replies; 6+ messages in thread
From: Stephen Hemminger @ 2017-02-19  0:11 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, luto

On Thu, 16 Feb 2017 08:58:54 -0800
David Ahern <dsa@cumulusnetworks.com> wrote:

> More updates to ip vrf for 4.10. Major changes: handle vrf in an existing
> cgroup hierarchy and handle vrf nesting in network namespaces.
> 
> Comparison of the netns in bpf code will be added once the kernel patch
> is accepted.
> 
> David Ahern (4):
>   ip vrf: Handle vrf in a cgroup hierarchy
>   ip netns: refactor netns_identify
>   ip vrf: Handle VRF nesting in namespace
>   ip vrf: Detect invalid vrf name in pids command
> 
>  ip/ip_common.h |   1 +
>  ip/ipnetns.c   |  47 +++++++-----
>  ip/ipvrf.c     | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
>  3 files changed, 227 insertions(+), 43 deletions(-)
> 

Applied all four thanks

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-02-19  0:11 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-16 16:58 [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting David Ahern
2017-02-16 16:58 ` [PATCH iproute2 1/4] ip vrf: Handle vrf in a cgroup hierarchy David Ahern
2017-02-16 16:58 ` [PATCH iproute2 2/4] ip netns: refactor netns_identify David Ahern
2017-02-16 16:58 ` [PATCH iproute2 3/4] ip vrf: Handle VRF nesting in namespace David Ahern
2017-02-16 16:58 ` [PATCH iproute2 4/4] ip vrf: Detect invalid vrf name in pids command David Ahern
2017-02-19  0:11 ` [PATCH iproute2 0/4] ip vrf: updates to handle cgroup hiearchy and namespace nesting Stephen Hemminger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.