naccyde / rpms / iproute

Forked from rpms/iproute 9 months ago
Clone

Blame SOURCES/0074-netns-switch-netns-in-the-child-when-executing-comma.patch

8def76
From 95436dbf882f32ed98f73ec080021daf3841f4a9 Mon Sep 17 00:00:00 2001
8def76
From: Andrea Claudi <aclaudi@redhat.com>
8def76
Date: Fri, 28 Jun 2019 14:12:36 +0200
8def76
Subject: [PATCH] netns: switch netns in the child when executing commands
8def76
8def76
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1719759
8def76
Upstream Status: iproute2.git commit 903818fbf9c73
8def76
8def76
commit 903818fbf9c73dd71793e5829775d2ccc1775af5
8def76
Author: Matteo Croce <mcroce@redhat.com>
8def76
Date:   Tue Jun 18 16:49:33 2019 +0200
8def76
8def76
    netns: switch netns in the child when executing commands
8def76
8def76
    'ip netns exec' changes the current netns just before executing a child
8def76
    process, and restores it after forking. This is needed if we're running
8def76
    in batch or do_all mode.
8def76
    Some cleanups must be done both in the parent and in the child: the
8def76
    parent must restore the previous netns, while the child must reset any
8def76
    VRF association.
8def76
    Unfortunately, if do_all is set, the VRF are not reset in the child, and
8def76
    the spawned processes are started with the wrong VRF context. This can
8def76
    be triggered with this script:
8def76
8def76
            # ip -b - <<-'EOF'
8def76
                    link add type vrf table 100
8def76
                    link set vrf0 up
8def76
                    link add type dummy
8def76
                    link set dummy0 vrf vrf0 up
8def76
                    netns add ns1
8def76
            EOF
8def76
            # ip -all -b - <<-'EOF'
8def76
                    vrf exec vrf0 true
8def76
                    netns exec setsid -f sleep 1h
8def76
            EOF
8def76
            # ip vrf pids vrf0
8def76
              314  sleep
8def76
            # ps 314
8def76
              PID TTY      STAT   TIME COMMAND
8def76
              314 ?        Ss     0:00 sleep 1h
8def76
8def76
    Refactor cmd_exec() and pass to it a function pointer which is called in
8def76
    the child before the final exec. In the netns exec case the function just
8def76
    resets the VRF and switches netns.
8def76
8def76
    Doing it in the child is less error prone and safer, because the parent
8def76
    environment is always kept unaltered.
8def76
8def76
    After this refactor some utility functions became unused, so remove them.
8def76
8def76
    Signed-off-by: Matteo Croce <mcroce@redhat.com>
8def76
    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
8def76
---
8def76
 include/utils.h |  6 ++----
8def76
 ip/ipnetns.c    | 30 ++++++++++++++++--------------
8def76
 ip/ipvrf.c      |  2 +-
8def76
 lib/exec.c      |  7 ++++++-
8def76
 lib/utils.c     | 27 ---------------------------
8def76
 5 files changed, 25 insertions(+), 47 deletions(-)
8def76
8def76
diff --git a/include/utils.h b/include/utils.h
8def76
index c32b37a1797d8..f00e7742b3c2a 100644
8def76
--- a/include/utils.h
8def76
+++ b/include/utils.h
8def76
@@ -292,14 +292,12 @@ extern int cmdlineno;
8def76
 ssize_t getcmdline(char **line, size_t *len, FILE *in);
8def76
 int makeargs(char *line, char *argv[], int maxargs);
8def76
 
8def76
-int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
8def76
-		bool show_label);
8def76
-
8def76
 char *int_to_str(int val, char *buf);
8def76
 int get_guid(__u64 *guid, const char *arg);
8def76
 int get_real_family(int rtm_type, int rtm_family);
8def76
 
8def76
-int cmd_exec(const char *cmd, char **argv, bool do_fork);
8def76
+int cmd_exec(const char *cmd, char **argv, bool do_fork,
8def76
+	     int (*setup)(void *), void *arg);
8def76
 int make_path(const char *path, mode_t mode);
8def76
 char *find_cgroup2_mount(void);
8def76
 int get_command_name(const char *pid, char *comm, size_t len);
8def76
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
8def76
index a6e3ea575c363..10bfe2eb69e0b 100644
8def76
--- a/ip/ipnetns.c
8def76
+++ b/ip/ipnetns.c
8def76
@@ -395,11 +395,24 @@ static int netns_list(int argc, char **argv)
8def76
 	return 0;
8def76
 }
8def76
 
8def76
+static int do_switch(void *arg)
8def76
+{
8def76
+	char *netns = arg;
8def76
+
8def76
+	/* we just changed namespaces. clear any vrf association
8def76
+	 * with prior namespace before exec'ing command
8def76
+	 */
8def76
+	vrf_reset();
8def76
+
8def76
+	return netns_switch(netns);
8def76
+}
8def76
+
8def76
 static int on_netns_exec(char *nsname, void *arg)
