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