]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipnetns.c
ip netns: Fix rtnl error while print netns list
[mirror_iproute2.git] / ip / ipnetns.c
CommitLineData
0dc34c77
EB
1#define _ATFILE_SOURCE
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <sys/wait.h>
5#include <sys/inotify.h>
6#include <sys/mount.h>
7#include <sys/param.h>
8#include <sys/syscall.h>
9#include <stdio.h>
10#include <string.h>
11#include <sched.h>
12#include <fcntl.h>
13#include <dirent.h>
14#include <errno.h>
15#include <unistd.h>
9a7b3d91 16#include <ctype.h>
0dc34c77 17
d182ee13
ND
18#include <linux/net_namespace.h>
19
0dc34c77
EB
20#include "utils.h"
21#include "ip_common.h"
eb67e449 22#include "namespace.h"
0dc34c77 23
8e2d47dc 24static int usage(void)
0dc34c77
EB
25{
26 fprintf(stderr, "Usage: ip netns list\n");
27 fprintf(stderr, " ip netns add NAME\n");
d182ee13 28 fprintf(stderr, " ip netns set NAME NETNSID\n");
33724939 29 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
0948adc0 30 fprintf(stderr, " ip netns identify [PID]\n");
9a7b3d91 31 fprintf(stderr, " ip netns pids NAME\n");
b13ba03f 32 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
0dc34c77 33 fprintf(stderr, " ip netns monitor\n");
a05f6511 34 exit(-1);
0dc34c77
EB
35}
36
d116ff34 37#ifdef HAVE_NETNSID
d182ee13
ND
38static int get_netnsid_from_name(const char *name)
39{
40 struct {
41 struct nlmsghdr n;
42 struct rtgenmsg g;
43 char buf[1024];
44 } req, answer;
45 struct rtattr *tb[NETNSA_MAX + 1];
46 struct rtgenmsg *rthdr;
47 int len, fd;
48
49 memset(&req, 0, sizeof(req));
50 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
51 req.n.nlmsg_flags = NLM_F_REQUEST;
52 req.n.nlmsg_type = RTM_GETNSID;
53 req.g.rtgen_family = AF_UNSPEC;
54
55 fd = netns_get_fd(name);
56 if (fd < 0)
57 return fd;
58
59 addattr32(&req.n, 1024, NETNSA_FD, fd);
60 if (rtnl_talk(&rth, &req.n, 0, 0, &answer.n) < 0) {
61 close(fd);
62 return -2;
63 }
64 close(fd);
65
66 /* Validate message and parse attributes */
67 if (answer.n.nlmsg_type == NLMSG_ERROR)
68 return -1;
69
70 rthdr = NLMSG_DATA(&answer.n);
71 len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
72 if (len < 0)
73 return -1;
74
75 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
76
77 if (tb[NETNSA_NSID])
78 return rta_getattr_u32(tb[NETNSA_NSID]);
79
80 return -1;
81}
d116ff34
VK
82#else
83static int get_netnsid_from_name(const char *name)
84{
85 return -1;
86}
87#endif /* HAVE_NETNSID */
d182ee13 88
0dc34c77
EB
89static int netns_list(int argc, char **argv)
90{
91 struct dirent *entry;
92 DIR *dir;
d182ee13 93 int id;
0dc34c77
EB
94
95 dir = opendir(NETNS_RUN_DIR);
96 if (!dir)
a05f6511 97 return 0;
0dc34c77
EB
98
99 while ((entry = readdir(dir)) != NULL) {
100 if (strcmp(entry->d_name, ".") == 0)
101 continue;
102 if (strcmp(entry->d_name, "..") == 0)
103 continue;
d182ee13
ND
104 printf("%s", entry->d_name);
105 id = get_netnsid_from_name(entry->d_name);
106 if (id >= 0)
107 printf(" (id: %d)", id);
108 printf("\n");
0dc34c77
EB
109 }
110 closedir(dir);
a05f6511 111 return 0;
0dc34c77
EB
112}
113
b13ba03f 114static int cmd_exec(const char *cmd, char **argv, bool do_fork)
0dc34c77 115{
95592b47 116 fflush(stdout);
b13ba03f 117 if (do_fork) {
95592b47
J
118 int status;
119 pid_t pid;
120
121 pid = fork();
122 if (pid < 0) {
123 perror("fork");
a05f6511 124 exit(1);
95592b47
J
125 }
126
127 if (pid != 0) {
128 /* Parent */
129 if (waitpid(pid, &status, 0) < 0) {
130 perror("waitpid");
a05f6511 131 exit(1);
95592b47
J
132 }
133
3c61c01a 134 if (WIFEXITED(status)) {
b13ba03f 135 return WEXITSTATUS(status);
3c61c01a 136 }
95592b47 137
3c61c01a 138 exit(1);
95592b47
J
139 }
140 }
141
b13ba03f 142 if (execvp(cmd, argv) < 0)
14645ec2 143 fprintf(stderr, "exec of \"%s\" failed: %s\n",
b13ba03f 144 cmd, strerror(errno));
a05f6511 145 _exit(1);
0dc34c77
EB
146}
147
b13ba03f
VK
148static int on_netns_exec(char *nsname, void *arg)
149{
150 char **argv = arg;
151 cmd_exec(argv[1], argv + 1, true);
152 return 0;
153}
154
155static int netns_exec(int argc, char **argv)
156{
157 /* Setup the proper environment for apps that are not netns
158 * aware, and execute a program in that environment.
159 */
160 const char *cmd;
161
162 if (argc < 1 && !do_all) {
163 fprintf(stderr, "No netns name specified\n");
164 return -1;
165 }
166 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
167 fprintf(stderr, "No command specified\n");
168 return -1;
169 }
170
171 if (do_all)
172 return do_each_netns(on_netns_exec, --argv, 1);
173
174 if (netns_switch(argv[0]))
175 return -1;
176
177 /* ip must return the status of the child,
178 * but do_cmd() will add a minus to this,
179 * so let's add another one here to cancel it.
180 */
181 cmd = argv[1];
182 return -cmd_exec(cmd, argv + 1, !!batch_mode);
183}
184
9a7b3d91
EB
185static int is_pid(const char *str)
186{
187 int ch;
188 for (; (ch = *str); str++) {
189 if (!isdigit(ch))
190 return 0;
191 }
192 return 1;
193}
194
195static int netns_pids(int argc, char **argv)
196{
197 const char *name;
198 char net_path[MAXPATHLEN];
199 int netns;
200 struct stat netst;
201 DIR *dir;
202 struct dirent *entry;
203
204 if (argc < 1) {
205 fprintf(stderr, "No netns name specified\n");
a05f6511 206 return -1;
9a7b3d91
EB
207 }
208 if (argc > 1) {
209 fprintf(stderr, "extra arguments specified\n");
a05f6511 210 return -1;
9a7b3d91
EB
211 }
212
213 name = argv[0];
214 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
215 netns = open(net_path, O_RDONLY);
216 if (netns < 0) {
217 fprintf(stderr, "Cannot open network namespace: %s\n",
218 strerror(errno));
a05f6511 219 return -1;
9a7b3d91
EB
220 }
221 if (fstat(netns, &netst) < 0) {
222 fprintf(stderr, "Stat of netns failed: %s\n",
223 strerror(errno));
a05f6511 224 return -1;
9a7b3d91
EB
225 }
226 dir = opendir("/proc/");
227 if (!dir) {
228 fprintf(stderr, "Open of /proc failed: %s\n",
229 strerror(errno));
a05f6511 230 return -1;
9a7b3d91
EB
231 }
232 while((entry = readdir(dir))) {
233 char pid_net_path[MAXPATHLEN];
234 struct stat st;
235 if (!is_pid(entry->d_name))
236 continue;
237 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
238 entry->d_name);
239 if (stat(pid_net_path, &st) != 0)
240 continue;
241 if ((st.st_dev == netst.st_dev) &&
242 (st.st_ino == netst.st_ino)) {
243 printf("%s\n", entry->d_name);
244 }
245 }
246 closedir(dir);
a05f6511 247 return 0;
0612519e 248
9a7b3d91
EB
249}
250
251static int netns_identify(int argc, char **argv)
252{
253 const char *pidstr;
254 char net_path[MAXPATHLEN];
255 int netns;
256 struct stat netst;
257 DIR *dir;
258 struct dirent *entry;
259
260 if (argc < 1) {
0948adc0 261 pidstr = "self";
262 } else if (argc > 1) {
9a7b3d91 263 fprintf(stderr, "extra arguments specified\n");
a05f6511 264 return -1;
0948adc0 265 } else {
266 pidstr = argv[0];
267 if (!is_pid(pidstr)) {
268 fprintf(stderr, "Specified string '%s' is not a pid\n",
269 pidstr);
270 return -1;
271 }
9a7b3d91
EB
272 }
273
274 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
275 netns = open(net_path, O_RDONLY);
276 if (netns < 0) {
277 fprintf(stderr, "Cannot open network namespace: %s\n",
278 strerror(errno));
a05f6511 279 return -1;
9a7b3d91
EB
280 }
281 if (fstat(netns, &netst) < 0) {
282 fprintf(stderr, "Stat of netns failed: %s\n",
283 strerror(errno));
a05f6511 284 return -1;
9a7b3d91
EB
285 }
286 dir = opendir(NETNS_RUN_DIR);
287 if (!dir) {
288 /* Succeed treat a missing directory as an empty directory */
289 if (errno == ENOENT)
a05f6511 290 return 0;
9a7b3d91
EB
291
292 fprintf(stderr, "Failed to open directory %s:%s\n",
293 NETNS_RUN_DIR, strerror(errno));
a05f6511 294 return -1;
9a7b3d91
EB
295 }
296
297 while((entry = readdir(dir))) {
298 char name_path[MAXPATHLEN];
299 struct stat st;
300
301 if (strcmp(entry->d_name, ".") == 0)
302 continue;
303 if (strcmp(entry->d_name, "..") == 0)
304 continue;
305
306 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
307 entry->d_name);
308
309 if (stat(name_path, &st) != 0)
310 continue;
311
312 if ((st.st_dev == netst.st_dev) &&
313 (st.st_ino == netst.st_ino)) {
314 printf("%s\n", entry->d_name);
315 }
316 }
317 closedir(dir);
a05f6511 318 return 0;
0612519e 319
9a7b3d91
EB
320}
321
33724939 322static int on_netns_del(char *nsname, void *arg)
0dc34c77 323{
0dc34c77
EB
324 char netns_path[MAXPATHLEN];
325
33724939 326 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
0dc34c77
EB
327 umount2(netns_path, MNT_DETACH);
328 if (unlink(netns_path) < 0) {
14645ec2 329 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
0dc34c77 330 netns_path, strerror(errno));
a05f6511 331 return -1;
0dc34c77 332 }
a05f6511 333 return 0;
0dc34c77
EB
334}
335
33724939
VK
336static int netns_delete(int argc, char **argv)
337{
338 if (argc < 1 && !do_all) {
339 fprintf(stderr, "No netns name specified\n");
340 return -1;
341 }
342
343 if (do_all)
344 return netns_foreach(on_netns_del, NULL);
345
346 return on_netns_del(argv[0], NULL);
347}
348
c1cbb18a 349static int create_netns_dir(void)
350{
351 /* Create the base netns directory if it doesn't exist */
352 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
353 if (errno != EEXIST) {
354 fprintf(stderr, "mkdir %s failed: %s\n",
355 NETNS_RUN_DIR, strerror(errno));
356 return -1;
357 }
358 }
359
360 return 0;
361}
362
0dc34c77
EB
363static int netns_add(int argc, char **argv)
364{
365 /* This function creates a new network namespace and
366 * a new mount namespace and bind them into a well known
367 * location in the filesystem based on the name provided.
368 *
369 * The mount namespace is created so that any necessary
370 * userspace tweaks like remounting /sys, or bind mounting
371 * a new /etc/resolv.conf can be shared between uers.
372 */
373 char netns_path[MAXPATHLEN];
374 const char *name;
223f4d8e 375 int fd;
58a3e827 376 int made_netns_run_dir_mount = 0;
0dc34c77
EB
377
378 if (argc < 1) {
379 fprintf(stderr, "No netns name specified\n");
a05f6511 380 return -1;
0dc34c77
EB
381 }
382 name = argv[0];
383
384 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
385
c1cbb18a 386 if (create_netns_dir())
387 return -1;
0dc34c77 388
d259f030 389 /* Make it possible for network namespace mounts to propagate between
58a3e827
EB
390 * mount namespaces. This makes it likely that a unmounting a network
391 * namespace file in one namespace will unmount the network namespace
392 * file in all namespaces allowing the network namespace to be freed
393 * sooner.
394 */
395 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
396 /* Fail unless we need to make the mount point */
397 if (errno != EINVAL || made_netns_run_dir_mount) {
398 fprintf(stderr, "mount --make-shared %s failed: %s\n",
399 NETNS_RUN_DIR, strerror(errno));
a05f6511 400 return -1;
58a3e827
EB
401 }
402
403 /* Upgrade NETNS_RUN_DIR to a mount point */
404 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) {
405 fprintf(stderr, "mount --bind %s %s failed: %s\n",
406 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
a05f6511 407 return -1;
58a3e827
EB
408 }
409 made_netns_run_dir_mount = 1;
410 }
411
0dc34c77 412 /* Create the filesystem state */
223f4d8e
EB
413 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
414 if (fd < 0) {
55713c8c 415 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
0dc34c77 416 netns_path, strerror(errno));
a05f6511 417 return -1;
0dc34c77 418 }
223f4d8e 419 close(fd);
0dc34c77 420 if (unshare(CLONE_NEWNET) < 0) {
14645ec2
KR
421 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
422 name, strerror(errno));
0dc34c77
EB
423 goto out_delete;
424 }
425
426 /* Bind the netns last so I can watch for it */
427 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
428 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
429 netns_path, strerror(errno));
430 goto out_delete;
431 }
a05f6511 432 return 0;
0dc34c77
EB
433out_delete:
434 netns_delete(argc, argv);
a05f6511 435 return -1;
0dc34c77
EB
436}
437
d182ee13
ND
438static int set_netnsid_from_name(const char *name, int nsid)
439{
440 struct {
441 struct nlmsghdr n;
442 struct rtgenmsg g;
443 char buf[1024];
444 } req;
445 int fd, err = 0;
446
447 memset(&req, 0, sizeof(req));
448 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
449 req.n.nlmsg_flags = NLM_F_REQUEST;
450 req.n.nlmsg_type = RTM_NEWNSID;
451 req.g.rtgen_family = AF_UNSPEC;
452
453 fd = netns_get_fd(name);
454 if (fd < 0)
455 return fd;
456
457 addattr32(&req.n, 1024, NETNSA_FD, fd);
458 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
459 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
460 err = -2;
461
462 close(fd);
463 return err;
464}
465
466static int netns_set(int argc, char **argv)
467{
468 char netns_path[MAXPATHLEN];
469 const char *name;
470 int netns, nsid;
471
472 if (argc < 1) {
473 fprintf(stderr, "No netns name specified\n");
474 return -1;
475 }
476 if (argc < 2) {
477 fprintf(stderr, "No nsid specified\n");
478 return -1;
479 }
480 name = argv[0];
481 nsid = atoi(argv[1]);
482
483 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
484 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
485 if (netns < 0) {
486 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
487 name, strerror(errno));
488 return -1;
489 }
490
491 return set_netnsid_from_name(name, nsid);
492}
0dc34c77
EB
493
494static int netns_monitor(int argc, char **argv)
495{
496 char buf[4096];
497 struct inotify_event *event;
498 int fd;
499 fd = inotify_init();
500 if (fd < 0) {
501 fprintf(stderr, "inotify_init failed: %s\n",
502 strerror(errno));
a05f6511 503 return -1;
0dc34c77 504 }
c1cbb18a 505
506 if (create_netns_dir())
507 return -1;
508
0dc34c77
EB
509 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
510 fprintf(stderr, "inotify_add_watch failed: %s\n",
511 strerror(errno));
a05f6511 512 return -1;
0dc34c77
EB
513 }
514 for(;;) {
515 ssize_t len = read(fd, buf, sizeof(buf));
516 if (len < 0) {
517 fprintf(stderr, "read failed: %s\n",
518 strerror(errno));
a05f6511 519 return -1;
0dc34c77
EB
520 }
521 for (event = (struct inotify_event *)buf;
522 (char *)event < &buf[len];
523 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
524 if (event->mask & IN_CREATE)
525 printf("add %s\n", event->name);
526 if (event->mask & IN_DELETE)
527 printf("delete %s\n", event->name);
528 }
529 }
a05f6511 530 return 0;
0dc34c77
EB
531}
532
533int do_netns(int argc, char **argv)
534{
535 if (argc < 1)
536 return netns_list(0, NULL);
537
538 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
539 (matches(*argv, "lst") == 0))
540 return netns_list(argc-1, argv+1);
541
542 if (matches(*argv, "help") == 0)
8e2d47dc 543 return usage();
0dc34c77
EB
544
545 if (matches(*argv, "add") == 0)
546 return netns_add(argc-1, argv+1);
547
d182ee13
ND
548 if (matches(*argv, "set") == 0)
549 return netns_set(argc-1, argv+1);
550
0dc34c77
EB
551 if (matches(*argv, "delete") == 0)
552 return netns_delete(argc-1, argv+1);
553
9a7b3d91
EB
554 if (matches(*argv, "identify") == 0)
555 return netns_identify(argc-1, argv+1);
556
557 if (matches(*argv, "pids") == 0)
558 return netns_pids(argc-1, argv+1);
559
0dc34c77
EB
560 if (matches(*argv, "exec") == 0)
561 return netns_exec(argc-1, argv+1);
562
563 if (matches(*argv, "monitor") == 0)
564 return netns_monitor(argc-1, argv+1);
565
566 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
a05f6511 567 exit(-1);
0dc34c77 568}