8def76
 {
8def76
 	char **argv = arg;
8def76
 
8def76
-	cmd_exec(argv[1], argv + 1, true);
8def76
+	printf("\nnetns: %s\n", nsname);
8def76
+	cmd_exec(argv[0], argv, true, do_switch, nsname);
8def76
 	return 0;
8def76
 }
8def76
 
8def76
@@ -408,8 +421,6 @@ static int netns_exec(int argc, char **argv)
8def76
 	/* Setup the proper environment for apps that are not netns
8def76
 	 * aware, and execute a program in that environment.
8def76
 	 */
8def76
-	const char *cmd;
8def76
-
8def76
 	if (argc < 1 && !do_all) {
8def76
 		fprintf(stderr, "No netns name specified\n");
8def76
 		return -1;
8def76
@@ -420,22 +431,13 @@ static int netns_exec(int argc, char **argv)
8def76
 	}
8def76
 
8def76
 	if (do_all)
8def76
-		return do_each_netns(on_netns_exec, --argv, 1);
8def76
-
8def76
-	if (netns_switch(argv[0]))
8def76
-		return -1;
8def76
-
8def76
-	/* we just changed namespaces. clear any vrf association
8def76
-	 * with prior namespace before exec'ing command
8def76
-	 */
8def76
-	vrf_reset();
8def76
+		return netns_foreach(on_netns_exec, argv);
8def76
 
8def76
 	/* ip must return the status of the child,
8def76
 	 * but do_cmd() will add a minus to this,
8def76
 	 * so let's add another one here to cancel it.
8def76
 	 */
8def76
-	cmd = argv[1];
8def76
-	return -cmd_exec(cmd, argv + 1, !!batch_mode);
8def76
+	return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
8def76
 }
8def76
 
8def76
 static int is_pid(const char *str)
8def76
diff --git a/ip/ipvrf.c b/ip/ipvrf.c
8def76
index 8a6b7f977b142..c93ff71b39070 100644
8def76
--- a/ip/ipvrf.c
8def76
+++ b/ip/ipvrf.c
8def76
@@ -455,7 +455,7 @@ static int ipvrf_exec(int argc, char **argv)
8def76
 	if (vrf_switch(argv[0]))
8def76
 		return -1;
8def76
 
8def76
-	return -cmd_exec(argv[1], argv + 1, !!batch_mode);
8def76
+	return -cmd_exec(argv[1], argv + 1, !!batch_mode, NULL, NULL);
8def76
 }
8def76
 
8def76
 /* reset VRF association of current process to default VRF;
8def76
diff --git a/lib/exec.c b/lib/exec.c
8def76
index eb36b59dee7f4..9b1c8f4a13960 100644
8def76
--- a/lib/exec.c
8def76
+++ b/lib/exec.c
8def76
@@ -5,8 +5,10 @@
8def76
 #include <unistd.h>
8def76
 
8def76
 #include "utils.h"
8def76
+#include "namespace.h"
8def76
 
8def76
-int cmd_exec(const char *cmd, char **argv, bool do_fork)
8def76
+int cmd_exec(const char *cmd, char **argv, bool do_fork,
8def76
+	     int (*setup)(void *), void *arg)
8def76
 {
8def76
 	fflush(stdout);
8def76
 	if (do_fork) {
8def76
@@ -34,6 +36,9 @@ int cmd_exec(const char *cmd, char **argv, bool do_fork)
8def76
 		}
8def76
 	}
8def76
 
8def76
+	if (setup && setup(arg))
8def76
+		return -1;
8def76
+
8def76
 	if (execvp(cmd, argv)  < 0)
8def76
 		fprintf(stderr, "exec of \"%s\" failed: %s\n",
8def76
 				cmd, strerror(errno));
8def76
diff --git a/lib/utils.c b/lib/utils.c
8def76
index 7be2d6bec5215..5f229a9a4f584 100644
8def76
--- a/lib/utils.c
8def76
+++ b/lib/utils.c
8def76
@@ -1455,33 +1455,6 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n)
8def76
 	fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs);
8def76
 }
8def76
 
8def76
-static int on_netns(char *nsname, void *arg)
8def76
-{
8def76
-	struct netns_func *f = arg;
8def76
-
8def76
-	if (netns_switch(nsname))
8def76
-		return -1;
8def76
-
8def76
-	return f->func(nsname, f->arg);
8def76
-}
8def76
-
8def76
-static int on_netns_label(char *nsname, void *arg)
8def76
-{
8def76
-	printf("\nnetns: %s\n", nsname);
8def76
-	return on_netns(nsname, arg);
8def76
-}
8def76
-
8def76
-int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
8def76
-		bool show_label)
8def76
-{
8def76
-	struct netns_func nsf = { .func = func, .arg = arg };
8def76
-
8def76
-	if (show_label)
8def76
-		return netns_foreach(on_netns_label, &nsf;;
8def76
-
8def76
-	return netns_foreach(on_netns, &nsf;;
8def76
-}
8def76
-
8def76
 char *int_to_str(int val, char *buf)
8def76
 {
8def76
 	sprintf(buf, "%d", val);
8def76
-- 
8def76
2.20.1
8def76