]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipnetns.c
06a773e43b7dffc3843c7595b60d52c74694dc3c
1 /* SPDX-License-Identifier: GPL-2.0 */
6 #include <sys/inotify.h>
8 #include <sys/syscall.h>
17 #include <linux/limits.h>
19 #include <linux/net_namespace.h>
23 #include "ip_common.h"
24 #include "namespace.h"
25 #include "json_print.h"
27 static int usage(void)
30 "Usage: ip netns list\n"
31 " ip netns add NAME\n"
32 " ip netns attach NAME PID\n"
33 " ip netns set NAME NETNSID\n"
34 " ip [-all] netns delete [NAME]\n"
35 " ip netns identify [PID]\n"
36 " ip netns pids NAME\n"
37 " ip [-all] netns exec [NAME] cmd ...\n"
39 " ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT]\n"
40 "NETNSID := auto | POSITIVE-INT\n");
44 /* This socket is used to get nsid */
45 static struct rtnl_handle rtnsh
= { .fd
= -1 };
47 static int have_rtnl_getnsid
= -1;
48 static int saved_netns
= -1;
49 static struct link_filter filter
;
51 static int ipnetns_accept_msg(struct rtnl_ctrl_data
*ctrl
,
52 struct nlmsghdr
*n
, void *arg
)
54 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(n
);
56 if (n
->nlmsg_type
== NLMSG_ERROR
&&
57 (err
->error
== -EOPNOTSUPP
|| err
->error
== -EINVAL
))
58 have_rtnl_getnsid
= 0;
60 have_rtnl_getnsid
= 1;
64 static int ipnetns_have_nsid(void)
71 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtgenmsg
)),
72 .n
.nlmsg_flags
= NLM_F_REQUEST
,
73 .n
.nlmsg_type
= RTM_GETNSID
,
74 .g
.rtgen_family
= AF_UNSPEC
,
78 if (have_rtnl_getnsid
< 0) {
79 fd
= open("/proc/self/ns/net", O_RDONLY
);
81 have_rtnl_getnsid
= 0;
85 addattr32(&req
.n
, 1024, NETNSA_FD
, fd
);
87 if (rtnl_send(&rth
, &req
.n
, req
.n
.nlmsg_len
) < 0) {
88 perror("request send failed");
91 rtnl_listen(&rth
, ipnetns_accept_msg
, NULL
);
95 return have_rtnl_getnsid
;
98 int get_netnsid_from_name(const char *name
)
105 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtgenmsg
)),
106 .n
.nlmsg_flags
= NLM_F_REQUEST
,
107 .n
.nlmsg_type
= RTM_GETNSID
,
108 .g
.rtgen_family
= AF_UNSPEC
,
110 struct nlmsghdr
*answer
;
111 struct rtattr
*tb
[NETNSA_MAX
+ 1];
112 struct rtgenmsg
*rthdr
;
113 int len
, fd
, ret
= -1;
115 netns_nsid_socket_init();
117 fd
= netns_get_fd(name
);
121 addattr32(&req
.n
, 1024, NETNSA_FD
, fd
);
122 if (rtnl_talk(&rtnsh
, &req
.n
, &answer
) < 0) {
128 /* Validate message and parse attributes */
129 if (answer
->nlmsg_type
== NLMSG_ERROR
)
132 rthdr
= NLMSG_DATA(answer
);
133 len
= answer
->nlmsg_len
- NLMSG_SPACE(sizeof(*rthdr
));
137 parse_rtattr(tb
, NETNSA_MAX
, NETNS_RTA(rthdr
), len
);
139 if (tb
[NETNSA_NSID
]) {
140 ret
= rta_getattr_s32(tb
[NETNSA_NSID
]);
149 struct hlist_node nsid_hash
;
150 struct hlist_node name_hash
;
155 #define NSIDMAP_SIZE 128
156 #define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
157 #define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
159 static struct hlist_head nsid_head
[NSIDMAP_SIZE
];
160 static struct hlist_head name_head
[NSIDMAP_SIZE
];
162 static struct nsid_cache
*netns_map_get_by_nsid(int nsid
)
164 uint32_t h
= NSID_HASH_NSID(nsid
);
165 struct hlist_node
*n
;
167 hlist_for_each(n
, &nsid_head
[h
]) {
168 struct nsid_cache
*c
= container_of(n
, struct nsid_cache
,
177 char *get_name_from_nsid(int nsid
)
179 struct nsid_cache
*c
;
181 netns_nsid_socket_init();
184 c
= netns_map_get_by_nsid(nsid
);
191 static int netns_map_add(int nsid
, const char *name
)
193 struct nsid_cache
*c
;
196 if (netns_map_get_by_nsid(nsid
) != NULL
)
199 c
= malloc(sizeof(*c
) + strlen(name
) + 1);
205 strcpy(c
->name
, name
);
207 h
= NSID_HASH_NSID(nsid
);
208 hlist_add_head(&c
->nsid_hash
, &nsid_head
[h
]);
210 h
= NSID_HASH_NAME(name
);
211 hlist_add_head(&c
->name_hash
, &name_head
[h
]);
216 static void netns_map_del(struct nsid_cache
*c
)
218 hlist_del(&c
->name_hash
);
219 hlist_del(&c
->nsid_hash
);
223 void netns_nsid_socket_init(void)
225 if (rtnsh
.fd
> -1 || !ipnetns_have_nsid())
228 if (rtnl_open(&rtnsh
, 0) < 0) {
229 fprintf(stderr
, "Cannot open rtnetlink\n");
235 void netns_map_init(void)
237 static int initialized
;
238 struct dirent
*entry
;
242 if (initialized
|| !ipnetns_have_nsid())
245 dir
= opendir(NETNS_RUN_DIR
);
249 while ((entry
= readdir(dir
)) != NULL
) {
250 if (strcmp(entry
->d_name
, ".") == 0)
252 if (strcmp(entry
->d_name
, "..") == 0)
254 nsid
= get_netnsid_from_name(entry
->d_name
);
257 netns_map_add(nsid
, entry
->d_name
);
263 static int netns_get_name(int nsid
, char *name
)
265 struct dirent
*entry
;
269 dir
= opendir(NETNS_RUN_DIR
);
273 while ((entry
= readdir(dir
)) != NULL
) {
274 if (strcmp(entry
->d_name
, ".") == 0)
276 if (strcmp(entry
->d_name
, "..") == 0)
278 id
= get_netnsid_from_name(entry
->d_name
);
281 strcpy(name
, entry
->d_name
);
290 int print_nsid(struct nlmsghdr
*n
, void *arg
)
292 struct rtgenmsg
*rthdr
= NLMSG_DATA(n
);
293 struct rtattr
*tb
[NETNSA_MAX
+1];
294 int len
= n
->nlmsg_len
;
295 FILE *fp
= (FILE *)arg
;
296 struct nsid_cache
*c
;
300 if (n
->nlmsg_type
!= RTM_NEWNSID
&& n
->nlmsg_type
!= RTM_DELNSID
)
303 len
-= NLMSG_SPACE(sizeof(*rthdr
));
305 fprintf(stderr
, "BUG: wrong nlmsg len %d in %s\n", len
,
310 parse_rtattr(tb
, NETNSA_MAX
, NETNS_RTA(rthdr
), len
);
311 if (tb
[NETNSA_NSID
] == NULL
) {
312 fprintf(stderr
, "BUG: NETNSA_NSID is missing %s\n", __func__
);
316 open_json_object(NULL
);
317 if (n
->nlmsg_type
== RTM_DELNSID
)
318 print_bool(PRINT_ANY
, "deleted", "Deleted ", true);
320 nsid
= rta_getattr_s32(tb
[NETNSA_NSID
]);
322 print_string(PRINT_ANY
, "nsid", "nsid %s ", "not-assigned");
324 print_int(PRINT_ANY
, "nsid", "nsid %d ", nsid
);
326 if (tb
[NETNSA_CURRENT_NSID
]) {
327 current
= rta_getattr_s32(tb
[NETNSA_CURRENT_NSID
]);
329 print_string(PRINT_ANY
, "current-nsid",
330 "current-nsid %s ", "not-assigned");
332 print_int(PRINT_ANY
, "current-nsid",
333 "current-nsid %d ", current
);
336 c
= netns_map_get_by_nsid(tb
[NETNSA_CURRENT_NSID
] ? current
: nsid
);
338 print_string(PRINT_ANY
, "name",
339 "(iproute2 netns name: %s)", c
->name
);
343 /* During 'ip monitor nsid', no chance to have new nsid in cache. */
344 if (c
== NULL
&& n
->nlmsg_type
== RTM_NEWNSID
)
345 if (netns_get_name(nsid
, name
) == 0) {
346 print_string(PRINT_ANY
, "name",
347 "(iproute2 netns name: %s)", name
);
348 netns_map_add(nsid
, name
);
351 print_string(PRINT_FP
, NULL
, "\n", NULL
);
357 static int get_netnsid_from_netnsid(int nsid
)
364 .n
.nlmsg_len
= NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg
))),
365 .n
.nlmsg_flags
= NLM_F_REQUEST
,
366 .n
.nlmsg_type
= RTM_GETNSID
,
367 .g
.rtgen_family
= AF_UNSPEC
,
369 struct nlmsghdr
*answer
;
372 netns_nsid_socket_init();
374 err
= addattr32(&req
.n
, sizeof(req
), NETNSA_NSID
, nsid
);
378 if (filter
.target_nsid
>= 0) {
379 err
= addattr32(&req
.n
, sizeof(req
), NETNSA_TARGET_NSID
,
385 if (rtnl_talk(&rtnsh
, &req
.n
, &answer
) < 0)
388 /* Validate message and parse attributes */
389 if (answer
->nlmsg_type
== NLMSG_ERROR
)
393 err
= print_nsid(answer
, stdout
);
400 static int netns_filter_req(struct nlmsghdr
*nlh
, int reqlen
)
404 if (filter
.target_nsid
>= 0) {
405 err
= addattr32(nlh
, reqlen
, NETNSA_TARGET_NSID
,
414 static int netns_list_id(int argc
, char **argv
)
418 if (!ipnetns_have_nsid()) {
420 "RTM_GETNSID is not supported by the kernel.\n");
424 filter
.target_nsid
= -1;
426 if (strcmp(*argv
, "target-nsid") == 0) {
427 if (filter
.target_nsid
>= 0)
428 duparg("target-nsid", *argv
);
431 if (get_integer(&filter
.target_nsid
, *argv
, 0))
432 invarg("\"target-nsid\" value is invalid\n",
434 else if (filter
.target_nsid
< 0)
435 invarg("\"target-nsid\" value should be >= 0\n",
437 } else if (strcmp(*argv
, "nsid") == 0) {
439 duparg("nsid", *argv
);
442 if (get_integer(&nsid
, *argv
, 0))
443 invarg("\"nsid\" value is invalid\n", *argv
);
445 invarg("\"nsid\" value should be >= 0\n",
453 return get_netnsid_from_netnsid(nsid
);
455 if (rtnl_nsiddump_req_filter_fn(&rth
, AF_UNSPEC
,
456 netns_filter_req
) < 0) {
457 perror("Cannot send dump request");
462 if (rtnl_dump_filter(&rth
, print_nsid
, stdout
) < 0) {
464 fprintf(stderr
, "Dump terminated\n");
471 static int netns_list(int argc
, char **argv
)
473 struct dirent
*entry
;
477 dir
= opendir(NETNS_RUN_DIR
);
482 while ((entry
= readdir(dir
)) != NULL
) {
483 if (strcmp(entry
->d_name
, ".") == 0)
485 if (strcmp(entry
->d_name
, "..") == 0)
488 open_json_object(NULL
);
489 print_string(PRINT_ANY
, "name",
490 "%s", entry
->d_name
);
491 if (ipnetns_have_nsid()) {
492 id
= get_netnsid_from_name(entry
->d_name
);
494 print_int(PRINT_ANY
, "id", " (id: %d)", id
);
496 print_string(PRINT_FP
, NULL
, "\n", NULL
);
504 static int do_switch(void *arg
)
508 /* we just changed namespaces. clear any vrf association
509 * with prior namespace before exec'ing command
513 return netns_switch(netns
);
516 static int on_netns_exec(char *nsname
, void *arg
)
520 printf("\nnetns: %s\n", nsname
);
521 cmd_exec(argv
[0], argv
, true, do_switch
, nsname
);
525 static int netns_exec(int argc
, char **argv
)
527 /* Setup the proper environment for apps that are not netns
528 * aware, and execute a program in that environment.
530 if (argc
< 1 && !do_all
) {
531 fprintf(stderr
, "No netns name specified\n");
534 if ((argc
< 2 && !do_all
) || (argc
< 1 && do_all
)) {
535 fprintf(stderr
, "No command specified\n");
540 return netns_foreach(on_netns_exec
, argv
);
542 /* ip must return the status of the child,
543 * but do_cmd() will add a minus to this,
544 * so let's add another one here to cancel it.
546 return -cmd_exec(argv
[1], argv
+ 1, !!batch_mode
, do_switch
, argv
[0]);
549 static int is_pid(const char *str
)
553 for (; (ch
= *str
); str
++) {
560 static int netns_pids(int argc
, char **argv
)
563 char net_path
[PATH_MAX
];
567 struct dirent
*entry
;
570 fprintf(stderr
, "No netns name specified\n");
574 fprintf(stderr
, "extra arguments specified\n");
579 snprintf(net_path
, sizeof(net_path
), "%s/%s", NETNS_RUN_DIR
, name
);
580 netns
= open(net_path
, O_RDONLY
);
582 fprintf(stderr
, "Cannot open network namespace: %s\n",
586 if (fstat(netns
, &netst
) < 0) {
587 fprintf(stderr
, "Stat of netns failed: %s\n",
591 dir
= opendir("/proc/");
593 fprintf(stderr
, "Open of /proc failed: %s\n",
597 while ((entry
= readdir(dir
))) {
598 char pid_net_path
[PATH_MAX
];
601 if (!is_pid(entry
->d_name
))
603 snprintf(pid_net_path
, sizeof(pid_net_path
), "/proc/%s/ns/net",
605 if (stat(pid_net_path
, &st
) != 0)
607 if ((st
.st_dev
== netst
.st_dev
) &&
608 (st
.st_ino
== netst
.st_ino
)) {
609 printf("%s\n", entry
->d_name
);
617 int netns_identify_pid(const char *pidstr
, char *name
, int len
)
619 char net_path
[PATH_MAX
];
623 struct dirent
*entry
;
627 snprintf(net_path
, sizeof(net_path
), "/proc/%s/ns/net", pidstr
);
628 netns
= open(net_path
, O_RDONLY
);
630 fprintf(stderr
, "Cannot open network namespace: %s\n",
634 if (fstat(netns
, &netst
) < 0) {
635 fprintf(stderr
, "Stat of netns failed: %s\n",
639 dir
= opendir(NETNS_RUN_DIR
);
641 /* Succeed treat a missing directory as an empty directory */
645 fprintf(stderr
, "Failed to open directory %s:%s\n",
646 NETNS_RUN_DIR
, strerror(errno
));
650 while ((entry
= readdir(dir
))) {
651 char name_path
[PATH_MAX
];
654 if (strcmp(entry
->d_name
, ".") == 0)
656 if (strcmp(entry
->d_name
, "..") == 0)
659 snprintf(name_path
, sizeof(name_path
), "%s/%s", NETNS_RUN_DIR
,
662 if (stat(name_path
, &st
) != 0)
665 if ((st
.st_dev
== netst
.st_dev
) &&
666 (st
.st_ino
== netst
.st_ino
)) {
667 strlcpy(name
, entry
->d_name
, len
);
675 static int netns_identify(int argc
, char **argv
)
683 } else if (argc
> 1) {
684 fprintf(stderr
, "extra arguments specified\n");
688 if (!is_pid(pidstr
)) {
689 fprintf(stderr
, "Specified string '%s' is not a pid\n",
695 rc
= netns_identify_pid(pidstr
, name
, sizeof(name
));
697 printf("%s\n", name
);
702 static int on_netns_del(char *nsname
, void *arg
)
704 char netns_path
[PATH_MAX
];
706 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, nsname
);
707 umount2(netns_path
, MNT_DETACH
);
708 if (unlink(netns_path
) < 0) {
709 fprintf(stderr
, "Cannot remove namespace file \"%s\": %s\n",
710 netns_path
, strerror(errno
));
716 static int netns_delete(int argc
, char **argv
)
718 if (argc
< 1 && !do_all
) {
719 fprintf(stderr
, "No netns name specified\n");
724 return netns_foreach(on_netns_del
, NULL
);
726 return on_netns_del(argv
[0], NULL
);
729 static int create_netns_dir(void)
731 /* Create the base netns directory if it doesn't exist */
732 if (mkdir(NETNS_RUN_DIR
, S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
)) {
733 if (errno
!= EEXIST
) {
734 fprintf(stderr
, "mkdir %s failed: %s\n",
735 NETNS_RUN_DIR
, strerror(errno
));
743 /* Obtain a FD for the current namespace, so we can reenter it later */
744 static void netns_save(void)
746 if (saved_netns
!= -1)
749 saved_netns
= open("/proc/self/ns/net", O_RDONLY
| O_CLOEXEC
);
750 if (saved_netns
== -1) {
751 perror("Cannot open init namespace");
756 static void netns_restore(void)
758 if (saved_netns
== -1)
761 if (setns(saved_netns
, CLONE_NEWNET
)) {
770 static int netns_add(int argc
, char **argv
, bool create
)
772 /* This function creates a new network namespace and
773 * a new mount namespace and bind them into a well known
774 * location in the filesystem based on the name provided.
776 * If create is true, a new namespace will be created,
777 * otherwise an existing one will be attached to the file.
779 * The mount namespace is created so that any necessary
780 * userspace tweaks like remounting /sys, or bind mounting
781 * a new /etc/resolv.conf can be shared between users.
783 char netns_path
[PATH_MAX
], proc_path
[PATH_MAX
];
787 int made_netns_run_dir_mount
= 0;
791 fprintf(stderr
, "No netns name specified\n");
796 fprintf(stderr
, "No netns name and PID specified\n");
800 if (get_s32(&pid
, argv
[1], 0) || !pid
) {
801 fprintf(stderr
, "Invalid PID: %s\n", argv
[1]);
807 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, name
);
809 if (create_netns_dir())
812 /* Make it possible for network namespace mounts to propagate between
813 * mount namespaces. This makes it likely that a unmounting a network
814 * namespace file in one namespace will unmount the network namespace
815 * file in all namespaces allowing the network namespace to be freed
818 while (mount("", NETNS_RUN_DIR
, "none", MS_SHARED
| MS_REC
, NULL
)) {
819 /* Fail unless we need to make the mount point */
820 if (errno
!= EINVAL
|| made_netns_run_dir_mount
) {
821 fprintf(stderr
, "mount --make-shared %s failed: %s\n",
822 NETNS_RUN_DIR
, strerror(errno
));
826 /* Upgrade NETNS_RUN_DIR to a mount point */
827 if (mount(NETNS_RUN_DIR
, NETNS_RUN_DIR
, "none", MS_BIND
| MS_REC
, NULL
)) {
828 fprintf(stderr
, "mount --bind %s %s failed: %s\n",
829 NETNS_RUN_DIR
, NETNS_RUN_DIR
, strerror(errno
));
832 made_netns_run_dir_mount
= 1;
835 /* Create the filesystem state */
836 fd
= open(netns_path
, O_RDONLY
|O_CREAT
|O_EXCL
, 0);
838 fprintf(stderr
, "Cannot create namespace file \"%s\": %s\n",
839 netns_path
, strerror(errno
));
846 if (unshare(CLONE_NEWNET
) < 0) {
847 fprintf(stderr
, "Failed to create a new network namespace \"%s\": %s\n",
848 name
, strerror(errno
));
852 strcpy(proc_path
, "/proc/self/ns/net");
854 snprintf(proc_path
, sizeof(proc_path
), "/proc/%d/ns/net", pid
);
857 /* Bind the netns last so I can watch for it */
858 if (mount(proc_path
, netns_path
, "none", MS_BIND
, NULL
) < 0) {
859 fprintf(stderr
, "Bind %s -> %s failed: %s\n",
860 proc_path
, netns_path
, strerror(errno
));
869 netns_delete(argc
, argv
);
870 } else if (unlink(netns_path
) < 0) {
871 fprintf(stderr
, "Cannot remove namespace file \"%s\": %s\n",
872 netns_path
, strerror(errno
));
877 int set_netnsid_from_name(const char *name
, int nsid
)
884 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtgenmsg
)),
885 .n
.nlmsg_flags
= NLM_F_REQUEST
,
886 .n
.nlmsg_type
= RTM_NEWNSID
,
887 .g
.rtgen_family
= AF_UNSPEC
,
891 netns_nsid_socket_init();
893 fd
= netns_get_fd(name
);
897 addattr32(&req
.n
, 1024, NETNSA_FD
, fd
);
898 addattr32(&req
.n
, 1024, NETNSA_NSID
, nsid
);
899 if (rtnl_talk(&rth
, &req
.n
, NULL
) < 0)
906 static int netns_set(int argc
, char **argv
)
908 char netns_path
[PATH_MAX
];
913 fprintf(stderr
, "No netns name specified\n");
917 fprintf(stderr
, "No nsid specified\n");
921 /* If a negative nsid is specified the kernel will select the nsid. */
922 if (strcmp(argv
[1], "auto") == 0)
924 else if (get_integer(&nsid
, argv
[1], 0))
925 invarg("Invalid \"netnsid\" value\n", argv
[1]);
927 invarg("\"netnsid\" value should be >= 0\n", argv
[1]);
929 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, name
);
930 netns
= open(netns_path
, O_RDONLY
| O_CLOEXEC
);
932 fprintf(stderr
, "Cannot open network namespace \"%s\": %s\n",
933 name
, strerror(errno
));
937 return set_netnsid_from_name(name
, nsid
);
940 static int netns_monitor(int argc
, char **argv
)
943 struct inotify_event
*event
;
948 fprintf(stderr
, "inotify_init failed: %s\n",
953 if (create_netns_dir())
956 if (inotify_add_watch(fd
, NETNS_RUN_DIR
, IN_CREATE
| IN_DELETE
) < 0) {
957 fprintf(stderr
, "inotify_add_watch failed: %s\n",
962 ssize_t len
= read(fd
, buf
, sizeof(buf
));
965 fprintf(stderr
, "read failed: %s\n",
969 for (event
= (struct inotify_event
*)buf
;
970 (char *)event
< &buf
[len
];
971 event
= (struct inotify_event
*)((char *)event
+ sizeof(*event
) + event
->len
)) {
972 if (event
->mask
& IN_CREATE
)
973 printf("add %s\n", event
->name
);
974 if (event
->mask
& IN_DELETE
)
975 printf("delete %s\n", event
->name
);
981 static int invalid_name(const char *name
)
983 return !*name
|| strlen(name
) > NAME_MAX
||
984 strchr(name
, '/') || !strcmp(name
, ".") || !strcmp(name
, "..");
987 int do_netns(int argc
, char **argv
)
989 netns_nsid_socket_init();
993 return netns_list(0, NULL
);
996 if (!do_all
&& argc
> 1 && invalid_name(argv
[1])) {
997 fprintf(stderr
, "Invalid netns name \"%s\"\n", argv
[1]);
1001 if ((matches(*argv
, "list") == 0) || (matches(*argv
, "show") == 0) ||
1002 (matches(*argv
, "lst") == 0)) {
1004 return netns_list(argc
-1, argv
+1);
1007 if ((matches(*argv
, "list-id") == 0)) {
1009 return netns_list_id(argc
-1, argv
+1);
1012 if (matches(*argv
, "help") == 0)
1015 if (matches(*argv
, "add") == 0)
1016 return netns_add(argc
-1, argv
+1, true);
1018 if (matches(*argv
, "set") == 0)
1019 return netns_set(argc
-1, argv
+1);
1021 if (matches(*argv
, "delete") == 0)
1022 return netns_delete(argc
-1, argv
+1);
1024 if (matches(*argv
, "identify") == 0)
1025 return netns_identify(argc
-1, argv
+1);
1027 if (matches(*argv
, "pids") == 0)
1028 return netns_pids(argc
-1, argv
+1);
1030 if (matches(*argv
, "exec") == 0)
1031 return netns_exec(argc
-1, argv
+1);
1033 if (matches(*argv
, "monitor") == 0)
1034 return netns_monitor(argc
-1, argv
+1);
1036 if (matches(*argv
, "attach") == 0)
1037 return netns_add(argc
-1, argv
+1, false);
1039 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv
);