ip netns: Allow exec on each netns
This change allows to exec some cmd on each
named netns (except default) by specifying '-all' option:
# ip -all netns exec ip link
Each command executes synchronously.
Exit status is not considered, so there might be a case
that some CMD can fail on some netns but success on the other.
EXAMPLES:
1) Show link info on all netns:
$ ip -all netns exec ip link
netns: test_net
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 500
link/ether 1a:19:6f:25:eb:85 brd ff:ff:ff:ff:ff:ff
netns: home0
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 500
link/ether ea:1a:59:40:d3:29 brd ff:ff:ff:ff:ff:ff
netns: lan0
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: tap0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 500
link/ether ce:49:d5:46:81:ea brd ff:ff:ff:ff:ff:ff
2) Set UP tap0 device for the all netns:
$ ip -all netns exec ip link set dev tap0 up
netns: test_net
netns: home0
netns: lan0
Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 123318e..59a9321 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -26,7 +26,7 @@
fprintf(stderr, " ip netns delete NAME\n");
fprintf(stderr, " ip netns identify [PID]\n");
fprintf(stderr, " ip netns pids NAME\n");
- fprintf(stderr, " ip netns exec NAME cmd ...\n");
+ fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
fprintf(stderr, " ip netns monitor\n");
exit(-1);
}
@@ -51,29 +51,10 @@
return 0;
}
-static int netns_exec(int argc, char **argv)
+static int cmd_exec(const char *cmd, char **argv, bool do_fork)
{
- /* Setup the proper environment for apps that are not netns
- * aware, and execute a program in that environment.
- */
- const char *cmd;
-
- if (argc < 1) {
- fprintf(stderr, "No netns name specified\n");
- return -1;
- }
- if (argc < 2) {
- fprintf(stderr, "No command specified\n");
- return -1;
- }
- cmd = argv[1];
-
- if (netns_switch(argv[0]))
- return -1;
-
fflush(stdout);
-
- if (batch_mode) {
+ if (do_fork) {
int status;
pid_t pid;
@@ -91,23 +72,56 @@
}
if (WIFEXITED(status)) {
- /* ip must return the status of the child,
- * but do_cmd() will add a minus to this,
- * so let's add another one here to cancel it.
- */
- return -WEXITSTATUS(status);
+ return WEXITSTATUS(status);
}
exit(1);
}
}
- if (execvp(cmd, argv + 1) < 0)
+ if (execvp(cmd, argv) < 0)
fprintf(stderr, "exec of \"%s\" failed: %s\n",
- cmd, strerror(errno));
+ cmd, strerror(errno));
_exit(1);
}
+static int on_netns_exec(char *nsname, void *arg)
+{
+ char **argv = arg;
+ cmd_exec(argv[1], argv + 1, true);
+ return 0;
+}
+
+static int netns_exec(int argc, char **argv)
+{
+ /* Setup the proper environment for apps that are not netns
+ * aware, and execute a program in that environment.
+ */
+ const char *cmd;
+
+ if (argc < 1 && !do_all) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+ if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
+ fprintf(stderr, "No command specified\n");
+ return -1;
+ }
+
+ if (do_all)
+ return do_each_netns(on_netns_exec, --argv, 1);
+
+ if (netns_switch(argv[0]))
+ return -1;
+
+ /* ip must return the status of the child,
+ * but do_cmd() will add a minus to this,
+ * so let's add another one here to cancel it.
+ */
+ cmd = argv[1];
+ return -cmd_exec(cmd, argv + 1, !!batch_mode);
+}
+
static int is_pid(const char *str)
{
int ch;