]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipnetns.c
Use libbsd for strlcpy if available
[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>
508f3c23
LB
11#ifdef HAVE_LIBBSD
12#include <bsd/string.h>
13#endif
0dc34c77
EB
14#include <sched.h>
15#include <fcntl.h>
16#include <dirent.h>
17#include <errno.h>
18#include <unistd.h>
9a7b3d91 19#include <ctype.h>
d652ccbf 20#include <linux/limits.h>
0dc34c77 21
d182ee13
ND
22#include <linux/net_namespace.h>
23
0dc34c77 24#include "utils.h"
4952b459 25#include "list.h"
0dc34c77 26#include "ip_common.h"
eb67e449 27#include "namespace.h"
e93d9221 28#include "json_print.h"
0dc34c77 29
8e2d47dc 30static int usage(void)
0dc34c77
EB
31{
32 fprintf(stderr, "Usage: ip netns list\n");
33 fprintf(stderr, " ip netns add NAME\n");
d182ee13 34 fprintf(stderr, " ip netns set NAME NETNSID\n");
33724939 35 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
0948adc0 36 fprintf(stderr, " ip netns identify [PID]\n");
9a7b3d91 37 fprintf(stderr, " ip netns pids NAME\n");
b13ba03f 38 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
0dc34c77 39 fprintf(stderr, " ip netns monitor\n");
d652ccbf 40 fprintf(stderr, " ip netns list-id\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
ND
47static int have_rtnl_getnsid = -1;
48
cd554f2c 49static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
4c7d9a58
ND
50 struct nlmsghdr *n, void *arg)
51{
52 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
53
54 if (n->nlmsg_type == NLMSG_ERROR &&
55 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
56 have_rtnl_getnsid = 0;
57 else
58 have_rtnl_getnsid = 1;
59 return -1;
60}
61
62static int ipnetns_have_nsid(void)
63{
64 struct {
65 struct nlmsghdr n;
66 struct rtgenmsg g;
67 char buf[1024];
d17b136f
PS
68 } req = {
69 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
70 .n.nlmsg_flags = NLM_F_REQUEST,
71 .n.nlmsg_type = RTM_GETNSID,
72 .g.rtgen_family = AF_UNSPEC,
73 };
4c7d9a58
ND
74 int fd;
75
76 if (have_rtnl_getnsid < 0) {
4c7d9a58
ND
77 fd = open("/proc/self/ns/net", O_RDONLY);
78 if (fd < 0) {
c44003f7
LZ
79 have_rtnl_getnsid = 0;
80 return 0;
4c7d9a58
ND
81 }
82
83 addattr32(&req.n, 1024, NETNSA_FD, fd);
84
85 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
86 perror("request send failed");
87 exit(1);
88 }
89 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
90 close(fd);
91 }
92
93 return have_rtnl_getnsid;
94}
95
974ef93b 96int get_netnsid_from_name(const char *name)
d182ee13
ND
97{
98 struct {
99 struct nlmsghdr n;
100 struct rtgenmsg g;
101 char buf[1024];
86bf43c7 102 } req = {
d17b136f
PS
103 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
104 .n.nlmsg_flags = NLM_F_REQUEST,
105 .n.nlmsg_type = RTM_GETNSID,
106 .g.rtgen_family = AF_UNSPEC,
107 };
86bf43c7 108 struct nlmsghdr *answer;
d182ee13
ND
109 struct rtattr *tb[NETNSA_MAX + 1];
110 struct rtgenmsg *rthdr;
111 int len, fd;
112
974ef93b
ND
113 netns_nsid_socket_init();
114
d182ee13
ND
115 fd = netns_get_fd(name);
116 if (fd < 0)
117 return fd;
118
119 addattr32(&req.n, 1024, NETNSA_FD, fd);
86bf43c7 120 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
d182ee13
ND
121 close(fd);
122 return -2;
123 }
124 close(fd);
125
126 /* Validate message and parse attributes */
86bf43c7
HL
127 if (answer->nlmsg_type == NLMSG_ERROR)
128 goto err_out;
d182ee13 129
86bf43c7
HL
130 rthdr = NLMSG_DATA(answer);
131 len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
d182ee13 132 if (len < 0)
86bf43c7 133 goto err_out;
d182ee13
ND
134
135 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
136
86bf43c7
HL
137 if (tb[NETNSA_NSID]) {
138 free(answer);
d182ee13 139 return rta_getattr_u32(tb[NETNSA_NSID]);
86bf43c7 140 }
d182ee13 141
86bf43c7
HL
142err_out:
143 free(answer);
d182ee13
ND
144 return -1;
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
b13ba03f
VK
400static int on_netns_exec(char *nsname, void *arg)
401{
402 char **argv = arg;
56f5daac 403
b13ba03f
VK
404 cmd_exec(argv[1], argv + 1, true);
405 return 0;
406}
407
408static int netns_exec(int argc, char **argv)
409{
410 /* Setup the proper environment for apps that are not netns
411 * aware, and execute a program in that environment.
412 */
413 const char *cmd;
414
415 if (argc < 1 && !do_all) {
416 fprintf(stderr, "No netns name specified\n");
417 return -1;
418 }
419 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
420 fprintf(stderr, "No command specified\n");
421 return -1;
422 }
423
424 if (do_all)
425 return do_each_netns(on_netns_exec, --argv, 1);
426
427 if (netns_switch(argv[0]))
428 return -1;
429
ee9369a0
DA
430 /* we just changed namespaces. clear any vrf association
431 * with prior namespace before exec'ing command
432 */
433 vrf_reset();
434
b13ba03f
VK
435 /* ip must return the status of the child,
436 * but do_cmd() will add a minus to this,
437 * so let's add another one here to cancel it.
438 */
439 cmd = argv[1];
440 return -cmd_exec(cmd, argv + 1, !!batch_mode);
441}
442
9a7b3d91
EB
443static int is_pid(const char *str)
444{
445 int ch;
56f5daac 446
9a7b3d91
EB
447 for (; (ch = *str); str++) {
448 if (!isdigit(ch))
449 return 0;
450 }
451 return 1;
452}
453
454static int netns_pids(int argc, char **argv)
455{
456 const char *name;
ea343669 457 char net_path[PATH_MAX];
9a7b3d91
EB
458 int netns;
459 struct stat netst;
460 DIR *dir;
461 struct dirent *entry;
462
463 if (argc < 1) {
464 fprintf(stderr, "No netns name specified\n");
a05f6511 465 return -1;
9a7b3d91
EB
466 }
467 if (argc > 1) {
468 fprintf(stderr, "extra arguments specified\n");
a05f6511 469 return -1;
9a7b3d91
EB
470 }
471
472 name = argv[0];
473 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
474 netns = open(net_path, O_RDONLY);
475 if (netns < 0) {
476 fprintf(stderr, "Cannot open network namespace: %s\n",
477 strerror(errno));
a05f6511 478 return -1;
9a7b3d91
EB
479 }
480 if (fstat(netns, &netst) < 0) {
481 fprintf(stderr, "Stat of netns failed: %s\n",
482 strerror(errno));
a05f6511 483 return -1;
9a7b3d91
EB
484 }
485 dir = opendir("/proc/");
486 if (!dir) {
487 fprintf(stderr, "Open of /proc failed: %s\n",
488 strerror(errno));
a05f6511 489 return -1;
9a7b3d91 490 }
56f5daac 491 while ((entry = readdir(dir))) {
ea343669 492 char pid_net_path[PATH_MAX];
9a7b3d91 493 struct stat st;
56f5daac 494
9a7b3d91
EB
495 if (!is_pid(entry->d_name))
496 continue;
497 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
498 entry->d_name);
499 if (stat(pid_net_path, &st) != 0)
500 continue;
501 if ((st.st_dev == netst.st_dev) &&
502 (st.st_ino == netst.st_ino)) {
503 printf("%s\n", entry->d_name);
504 }
505 }
506 closedir(dir);
a05f6511 507 return 0;
0612519e 508
9a7b3d91
EB
509}
510
9c49438a 511int netns_identify_pid(const char *pidstr, char *name, int len)
9a7b3d91 512{
ea343669 513 char net_path[PATH_MAX];
9a7b3d91
EB
514 int netns;
515 struct stat netst;
516 DIR *dir;
517 struct dirent *entry;
518
9c49438a 519 name[0] = '\0';
9a7b3d91
EB
520
521 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
522 netns = open(net_path, O_RDONLY);
523 if (netns < 0) {
524 fprintf(stderr, "Cannot open network namespace: %s\n",
525 strerror(errno));
a05f6511 526 return -1;
9a7b3d91
EB
527 }
528 if (fstat(netns, &netst) < 0) {
529 fprintf(stderr, "Stat of netns failed: %s\n",
530 strerror(errno));
a05f6511 531 return -1;
9a7b3d91
EB
532 }
533 dir = opendir(NETNS_RUN_DIR);
534 if (!dir) {
535 /* Succeed treat a missing directory as an empty directory */
536 if (errno == ENOENT)
a05f6511 537 return 0;
9a7b3d91
EB
538
539 fprintf(stderr, "Failed to open directory %s:%s\n",
540 NETNS_RUN_DIR, strerror(errno));
a05f6511 541 return -1;
9a7b3d91
EB
542 }
543
56f5daac 544 while ((entry = readdir(dir))) {
ea343669 545 char name_path[PATH_MAX];
9a7b3d91
EB
546 struct stat st;
547
548 if (strcmp(entry->d_name, ".") == 0)
549 continue;
550 if (strcmp(entry->d_name, "..") == 0)
551 continue;
552
553 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
554 entry->d_name);
555
556 if (stat(name_path, &st) != 0)
557 continue;
558
559 if ((st.st_dev == netst.st_dev) &&
560 (st.st_ino == netst.st_ino)) {
18f156bf 561 strlcpy(name, entry->d_name, len);
9a7b3d91
EB
562 }
563 }
564 closedir(dir);
a05f6511 565 return 0;
0612519e 566
9a7b3d91
EB
567}
568
9c49438a
DA
569static int netns_identify(int argc, char **argv)
570{
571 const char *pidstr;
572 char name[256];
573 int rc;
574
575 if (argc < 1) {
576 pidstr = "self";
577 } else if (argc > 1) {
578 fprintf(stderr, "extra arguments specified\n");
579 return -1;
580 } else {
581 pidstr = argv[0];
582 if (!is_pid(pidstr)) {
583 fprintf(stderr, "Specified string '%s' is not a pid\n",
584 pidstr);
585 return -1;
586 }
587 }
588
589 rc = netns_identify_pid(pidstr, name, sizeof(name));
590 if (!rc)
591 printf("%s\n", name);
592
593 return rc;
594}
595
33724939 596static int on_netns_del(char *nsname, void *arg)
0dc34c77 597{
ea343669 598 char netns_path[PATH_MAX];
0dc34c77 599
33724939 600 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
0dc34c77
EB
601 umount2(netns_path, MNT_DETACH);
602 if (unlink(netns_path) < 0) {
14645ec2 603 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
0dc34c77 604 netns_path, strerror(errno));
a05f6511 605 return -1;
0dc34c77 606 }
a05f6511 607 return 0;
0dc34c77
EB
608}
609
33724939
VK
610static int netns_delete(int argc, char **argv)
611{
612 if (argc < 1 && !do_all) {
613 fprintf(stderr, "No netns name specified\n");
614 return -1;
615 }
616
617 if (do_all)
618 return netns_foreach(on_netns_del, NULL);
619
620 return on_netns_del(argv[0], NULL);
621}
622
c1cbb18a 623static int create_netns_dir(void)
624{
625 /* Create the base netns directory if it doesn't exist */
626 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
627 if (errno != EEXIST) {
628 fprintf(stderr, "mkdir %s failed: %s\n",
629 NETNS_RUN_DIR, strerror(errno));
630 return -1;
631 }
632 }
633
634 return 0;
635}
636
0dc34c77
EB
637static int netns_add(int argc, char **argv)
638{
639 /* This function creates a new network namespace and
640 * a new mount namespace and bind them into a well known
641 * location in the filesystem based on the name provided.
642 *
643 * The mount namespace is created so that any necessary
644 * userspace tweaks like remounting /sys, or bind mounting
645 * a new /etc/resolv.conf can be shared between uers.
646 */
ea343669 647 char netns_path[PATH_MAX];
0dc34c77 648 const char *name;
223f4d8e 649 int fd;
58a3e827 650 int made_netns_run_dir_mount = 0;
0dc34c77
EB
651
652 if (argc < 1) {
653 fprintf(stderr, "No netns name specified\n");
a05f6511 654 return -1;
0dc34c77
EB
655 }
656 name = argv[0];
657
658 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
659
c1cbb18a 660 if (create_netns_dir())
661 return -1;
0dc34c77 662
d259f030 663 /* Make it possible for network namespace mounts to propagate between
58a3e827
EB
664 * mount namespaces. This makes it likely that a unmounting a network
665 * namespace file in one namespace will unmount the network namespace
666 * file in all namespaces allowing the network namespace to be freed
667 * sooner.
668 */
669 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
670 /* Fail unless we need to make the mount point */
671 if (errno != EINVAL || made_netns_run_dir_mount) {
672 fprintf(stderr, "mount --make-shared %s failed: %s\n",
673 NETNS_RUN_DIR, strerror(errno));
a05f6511 674 return -1;
58a3e827
EB
675 }
676
677 /* Upgrade NETNS_RUN_DIR to a mount point */
d6a4076b 678 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
58a3e827
EB
679 fprintf(stderr, "mount --bind %s %s failed: %s\n",
680 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
a05f6511 681 return -1;
58a3e827
EB
682 }
683 made_netns_run_dir_mount = 1;
684 }
685
0dc34c77 686 /* Create the filesystem state */
223f4d8e
EB
687 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
688 if (fd < 0) {
55713c8c 689 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
0dc34c77 690 netns_path, strerror(errno));
a05f6511 691 return -1;
0dc34c77 692 }
223f4d8e 693 close(fd);
0dc34c77 694 if (unshare(CLONE_NEWNET) < 0) {
14645ec2
KR
695 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
696 name, strerror(errno));
0dc34c77
EB
697 goto out_delete;
698 }
699
700 /* Bind the netns last so I can watch for it */
701 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
702 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
703 netns_path, strerror(errno));
704 goto out_delete;
705 }
a05f6511 706 return 0;
0dc34c77
EB
707out_delete:
708 netns_delete(argc, argv);
a05f6511 709 return -1;
0dc34c77
EB
710}
711
974ef93b 712int set_netnsid_from_name(const char *name, int nsid)
d182ee13
ND
713{
714 struct {
715 struct nlmsghdr n;
716 struct rtgenmsg g;
717 char buf[1024];
d17b136f
PS
718 } req = {
719 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
720 .n.nlmsg_flags = NLM_F_REQUEST,
721 .n.nlmsg_type = RTM_NEWNSID,
722 .g.rtgen_family = AF_UNSPEC,
723 };
d182ee13
ND
724 int fd, err = 0;
725
974ef93b
ND
726 netns_nsid_socket_init();
727
d182ee13
ND
728 fd = netns_get_fd(name);
729 if (fd < 0)
730 return fd;
731
732 addattr32(&req.n, 1024, NETNSA_FD, fd);
733 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
86bf43c7 734 if (rtnl_talk(&rth, &req.n, NULL) < 0)
d182ee13
ND
735 err = -2;
736
737 close(fd);
738 return err;
739}
740
741static int netns_set(int argc, char **argv)
742{
ea343669 743 char netns_path[PATH_MAX];
d182ee13 744 const char *name;
acbe9118
RM
745 unsigned int nsid;
746 int netns;
d182ee13
ND
747
748 if (argc < 1) {
749 fprintf(stderr, "No netns name specified\n");
750 return -1;
751 }
752 if (argc < 2) {
753 fprintf(stderr, "No nsid specified\n");
754 return -1;
755 }
756 name = argv[0];
375d51ca
CB
757 /* If a negative nsid is specified the kernel will select the nsid. */
758 if (strcmp(argv[1], "auto") == 0)
759 nsid = -1;
760 else if (get_unsigned(&nsid, argv[1], 0))
acbe9118 761 invarg("Invalid \"netnsid\" value\n", argv[1]);
d182ee13
ND
762
763 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
764 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
765 if (netns < 0) {
766 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
767 name, strerror(errno));
768 return -1;
769 }
770
771 return set_netnsid_from_name(name, nsid);
772}
0dc34c77
EB
773
774static int netns_monitor(int argc, char **argv)
775{
776 char buf[4096];
777 struct inotify_event *event;
778 int fd;
56f5daac 779
0dc34c77
EB
780 fd = inotify_init();
781 if (fd < 0) {
782 fprintf(stderr, "inotify_init failed: %s\n",
783 strerror(errno));
a05f6511 784 return -1;
0dc34c77 785 }
c1cbb18a 786
787 if (create_netns_dir())
788 return -1;
789
0dc34c77
EB
790 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
791 fprintf(stderr, "inotify_add_watch failed: %s\n",
792 strerror(errno));
a05f6511 793 return -1;
0dc34c77 794 }
56f5daac 795 for (;;) {
0dc34c77 796 ssize_t len = read(fd, buf, sizeof(buf));
56f5daac 797
0dc34c77
EB
798 if (len < 0) {
799 fprintf(stderr, "read failed: %s\n",
800 strerror(errno));
a05f6511 801 return -1;
0dc34c77
EB
802 }
803 for (event = (struct inotify_event *)buf;
804 (char *)event < &buf[len];
805 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
806 if (event->mask & IN_CREATE)
807 printf("add %s\n", event->name);
808 if (event->mask & IN_DELETE)
809 printf("delete %s\n", event->name);
810 }
811 }
a05f6511 812 return 0;
0dc34c77
EB
813}
814
79928fd0
MC
815static int invalid_name(const char *name)
816{
d3f0b091
MC
817 return !*name || strlen(name) > NAME_MAX ||
818 strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
79928fd0
MC
819}
820
0dc34c77
EB
821int do_netns(int argc, char **argv)
822{
e29a8e05 823 netns_nsid_socket_init();
d652ccbf 824
e29a8e05
AA
825 if (argc < 1) {
826 netns_map_init();
0dc34c77 827 return netns_list(0, NULL);
e29a8e05 828 }
0dc34c77 829
79928fd0
MC
830 if (argc > 1 && invalid_name(argv[1])) {
831 fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
832 exit(-1);
833 }
834
0dc34c77 835 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
e29a8e05
AA
836 (matches(*argv, "lst") == 0)) {
837 netns_map_init();
0dc34c77 838 return netns_list(argc-1, argv+1);
e29a8e05 839 }
0dc34c77 840
e29a8e05
AA
841 if ((matches(*argv, "list-id") == 0)) {
842 netns_map_init();
d652ccbf 843 return netns_list_id(argc-1, argv+1);
e29a8e05 844 }
d652ccbf 845
0dc34c77 846 if (matches(*argv, "help") == 0)
8e2d47dc 847 return usage();
0dc34c77
EB
848
849 if (matches(*argv, "add") == 0)
850 return netns_add(argc-1, argv+1);
851
d182ee13
ND
852 if (matches(*argv, "set") == 0)
853 return netns_set(argc-1, argv+1);
854
0dc34c77
EB
855 if (matches(*argv, "delete") == 0)
856 return netns_delete(argc-1, argv+1);
857
9a7b3d91
EB
858 if (matches(*argv, "identify") == 0)
859 return netns_identify(argc-1, argv+1);
860
861 if (matches(*argv, "pids") == 0)
862 return netns_pids(argc-1, argv+1);
863
0dc34c77
EB
864 if (matches(*argv, "exec") == 0)
865 return netns_exec(argc-1, argv+1);
866
867 if (matches(*argv, "monitor") == 0)
868 return netns_monitor(argc-1, argv+1);
869
870 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
a05f6511 871 exit(-1);
0dc34c77 872}