@@ -26,7 +26,7 @@ static int usage(void)
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 netns exec { NAME | all } cmd ...\n");
fprintf(stderr, " ip netns monitor\n");
exit(-1);
}
@@ -66,29 +66,10 @@ static int netns_list(int argc, char **argv)
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;
@@ -106,23 +87,56 @@ static int netns_exec(int argc, char **argv)
}
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, 1);
+ 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) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "No command specified\n");
+ return -1;
+ }
+ cmd = argv[1];
+
+ if (strcmp(argv[0], "all") == 0)
+ 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.
+ */
+ return -cmd_exec(cmd, argv + 1, batch_mode);
+}
+
static int is_pid(const char *str)
{
int ch;
@@ -29,7 +29,7 @@ ip-netns \- process network namespace management
.ti -8
.BR "ip netns exec "
-.I NETNSNAME command ...
+.RI "{ " NETNSNAME " | " all " } " command ...
.ti -8
.BR "ip netns monitor"
@@ -98,7 +98,7 @@ This command walks through proc and finds all of the process who have
the named network namespace as their primary network namespace.
.TP
-.B ip netns exec NAME cmd ... - Run cmd in the named network namespace
+.B ip netns exec { NAME | all } cmd ... - Run cmd in the named network namespace
.sp
This command allows applications that are network namespace unaware
to be run in something other than the default network namespace with
@@ -107,6 +107,16 @@ in the customary global locations. A network namespace and bind mounts
are used to move files from their network namespace specific location
to their default locations without affecting other processes.
+If
+.B all
+was specified then
+.B cmd
+will be executed synchronously on the each named network namespace even if
+.B cmd
+fails on some of them. Network namespace name is printed on each
+.B cmd
+executing.
+
.TP
.B ip netns monitor - Report as network namespace names are added and deleted
.sp