1
2#define _ATFILE_SOURCE
3#include <sys/file.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <sys/wait.h>
7#include <sys/inotify.h>
8#include <sys/mount.h>
9#include <sys/syscall.h>
10#include <stdio.h>
11#include <string.h>
12#include <sched.h>
13#include <fcntl.h>
14#include <dirent.h>
15#include <errno.h>
16#include <unistd.h>
17#include <ctype.h>
18#include <linux/limits.h>
19
20#include <linux/net_namespace.h>
21
22#include "utils.h"
23#include "list.h"
24#include "ip_common.h"
25#include "namespace.h"
26#include "json_print.h"
27
28static int usage(void)
29{
30 fprintf(stderr,
31 "Usage: ip netns list\n"
32 " ip netns add NAME\n"
33 " ip netns attach NAME PID\n"
34 " ip netns set NAME NETNSID\n"
35 " ip [-all] netns delete [NAME]\n"
36 " ip netns identify [PID]\n"
37 " ip netns pids NAME\n"
38 " ip [-all] netns exec [NAME] cmd ...\n"
39 " ip netns monitor\n"
40 " ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT]\n"
41 "NETNSID := auto | POSITIVE-INT\n");
42 exit(-1);
43}
44
45
46static struct rtnl_handle rtnsh = { .fd = -1 };
47
48static int have_rtnl_getnsid = -1;
49static int saved_netns = -1;
50static struct link_filter filter;
51
52static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
53 struct nlmsghdr *n, void *arg)
54{
55 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
56
57 if (n->nlmsg_type == NLMSG_ERROR &&
58 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
59 have_rtnl_getnsid = 0;
60 else
61 have_rtnl_getnsid = 1;
62 return -1;
63}
64
65static int ipnetns_have_nsid(void)
66{
67 struct {
68 struct nlmsghdr n;
69 struct rtgenmsg g;
70 char buf[1024];
71 } req = {
72 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
73 .n.nlmsg_flags = NLM_F_REQUEST,
74 .n.nlmsg_type = RTM_GETNSID,
75 .g.rtgen_family = AF_UNSPEC,
76 };
77 int fd;
78
79 if (have_rtnl_getnsid >= 0) {
80 fd = open("/proc/self/ns/net", O_RDONLY);
81 if (fd < 0) {
82 fprintf(stderr,
83 "/proc/self/ns/net: %s. Continuing anyway.\n",
84 strerror(errno));
85 have_rtnl_getnsid = 0;
86 return 0;
87 }
88
89 addattr32(&req.n, 1024, NETNSA_FD, fd);
90
91 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
92 fprintf(stderr,
93 "rtnl_send(RTM_GETNSID): %s. Continuing anyway.\n",
94 strerror(errno));
95 have_rtnl_getnsid = 0;
96 close(fd);
97 return 0;
98 }
99 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
100 close(fd);
101 }
102
103 return have_rtnl_getnsid;
104}
105
106int get_netnsid_from_name(const char *name)
107{
108 struct {
109 struct nlmsghdr n;
110 struct rtgenmsg g;
111 char buf[1024];
112 } req = {
113 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
114 .n.nlmsg_flags = NLM_F_REQUEST,
115 .n.nlmsg_type = RTM_GETNSID,
116 .g.rtgen_family = AF_UNSPEC,
117 };
118 struct nlmsghdr *answer;
119 struct rtattr *tb[NETNSA_MAX + 1];
120 struct rtgenmsg *rthdr;
121 int len, fd, ret = -1;
122
123 netns_nsid_socket_init();
124
125 fd = netns_get_fd(name);
126 if (fd < 0)
127 return fd;
128
129 addattr32(&req.n, 1024, NETNSA_FD, fd);
130 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
131 close(fd);
132 return -2;
133 }
134 close(fd);
135
136
137 if (answer->nlmsg_type == NLMSG_ERROR)
138 goto out;
139
140 rthdr = NLMSG_DATA(answer);
141 len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
142 if (len < 0)
143 goto out;
144
145 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
146
147 if (tb[NETNSA_NSID]) {
148 ret = rta_getattr_s32(tb[NETNSA_NSID]);
149 }
150
151out:
152 free(answer);
153 return ret;
154}
155
156struct nsid_cache {
157 struct hlist_node nsid_hash;
158 struct hlist_node name_hash;
159 int nsid;
160 char name[0];
161};
162
163#define NSIDMAP_SIZE 128
164#define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
165#define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
166
167static struct hlist_head nsid_head[NSIDMAP_SIZE];
168static struct hlist_head name_head[NSIDMAP_SIZE];
169
170static struct nsid_cache *netns_map_get_by_nsid(int nsid)
171{
172 struct hlist_node *n;
173 uint32_t h;
174
175 if (nsid < 0)
176 return NULL;
177
178 h = NSID_HASH_NSID(nsid);
179 hlist_for_each(n, &nsid_head[h]) {
180 struct nsid_cache *c = container_of(n, struct nsid_cache,
181 nsid_hash);
182 if (c->nsid == nsid)
183 return c;
184 }
185
186 return NULL;
187}
188
189char *get_name_from_nsid(int nsid)
190{
191 struct nsid_cache *c;
192
193 if (nsid < 0)
194 return NULL;
195
196 netns_nsid_socket_init();
197 netns_map_init();
198
199 c = netns_map_get_by_nsid(nsid);
200 if (c)
201 return c->name;
202
203 return NULL;
204}
205
206static int netns_map_add(int nsid, const char *name)
207{
208 struct nsid_cache *c;
209 uint32_t h;
210
211 if (netns_map_get_by_nsid(nsid) != NULL)
212 return -EEXIST;
213
214 c = malloc(sizeof(*c) + strlen(name) + 1);
215 if (c == NULL) {
216 perror("malloc");
217 return -ENOMEM;
218 }
219 c->nsid = nsid;
220 strcpy(c->name, name);
221
222 h = NSID_HASH_NSID(nsid);
223 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
224
225 h = NSID_HASH_NAME(name);
226 hlist_add_head(&c->name_hash, &name_head[h]);
227
228 return 0;
229}
230
231static void netns_map_del(struct nsid_cache *c)
232{
233 hlist_del(&c->name_hash);
234 hlist_del(&c->nsid_hash);
235 free(c);
236}
237
238void netns_nsid_socket_init(void)
239{
240 if (rtnsh.fd > -1 || !ipnetns_have_nsid())
241 return;
242
243 if (rtnl_open(&rtnsh, 0) < 0) {
244 fprintf(stderr, "Cannot open rtnetlink\n");
245 exit(1);
246 }
247
248}
249
250void netns_map_init(void)
251{
252 static int initialized;
253 struct dirent *entry;
254 DIR *dir;
255 int nsid;
256
257 if (initialized || !ipnetns_have_nsid())
258 return;
259
260 dir = opendir(NETNS_RUN_DIR);
261 if (!dir)
262 return;
263
264 while ((entry = readdir(dir)) != NULL) {
265 if (strcmp(entry->d_name, ".") == 0)
266 continue;
267 if (strcmp(entry->d_name, "..") == 0)
268 continue;
269 nsid = get_netnsid_from_name(entry->d_name);
270
271 if (nsid >= 0)
272 netns_map_add(nsid, entry->d_name);
273 }
274 closedir(dir);
275 initialized = 1;
276}
277
278static int netns_get_name(int nsid, char *name)
279{
280 struct dirent *entry;
281 DIR *dir;
282 int id;
283
284 if (nsid < 0)
285 return -EINVAL;
286
287 dir = opendir(NETNS_RUN_DIR);
288 if (!dir)
289 return -ENOENT;
290
291 while ((entry = readdir(dir)) != NULL) {
292 if (strcmp(entry->d_name, ".") == 0)
293 continue;
294 if (strcmp(entry->d_name, "..") == 0)
295 continue;
296 id = get_netnsid_from_name(entry->d_name);
297
298 if (id >= 0 && nsid == id) {
299 strcpy(name, entry->d_name);
300 closedir(dir);
301 return 0;
302 }
303 }
304 closedir(dir);
305 return -ENOENT;
306}
307
308int print_nsid(struct nlmsghdr *n, void *arg)
309{
310 struct rtgenmsg *rthdr = NLMSG_DATA(n);
311 struct rtattr *tb[NETNSA_MAX+1];
312 int len = n->nlmsg_len;
313 FILE *fp = (FILE *)arg;
314 struct nsid_cache *c;
315 char name[NAME_MAX];
316 int nsid, current;
317
318 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
319 return 0;
320
321 len -= NLMSG_SPACE(sizeof(*rthdr));
322 if (len < 0) {
323 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
324 __func__);
325 return -1;
326 }
327
328 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
329 if (tb[NETNSA_NSID] == NULL) {
330 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
331 return -1;
332 }
333
334 open_json_object(NULL);
335 if (n->nlmsg_type == RTM_DELNSID)
336 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
337
338 nsid = rta_getattr_s32(tb[NETNSA_NSID]);
339 if (nsid < 0)
340 print_string(PRINT_FP, NULL, "nsid unassigned ", NULL);
341 else
342 print_int(PRINT_ANY, "nsid", "nsid %d ", nsid);
343
344 if (tb[NETNSA_CURRENT_NSID]) {
345 current = rta_getattr_s32(tb[NETNSA_CURRENT_NSID]);
346 if (current < 0)
347 print_string(PRINT_FP, NULL,
348 "current-nsid unassigned ", NULL);
349 else
350 print_int(PRINT_ANY, "current-nsid",
351 "current-nsid %d ", current);
352 }
353
354 c = netns_map_get_by_nsid(tb[NETNSA_CURRENT_NSID] ? current : nsid);
355 if (c != NULL) {
356 print_string(PRINT_ANY, "name",
357 "(iproute2 netns name: %s)", c->name);
358 netns_map_del(c);
359 }
360
361
362 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
363 if (netns_get_name(nsid, name) == 0) {
364 print_string(PRINT_ANY, "name",
365 "(iproute2 netns name: %s)", name);
366 netns_map_add(nsid, name);
367 }
368
369 print_string(PRINT_FP, NULL, "\n", NULL);
370 close_json_object();
371 fflush(fp);
372 return 0;
373}
374
375static int get_netnsid_from_netnsid(int nsid)
376{
377 struct {
378 struct nlmsghdr n;
379 struct rtgenmsg g;
380 char buf[1024];
381 } req = {
382 .n.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
383 .n.nlmsg_flags = NLM_F_REQUEST,
384 .n.nlmsg_type = RTM_GETNSID,
385 .g.rtgen_family = AF_UNSPEC,
386 };
387 struct nlmsghdr *answer;
388 int err;
389
390 netns_nsid_socket_init();
391
392 err = addattr32(&req.n, sizeof(req), NETNSA_NSID, nsid);
393 if (err)
394 return err;
395
396 if (filter.target_nsid >= 0) {
397 err = addattr32(&req.n, sizeof(req), NETNSA_TARGET_NSID,
398 filter.target_nsid);
399 if (err)
400 return err;
401 }
402
403 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0)
404 return -2;
405
406
407 if (answer->nlmsg_type == NLMSG_ERROR)
408 goto err_out;
409
410 new_json_obj(json);
411 err = print_nsid(answer, stdout);
412 delete_json_obj();
413err_out:
414 free(answer);
415 return err;
416}
417
418static int netns_filter_req(struct nlmsghdr *nlh, int reqlen)
419{
420 int err;
421
422 if (filter.target_nsid >= 0) {
423 err = addattr32(nlh, reqlen, NETNSA_TARGET_NSID,
424 filter.target_nsid);
425 if (err)
426 return err;
427 }
428
429 return 0;
430}
431
432static int netns_list_id(int argc, char **argv)
433{
434 int nsid = -1;
435
436 if (!ipnetns_have_nsid()) {
437 fprintf(stderr,
438 "RTM_GETNSID is not supported by the kernel.\n");
439 return -ENOTSUP;
440 }
441
442 filter.target_nsid = -1;
443 while (argc > 0) {
444 if (strcmp(*argv, "target-nsid") == 0) {
445 if (filter.target_nsid >= 0)
446 duparg("target-nsid", *argv);
447 NEXT_ARG();
448
449 if (get_integer(&filter.target_nsid, *argv, 0))
450 invarg("\"target-nsid\" value is invalid",
451 *argv);
452 else if (filter.target_nsid < 0)
453 invarg("\"target-nsid\" value should be >= 0",
454 argv[1]);
455 } else if (strcmp(*argv, "nsid") == 0) {
456 if (nsid >= 0)
457 duparg("nsid", *argv);
458 NEXT_ARG();
459
460 if (get_integer(&nsid, *argv, 0))
461 invarg("\"nsid\" value is invalid", *argv);
462 else if (nsid < 0)
463 invarg("\"nsid\" value should be >= 0",
464 argv[1]);
465 } else
466 usage();
467 argc--; argv++;
468 }
469
470 if (nsid >= 0)
471 return get_netnsid_from_netnsid(nsid);
472
473 if (rtnl_nsiddump_req_filter_fn(&rth, AF_UNSPEC,
474 netns_filter_req) < 0) {
475 perror("Cannot send dump request");
476 exit(1);
477 }
478
479 new_json_obj(json);
480 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
481 delete_json_obj();
482 fprintf(stderr, "Dump terminated\n");
483 exit(1);
484 }
485 delete_json_obj();
486 return 0;
487}
488
489static int netns_list(int argc, char **argv)
490{
491 struct dirent *entry;
492 DIR *dir;
493 int id;
494
495 dir = opendir(NETNS_RUN_DIR);
496 if (!dir)
497 return 0;
498
499 new_json_obj(json);
500 while ((entry = readdir(dir)) != NULL) {
501 if (strcmp(entry->d_name, ".") == 0)
502 continue;
503 if (strcmp(entry->d_name, "..") == 0)
504 continue;
505
506 open_json_object(NULL);
507 print_string(PRINT_ANY, "name",
508 "%s", entry->d_name);
509 if (ipnetns_have_nsid()) {
510 id = get_netnsid_from_name(entry->d_name);
511 if (id >= 0)
512 print_int(PRINT_ANY, "id", " (id: %d)", id);
513 }
514 print_string(PRINT_FP, NULL, "\n", NULL);
515 close_json_object();
516 }
517 closedir(dir);
518 delete_json_obj();
519 return 0;
520}
521
522static int do_switch(void *arg)
523{
524 char *netns = arg;
525
526
527
528
529 vrf_reset();
530
531 return netns_switch(netns);
532}
533
534static int on_netns_exec(char *nsname, void *arg)
535{
536 char **argv = arg;
537
538 printf("\nnetns: %s\n", nsname);
539 cmd_exec(argv[0], argv, true, do_switch, nsname);
540 return 0;
541}
542
543static int netns_exec(int argc, char **argv)
544{
545
546
547
548 if (argc < 1 && !do_all) {
549 fprintf(stderr, "No netns name specified\n");
550 return -1;
551 }
552 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
553 fprintf(stderr, "No command specified\n");
554 return -1;
555 }
556
557 if (do_all)
558 return netns_foreach(on_netns_exec, argv);
559
560
561
562
563
564 return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
565}
566
567static int is_pid(const char *str)
568{
569 int ch;
570
571 for (; (ch = *str); str++) {
572 if (!isdigit(ch))
573 return 0;
574 }
575 return 1;
576}
577
578static int netns_pids(int argc, char **argv)
579{
580 const char *name;
581 char net_path[PATH_MAX];
582 int netns = -1, ret = -1;
583 struct stat netst;
584 DIR *dir;
585 struct dirent *entry;
586
587 if (argc < 1) {
588 fprintf(stderr, "No netns name specified\n");
589 goto out;
590 }
591 if (argc > 1) {
592 fprintf(stderr, "extra arguments specified\n");
593 goto out;
594 }
595
596 name = argv[0];
597 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
598 netns = open(net_path, O_RDONLY);
599 if (netns < 0) {
600 fprintf(stderr, "Cannot open network namespace: %s\n",
601 strerror(errno));
602 goto out;
603 }
604 if (fstat(netns, &netst) < 0) {
605 fprintf(stderr, "Stat of netns failed: %s\n",
606 strerror(errno));
607 goto out;
608 }
609 dir = opendir("/proc/");
610 if (!dir) {
611 fprintf(stderr, "Open of /proc failed: %s\n",
612 strerror(errno));
613 goto out;
614 }
615 while ((entry = readdir(dir))) {
616 char pid_net_path[PATH_MAX];
617 struct stat st;
618
619 if (!is_pid(entry->d_name))
620 continue;
621 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
622 entry->d_name);
623 if (stat(pid_net_path, &st) != 0)
624 continue;
625 if ((st.st_dev == netst.st_dev) &&
626 (st.st_ino == netst.st_ino)) {
627 printf("%s\n", entry->d_name);
628 }
629 }
630 ret = 0;
631 closedir(dir);
632out:
633 if (netns >= 0)
634 close(netns);
635 return ret;
636
637}
638
639int netns_identify_pid(const char *pidstr, char *name, int len)
640{
641 char net_path[PATH_MAX];
642 int netns = -1, ret = -1;
643 struct stat netst;
644 DIR *dir;
645 struct dirent *entry;
646
647 name[0] = '\0';
648
649 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
650 netns = open(net_path, O_RDONLY);
651 if (netns < 0) {
652 fprintf(stderr, "Cannot open network namespace: %s\n",
653 strerror(errno));
654 goto out;
655 }
656 if (fstat(netns, &netst) < 0) {
657 fprintf(stderr, "Stat of netns failed: %s\n",
658 strerror(errno));
659 goto out;
660 }
661 dir = opendir(NETNS_RUN_DIR);
662 if (!dir) {
663
664 if (errno == ENOENT) {
665 ret = 0;
666 goto out;
667 }
668
669 fprintf(stderr, "Failed to open directory %s:%s\n",
670 NETNS_RUN_DIR, strerror(errno));
671 goto out;
672 }
673
674 while ((entry = readdir(dir))) {
675 char name_path[PATH_MAX];
676 struct stat st;
677
678 if (strcmp(entry->d_name, ".") == 0)
679 continue;
680 if (strcmp(entry->d_name, "..") == 0)
681 continue;
682
683 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
684 entry->d_name);
685
686 if (stat(name_path, &st) != 0)
687 continue;
688
689 if ((st.st_dev == netst.st_dev) &&
690 (st.st_ino == netst.st_ino)) {
691 strlcpy(name, entry->d_name, len);
692 }
693 }
694 ret = 0;
695 closedir(dir);
696out:
697 if (netns >= 0)
698 close(netns);
699 return ret;
700
701}
702
703static int netns_identify(int argc, char **argv)
704{
705 const char *pidstr;
706 char name[256];
707 int rc;
708
709 if (argc < 1) {
710 pidstr = "self";
711 } else if (argc > 1) {
712 fprintf(stderr, "extra arguments specified\n");
713 return -1;
714 } else {
715 pidstr = argv[0];
716 if (!is_pid(pidstr)) {
717 fprintf(stderr, "Specified string '%s' is not a pid\n",
718 pidstr);
719 return -1;
720 }
721 }
722
723 rc = netns_identify_pid(pidstr, name, sizeof(name));
724 if (!rc)
725 printf("%s\n", name);
726
727 return rc;
728}
729
730static int on_netns_del(char *nsname, void *arg)
731{
732 char netns_path[PATH_MAX];
733
734 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
735 umount2(netns_path, MNT_DETACH);
736 if (unlink(netns_path) < 0) {
737 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
738 netns_path, strerror(errno));
739 return -1;
740 }
741 return 0;
742}
743
744static int netns_delete(int argc, char **argv)
745{
746 if (argc < 1 && !do_all) {
747 fprintf(stderr, "No netns name specified\n");
748 return -1;
749 }
750
751 if (do_all)
752 return netns_foreach(on_netns_del, NULL);
753
754 return on_netns_del(argv[0], NULL);
755}
756
757static int create_netns_dir(void)
758{
759
760 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
761 if (errno != EEXIST) {
762 fprintf(stderr, "mkdir %s failed: %s\n",
763 NETNS_RUN_DIR, strerror(errno));
764 return -1;
765 }
766 }
767
768 return 0;
769}
770
771
772static void netns_save(void)
773{
774 if (saved_netns != -1)
775 return;
776
777 saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
778 if (saved_netns == -1) {
779 perror("Cannot open init namespace");
780 exit(1);
781 }
782}
783
784static void netns_restore(void)
785{
786 if (saved_netns == -1)
787 return;
788
789 if (setns(saved_netns, CLONE_NEWNET)) {
790 perror("setns");
791 exit(1);
792 }
793
794 close(saved_netns);
795 saved_netns = -1;
796}
797
798static int netns_add(int argc, char **argv, bool create)
799{
800
801
802
803
804
805
806
807
808
809
810
811 char netns_path[PATH_MAX], proc_path[PATH_MAX];
812 const char *name;
813 pid_t pid;
814 int fd;
815 int lock;
816 int made_netns_run_dir_mount = 0;
817
818 if (create) {
819 if (argc < 1) {
820 fprintf(stderr, "No netns name specified\n");
821 return -1;
822 }
823 } else {
824 if (argc < 2) {
825 fprintf(stderr, "No netns name and PID specified\n");
826 return -1;
827 }
828
829 if (get_s32(&pid, argv[1], 0) || !pid) {
830 fprintf(stderr, "Invalid PID: %s\n", argv[1]);
831 return -1;
832 }
833 }
834 name = argv[0];
835
836 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
837
838 if (create_netns_dir())
839 return -1;
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 lock = open(NETNS_RUN_DIR, O_RDONLY|O_DIRECTORY, 0);
857 if (lock < 0) {
858 fprintf(stderr, "Cannot open netns runtime directory \"%s\": %s\n",
859 NETNS_RUN_DIR, strerror(errno));
860 return -1;
861 }
862 if (flock(lock, LOCK_EX) < 0) {
863 fprintf(stderr, "Warning: could not flock netns runtime directory \"%s\": %s\n",
864 NETNS_RUN_DIR, strerror(errno));
865 close(lock);
866 lock = -1;
867 }
868 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
869
870 if (errno != EINVAL || made_netns_run_dir_mount) {
871 fprintf(stderr, "mount --make-shared %s failed: %s\n",
872 NETNS_RUN_DIR, strerror(errno));
873 if (lock != -1) {
874 flock(lock, LOCK_UN);
875 close(lock);
876 }
877 return -1;
878 }
879
880
881 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
882 fprintf(stderr, "mount --bind %s %s failed: %s\n",
883 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
884 if (lock != -1) {
885 flock(lock, LOCK_UN);
886 close(lock);
887 }
888 return -1;
889 }
890 made_netns_run_dir_mount = 1;
891 }
892 if (lock != -1) {
893 flock(lock, LOCK_UN);
894 close(lock);
895 }
896
897
898 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
899 if (fd < 0) {
900 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
901 netns_path, strerror(errno));
902 return -1;
903 }
904 close(fd);
905
906 if (create) {
907 netns_save();
908 if (unshare(CLONE_NEWNET) < 0) {
909 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
910 name, strerror(errno));
911 goto out_delete;
912 }
913
914 strcpy(proc_path, "/proc/self/ns/net");
915 } else {
916 snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
917 }
918
919
920 if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
921 fprintf(stderr, "Bind %s -> %s failed: %s\n",
922 proc_path, netns_path, strerror(errno));
923 goto out_delete;
924 }
925 netns_restore();
926
927 return 0;
928out_delete:
929 if (create) {
930 netns_restore();
931 netns_delete(argc, argv);
932 } else if (unlink(netns_path) < 0) {
933 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
934 netns_path, strerror(errno));
935 }
936 return -1;
937}
938
939int set_netnsid_from_name(const char *name, int nsid)
940{
941 struct {
942 struct nlmsghdr n;
943 struct rtgenmsg g;
944 char buf[1024];
945 } req = {
946 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
947 .n.nlmsg_flags = NLM_F_REQUEST,
948 .n.nlmsg_type = RTM_NEWNSID,
949 .g.rtgen_family = AF_UNSPEC,
950 };
951 int fd, err = 0;
952
953 netns_nsid_socket_init();
954
955 fd = netns_get_fd(name);
956 if (fd < 0)
957 return fd;
958
959 addattr32(&req.n, 1024, NETNSA_FD, fd);
960 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
961 if (rtnl_talk(&rth, &req.n, NULL) < 0)
962 err = -2;
963
964 close(fd);
965 return err;
966}
967
968static int netns_set(int argc, char **argv)
969{
970 char netns_path[PATH_MAX];
971 const char *name;
972 int netns, nsid;
973
974 if (argc < 1) {
975 fprintf(stderr, "No netns name specified\n");
976 return -1;
977 }
978 if (argc < 2) {
979 fprintf(stderr, "No nsid specified\n");
980 return -1;
981 }
982 name = argv[0];
983
984 if (strcmp(argv[1], "auto") == 0)
985 nsid = -1;
986 else if (get_integer(&nsid, argv[1], 0))
987 invarg("Invalid \"netnsid\" value", argv[1]);
988 else if (nsid < 0)
989 invarg("\"netnsid\" value should be >= 0", argv[1]);
990
991 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
992 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
993 if (netns < 0) {
994 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
995 name, strerror(errno));
996 return -1;
997 }
998
999 return set_netnsid_from_name(name, nsid);
1000}
1001
1002static int netns_monitor(int argc, char **argv)
1003{
1004 char buf[4096];
1005 struct inotify_event *event;
1006 int fd;
1007
1008 fd = inotify_init();
1009 if (fd < 0) {
1010 fprintf(stderr, "inotify_init failed: %s\n",
1011 strerror(errno));
1012 return -1;
1013 }
1014
1015 if (create_netns_dir())
1016 return -1;
1017
1018 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
1019 fprintf(stderr, "inotify_add_watch failed: %s\n",
1020 strerror(errno));
1021 return -1;
1022 }
1023 for (;;) {
1024 ssize_t len = read(fd, buf, sizeof(buf));
1025
1026 if (len < 0) {
1027 fprintf(stderr, "read failed: %s\n",
1028 strerror(errno));
1029 return -1;
1030 }
1031 for (event = (struct inotify_event *)buf;
1032 (char *)event < &buf[len];
1033 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
1034 if (event->mask & IN_CREATE)
1035 printf("add %s\n", event->name);
1036 if (event->mask & IN_DELETE)
1037 printf("delete %s\n", event->name);
1038 }
1039 }
1040 return 0;
1041}
1042
1043static int invalid_name(const char *name)
1044{
1045 return !*name || strlen(name) > NAME_MAX ||
1046 strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
1047}
1048
1049int do_netns(int argc, char **argv)
1050{
1051 netns_nsid_socket_init();
1052
1053 if (argc < 1) {
1054 netns_map_init();
1055 return netns_list(0, NULL);
1056 }
1057
1058 if (!do_all && argc > 1 && invalid_name(argv[1])) {
1059 fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
1060 exit(-1);
1061 }
1062
1063 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
1064 (matches(*argv, "lst") == 0)) {
1065 netns_map_init();
1066 return netns_list(argc-1, argv+1);
1067 }
1068
1069 if ((matches(*argv, "list-id") == 0)) {
1070 netns_map_init();
1071 return netns_list_id(argc-1, argv+1);
1072 }
1073
1074 if (matches(*argv, "help") == 0)
1075 return usage();
1076
1077 if (matches(*argv, "add") == 0)
1078 return netns_add(argc-1, argv+1, true);
1079
1080 if (matches(*argv, "set") == 0)
1081 return netns_set(argc-1, argv+1);
1082
1083 if (matches(*argv, "delete") == 0)
1084 return netns_delete(argc-1, argv+1);
1085
1086 if (matches(*argv, "identify") == 0)
1087 return netns_identify(argc-1, argv+1);
1088
1089 if (matches(*argv, "pids") == 0)
1090 return netns_pids(argc-1, argv+1);
1091
1092 if (matches(*argv, "exec") == 0)
1093 return netns_exec(argc-1, argv+1);
1094
1095 if (matches(*argv, "monitor") == 0)
1096 return netns_monitor(argc-1, argv+1);
1097
1098 if (matches(*argv, "attach") == 0)
1099 return netns_add(argc-1, argv+1, false);
1100
1101 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
1102 exit(-1);
1103}
1104