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/syscall.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <sched.h> 11 #include <fcntl.h> 12 #include <dirent.h> 13 #include <errno.h> 14 #include <unistd.h> 15 #include <ctype.h> 16 #include <linux/limits.h> 17 18 #include <linux/net_namespace.h> 19 20 #include "utils.h" 21 #include "hlist.h" 22 #include "ip_common.h" 23 #include "namespace.h" 24 25 static int usage(void) 26 { 27 fprintf(stderr, "Usage: ip netns list\n"); 28 fprintf(stderr, " ip netns add NAME\n"); 29 fprintf(stderr, " ip netns set NAME NETNSID\n"); 30 fprintf(stderr, " ip [-all] netns delete [NAME]\n"); 31 fprintf(stderr, " ip netns identify [PID]\n"); 32 fprintf(stderr, " ip netns pids NAME\n"); 33 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n"); 34 fprintf(stderr, " ip netns monitor\n"); 35 fprintf(stderr, " ip netns list-id\n"); 36 exit(-1); 37 } 38 39 /* This socket is used to get nsid */ 40 static struct rtnl_handle rtnsh = { .fd = -1 }; 41 42 static int have_rtnl_getnsid = -1; 43 44 static int ipnetns_accept_msg(const struct sockaddr_nl *who, 45 struct rtnl_ctrl_data *ctrl, 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[0]; 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, const 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) + strlen(name)); 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[PATH_MAX]; 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[PATH_MAX]; 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[PATH_MAX]; 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[PATH_MAX]; 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[PATH_MAX]; 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[PATH_MAX]; 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[PATH_MAX]; 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 } 815