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