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