]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipnetns.c
52aefacf4dc2e35be14f2560a649d777f9b17a59
[mirror_iproute2.git] / ip / ipnetns.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #define _ATFILE_SOURCE
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <sys/wait.h>
6 #include <sys/inotify.h>
7 #include <sys/mount.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>
16 #include <ctype.h>
17 #include <linux/limits.h>
18
19 #include <linux/net_namespace.h>
20
21 #include "utils.h"
22 #include "list.h"
23 #include "ip_common.h"
24 #include "namespace.h"
25 #include "json_print.h"
26
27 static int usage(void)
28 {
29 fprintf(stderr, "Usage: ip netns list\n");
30 fprintf(stderr, " ip netns add NAME\n");
31 fprintf(stderr, " ip netns attach NAME PID\n");
32 fprintf(stderr, " ip netns set NAME NETNSID\n");
33 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
34 fprintf(stderr, " ip netns identify [PID]\n");
35 fprintf(stderr, " ip netns pids NAME\n");
36 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
37 fprintf(stderr, " ip netns monitor\n");
38 fprintf(stderr, " ip netns list-id\n");
39 fprintf(stderr, "NETNSID := auto | POSITIVE-INT\n");
40 exit(-1);
41 }
42
43 /* This socket is used to get nsid */
44 static struct rtnl_handle rtnsh = { .fd = -1 };
45
46 static int have_rtnl_getnsid = -1;
47
48 static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
49 struct nlmsghdr *n, void *arg)
50 {
51 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
52
53 if (n->nlmsg_type == NLMSG_ERROR &&
54 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
55 have_rtnl_getnsid = 0;
56 else
57 have_rtnl_getnsid = 1;
58 return -1;
59 }
60
61 static int ipnetns_have_nsid(void)
62 {
63 struct {
64 struct nlmsghdr n;
65 struct rtgenmsg g;
66 char buf[1024];
67 } req = {
68 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
69 .n.nlmsg_flags = NLM_F_REQUEST,
70 .n.nlmsg_type = RTM_GETNSID,
71 .g.rtgen_family = AF_UNSPEC,
72 };
73 int fd;
74
75 if (have_rtnl_getnsid < 0) {
76 fd = open("/proc/self/ns/net", O_RDONLY);
77 if (fd < 0) {
78 have_rtnl_getnsid = 0;
79 return 0;
80 }
81
82 addattr32(&req.n, 1024, NETNSA_FD, fd);
83
84 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
85 perror("request send failed");
86 exit(1);
87 }
88 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
89 close(fd);
90 }
91
92 return have_rtnl_getnsid;
93 }
94
95 int get_netnsid_from_name(const char *name)
96 {
97 struct {
98 struct nlmsghdr n;
99 struct rtgenmsg g;
100 char buf[1024];
101 } req = {
102 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
103 .n.nlmsg_flags = NLM_F_REQUEST,
104 .n.nlmsg_type = RTM_GETNSID,
105 .g.rtgen_family = AF_UNSPEC,
106 };
107 struct nlmsghdr *answer;
108 struct rtattr *tb[NETNSA_MAX + 1];
109 struct rtgenmsg *rthdr;
110 int len, fd, ret = -1;
111
112 netns_nsid_socket_init();
113
114 fd = netns_get_fd(name);
115 if (fd < 0)
116 return fd;
117
118 addattr32(&req.n, 1024, NETNSA_FD, fd);
119 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
120 close(fd);
121 return -2;
122 }
123 close(fd);
124
125 /* Validate message and parse attributes */
126 if (answer->nlmsg_type == NLMSG_ERROR)
127 goto out;
128
129 rthdr = NLMSG_DATA(answer);
130 len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
131 if (len < 0)
132 goto out;
133
134 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
135
136 if (tb[NETNSA_NSID]) {
137 ret = rta_getattr_u32(tb[NETNSA_NSID]);
138 }
139
140 out:
141 free(answer);
142 return ret;
143 }
144
145 struct nsid_cache {
146 struct hlist_node nsid_hash;
147 struct hlist_node name_hash;
148 int nsid;
149 char name[0];
150 };
151
152 #define NSIDMAP_SIZE 128
153 #define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
154 #define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
155
156 static struct hlist_head nsid_head[NSIDMAP_SIZE];
157 static struct hlist_head name_head[NSIDMAP_SIZE];
158
159 static struct nsid_cache *netns_map_get_by_nsid(int nsid)
160 {
161 uint32_t h = NSID_HASH_NSID(nsid);
162 struct hlist_node *n;
163
164 hlist_for_each(n, &nsid_head[h]) {
165 struct nsid_cache *c = container_of(n, struct nsid_cache,
166 nsid_hash);
167 if (c->nsid == nsid)
168 return c;
169 }
170
171 return NULL;
172 }
173
174 char *get_name_from_nsid(int nsid)
175 {
176 struct nsid_cache *c;
177
178 netns_nsid_socket_init();
179 netns_map_init();
180
181 c = netns_map_get_by_nsid(nsid);
182 if (c)
183 return c->name;
184
185 return NULL;
186 }
187
188 static int netns_map_add(int nsid, const char *name)
189 {
190 struct nsid_cache *c;
191 uint32_t h;
192
193 if (netns_map_get_by_nsid(nsid) != NULL)
194 return -EEXIST;
195
196 c = malloc(sizeof(*c) + strlen(name) + 1);
197 if (c == NULL) {
198 perror("malloc");
199 return -ENOMEM;
200 }
201 c->nsid = nsid;
202 strcpy(c->name, name);
203
204 h = NSID_HASH_NSID(nsid);
205 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
206
207 h = NSID_HASH_NAME(name);
208 hlist_add_head(&c->name_hash, &name_head[h]);
209
210 return 0;
211 }
212
213 static void netns_map_del(struct nsid_cache *c)
214 {
215 hlist_del(&c->name_hash);
216 hlist_del(&c->nsid_hash);
217 free(c);
218 }
219
220 void netns_nsid_socket_init(void)
221 {
222 if (rtnsh.fd > -1 || !ipnetns_have_nsid())
223 return;
224
225 if (rtnl_open(&rtnsh, 0) < 0) {
226 fprintf(stderr, "Cannot open rtnetlink\n");
227 exit(1);
228 }
229
230 }
231
232 void netns_map_init(void)
233 {
234 static int initialized;
235 struct dirent *entry;
236 DIR *dir;
237 int nsid;
238
239 if (initialized || !ipnetns_have_nsid())
240 return;
241
242 dir = opendir(NETNS_RUN_DIR);
243 if (!dir)
244 return;
245
246 while ((entry = readdir(dir)) != NULL) {
247 if (strcmp(entry->d_name, ".") == 0)
248 continue;
249 if (strcmp(entry->d_name, "..") == 0)
250 continue;
251 nsid = get_netnsid_from_name(entry->d_name);
252
253 if (nsid >= 0)
254 netns_map_add(nsid, entry->d_name);
255 }
256 closedir(dir);
257 initialized = 1;
258 }
259
260 static int netns_get_name(int nsid, char *name)
261 {
262 struct dirent *entry;
263 DIR *dir;
264 int id;
265
266 dir = opendir(NETNS_RUN_DIR);
267 if (!dir)
268 return -ENOENT;
269
270 while ((entry = readdir(dir)) != NULL) {
271 if (strcmp(entry->d_name, ".") == 0)
272 continue;
273 if (strcmp(entry->d_name, "..") == 0)
274 continue;
275 id = get_netnsid_from_name(entry->d_name);
276
277 if (nsid == id) {
278 strcpy(name, entry->d_name);
279 closedir(dir);
280 return 0;
281 }
282 }
283 closedir(dir);
284 return -ENOENT;
285 }
286
287 int print_nsid(struct nlmsghdr *n, void *arg)
288 {
289 struct rtgenmsg *rthdr = NLMSG_DATA(n);
290 struct rtattr *tb[NETNSA_MAX+1];
291 int len = n->nlmsg_len;
292 FILE *fp = (FILE *)arg;
293 struct nsid_cache *c;
294 char name[NAME_MAX];
295 int nsid;
296
297 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
298 return 0;
299
300 len -= NLMSG_SPACE(sizeof(*rthdr));
301 if (len < 0) {
302 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
303 __func__);
304 return -1;
305 }
306
307 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
308 if (tb[NETNSA_NSID] == NULL) {
309 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
310 return -1;
311 }
312
313 open_json_object(NULL);
314 if (n->nlmsg_type == RTM_DELNSID)
315 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
316
317 nsid = rta_getattr_u32(tb[NETNSA_NSID]);
318 print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid);
319
320 c = netns_map_get_by_nsid(nsid);
321 if (c != NULL) {
322 print_string(PRINT_ANY, "name",
323 "(iproute2 netns name: %s)", c->name);
324 netns_map_del(c);
325 }
326
327 /* During 'ip monitor nsid', no chance to have new nsid in cache. */
328 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
329 if (netns_get_name(nsid, name) == 0) {
330 print_string(PRINT_ANY, "name",
331 "(iproute2 netns name: %s)", name);
332 netns_map_add(nsid, name);
333 }
334
335 print_string(PRINT_FP, NULL, "\n", NULL);
336 close_json_object();
337 fflush(fp);
338 return 0;
339 }
340
341 static int netns_list_id(int argc, char **argv)
342 {
343 if (!ipnetns_have_nsid()) {
344 fprintf(stderr,
345 "RTM_GETNSID is not supported by the kernel.\n");
346 return -ENOTSUP;
347 }
348
349 if (rtnl_nsiddump_req(&rth, AF_UNSPEC) < 0) {
350 perror("Cannot send dump request");
351 exit(1);
352 }
353
354 new_json_obj(json);
355 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
356 delete_json_obj();
357 fprintf(stderr, "Dump terminated\n");
358 exit(1);
359 }
360 delete_json_obj();
361 return 0;
362 }
363
364 static int netns_list(int argc, char **argv)
365 {
366 struct dirent *entry;
367 DIR *dir;
368 int id;
369
370 dir = opendir(NETNS_RUN_DIR);
371 if (!dir)
372 return 0;
373
374 new_json_obj(json);
375 while ((entry = readdir(dir)) != NULL) {
376 if (strcmp(entry->d_name, ".") == 0)
377 continue;
378 if (strcmp(entry->d_name, "..") == 0)
379 continue;
380
381 open_json_object(NULL);
382 print_string(PRINT_ANY, "name",
383 "%s", entry->d_name);
384 if (ipnetns_have_nsid()) {
385 id = get_netnsid_from_name(entry->d_name);
386 if (id >= 0)
387 print_uint(PRINT_ANY, "id",
388 " (id: %d)", id);
389 }
390 print_string(PRINT_FP, NULL, "\n", NULL);
391 close_json_object();
392 }
393 closedir(dir);
394 delete_json_obj();
395 return 0;
396 }
397
398 static int on_netns_exec(char *nsname, void *arg)
399 {
400 char **argv = arg;
401
402 cmd_exec(argv[1], argv + 1, true);
403 return 0;
404 }
405
406 static int netns_exec(int argc, char **argv)
407 {
408 /* Setup the proper environment for apps that are not netns
409 * aware, and execute a program in that environment.
410 */
411 const char *cmd;
412
413 if (argc < 1 && !do_all) {
414 fprintf(stderr, "No netns name specified\n");
415 return -1;
416 }
417 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
418 fprintf(stderr, "No command specified\n");
419 return -1;
420 }
421
422 if (do_all)
423 return do_each_netns(on_netns_exec, --argv, 1);
424
425 if (netns_switch(argv[0]))
426 return -1;
427
428 /* we just changed namespaces. clear any vrf association
429 * with prior namespace before exec'ing command
430 */
431 vrf_reset();
432
433 /* ip must return the status of the child,
434 * but do_cmd() will add a minus to this,
435 * so let's add another one here to cancel it.
436 */
437 cmd = argv[1];
438 return -cmd_exec(cmd, argv + 1, !!batch_mode);
439 }
440
441 static int is_pid(const char *str)
442 {
443 int ch;
444
445 for (; (ch = *str); str++) {
446 if (!isdigit(ch))
447 return 0;
448 }
449 return 1;
450 }
451
452 static int netns_pids(int argc, char **argv)
453 {
454 const char *name;
455 char net_path[PATH_MAX];
456 int netns;
457 struct stat netst;
458 DIR *dir;
459 struct dirent *entry;
460
461 if (argc < 1) {
462 fprintf(stderr, "No netns name specified\n");
463 return -1;
464 }
465 if (argc > 1) {
466 fprintf(stderr, "extra arguments specified\n");
467 return -1;
468 }
469
470 name = argv[0];
471 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
472 netns = open(net_path, O_RDONLY);
473 if (netns < 0) {
474 fprintf(stderr, "Cannot open network namespace: %s\n",
475 strerror(errno));
476 return -1;
477 }
478 if (fstat(netns, &netst) < 0) {
479 fprintf(stderr, "Stat of netns failed: %s\n",
480 strerror(errno));
481 return -1;
482 }
483 dir = opendir("/proc/");
484 if (!dir) {
485 fprintf(stderr, "Open of /proc failed: %s\n",
486 strerror(errno));
487 return -1;
488 }
489 while ((entry = readdir(dir))) {
490 char pid_net_path[PATH_MAX];
491 struct stat st;
492
493 if (!is_pid(entry->d_name))
494 continue;
495 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
496 entry->d_name);
497 if (stat(pid_net_path, &st) != 0)
498 continue;
499 if ((st.st_dev == netst.st_dev) &&
500 (st.st_ino == netst.st_ino)) {
501 printf("%s\n", entry->d_name);
502 }
503 }
504 closedir(dir);
505 return 0;
506
507 }
508
509 int netns_identify_pid(const char *pidstr, char *name, int len)
510 {
511 char net_path[PATH_MAX];
512 int netns;
513 struct stat netst;
514 DIR *dir;
515 struct dirent *entry;
516
517 name[0] = '\0';
518
519 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
520 netns = open(net_path, O_RDONLY);
521 if (netns < 0) {
522 fprintf(stderr, "Cannot open network namespace: %s\n",
523 strerror(errno));
524 return -1;
525 }
526 if (fstat(netns, &netst) < 0) {
527 fprintf(stderr, "Stat of netns failed: %s\n",
528 strerror(errno));
529 return -1;
530 }
531 dir = opendir(NETNS_RUN_DIR);
532 if (!dir) {
533 /* Succeed treat a missing directory as an empty directory */
534 if (errno == ENOENT)
535 return 0;
536
537 fprintf(stderr, "Failed to open directory %s:%s\n",
538 NETNS_RUN_DIR, strerror(errno));
539 return -1;
540 }
541
542 while ((entry = readdir(dir))) {
543 char name_path[PATH_MAX];
544 struct stat st;
545
546 if (strcmp(entry->d_name, ".") == 0)
547 continue;
548 if (strcmp(entry->d_name, "..") == 0)
549 continue;
550
551 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
552 entry->d_name);
553
554 if (stat(name_path, &st) != 0)
555 continue;
556
557 if ((st.st_dev == netst.st_dev) &&
558 (st.st_ino == netst.st_ino)) {
559 strlcpy(name, entry->d_name, len);
560 }
561 }
562 closedir(dir);
563 return 0;
564
565 }
566
567 static int netns_identify(int argc, char **argv)
568 {
569 const char *pidstr;
570 char name[256];
571 int rc;
572
573 if (argc < 1) {
574 pidstr = "self";
575 } else if (argc > 1) {
576 fprintf(stderr, "extra arguments specified\n");
577 return -1;
578 } else {
579 pidstr = argv[0];
580 if (!is_pid(pidstr)) {
581 fprintf(stderr, "Specified string '%s' is not a pid\n",
582 pidstr);
583 return -1;
584 }
585 }
586
587 rc = netns_identify_pid(pidstr, name, sizeof(name));
588 if (!rc)
589 printf("%s\n", name);
590
591 return rc;
592 }
593
594 static int on_netns_del(char *nsname, void *arg)
595 {
596 char netns_path[PATH_MAX];
597
598 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
599 umount2(netns_path, MNT_DETACH);
600 if (unlink(netns_path) < 0) {
601 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
602 netns_path, strerror(errno));
603 return -1;
604 }
605 return 0;
606 }
607
608 static int netns_delete(int argc, char **argv)
609 {
610 if (argc < 1 && !do_all) {
611 fprintf(stderr, "No netns name specified\n");
612 return -1;
613 }
614
615 if (do_all)
616 return netns_foreach(on_netns_del, NULL);
617
618 return on_netns_del(argv[0], NULL);
619 }
620
621 static int create_netns_dir(void)
622 {
623 /* Create the base netns directory if it doesn't exist */
624 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
625 if (errno != EEXIST) {
626 fprintf(stderr, "mkdir %s failed: %s\n",
627 NETNS_RUN_DIR, strerror(errno));
628 return -1;
629 }
630 }
631
632 return 0;
633 }
634
635 static int netns_add(int argc, char **argv, bool create)
636 {
637 /* This function creates a new network namespace and
638 * a new mount namespace and bind them into a well known
639 * location in the filesystem based on the name provided.
640 *
641 * If create is true, a new namespace will be created,
642 * otherwise an existing one will be attached to the file.
643 *
644 * The mount namespace is created so that any necessary
645 * userspace tweaks like remounting /sys, or bind mounting
646 * a new /etc/resolv.conf can be shared between users.
647 */
648 char netns_path[PATH_MAX], proc_path[PATH_MAX];
649 const char *name;
650 pid_t pid;
651 int fd;
652 int made_netns_run_dir_mount = 0;
653
654 if (create) {
655 if (argc < 1) {
656 fprintf(stderr, "No netns name specified\n");
657 return -1;
658 }
659 } else {
660 if (argc < 2) {
661 fprintf(stderr, "No netns name and PID specified\n");
662 return -1;
663 }
664
665 if (get_s32(&pid, argv[1], 0) || !pid) {
666 fprintf(stderr, "Invalid PID: %s\n", argv[1]);
667 return -1;
668 }
669 }
670 name = argv[0];
671
672 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
673
674 if (create_netns_dir())
675 return -1;
676
677 /* Make it possible for network namespace mounts to propagate between
678 * mount namespaces. This makes it likely that a unmounting a network
679 * namespace file in one namespace will unmount the network namespace
680 * file in all namespaces allowing the network namespace to be freed
681 * sooner.
682 */
683 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
684 /* Fail unless we need to make the mount point */
685 if (errno != EINVAL || made_netns_run_dir_mount) {
686 fprintf(stderr, "mount --make-shared %s failed: %s\n",
687 NETNS_RUN_DIR, strerror(errno));
688 return -1;
689 }
690
691 /* Upgrade NETNS_RUN_DIR to a mount point */
692 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
693 fprintf(stderr, "mount --bind %s %s failed: %s\n",
694 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
695 return -1;
696 }
697 made_netns_run_dir_mount = 1;
698 }
699
700 /* Create the filesystem state */
701 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
702 if (fd < 0) {
703 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
704 netns_path, strerror(errno));
705 return -1;
706 }
707 close(fd);
708
709 if (create) {
710 if (unshare(CLONE_NEWNET) < 0) {
711 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
712 name, strerror(errno));
713 goto out_delete;
714 }
715
716 strcpy(proc_path, "/proc/self/ns/net");
717 } else {
718 snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
719 }
720
721 /* Bind the netns last so I can watch for it */
722 if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
723 fprintf(stderr, "Bind %s -> %s failed: %s\n",
724 proc_path, netns_path, strerror(errno));
725 goto out_delete;
726 }
727 return 0;
728 out_delete:
729 if (create) {
730 netns_delete(argc, argv);
731 } else if (unlink(netns_path) < 0) {
732 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
733 netns_path, strerror(errno));
734 }
735 return -1;
736 }
737
738 int set_netnsid_from_name(const char *name, int nsid)
739 {
740 struct {
741 struct nlmsghdr n;
742 struct rtgenmsg g;
743 char buf[1024];
744 } req = {
745 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
746 .n.nlmsg_flags = NLM_F_REQUEST,
747 .n.nlmsg_type = RTM_NEWNSID,
748 .g.rtgen_family = AF_UNSPEC,
749 };
750 int fd, err = 0;
751
752 netns_nsid_socket_init();
753
754 fd = netns_get_fd(name);
755 if (fd < 0)
756 return fd;
757
758 addattr32(&req.n, 1024, NETNSA_FD, fd);
759 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
760 if (rtnl_talk(&rth, &req.n, NULL) < 0)
761 err = -2;
762
763 close(fd);
764 return err;
765 }
766
767 static int netns_set(int argc, char **argv)
768 {
769 char netns_path[PATH_MAX];
770 const char *name;
771 int netns, nsid;
772
773 if (argc < 1) {
774 fprintf(stderr, "No netns name specified\n");
775 return -1;
776 }
777 if (argc < 2) {
778 fprintf(stderr, "No nsid specified\n");
779 return -1;
780 }
781 name = argv[0];
782 /* If a negative nsid is specified the kernel will select the nsid. */
783 if (strcmp(argv[1], "auto") == 0)
784 nsid = -1;
785 else if (get_integer(&nsid, argv[1], 0))
786 invarg("Invalid \"netnsid\" value\n", argv[1]);
787 else if (nsid < 0)
788 invarg("\"netnsid\" value should be >= 0\n", argv[1]);
789
790 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
791 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
792 if (netns < 0) {
793 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
794 name, strerror(errno));
795 return -1;
796 }
797
798 return set_netnsid_from_name(name, nsid);
799 }
800
801 static int netns_monitor(int argc, char **argv)
802 {
803 char buf[4096];
804 struct inotify_event *event;
805 int fd;
806
807 fd = inotify_init();
808 if (fd < 0) {
809 fprintf(stderr, "inotify_init failed: %s\n",
810 strerror(errno));
811 return -1;
812 }
813
814 if (create_netns_dir())
815 return -1;
816
817 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
818 fprintf(stderr, "inotify_add_watch failed: %s\n",
819 strerror(errno));
820 return -1;
821 }
822 for (;;) {
823 ssize_t len = read(fd, buf, sizeof(buf));
824
825 if (len < 0) {
826 fprintf(stderr, "read failed: %s\n",
827 strerror(errno));
828 return -1;
829 }
830 for (event = (struct inotify_event *)buf;
831 (char *)event < &buf[len];
832 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
833 if (event->mask & IN_CREATE)
834 printf("add %s\n", event->name);
835 if (event->mask & IN_DELETE)
836 printf("delete %s\n", event->name);
837 }
838 }
839 return 0;
840 }
841
842 static int invalid_name(const char *name)
843 {
844 return !*name || strlen(name) > NAME_MAX ||
845 strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
846 }
847
848 int do_netns(int argc, char **argv)
849 {
850 netns_nsid_socket_init();
851
852 if (argc < 1) {
853 netns_map_init();
854 return netns_list(0, NULL);
855 }
856
857 if (argc > 1 && invalid_name(argv[1])) {
858 fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
859 exit(-1);
860 }
861
862 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
863 (matches(*argv, "lst") == 0)) {
864 netns_map_init();
865 return netns_list(argc-1, argv+1);
866 }
867
868 if ((matches(*argv, "list-id") == 0)) {
869 netns_map_init();
870 return netns_list_id(argc-1, argv+1);
871 }
872
873 if (matches(*argv, "help") == 0)
874 return usage();
875
876 if (matches(*argv, "add") == 0)
877 return netns_add(argc-1, argv+1, true);
878
879 if (matches(*argv, "set") == 0)
880 return netns_set(argc-1, argv+1);
881
882 if (matches(*argv, "delete") == 0)
883 return netns_delete(argc-1, argv+1);
884
885 if (matches(*argv, "identify") == 0)
886 return netns_identify(argc-1, argv+1);
887
888 if (matches(*argv, "pids") == 0)
889 return netns_pids(argc-1, argv+1);
890
891 if (matches(*argv, "exec") == 0)
892 return netns_exec(argc-1, argv+1);
893
894 if (matches(*argv, "monitor") == 0)
895 return netns_monitor(argc-1, argv+1);
896
897 if (matches(*argv, "attach") == 0)
898 return netns_add(argc-1, argv+1, false);
899
900 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
901 exit(-1);
902 }