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