]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipnetns.c
5 #include <sys/inotify.h>
8 #include <sys/syscall.h>
19 #include "ip_common.h"
20 #include "namespace.h"
22 static int usage(void)
24 fprintf(stderr
, "Usage: ip netns list\n");
25 fprintf(stderr
, " ip netns add NAME\n");
26 fprintf(stderr
, " ip [-all] netns delete [NAME]\n");
27 fprintf(stderr
, " ip netns identify [PID]\n");
28 fprintf(stderr
, " ip netns pids NAME\n");
29 fprintf(stderr
, " ip [-all] netns exec [NAME] cmd ...\n");
30 fprintf(stderr
, " ip netns monitor\n");
34 static int netns_list(int argc
, char **argv
)
39 dir
= opendir(NETNS_RUN_DIR
);
43 while ((entry
= readdir(dir
)) != NULL
) {
44 if (strcmp(entry
->d_name
, ".") == 0)
46 if (strcmp(entry
->d_name
, "..") == 0)
48 printf("%s\n", entry
->d_name
);
54 static int cmd_exec(const char *cmd
, char **argv
, bool do_fork
)
69 if (waitpid(pid
, &status
, 0) < 0) {
74 if (WIFEXITED(status
)) {
75 return WEXITSTATUS(status
);
82 if (execvp(cmd
, argv
) < 0)
83 fprintf(stderr
, "exec of \"%s\" failed: %s\n",
84 cmd
, strerror(errno
));
88 static int on_netns_exec(char *nsname
, void *arg
)
91 cmd_exec(argv
[1], argv
+ 1, true);
95 static int netns_exec(int argc
, char **argv
)
97 /* Setup the proper environment for apps that are not netns
98 * aware, and execute a program in that environment.
102 if (argc
< 1 && !do_all
) {
103 fprintf(stderr
, "No netns name specified\n");
106 if ((argc
< 2 && !do_all
) || (argc
< 1 && do_all
)) {
107 fprintf(stderr
, "No command specified\n");
112 return do_each_netns(on_netns_exec
, --argv
, 1);
114 if (netns_switch(argv
[0]))
117 /* ip must return the status of the child,
118 * but do_cmd() will add a minus to this,
119 * so let's add another one here to cancel it.
122 return -cmd_exec(cmd
, argv
+ 1, !!batch_mode
);
125 static int is_pid(const char *str
)
128 for (; (ch
= *str
); str
++) {
135 static int netns_pids(int argc
, char **argv
)
138 char net_path
[MAXPATHLEN
];
142 struct dirent
*entry
;
145 fprintf(stderr
, "No netns name specified\n");
149 fprintf(stderr
, "extra arguments specified\n");
154 snprintf(net_path
, sizeof(net_path
), "%s/%s", NETNS_RUN_DIR
, name
);
155 netns
= open(net_path
, O_RDONLY
);
157 fprintf(stderr
, "Cannot open network namespace: %s\n",
161 if (fstat(netns
, &netst
) < 0) {
162 fprintf(stderr
, "Stat of netns failed: %s\n",
166 dir
= opendir("/proc/");
168 fprintf(stderr
, "Open of /proc failed: %s\n",
172 while((entry
= readdir(dir
))) {
173 char pid_net_path
[MAXPATHLEN
];
175 if (!is_pid(entry
->d_name
))
177 snprintf(pid_net_path
, sizeof(pid_net_path
), "/proc/%s/ns/net",
179 if (stat(pid_net_path
, &st
) != 0)
181 if ((st
.st_dev
== netst
.st_dev
) &&
182 (st
.st_ino
== netst
.st_ino
)) {
183 printf("%s\n", entry
->d_name
);
191 static int netns_identify(int argc
, char **argv
)
194 char net_path
[MAXPATHLEN
];
198 struct dirent
*entry
;
202 } else if (argc
> 1) {
203 fprintf(stderr
, "extra arguments specified\n");
207 if (!is_pid(pidstr
)) {
208 fprintf(stderr
, "Specified string '%s' is not a pid\n",
214 snprintf(net_path
, sizeof(net_path
), "/proc/%s/ns/net", pidstr
);
215 netns
= open(net_path
, O_RDONLY
);
217 fprintf(stderr
, "Cannot open network namespace: %s\n",
221 if (fstat(netns
, &netst
) < 0) {
222 fprintf(stderr
, "Stat of netns failed: %s\n",
226 dir
= opendir(NETNS_RUN_DIR
);
228 /* Succeed treat a missing directory as an empty directory */
232 fprintf(stderr
, "Failed to open directory %s:%s\n",
233 NETNS_RUN_DIR
, strerror(errno
));
237 while((entry
= readdir(dir
))) {
238 char name_path
[MAXPATHLEN
];
241 if (strcmp(entry
->d_name
, ".") == 0)
243 if (strcmp(entry
->d_name
, "..") == 0)
246 snprintf(name_path
, sizeof(name_path
), "%s/%s", NETNS_RUN_DIR
,
249 if (stat(name_path
, &st
) != 0)
252 if ((st
.st_dev
== netst
.st_dev
) &&
253 (st
.st_ino
== netst
.st_ino
)) {
254 printf("%s\n", entry
->d_name
);
262 static int on_netns_del(char *nsname
, void *arg
)
264 char netns_path
[MAXPATHLEN
];
266 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, nsname
);
267 umount2(netns_path
, MNT_DETACH
);
268 if (unlink(netns_path
) < 0) {
269 fprintf(stderr
, "Cannot remove namespace file \"%s\": %s\n",
270 netns_path
, strerror(errno
));
276 static int netns_delete(int argc
, char **argv
)
278 if (argc
< 1 && !do_all
) {
279 fprintf(stderr
, "No netns name specified\n");
284 return netns_foreach(on_netns_del
, NULL
);
286 return on_netns_del(argv
[0], NULL
);
289 static int create_netns_dir(void)
291 /* Create the base netns directory if it doesn't exist */
292 if (mkdir(NETNS_RUN_DIR
, S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
)) {
293 if (errno
!= EEXIST
) {
294 fprintf(stderr
, "mkdir %s failed: %s\n",
295 NETNS_RUN_DIR
, strerror(errno
));
303 static int netns_add(int argc
, char **argv
)
305 /* This function creates a new network namespace and
306 * a new mount namespace and bind them into a well known
307 * location in the filesystem based on the name provided.
309 * The mount namespace is created so that any necessary
310 * userspace tweaks like remounting /sys, or bind mounting
311 * a new /etc/resolv.conf can be shared between uers.
313 char netns_path
[MAXPATHLEN
];
316 int made_netns_run_dir_mount
= 0;
319 fprintf(stderr
, "No netns name specified\n");
324 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, name
);
326 if (create_netns_dir())
329 /* Make it possible for network namespace mounts to propagate between
330 * mount namespaces. This makes it likely that a unmounting a network
331 * namespace file in one namespace will unmount the network namespace
332 * file in all namespaces allowing the network namespace to be freed
335 while (mount("", NETNS_RUN_DIR
, "none", MS_SHARED
| MS_REC
, NULL
)) {
336 /* Fail unless we need to make the mount point */
337 if (errno
!= EINVAL
|| made_netns_run_dir_mount
) {
338 fprintf(stderr
, "mount --make-shared %s failed: %s\n",
339 NETNS_RUN_DIR
, strerror(errno
));
343 /* Upgrade NETNS_RUN_DIR to a mount point */
344 if (mount(NETNS_RUN_DIR
, NETNS_RUN_DIR
, "none", MS_BIND
, NULL
)) {
345 fprintf(stderr
, "mount --bind %s %s failed: %s\n",
346 NETNS_RUN_DIR
, NETNS_RUN_DIR
, strerror(errno
));
349 made_netns_run_dir_mount
= 1;
352 /* Create the filesystem state */
353 fd
= open(netns_path
, O_RDONLY
|O_CREAT
|O_EXCL
, 0);
355 fprintf(stderr
, "Cannot create namespace file \"%s\": %s\n",
356 netns_path
, strerror(errno
));
360 if (unshare(CLONE_NEWNET
) < 0) {
361 fprintf(stderr
, "Failed to create a new network namespace \"%s\": %s\n",
362 name
, strerror(errno
));
366 /* Bind the netns last so I can watch for it */
367 if (mount("/proc/self/ns/net", netns_path
, "none", MS_BIND
, NULL
) < 0) {
368 fprintf(stderr
, "Bind /proc/self/ns/net -> %s failed: %s\n",
369 netns_path
, strerror(errno
));
374 netns_delete(argc
, argv
);
379 static int netns_monitor(int argc
, char **argv
)
382 struct inotify_event
*event
;
386 fprintf(stderr
, "inotify_init failed: %s\n",
391 if (create_netns_dir())
394 if (inotify_add_watch(fd
, NETNS_RUN_DIR
, IN_CREATE
| IN_DELETE
) < 0) {
395 fprintf(stderr
, "inotify_add_watch failed: %s\n",
400 ssize_t len
= read(fd
, buf
, sizeof(buf
));
402 fprintf(stderr
, "read failed: %s\n",
406 for (event
= (struct inotify_event
*)buf
;
407 (char *)event
< &buf
[len
];
408 event
= (struct inotify_event
*)((char *)event
+ sizeof(*event
) + event
->len
)) {
409 if (event
->mask
& IN_CREATE
)
410 printf("add %s\n", event
->name
);
411 if (event
->mask
& IN_DELETE
)
412 printf("delete %s\n", event
->name
);
418 int do_netns(int argc
, char **argv
)
421 return netns_list(0, NULL
);
423 if ((matches(*argv
, "list") == 0) || (matches(*argv
, "show") == 0) ||
424 (matches(*argv
, "lst") == 0))
425 return netns_list(argc
-1, argv
+1);
427 if (matches(*argv
, "help") == 0)
430 if (matches(*argv
, "add") == 0)
431 return netns_add(argc
-1, argv
+1);
433 if (matches(*argv
, "delete") == 0)
434 return netns_delete(argc
-1, argv
+1);
436 if (matches(*argv
, "identify") == 0)
437 return netns_identify(argc
-1, argv
+1);
439 if (matches(*argv
, "pids") == 0)
440 return netns_pids(argc
-1, argv
+1);
442 if (matches(*argv
, "exec") == 0)
443 return netns_exec(argc
-1, argv
+1);
445 if (matches(*argv
, "monitor") == 0)
446 return netns_monitor(argc
-1, argv
+1);
448 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv
);