]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipnetns.c
devlink: Add man page for devlink-trap
[mirror_iproute2.git] / ip / ipnetns.c
CommitLineData
6054c1eb 1/* SPDX-License-Identifier: GPL-2.0 */
0dc34c77
EB
2#define _ATFILE_SOURCE
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <sys/wait.h>
6#include <sys/inotify.h>
7#include <sys/mount.h>
0dc34c77
EB
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>
9a7b3d91 16#include <ctype.h>
d652ccbf 17#include <linux/limits.h>
0dc34c77 18
d182ee13
ND
19#include <linux/net_namespace.h>
20
0dc34c77 21#include "utils.h"
4952b459 22#include "list.h"
0dc34c77 23#include "ip_common.h"
eb67e449 24#include "namespace.h"
e93d9221 25#include "json_print.h"
0dc34c77 26
8e2d47dc 27static int usage(void)
0dc34c77 28{
8589eb4e
MC
29 fprintf(stderr,
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"
38 " ip netns monitor\n"
39 " ip netns list-id\n"
40 "NETNSID := auto | POSITIVE-INT\n");
a05f6511 41 exit(-1);
0dc34c77
EB
42}
43
d652ccbf
ND
44/* This socket is used to get nsid */
45static struct rtnl_handle rtnsh = { .fd = -1 };
46
4c7d9a58 47static int have_rtnl_getnsid = -1;
b2e29223 48static int saved_netns = -1;
4c7d9a58 49
cd554f2c 50static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
4c7d9a58
ND
51 struct nlmsghdr *n, void *arg)
52{
53 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
54
55 if (n->nlmsg_type == NLMSG_ERROR &&
56 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
57 have_rtnl_getnsid = 0;
58 else
59 have_rtnl_getnsid = 1;
60 return -1;
61}
62
63static int ipnetns_have_nsid(void)
64{
65 struct {
66 struct nlmsghdr n;
67 struct rtgenmsg g;
68 char buf[1024];
d17b136f
PS
69 } req = {
70 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
71 .n.nlmsg_flags = NLM_F_REQUEST,
72 .n.nlmsg_type = RTM_GETNSID,
73 .g.rtgen_family = AF_UNSPEC,
74 };
4c7d9a58
ND
75 int fd;
76
77 if (have_rtnl_getnsid < 0) {
4c7d9a58
ND
78 fd = open("/proc/self/ns/net", O_RDONLY);
79 if (fd < 0) {
c44003f7
LZ
80 have_rtnl_getnsid = 0;
81 return 0;
4c7d9a58
ND
82 }
83
84 addattr32(&req.n, 1024, NETNSA_FD, fd);
85
86 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
87 perror("request send failed");
88 exit(1);
89 }
90 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
91 close(fd);
92 }
93
94 return have_rtnl_getnsid;
95}
96
974ef93b 97int get_netnsid_from_name(const char *name)
d182ee13
ND
98{
99 struct {
100 struct nlmsghdr n;
101 struct rtgenmsg g;
102 char buf[1024];
86bf43c7 103 } req = {
d17b136f
PS
104 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
105 .n.nlmsg_flags = NLM_F_REQUEST,
106 .n.nlmsg_type = RTM_GETNSID,
107 .g.rtgen_family = AF_UNSPEC,
108 };
86bf43c7 109 struct nlmsghdr *answer;
d182ee13
ND
110 struct rtattr *tb[NETNSA_MAX + 1];
111 struct rtgenmsg *rthdr;
9bf2c538 112 int len, fd, ret = -1;
d182ee13 113
974ef93b
ND
114 netns_nsid_socket_init();
115
d182ee13
ND
116 fd = netns_get_fd(name);
117 if (fd < 0)
118 return fd;
119
120 addattr32(&req.n, 1024, NETNSA_FD, fd);
86bf43c7 121 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
d182ee13
ND
122 close(fd);
123 return -2;
124 }
125 close(fd);
126
127 /* Validate message and parse attributes */
86bf43c7 128 if (answer->nlmsg_type == NLMSG_ERROR)
9bf2c538 129 goto out;
d182ee13 130
86bf43c7
HL
131 rthdr = NLMSG_DATA(answer);
132 len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
d182ee13 133 if (len < 0)
9bf2c538 134 goto out;
d182ee13
ND
135
136 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
137
86bf43c7 138 if (tb[NETNSA_NSID]) {
9bf2c538 139 ret = rta_getattr_u32(tb[NETNSA_NSID]);
86bf43c7 140 }
d182ee13 141
9bf2c538 142out:
86bf43c7 143 free(answer);
9bf2c538 144 return ret;
d182ee13
ND
145}
146
d652ccbf
ND
147struct nsid_cache {
148 struct hlist_node nsid_hash;
149 struct hlist_node name_hash;
150 int nsid;
2f29d6bb 151 char name[0];
d652ccbf
ND
152};
153
154#define NSIDMAP_SIZE 128
155#define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
156#define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
157
158static struct hlist_head nsid_head[NSIDMAP_SIZE];
159static struct hlist_head name_head[NSIDMAP_SIZE];
160
161static struct nsid_cache *netns_map_get_by_nsid(int nsid)
162{
163 uint32_t h = NSID_HASH_NSID(nsid);
164 struct hlist_node *n;
165
166 hlist_for_each(n, &nsid_head[h]) {
167 struct nsid_cache *c = container_of(n, struct nsid_cache,
168 nsid_hash);
169 if (c->nsid == nsid)
170 return c;
171 }
172
173 return NULL;
174}
175
9580bad7
ND
176char *get_name_from_nsid(int nsid)
177{
178 struct nsid_cache *c;
179
180 netns_nsid_socket_init();
181 netns_map_init();
182
183 c = netns_map_get_by_nsid(nsid);
184 if (c)
185 return c->name;
186
187 return NULL;
188}
189
2f29d6bb 190static int netns_map_add(int nsid, const char *name)
d652ccbf
ND
191{
192 struct nsid_cache *c;
193 uint32_t h;
194
195 if (netns_map_get_by_nsid(nsid) != NULL)
196 return -EEXIST;
197
a1b4a274 198 c = malloc(sizeof(*c) + strlen(name) + 1);
d652ccbf
ND
199 if (c == NULL) {
200 perror("malloc");
201 return -ENOMEM;
202 }
203 c->nsid = nsid;
204 strcpy(c->name, name);
205
206 h = NSID_HASH_NSID(nsid);
207 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
208
209 h = NSID_HASH_NAME(name);
210 hlist_add_head(&c->name_hash, &name_head[h]);
211
212 return 0;
213}
214
215static void netns_map_del(struct nsid_cache *c)
216{
217 hlist_del(&c->name_hash);
218 hlist_del(&c->nsid_hash);
219 free(c);
220}
221
e29a8e05
AA
222void netns_nsid_socket_init(void)
223{
224 if (rtnsh.fd > -1 || !ipnetns_have_nsid())
225 return;
226
227 if (rtnl_open(&rtnsh, 0) < 0) {
228 fprintf(stderr, "Cannot open rtnetlink\n");
229 exit(1);
230 }
231
232}
233
d652ccbf
ND
234void netns_map_init(void)
235{
236 static int initialized;
237 struct dirent *entry;
238 DIR *dir;
239 int nsid;
240
241 if (initialized || !ipnetns_have_nsid())
242 return;
243
d652ccbf
ND
244 dir = opendir(NETNS_RUN_DIR);
245 if (!dir)
246 return;
247
248 while ((entry = readdir(dir)) != NULL) {
249 if (strcmp(entry->d_name, ".") == 0)
250 continue;
251 if (strcmp(entry->d_name, "..") == 0)
252 continue;
253 nsid = get_netnsid_from_name(entry->d_name);
254
255 if (nsid >= 0)
256 netns_map_add(nsid, entry->d_name);
257 }
258 closedir(dir);
259 initialized = 1;
260}
261
262static int netns_get_name(int nsid, char *name)
263{
264 struct dirent *entry;
265 DIR *dir;
266 int id;
267
268 dir = opendir(NETNS_RUN_DIR);
269 if (!dir)
270 return -ENOENT;
271
272 while ((entry = readdir(dir)) != NULL) {
273 if (strcmp(entry->d_name, ".") == 0)
274 continue;
275 if (strcmp(entry->d_name, "..") == 0)
276 continue;
277 id = get_netnsid_from_name(entry->d_name);
278
279 if (nsid == id) {
280 strcpy(name, entry->d_name);
281 closedir(dir);
282 return 0;
283 }
284 }
285 closedir(dir);
286 return -ENOENT;
287}
288
cd554f2c 289int print_nsid(struct nlmsghdr *n, void *arg)
d652ccbf
ND
290{
291 struct rtgenmsg *rthdr = NLMSG_DATA(n);
292 struct rtattr *tb[NETNSA_MAX+1];
293 int len = n->nlmsg_len;
294 FILE *fp = (FILE *)arg;
295 struct nsid_cache *c;
296 char name[NAME_MAX];
297 int nsid;
298
299 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
300 return 0;
301
302 len -= NLMSG_SPACE(sizeof(*rthdr));
303 if (len < 0) {
304 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
305 __func__);
306 return -1;
307 }
308
309 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
310 if (tb[NETNSA_NSID] == NULL) {
311 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
312 return -1;
313 }
314
e93d9221 315 open_json_object(NULL);
d652ccbf 316 if (n->nlmsg_type == RTM_DELNSID)
e93d9221 317 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
d652ccbf
ND
318
319 nsid = rta_getattr_u32(tb[NETNSA_NSID]);
e93d9221 320 print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid);
d652ccbf
ND
321
322 c = netns_map_get_by_nsid(nsid);
323 if (c != NULL) {
e93d9221
SH
324 print_string(PRINT_ANY, "name",
325 "(iproute2 netns name: %s)", c->name);
d652ccbf
ND
326 netns_map_del(c);
327 }
328
329 /* During 'ip monitor nsid', no chance to have new nsid in cache. */
330 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
331 if (netns_get_name(nsid, name) == 0) {
e93d9221
SH
332 print_string(PRINT_ANY, "name",
333 "(iproute2 netns name: %s)", name);
d652ccbf
ND
334 netns_map_add(nsid, name);
335 }
336
e93d9221
SH
337 print_string(PRINT_FP, NULL, "\n", NULL);
338 close_json_object();
d652ccbf
ND
339 fflush(fp);
340 return 0;
341}
342
343static int netns_list_id(int argc, char **argv)
344{
345 if (!ipnetns_have_nsid()) {
346 fprintf(stderr,
347 "RTM_GETNSID is not supported by the kernel.\n");
348 return -ENOTSUP;
349 }
350
efb0b383 351 if (rtnl_nsiddump_req(&rth, AF_UNSPEC) < 0) {
d652ccbf
ND
352 perror("Cannot send dump request");
353 exit(1);
354 }
e93d9221
SH
355
356 new_json_obj(json);
d652ccbf 357 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
e93d9221 358 delete_json_obj();
d652ccbf
ND
359 fprintf(stderr, "Dump terminated\n");
360 exit(1);
361 }
e93d9221 362 delete_json_obj();
d652ccbf
ND
363 return 0;
364}
365
0dc34c77
EB
366static int netns_list(int argc, char **argv)
367{
368 struct dirent *entry;
369 DIR *dir;
d182ee13 370 int id;
0dc34c77
EB
371
372 dir = opendir(NETNS_RUN_DIR);
373 if (!dir)
a05f6511 374 return 0;
0dc34c77 375
e93d9221 376 new_json_obj(json);
0dc34c77
EB
377 while ((entry = readdir(dir)) != NULL) {
378 if (strcmp(entry->d_name, ".") == 0)
379 continue;
380 if (strcmp(entry->d_name, "..") == 0)
381 continue;
e93d9221
SH
382
383 open_json_object(NULL);
384 print_string(PRINT_ANY, "name",
385 "%s", entry->d_name);
4c7d9a58
ND
386 if (ipnetns_have_nsid()) {
387 id = get_netnsid_from_name(entry->d_name);
388 if (id >= 0)
e93d9221
SH
389 print_uint(PRINT_ANY, "id",
390 " (id: %d)", id);
4c7d9a58 391 }
e93d9221
SH
392 print_string(PRINT_FP, NULL, "\n", NULL);
393 close_json_object();
0dc34c77
EB
394 }
395 closedir(dir);
e93d9221 396 delete_json_obj();
a05f6511 397 return 0;
0dc34c77
EB
398}
399
903818fb
MC
400static int do_switch(void *arg)
401{
402 char *netns = arg;
403
404 /* we just changed namespaces. clear any vrf association
405 * with prior namespace before exec'ing command
406 */
407 vrf_reset();
408
409 return netns_switch(netns);
410}
411
b13ba03f
VK
412static int on_netns_exec(char *nsname, void *arg)
413{
414 char **argv = arg;
56f5daac 415
903818fb
MC
416 printf("\nnetns: %s\n", nsname);
417 cmd_exec(argv[0], argv, true, do_switch, nsname);
b13ba03f
VK
418 return 0;
419}
420
421static int netns_exec(int argc, char **argv)
422{
423 /* Setup the proper environment for apps that are not netns
424 * aware, and execute a program in that environment.
425 */
b13ba03f
VK
426 if (argc < 1 && !do_all) {
427 fprintf(stderr, "No netns name specified\n");
428 return -1;
429 }
430 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
431 fprintf(stderr, "No command specified\n");
432 return -1;
433 }
434
435 if (do_all)
903818fb 436 return netns_foreach(on_netns_exec, argv);
ee9369a0 437
b13ba03f
VK
438 /* ip must return the status of the child,
439 * but do_cmd() will add a minus to this,
440 * so let's add another one here to cancel it.
441 */
903818fb 442 return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
b13ba03f
VK
443}
444
9a7b3d91
EB
445static int is_pid(const char *str)
446{
447 int ch;
56f5daac 448
9a7b3d91
EB
449 for (; (ch = *str); str++) {
450 if (!isdigit(ch))
451 return 0;
452 }
453 return 1;
454}
455
456static int netns_pids(int argc, char **argv)
457{
458 const char *name;
ea343669 459 char net_path[PATH_MAX];
9a7b3d91
EB
460 int netns;
461 struct stat netst;
462 DIR *dir;
463 struct dirent *entry;
464
465 if (argc < 1) {
466 fprintf(stderr, "No netns name specified\n");
a05f6511 467 return -1;
9a7b3d91
EB
468 }
469 if (argc > 1) {
470 fprintf(stderr, "extra arguments specified\n");
a05f6511 471 return -1;
9a7b3d91
EB
472 }
473
474 name = argv[0];
475 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
476 netns = open(net_path, O_RDONLY);
477 if (netns < 0) {
478 fprintf(stderr, "Cannot open network namespace: %s\n",
479 strerror(errno));
a05f6511 480 return -1;
9a7b3d91
EB
481 }
482 if (fstat(netns, &netst) < 0) {
483 fprintf(stderr, "Stat of netns failed: %s\n",
484 strerror(errno));
a05f6511 485 return -1;
9a7b3d91
EB
486 }
487 dir = opendir("/proc/");
488 if (!dir) {
489 fprintf(stderr, "Open of /proc failed: %s\n",
490 strerror(errno));
a05f6511 491 return -1;
9a7b3d91 492 }
56f5daac 493 while ((entry = readdir(dir))) {
ea343669 494 char pid_net_path[PATH_MAX];
9a7b3d91 495 struct stat st;
56f5daac 496
9a7b3d91
EB
497 if (!is_pid(entry->d_name))
498 continue;
499 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
500 entry->d_name);
501 if (stat(pid_net_path, &st) != 0)
502 continue;
503 if ((st.st_dev == netst.st_dev) &&
504 (st.st_ino == netst.st_ino)) {
505 printf("%s\n", entry->d_name);
506 }
507 }
508 closedir(dir);
a05f6511 509 return 0;
0612519e 510
9a7b3d91
EB
511}
512
9c49438a 513int netns_identify_pid(const char *pidstr, char *name, int len)
9a7b3d91 514{
ea343669 515 char net_path[PATH_MAX];
9a7b3d91
EB
516 int netns;
517 struct stat netst;
518 DIR *dir;
519 struct dirent *entry;
520
9c49438a 521 name[0] = '\0';
9a7b3d91
EB
522
523 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
524 netns = open(net_path, O_RDONLY);
525 if (netns < 0) {
526 fprintf(stderr, "Cannot open network namespace: %s\n",
527 strerror(errno));
a05f6511 528 return -1;
9a7b3d91
EB
529 }
530 if (fstat(netns, &netst) < 0) {
531 fprintf(stderr, "Stat of netns failed: %s\n",
532 strerror(errno));
a05f6511 533 return -1;
9a7b3d91
EB
534 }
535 dir = opendir(NETNS_RUN_DIR);
536 if (!dir) {
537 /* Succeed treat a missing directory as an empty directory */
538 if (errno == ENOENT)
a05f6511 539 return 0;
9a7b3d91
EB
540
541 fprintf(stderr, "Failed to open directory %s:%s\n",
542 NETNS_RUN_DIR, strerror(errno));
a05f6511 543 return -1;
9a7b3d91
EB
544 }
545
56f5daac 546 while ((entry = readdir(dir))) {
ea343669 547 char name_path[PATH_MAX];
9a7b3d91
EB
548 struct stat st;
549
550 if (strcmp(entry->d_name, ".") == 0)
551 continue;
552 if (strcmp(entry->d_name, "..") == 0)
553 continue;
554
555 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
556 entry->d_name);
557
558 if (stat(name_path, &st) != 0)
559 continue;
560
561 if ((st.st_dev == netst.st_dev) &&
562 (st.st_ino == netst.st_ino)) {
18f156bf 563 strlcpy(name, entry->d_name, len);
9a7b3d91
EB
564 }
565 }
566 closedir(dir);
a05f6511 567 return 0;
0612519e 568
9a7b3d91
EB
569}
570
9c49438a
DA
571static int netns_identify(int argc, char **argv)
572{
573 const char *pidstr;
574 char name[256];
575 int rc;
576
577 if (argc < 1) {
578 pidstr = "self";
579 } else if (argc > 1) {
580 fprintf(stderr, "extra arguments specified\n");
581 return -1;
582 } else {
583 pidstr = argv[0];
584 if (!is_pid(pidstr)) {
585 fprintf(stderr, "Specified string '%s' is not a pid\n",
586 pidstr);
587 return -1;
588 }
589 }
590
591 rc = netns_identify_pid(pidstr, name, sizeof(name));
592 if (!rc)
593 printf("%s\n", name);
594
595 return rc;
596}
597
33724939 598static int on_netns_del(char *nsname, void *arg)
0dc34c77 599{
ea343669 600 char netns_path[PATH_MAX];
0dc34c77 601
33724939 602 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
0dc34c77
EB
603 umount2(netns_path, MNT_DETACH);
604 if (unlink(netns_path) < 0) {
14645ec2 605 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
0dc34c77 606 netns_path, strerror(errno));
a05f6511 607 return -1;
0dc34c77 608 }
a05f6511 609 return 0;
0dc34c77
EB
610}
611
33724939
VK
612static int netns_delete(int argc, char **argv)
613{
614 if (argc < 1 && !do_all) {
615 fprintf(stderr, "No netns name specified\n");
616 return -1;
617 }
618
619 if (do_all)
620 return netns_foreach(on_netns_del, NULL);
621
622 return on_netns_del(argv[0], NULL);
623}
624
c1cbb18a 625static int create_netns_dir(void)
626{
627 /* Create the base netns directory if it doesn't exist */
628 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
629 if (errno != EEXIST) {
630 fprintf(stderr, "mkdir %s failed: %s\n",
631 NETNS_RUN_DIR, strerror(errno));
632 return -1;
633 }
634 }
635
636 return 0;
637}
638
b2e29223
MC
639/* Obtain a FD for the current namespace, so we can reenter it later */
640static void netns_save(void)
641{
642 if (saved_netns != -1)
643 return;
644
645 saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
646 if (saved_netns == -1) {
647 perror("Cannot open init namespace");
648 exit(1);
649 }
650}
651
652static void netns_restore(void)
653{
654 if (saved_netns == -1)
655 return;
656
657 if (setns(saved_netns, CLONE_NEWNET)) {
658 perror("setns");
659 exit(1);
660 }
661
662 close(saved_netns);
663 saved_netns = -1;
664}
665
e3dbcb2a 666static int netns_add(int argc, char **argv, bool create)
0dc34c77
EB
667{
668 /* This function creates a new network namespace and
669 * a new mount namespace and bind them into a well known
670 * location in the filesystem based on the name provided.
671 *
e3dbcb2a
MC
672 * If create is true, a new namespace will be created,
673 * otherwise an existing one will be attached to the file.
674 *
0dc34c77
EB
675 * The mount namespace is created so that any necessary
676 * userspace tweaks like remounting /sys, or bind mounting
e3dbcb2a 677 * a new /etc/resolv.conf can be shared between users.
0dc34c77 678 */
e3dbcb2a 679 char netns_path[PATH_MAX], proc_path[PATH_MAX];
0dc34c77 680 const char *name;
e3dbcb2a 681 pid_t pid;
223f4d8e 682 int fd;
58a3e827 683 int made_netns_run_dir_mount = 0;
0dc34c77 684
e3dbcb2a
MC
685 if (create) {
686 if (argc < 1) {
687 fprintf(stderr, "No netns name specified\n");
688 return -1;
689 }
690 } else {
691 if (argc < 2) {
692 fprintf(stderr, "No netns name and PID specified\n");
693 return -1;
694 }
695
696 if (get_s32(&pid, argv[1], 0) || !pid) {
697 fprintf(stderr, "Invalid PID: %s\n", argv[1]);
698 return -1;
699 }
0dc34c77
EB
700 }
701 name = argv[0];
702
703 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
704
c1cbb18a 705 if (create_netns_dir())
706 return -1;
0dc34c77 707
d259f030 708 /* Make it possible for network namespace mounts to propagate between
58a3e827
EB
709 * mount namespaces. This makes it likely that a unmounting a network
710 * namespace file in one namespace will unmount the network namespace
711 * file in all namespaces allowing the network namespace to be freed
712 * sooner.
713 */
714 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
715 /* Fail unless we need to make the mount point */
716 if (errno != EINVAL || made_netns_run_dir_mount) {
717 fprintf(stderr, "mount --make-shared %s failed: %s\n",
718 NETNS_RUN_DIR, strerror(errno));
a05f6511 719 return -1;
58a3e827
EB
720 }
721
722 /* Upgrade NETNS_RUN_DIR to a mount point */
d6a4076b 723 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
58a3e827
EB
724 fprintf(stderr, "mount --bind %s %s failed: %s\n",
725 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
a05f6511 726 return -1;
58a3e827
EB
727 }
728 made_netns_run_dir_mount = 1;
729 }
730
0dc34c77 731 /* Create the filesystem state */
223f4d8e
EB
732 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
733 if (fd < 0) {
55713c8c 734 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
0dc34c77 735 netns_path, strerror(errno));
a05f6511 736 return -1;
0dc34c77 737 }
223f4d8e 738 close(fd);
e3dbcb2a
MC
739
740 if (create) {
80a931d4 741 netns_save();
e3dbcb2a
MC
742 if (unshare(CLONE_NEWNET) < 0) {
743 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
744 name, strerror(errno));
745 goto out_delete;
746 }
747
748 strcpy(proc_path, "/proc/self/ns/net");
749 } else {
750 snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
0dc34c77
EB
751 }
752
753 /* Bind the netns last so I can watch for it */
e3dbcb2a
MC
754 if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
755 fprintf(stderr, "Bind %s -> %s failed: %s\n",
756 proc_path, netns_path, strerror(errno));
0dc34c77
EB
757 goto out_delete;
758 }
b2e29223
MC
759 netns_restore();
760
a05f6511 761 return 0;
0dc34c77 762out_delete:
e3dbcb2a 763 if (create) {
b2e29223 764 netns_restore();
e3dbcb2a
MC
765 netns_delete(argc, argv);
766 } else if (unlink(netns_path) < 0) {
767 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
768 netns_path, strerror(errno));
769 }
a05f6511 770 return -1;
0dc34c77
EB
771}
772
974ef93b 773int set_netnsid_from_name(const char *name, int nsid)
d182ee13
ND
774{
775 struct {
776 struct nlmsghdr n;
777 struct rtgenmsg g;
778 char buf[1024];
d17b136f
PS
779 } req = {
780 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
781 .n.nlmsg_flags = NLM_F_REQUEST,
782 .n.nlmsg_type = RTM_NEWNSID,
783 .g.rtgen_family = AF_UNSPEC,
784 };
d182ee13
ND
785 int fd, err = 0;
786
974ef93b
ND
787 netns_nsid_socket_init();
788
d182ee13
ND
789 fd = netns_get_fd(name);
790 if (fd < 0)
791 return fd;
792
793 addattr32(&req.n, 1024, NETNSA_FD, fd);
794 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
86bf43c7 795 if (rtnl_talk(&rth, &req.n, NULL) < 0)
d182ee13
ND
796 err = -2;
797
798 close(fd);
799 return err;
800}
801
802static int netns_set(int argc, char **argv)
803{
ea343669 804 char netns_path[PATH_MAX];
d182ee13 805 const char *name;
ebe3ce2f 806 int netns, nsid;
d182ee13
ND
807
808 if (argc < 1) {
809 fprintf(stderr, "No netns name specified\n");
810 return -1;
811 }
812 if (argc < 2) {
813 fprintf(stderr, "No nsid specified\n");
814 return -1;
815 }
816 name = argv[0];
375d51ca
CB
817 /* If a negative nsid is specified the kernel will select the nsid. */
818 if (strcmp(argv[1], "auto") == 0)
819 nsid = -1;
ebe3ce2f 820 else if (get_integer(&nsid, argv[1], 0))
acbe9118 821 invarg("Invalid \"netnsid\" value\n", argv[1]);
ebe3ce2f
ND
822 else if (nsid < 0)
823 invarg("\"netnsid\" value should be >= 0\n", argv[1]);
d182ee13
ND
824
825 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
826 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
827 if (netns < 0) {
828 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
829 name, strerror(errno));
830 return -1;
831 }
832
833 return set_netnsid_from_name(name, nsid);
834}
0dc34c77
EB
835
836static int netns_monitor(int argc, char **argv)
837{
838 char buf[4096];
839 struct inotify_event *event;
840 int fd;
56f5daac 841
0dc34c77
EB
842 fd = inotify_init();
843 if (fd < 0) {
844 fprintf(stderr, "inotify_init failed: %s\n",
845 strerror(errno));
a05f6511 846 return -1;
0dc34c77 847 }
c1cbb18a 848
849 if (create_netns_dir())
850 return -1;
851
0dc34c77
EB
852 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
853 fprintf(stderr, "inotify_add_watch failed: %s\n",
854 strerror(errno));
a05f6511 855 return -1;
0dc34c77 856 }
56f5daac 857 for (;;) {
0dc34c77 858 ssize_t len = read(fd, buf, sizeof(buf));
56f5daac 859
0dc34c77
EB
860 if (len < 0) {
861 fprintf(stderr, "read failed: %s\n",
862 strerror(errno));
a05f6511 863 return -1;
0dc34c77
EB
864 }
865 for (event = (struct inotify_event *)buf;
866 (char *)event < &buf[len];
867 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
868 if (event->mask & IN_CREATE)
869 printf("add %s\n", event->name);
870 if (event->mask & IN_DELETE)
871 printf("delete %s\n", event->name);
872 }
873 }
a05f6511 874 return 0;
0dc34c77
EB
875}
876
79928fd0
MC
877static int invalid_name(const char *name)
878{
d3f0b091
MC
879 return !*name || strlen(name) > NAME_MAX ||
880 strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
79928fd0
MC
881}
882
0dc34c77
EB
883int do_netns(int argc, char **argv)
884{
e29a8e05 885 netns_nsid_socket_init();
d652ccbf 886
e29a8e05
AA
887 if (argc < 1) {
888 netns_map_init();
0dc34c77 889 return netns_list(0, NULL);
e29a8e05 890 }
0dc34c77 891
79928fd0
MC
892 if (argc > 1 && invalid_name(argv[1])) {
893 fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
894 exit(-1);
895 }
896
0dc34c77 897 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
e29a8e05
AA
898 (matches(*argv, "lst") == 0)) {
899 netns_map_init();
0dc34c77 900 return netns_list(argc-1, argv+1);
e29a8e05 901 }
0dc34c77 902
e29a8e05
AA
903 if ((matches(*argv, "list-id") == 0)) {
904 netns_map_init();
d652ccbf 905 return netns_list_id(argc-1, argv+1);
e29a8e05 906 }
d652ccbf 907
0dc34c77 908 if (matches(*argv, "help") == 0)
8e2d47dc 909 return usage();
0dc34c77
EB
910
911 if (matches(*argv, "add") == 0)
e3dbcb2a 912 return netns_add(argc-1, argv+1, true);
0dc34c77 913
d182ee13
ND
914 if (matches(*argv, "set") == 0)
915 return netns_set(argc-1, argv+1);
916
0dc34c77
EB
917 if (matches(*argv, "delete") == 0)
918 return netns_delete(argc-1, argv+1);
919
9a7b3d91
EB
920 if (matches(*argv, "identify") == 0)
921 return netns_identify(argc-1, argv+1);
922
923 if (matches(*argv, "pids") == 0)
924 return netns_pids(argc-1, argv+1);
925
0dc34c77
EB
926 if (matches(*argv, "exec") == 0)
927 return netns_exec(argc-1, argv+1);
928
929 if (matches(*argv, "monitor") == 0)
930 return netns_monitor(argc-1, argv+1);
931
e3dbcb2a
MC
932 if (matches(*argv, "attach") == 0)
933 return netns_add(argc-1, argv+1, false);
934
0dc34c77 935 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
a05f6511 936 exit(-1);
0dc34c77 937}