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