|
|
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 |
|