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