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