]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipnetns.c
lib: print_color_rate(): Fix formatting small rates in IEC mode
[mirror_iproute2.git] / ip / ipnetns.c
CommitLineData
6054c1eb 1/* SPDX-License-Identifier: GPL-2.0 */
0dc34c77 2#define _ATFILE_SOURCE
975c4944 3#include <sys/file.h>
0dc34c77
EB
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <sys/wait.h>
7#include <sys/inotify.h>
8#include <sys/mount.h>
0dc34c77
EB
9#include <sys/syscall.h>
10#include <stdio.h>
11#include <string.h>
12#include <sched.h>
13#include <fcntl.h>
14#include <dirent.h>
15#include <errno.h>
16#include <unistd.h>
9a7b3d91 17#include <ctype.h>
d652ccbf 18#include <linux/limits.h>
0dc34c77 19
d182ee13
ND
20#include <linux/net_namespace.h>
21
0dc34c77 22#include "utils.h"
4952b459 23#include "list.h"
0dc34c77 24#include "ip_common.h"
eb67e449 25#include "namespace.h"
e93d9221 26#include "json_print.h"
0dc34c77 27
8e2d47dc 28static int usage(void)
0dc34c77 29{
8589eb4e
MC
30 fprintf(stderr,
31 "Usage: ip netns list\n"
32 " ip netns add NAME\n"
33 " ip netns attach NAME PID\n"
34 " ip netns set NAME NETNSID\n"
35 " ip [-all] netns delete [NAME]\n"
36 " ip netns identify [PID]\n"
37 " ip netns pids NAME\n"
38 " ip [-all] netns exec [NAME] cmd ...\n"
39 " ip netns monitor\n"
eaefb078 40 " ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT]\n"
8589eb4e 41 "NETNSID := auto | POSITIVE-INT\n");
a05f6511 42 exit(-1);
0dc34c77
EB
43}
44
d652ccbf
ND
45/* This socket is used to get nsid */
46static struct rtnl_handle rtnsh = { .fd = -1 };
47
4c7d9a58 48static int have_rtnl_getnsid = -1;
b2e29223 49static int saved_netns = -1;
eaefb078 50static struct link_filter filter;
4c7d9a58 51
cd554f2c 52static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
4c7d9a58
ND
53 struct nlmsghdr *n, void *arg)
54{
55 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
56
57 if (n->nlmsg_type == NLMSG_ERROR &&
58 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
59 have_rtnl_getnsid = 0;
60 else
61 have_rtnl_getnsid = 1;
62 return -1;
63}
64
65static int ipnetns_have_nsid(void)
66{
67 struct {
68 struct nlmsghdr n;
69 struct rtgenmsg g;
70 char buf[1024];
d17b136f
PS
71 } req = {
72 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
73 .n.nlmsg_flags = NLM_F_REQUEST,
74 .n.nlmsg_type = RTM_GETNSID,
75 .g.rtgen_family = AF_UNSPEC,
76 };
4c7d9a58
ND
77 int fd;
78
0ca1312c 79 if (have_rtnl_getnsid >= 0) {
4c7d9a58
ND
80 fd = open("/proc/self/ns/net", O_RDONLY);
81 if (fd < 0) {
0ca1312c
JE
82 fprintf(stderr,
83 "/proc/self/ns/net: %s. Continuing anyway.\n",
84 strerror(errno));
c44003f7
LZ
85 have_rtnl_getnsid = 0;
86 return 0;
4c7d9a58
ND
87 }
88
89 addattr32(&req.n, 1024, NETNSA_FD, fd);
90
91 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
0ca1312c
JE
92 fprintf(stderr,
93 "rtnl_send(RTM_GETNSID): %s. Continuing anyway.\n",
94 strerror(errno));
95 have_rtnl_getnsid = 0;
96 close(fd);
97 return 0;
4c7d9a58
ND
98 }
99 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
100 close(fd);
101 }
102
103 return have_rtnl_getnsid;
104}
105
974ef93b 106int get_netnsid_from_name(const char *name)
d182ee13
ND
107{
108 struct {
109 struct nlmsghdr n;
110 struct rtgenmsg g;
111 char buf[1024];
86bf43c7 112 } req = {
d17b136f
PS
113 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
114 .n.nlmsg_flags = NLM_F_REQUEST,
115 .n.nlmsg_type = RTM_GETNSID,
116 .g.rtgen_family = AF_UNSPEC,
117 };
86bf43c7 118 struct nlmsghdr *answer;
d182ee13
ND
119 struct rtattr *tb[NETNSA_MAX + 1];
120 struct rtgenmsg *rthdr;
9bf2c538 121 int len, fd, ret = -1;
d182ee13 122
974ef93b
ND
123 netns_nsid_socket_init();
124
d182ee13
ND
125 fd = netns_get_fd(name);
126 if (fd < 0)
127 return fd;
128
129 addattr32(&req.n, 1024, NETNSA_FD, fd);
86bf43c7 130 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
d182ee13
ND
131 close(fd);
132 return -2;
133 }
134 close(fd);
135
136 /* Validate message and parse attributes */
86bf43c7 137 if (answer->nlmsg_type == NLMSG_ERROR)
9bf2c538 138 goto out;
d182ee13 139
86bf43c7
HL
140 rthdr = NLMSG_DATA(answer);
141 len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
d182ee13 142 if (len < 0)
9bf2c538 143 goto out;
d182ee13
ND
144
145 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
146
86bf43c7 147 if (tb[NETNSA_NSID]) {
f19966ef 148 ret = rta_getattr_s32(tb[NETNSA_NSID]);
86bf43c7 149 }
d182ee13 150
9bf2c538 151out:
86bf43c7 152 free(answer);
9bf2c538 153 return ret;
d182ee13
ND
154}
155
d652ccbf
ND
156struct nsid_cache {
157 struct hlist_node nsid_hash;
158 struct hlist_node name_hash;
159 int nsid;
2f29d6bb 160 char name[0];
d652ccbf
ND
161};
162
163#define NSIDMAP_SIZE 128
164#define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
165#define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
166
167static struct hlist_head nsid_head[NSIDMAP_SIZE];
168static struct hlist_head name_head[NSIDMAP_SIZE];
169
170static struct nsid_cache *netns_map_get_by_nsid(int nsid)
171{
d652ccbf 172 struct hlist_node *n;
08ba67db
GN
173 uint32_t h;
174
175 if (nsid < 0)
176 return NULL;
d652ccbf 177
08ba67db 178 h = NSID_HASH_NSID(nsid);
d652ccbf
ND
179 hlist_for_each(n, &nsid_head[h]) {
180 struct nsid_cache *c = container_of(n, struct nsid_cache,
181 nsid_hash);
182 if (c->nsid == nsid)
183 return c;
184 }
185
186 return NULL;
187}
188
9580bad7
ND
189char *get_name_from_nsid(int nsid)
190{
191 struct nsid_cache *c;
192
08ba67db
GN
193 if (nsid < 0)
194 return NULL;
195
9580bad7
ND
196 netns_nsid_socket_init();
197 netns_map_init();
198
199 c = netns_map_get_by_nsid(nsid);
200 if (c)
201 return c->name;
202
203 return NULL;
204}
205
2f29d6bb 206static int netns_map_add(int nsid, const char *name)
d652ccbf
ND
207{
208 struct nsid_cache *c;
209 uint32_t h;
210
211 if (netns_map_get_by_nsid(nsid) != NULL)
212 return -EEXIST;
213
a1b4a274 214 c = malloc(sizeof(*c) + strlen(name) + 1);
d652ccbf
ND
215 if (c == NULL) {
216 perror("malloc");
217 return -ENOMEM;
218 }
219 c->nsid = nsid;
220 strcpy(c->name, name);
221
222 h = NSID_HASH_NSID(nsid);
223 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
224
225 h = NSID_HASH_NAME(name);
226 hlist_add_head(&c->name_hash, &name_head[h]);
227
228 return 0;
229}
230
231static void netns_map_del(struct nsid_cache *c)
232{
233 hlist_del(&c->name_hash);
234 hlist_del(&c->nsid_hash);
235 free(c);
236}
237
e29a8e05
AA
238void netns_nsid_socket_init(void)
239{
240 if (rtnsh.fd > -1 || !ipnetns_have_nsid())
241 return;
242
243 if (rtnl_open(&rtnsh, 0) < 0) {
244 fprintf(stderr, "Cannot open rtnetlink\n");
245 exit(1);
246 }
247
248}
249
d652ccbf
ND
250void netns_map_init(void)
251{
252 static int initialized;
253 struct dirent *entry;
254 DIR *dir;
255 int nsid;
256
257 if (initialized || !ipnetns_have_nsid())
258 return;
259
d652ccbf
ND
260 dir = opendir(NETNS_RUN_DIR);
261 if (!dir)
262 return;
263
264 while ((entry = readdir(dir)) != NULL) {
265 if (strcmp(entry->d_name, ".") == 0)
266 continue;
267 if (strcmp(entry->d_name, "..") == 0)
268 continue;
269 nsid = get_netnsid_from_name(entry->d_name);
270
271 if (nsid >= 0)
272 netns_map_add(nsid, entry->d_name);
273 }
274 closedir(dir);
275 initialized = 1;
276}
277
278static int netns_get_name(int nsid, char *name)
279{
280 struct dirent *entry;
281 DIR *dir;
282 int id;
283
08ba67db
GN
284 if (nsid < 0)
285 return -EINVAL;
286
d652ccbf
ND
287 dir = opendir(NETNS_RUN_DIR);
288 if (!dir)
289 return -ENOENT;
290
291 while ((entry = readdir(dir)) != NULL) {
292 if (strcmp(entry->d_name, ".") == 0)
293 continue;
294 if (strcmp(entry->d_name, "..") == 0)
295 continue;
296 id = get_netnsid_from_name(entry->d_name);
297
08ba67db 298 if (id >= 0 && nsid == id) {
d652ccbf
ND
299 strcpy(name, entry->d_name);
300 closedir(dir);
301 return 0;
302 }
303 }
304 closedir(dir);
305 return -ENOENT;
306}
307
cd554f2c 308int print_nsid(struct nlmsghdr *n, void *arg)
d652ccbf
ND
309{
310 struct rtgenmsg *rthdr = NLMSG_DATA(n);
311 struct rtattr *tb[NETNSA_MAX+1];
312 int len = n->nlmsg_len;
313 FILE *fp = (FILE *)arg;
314 struct nsid_cache *c;
315 char name[NAME_MAX];
eaefb078 316 int nsid, current;
d652ccbf
ND
317
318 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
319 return 0;
320
321 len -= NLMSG_SPACE(sizeof(*rthdr));
322 if (len < 0) {
323 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
324 __func__);
325 return -1;
326 }
327
328 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
329 if (tb[NETNSA_NSID] == NULL) {
330 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
331 return -1;
332 }
333
e93d9221 334 open_json_object(NULL);
d652ccbf 335 if (n->nlmsg_type == RTM_DELNSID)
e93d9221 336 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
d652ccbf 337
f19966ef 338 nsid = rta_getattr_s32(tb[NETNSA_NSID]);
eaefb078 339 if (nsid < 0)
1c9b6927 340 print_string(PRINT_FP, NULL, "nsid unassigned ", NULL);
eaefb078 341 else
f19966ef 342 print_int(PRINT_ANY, "nsid", "nsid %d ", nsid);
eaefb078
ND
343
344 if (tb[NETNSA_CURRENT_NSID]) {
f19966ef 345 current = rta_getattr_s32(tb[NETNSA_CURRENT_NSID]);
eaefb078 346 if (current < 0)
1c9b6927
GN
347 print_string(PRINT_FP, NULL,
348 "current-nsid unassigned ", NULL);
eaefb078 349 else
f19966ef
GN
350 print_int(PRINT_ANY, "current-nsid",
351 "current-nsid %d ", current);
eaefb078 352 }
d652ccbf 353
eaefb078 354 c = netns_map_get_by_nsid(tb[NETNSA_CURRENT_NSID] ? current : nsid);
d652ccbf 355 if (c != NULL) {
e93d9221
SH
356 print_string(PRINT_ANY, "name",
357 "(iproute2 netns name: %s)", c->name);
d652ccbf
ND
358 netns_map_del(c);
359 }
360
df6da60b 361 /* nsid might not be in cache */
d652ccbf
ND
362 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
363 if (netns_get_name(nsid, name) == 0) {
e93d9221
SH
364 print_string(PRINT_ANY, "name",
365 "(iproute2 netns name: %s)", name);
d652ccbf
ND
366 netns_map_add(nsid, name);
367 }
368
e93d9221
SH
369 print_string(PRINT_FP, NULL, "\n", NULL);
370 close_json_object();
d652ccbf
ND
371 fflush(fp);
372 return 0;
373}
374
eaefb078
ND
375static int get_netnsid_from_netnsid(int nsid)
376{
377 struct {
378 struct nlmsghdr n;
379 struct rtgenmsg g;
380 char buf[1024];
381 } req = {
382 .n.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
383 .n.nlmsg_flags = NLM_F_REQUEST,
384 .n.nlmsg_type = RTM_GETNSID,
385 .g.rtgen_family = AF_UNSPEC,
386 };
387 struct nlmsghdr *answer;
388 int err;
389
390 netns_nsid_socket_init();
391
392 err = addattr32(&req.n, sizeof(req), NETNSA_NSID, nsid);
393 if (err)
394 return err;
395
396 if (filter.target_nsid >= 0) {
397 err = addattr32(&req.n, sizeof(req), NETNSA_TARGET_NSID,
398 filter.target_nsid);
399 if (err)
400 return err;
401 }
402
403 if (rtnl_talk(&rtnsh, &req.n, &answer) < 0)
404 return -2;
405
406 /* Validate message and parse attributes */
407 if (answer->nlmsg_type == NLMSG_ERROR)
408 goto err_out;
409
410 new_json_obj(json);
411 err = print_nsid(answer, stdout);
412 delete_json_obj();
413err_out:
414 free(answer);
415 return err;
416}
417
418static int netns_filter_req(struct nlmsghdr *nlh, int reqlen)
419{
420 int err;
421
422 if (filter.target_nsid >= 0) {
423 err = addattr32(nlh, reqlen, NETNSA_TARGET_NSID,
424 filter.target_nsid);
425 if (err)
426 return err;
427 }
428
429 return 0;
430}
431
d652ccbf
ND
432static int netns_list_id(int argc, char **argv)
433{
eaefb078
ND
434 int nsid = -1;
435
d652ccbf
ND
436 if (!ipnetns_have_nsid()) {
437 fprintf(stderr,
438 "RTM_GETNSID is not supported by the kernel.\n");
439 return -ENOTSUP;
440 }
441
eaefb078
ND
442 filter.target_nsid = -1;
443 while (argc > 0) {
444 if (strcmp(*argv, "target-nsid") == 0) {
445 if (filter.target_nsid >= 0)
446 duparg("target-nsid", *argv);
447 NEXT_ARG();
448
449 if (get_integer(&filter.target_nsid, *argv, 0))
d0b645a5 450 invarg("\"target-nsid\" value is invalid",
eaefb078
ND
451 *argv);
452 else if (filter.target_nsid < 0)
d0b645a5 453 invarg("\"target-nsid\" value should be >= 0",
eaefb078
ND
454 argv[1]);
455 } else if (strcmp(*argv, "nsid") == 0) {
456 if (nsid >= 0)
457 duparg("nsid", *argv);
458 NEXT_ARG();
459
460 if (get_integer(&nsid, *argv, 0))
d0b645a5 461 invarg("\"nsid\" value is invalid", *argv);
eaefb078 462 else if (nsid < 0)
d0b645a5 463 invarg("\"nsid\" value should be >= 0",
eaefb078
ND
464 argv[1]);
465 } else
466 usage();
467 argc--; argv++;
468 }
469
470 if (nsid >= 0)
471 return get_netnsid_from_netnsid(nsid);
472
473 if (rtnl_nsiddump_req_filter_fn(&rth, AF_UNSPEC,
474 netns_filter_req) < 0) {
d652ccbf
ND
475 perror("Cannot send dump request");
476 exit(1);
477 }
e93d9221
SH
478
479 new_json_obj(json);
d652ccbf 480 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
e93d9221 481 delete_json_obj();
d652ccbf
ND
482 fprintf(stderr, "Dump terminated\n");
483 exit(1);
484 }
e93d9221 485 delete_json_obj();
d652ccbf
ND
486 return 0;
487}
488
0dc34c77
EB
489static int netns_list(int argc, char **argv)
490{
491 struct dirent *entry;
492 DIR *dir;
d182ee13 493 int id;
0dc34c77
EB
494
495 dir = opendir(NETNS_RUN_DIR);
496 if (!dir)
a05f6511 497 return 0;
0dc34c77 498
e93d9221 499 new_json_obj(json);
0dc34c77
EB
500 while ((entry = readdir(dir)) != NULL) {
501 if (strcmp(entry->d_name, ".") == 0)
502 continue;
503 if (strcmp(entry->d_name, "..") == 0)
504 continue;
e93d9221
SH
505
506 open_json_object(NULL);
507 print_string(PRINT_ANY, "name",
508 "%s", entry->d_name);
4c7d9a58
ND
509 if (ipnetns_have_nsid()) {
510 id = get_netnsid_from_name(entry->d_name);
511 if (id >= 0)
f19966ef 512 print_int(PRINT_ANY, "id", " (id: %d)", id);
4c7d9a58 513 }
e93d9221
SH
514 print_string(PRINT_FP, NULL, "\n", NULL);
515 close_json_object();
0dc34c77
EB
516 }
517 closedir(dir);
e93d9221 518 delete_json_obj();
a05f6511 519 return 0;
0dc34c77
EB
520}
521
903818fb
MC
522static int do_switch(void *arg)
523{
524 char *netns = arg;
525
526 /* we just changed namespaces. clear any vrf association
527 * with prior namespace before exec'ing command
528 */
529 vrf_reset();
530
531 return netns_switch(netns);
532}
533
b13ba03f
VK
534static int on_netns_exec(char *nsname, void *arg)
535{
536 char **argv = arg;
56f5daac 537
903818fb
MC
538 printf("\nnetns: %s\n", nsname);
539 cmd_exec(argv[0], argv, true, do_switch, nsname);
b13ba03f
VK
540 return 0;
541}
542
543static int netns_exec(int argc, char **argv)
544{
545 /* Setup the proper environment for apps that are not netns
546 * aware, and execute a program in that environment.
547 */
b13ba03f
VK
548 if (argc < 1 && !do_all) {
549 fprintf(stderr, "No netns name specified\n");
550 return -1;
551 }
552 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
553 fprintf(stderr, "No command specified\n");
554 return -1;
555 }
556
557 if (do_all)
903818fb 558 return netns_foreach(on_netns_exec, argv);
ee9369a0 559
b13ba03f
VK
560 /* ip must return the status of the child,
561 * but do_cmd() will add a minus to this,
562 * so let's add another one here to cancel it.
563 */
903818fb 564 return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
b13ba03f
VK
565}
566
9a7b3d91
EB
567static int is_pid(const char *str)
568{
569 int ch;
56f5daac 570
9a7b3d91
EB
571 for (; (ch = *str); str++) {
572 if (!isdigit(ch))
573 return 0;
574 }
575 return 1;
576}
577
578static int netns_pids(int argc, char **argv)
579{
580 const char *name;
ea343669 581 char net_path[PATH_MAX];
9a7b3d91
EB
582 int netns;
583 struct stat netst;
584 DIR *dir;
585 struct dirent *entry;
586
587 if (argc < 1) {
588 fprintf(stderr, "No netns name specified\n");
a05f6511 589 return -1;
9a7b3d91
EB
590 }
591 if (argc > 1) {
592 fprintf(stderr, "extra arguments specified\n");
a05f6511 593 return -1;
9a7b3d91
EB
594 }
595
596 name = argv[0];
597 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
598 netns = open(net_path, O_RDONLY);
599 if (netns < 0) {
600 fprintf(stderr, "Cannot open network namespace: %s\n",
601 strerror(errno));
a05f6511 602 return -1;
9a7b3d91
EB
603 }
604 if (fstat(netns, &netst) < 0) {
605 fprintf(stderr, "Stat of netns failed: %s\n",
606 strerror(errno));
a05f6511 607 return -1;
9a7b3d91
EB
608 }
609 dir = opendir("/proc/");
610 if (!dir) {
611 fprintf(stderr, "Open of /proc failed: %s\n",
612 strerror(errno));
a05f6511 613 return -1;
9a7b3d91 614 }
56f5daac 615 while ((entry = readdir(dir))) {
ea343669 616 char pid_net_path[PATH_MAX];
9a7b3d91 617 struct stat st;
56f5daac 618
9a7b3d91
EB
619 if (!is_pid(entry->d_name))
620 continue;
621 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
622 entry->d_name);
623 if (stat(pid_net_path, &st) != 0)
624 continue;
625 if ((st.st_dev == netst.st_dev) &&
626 (st.st_ino == netst.st_ino)) {
627 printf("%s\n", entry->d_name);
628 }
629 }
630 closedir(dir);
a05f6511 631 return 0;
0612519e 632
9a7b3d91
EB
633}
634
9c49438a 635int netns_identify_pid(const char *pidstr, char *name, int len)
9a7b3d91 636{
ea343669 637 char net_path[PATH_MAX];
9a7b3d91
EB
638 int netns;
639 struct stat netst;
640 DIR *dir;
641 struct dirent *entry;
642
9c49438a 643 name[0] = '\0';
9a7b3d91
EB
644
645 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
646 netns = open(net_path, O_RDONLY);
647 if (netns < 0) {
648 fprintf(stderr, "Cannot open network namespace: %s\n",
649 strerror(errno));
a05f6511 650 return -1;
9a7b3d91
EB
651 }
652 if (fstat(netns, &netst) < 0) {
653 fprintf(stderr, "Stat of netns failed: %s\n",
654 strerror(errno));
a05f6511 655 return -1;
9a7b3d91
EB
656 }
657 dir = opendir(NETNS_RUN_DIR);
658 if (!dir) {
659 /* Succeed treat a missing directory as an empty directory */
660 if (errno == ENOENT)
a05f6511 661 return 0;
9a7b3d91
EB
662
663 fprintf(stderr, "Failed to open directory %s:%s\n",
664 NETNS_RUN_DIR, strerror(errno));
a05f6511 665 return -1;
9a7b3d91
EB
666 }
667
56f5daac 668 while ((entry = readdir(dir))) {
ea343669 669 char name_path[PATH_MAX];
9a7b3d91
EB
670 struct stat st;
671
672 if (strcmp(entry->d_name, ".") == 0)
673 continue;
674 if (strcmp(entry->d_name, "..") == 0)
675 continue;
676
677 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
678 entry->d_name);
679
680 if (stat(name_path, &st) != 0)
681 continue;
682
683 if ((st.st_dev == netst.st_dev) &&
684 (st.st_ino == netst.st_ino)) {
18f156bf 685 strlcpy(name, entry->d_name, len);
9a7b3d91
EB
686 }
687 }
688 closedir(dir);
a05f6511 689 return 0;
0612519e 690
9a7b3d91
EB
691}
692
9c49438a
DA
693static int netns_identify(int argc, char **argv)
694{
695 const char *pidstr;
696 char name[256];
697 int rc;
698
699 if (argc < 1) {
700 pidstr = "self";
701 } else if (argc > 1) {
702 fprintf(stderr, "extra arguments specified\n");
703 return -1;
704 } else {
705 pidstr = argv[0];
706 if (!is_pid(pidstr)) {
707 fprintf(stderr, "Specified string '%s' is not a pid\n",
708 pidstr);
709 return -1;
710 }
711 }
712
713 rc = netns_identify_pid(pidstr, name, sizeof(name));
714 if (!rc)
715 printf("%s\n", name);
716
717 return rc;
718}
719
33724939 720static int on_netns_del(char *nsname, void *arg)
0dc34c77 721{
ea343669 722 char netns_path[PATH_MAX];
0dc34c77 723
33724939 724 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
0dc34c77
EB
725 umount2(netns_path, MNT_DETACH);
726 if (unlink(netns_path) < 0) {
14645ec2 727 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
0dc34c77 728 netns_path, strerror(errno));
a05f6511 729 return -1;
0dc34c77 730 }
a05f6511 731 return 0;
0dc34c77
EB
732}
733
33724939
VK
734static int netns_delete(int argc, char **argv)
735{
736 if (argc < 1 && !do_all) {
737 fprintf(stderr, "No netns name specified\n");
738 return -1;
739 }
740
741 if (do_all)
742 return netns_foreach(on_netns_del, NULL);
743
744 return on_netns_del(argv[0], NULL);
745}
746
c1cbb18a 747static int create_netns_dir(void)
748{
749 /* Create the base netns directory if it doesn't exist */
750 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
751 if (errno != EEXIST) {
752 fprintf(stderr, "mkdir %s failed: %s\n",
753 NETNS_RUN_DIR, strerror(errno));
754 return -1;
755 }
756 }
757
758 return 0;
759}
760
b2e29223
MC
761/* Obtain a FD for the current namespace, so we can reenter it later */
762static void netns_save(void)
763{
764 if (saved_netns != -1)
765 return;
766
767 saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
768 if (saved_netns == -1) {
769 perror("Cannot open init namespace");
770 exit(1);
771 }
772}
773
774static void netns_restore(void)
775{
776 if (saved_netns == -1)
777 return;
778
779 if (setns(saved_netns, CLONE_NEWNET)) {
780 perror("setns");
781 exit(1);
782 }
783
784 close(saved_netns);
785 saved_netns = -1;
786}
787
e3dbcb2a 788static int netns_add(int argc, char **argv, bool create)
0dc34c77
EB
789{
790 /* This function creates a new network namespace and
791 * a new mount namespace and bind them into a well known
792 * location in the filesystem based on the name provided.
793 *
e3dbcb2a
MC
794 * If create is true, a new namespace will be created,
795 * otherwise an existing one will be attached to the file.
796 *
0dc34c77
EB
797 * The mount namespace is created so that any necessary
798 * userspace tweaks like remounting /sys, or bind mounting
e3dbcb2a 799 * a new /etc/resolv.conf can be shared between users.
0dc34c77 800 */
e3dbcb2a 801 char netns_path[PATH_MAX], proc_path[PATH_MAX];
0dc34c77 802 const char *name;
e3dbcb2a 803 pid_t pid;
223f4d8e 804 int fd;
975c4944 805 int lock;
58a3e827 806 int made_netns_run_dir_mount = 0;
0dc34c77 807
e3dbcb2a
MC
808 if (create) {
809 if (argc < 1) {
810 fprintf(stderr, "No netns name specified\n");
811 return -1;
812 }
813 } else {
814 if (argc < 2) {
815 fprintf(stderr, "No netns name and PID specified\n");
816 return -1;
817 }
818
819 if (get_s32(&pid, argv[1], 0) || !pid) {
820 fprintf(stderr, "Invalid PID: %s\n", argv[1]);
821 return -1;
822 }
0dc34c77
EB
823 }
824 name = argv[0];
825
826 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
827
c1cbb18a 828 if (create_netns_dir())
829 return -1;
0dc34c77 830
d259f030 831 /* Make it possible for network namespace mounts to propagate between
58a3e827
EB
832 * mount namespaces. This makes it likely that a unmounting a network
833 * namespace file in one namespace will unmount the network namespace
834 * file in all namespaces allowing the network namespace to be freed
835 * sooner.
975c4944
LB
836 * These setup steps need to happen only once, as if multiple ip processes
837 * try to attempt the same operation at the same time, the mountpoints will
838 * be recursively created multiple times, eventually causing the system
839 * to lock up. For example, this has been observed when multiple netns
840 * namespaces are created in parallel at boot. See:
841 * https://bugs.debian.org/949235
842 * Try to take an exclusive file lock on the top level directory to ensure
843 * this cannot happen, but proceed nonetheless if it cannot happen for any
844 * reason.
58a3e827 845 */
975c4944
LB
846 lock = open(NETNS_RUN_DIR, O_RDONLY|O_DIRECTORY, 0);
847 if (lock < 0) {
848 fprintf(stderr, "Cannot open netns runtime directory \"%s\": %s\n",
849 NETNS_RUN_DIR, strerror(errno));
850 return -1;
851 }
852 if (flock(lock, LOCK_EX) < 0) {
853 fprintf(stderr, "Warning: could not flock netns runtime directory \"%s\": %s\n",
854 NETNS_RUN_DIR, strerror(errno));
855 close(lock);
856 lock = -1;
857 }
58a3e827
EB
858 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
859 /* Fail unless we need to make the mount point */
860 if (errno != EINVAL || made_netns_run_dir_mount) {
861 fprintf(stderr, "mount --make-shared %s failed: %s\n",
862 NETNS_RUN_DIR, strerror(errno));
975c4944
LB
863 if (lock != -1) {
864 flock(lock, LOCK_UN);
865 close(lock);
866 }
a05f6511 867 return -1;
58a3e827
EB
868 }
869
870 /* Upgrade NETNS_RUN_DIR to a mount point */
d6a4076b 871 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
58a3e827
EB
872 fprintf(stderr, "mount --bind %s %s failed: %s\n",
873 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
975c4944
LB
874 if (lock != -1) {
875 flock(lock, LOCK_UN);
876 close(lock);
877 }
a05f6511 878 return -1;
58a3e827
EB
879 }
880 made_netns_run_dir_mount = 1;
881 }
975c4944
LB
882 if (lock != -1) {
883 flock(lock, LOCK_UN);
884 close(lock);
885 }
58a3e827 886
0dc34c77 887 /* Create the filesystem state */
223f4d8e
EB
888 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
889 if (fd < 0) {
55713c8c 890 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
0dc34c77 891 netns_path, strerror(errno));
a05f6511 892 return -1;
0dc34c77 893 }
223f4d8e 894 close(fd);
e3dbcb2a
MC
895
896 if (create) {
80a931d4 897 netns_save();
e3dbcb2a
MC
898 if (unshare(CLONE_NEWNET) < 0) {
899 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
900 name, strerror(errno));
901 goto out_delete;
902 }
903
904 strcpy(proc_path, "/proc/self/ns/net");
905 } else {
906 snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
0dc34c77
EB
907 }
908
909 /* Bind the netns last so I can watch for it */
e3dbcb2a
MC
910 if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
911 fprintf(stderr, "Bind %s -> %s failed: %s\n",
912 proc_path, netns_path, strerror(errno));
0dc34c77
EB
913 goto out_delete;
914 }
b2e29223
MC
915 netns_restore();
916
a05f6511 917 return 0;
0dc34c77 918out_delete:
e3dbcb2a 919 if (create) {
b2e29223 920 netns_restore();
e3dbcb2a
MC
921 netns_delete(argc, argv);
922 } else if (unlink(netns_path) < 0) {
923 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
924 netns_path, strerror(errno));
925 }
a05f6511 926 return -1;
0dc34c77
EB
927}
928
974ef93b 929int set_netnsid_from_name(const char *name, int nsid)
d182ee13
ND
930{
931 struct {
932 struct nlmsghdr n;
933 struct rtgenmsg g;
934 char buf[1024];
d17b136f
PS
935 } req = {
936 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
937 .n.nlmsg_flags = NLM_F_REQUEST,
938 .n.nlmsg_type = RTM_NEWNSID,
939 .g.rtgen_family = AF_UNSPEC,
940 };
d182ee13
ND
941 int fd, err = 0;
942
974ef93b
ND
943 netns_nsid_socket_init();
944
d182ee13
ND
945 fd = netns_get_fd(name);
946 if (fd < 0)
947 return fd;
948
949 addattr32(&req.n, 1024, NETNSA_FD, fd);
950 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
86bf43c7 951 if (rtnl_talk(&rth, &req.n, NULL) < 0)
d182ee13
ND
952 err = -2;
953
954 close(fd);
955 return err;
956}
957
958static int netns_set(int argc, char **argv)
959{
ea343669 960 char netns_path[PATH_MAX];
d182ee13 961 const char *name;
ebe3ce2f 962 int netns, nsid;
d182ee13
ND
963
964 if (argc < 1) {
965 fprintf(stderr, "No netns name specified\n");
966 return -1;
967 }
968 if (argc < 2) {
969 fprintf(stderr, "No nsid specified\n");
970 return -1;
971 }
972 name = argv[0];
375d51ca
CB
973 /* If a negative nsid is specified the kernel will select the nsid. */
974 if (strcmp(argv[1], "auto") == 0)
975 nsid = -1;
ebe3ce2f 976 else if (get_integer(&nsid, argv[1], 0))
d0b645a5 977 invarg("Invalid \"netnsid\" value", argv[1]);
ebe3ce2f 978 else if (nsid < 0)
d0b645a5 979 invarg("\"netnsid\" value should be >= 0", argv[1]);
d182ee13
ND
980
981 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
982 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
983 if (netns < 0) {
984 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
985 name, strerror(errno));
986 return -1;
987 }
988
989 return set_netnsid_from_name(name, nsid);
990}
0dc34c77
EB
991
992static int netns_monitor(int argc, char **argv)
993{
994 char buf[4096];
995 struct inotify_event *event;
996 int fd;
56f5daac 997
0dc34c77
EB
998 fd = inotify_init();
999 if (fd < 0) {
1000 fprintf(stderr, "inotify_init failed: %s\n",
1001 strerror(errno));
a05f6511 1002 return -1;
0dc34c77 1003 }
c1cbb18a 1004
1005 if (create_netns_dir())
1006 return -1;
1007
0dc34c77
EB
1008 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
1009 fprintf(stderr, "inotify_add_watch failed: %s\n",
1010 strerror(errno));
a05f6511 1011 return -1;
0dc34c77 1012 }
56f5daac 1013 for (;;) {
0dc34c77 1014 ssize_t len = read(fd, buf, sizeof(buf));
56f5daac 1015
0dc34c77
EB
1016 if (len < 0) {
1017 fprintf(stderr, "read failed: %s\n",
1018 strerror(errno));
a05f6511 1019 return -1;
0dc34c77
EB
1020 }
1021 for (event = (struct inotify_event *)buf;
1022 (char *)event < &buf[len];
1023 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
1024 if (event->mask & IN_CREATE)
1025 printf("add %s\n", event->name);
1026 if (event->mask & IN_DELETE)
1027 printf("delete %s\n", event->name);
1028 }
1029 }
a05f6511 1030 return 0;
0dc34c77
EB
1031}
1032
79928fd0
MC
1033static int invalid_name(const char *name)
1034{
d3f0b091
MC
1035 return !*name || strlen(name) > NAME_MAX ||
1036 strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
79928fd0
MC
1037}
1038
0dc34c77
EB
1039int do_netns(int argc, char **argv)
1040{
e29a8e05 1041 netns_nsid_socket_init();
d652ccbf 1042
e29a8e05
AA
1043 if (argc < 1) {
1044 netns_map_init();
0dc34c77 1045 return netns_list(0, NULL);
e29a8e05 1046 }
0dc34c77 1047
b7f28e0b 1048 if (!do_all && argc > 1 && invalid_name(argv[1])) {
79928fd0
MC
1049 fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
1050 exit(-1);
1051 }
1052
0dc34c77 1053 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
e29a8e05
AA
1054 (matches(*argv, "lst") == 0)) {
1055 netns_map_init();
0dc34c77 1056 return netns_list(argc-1, argv+1);
e29a8e05 1057 }
0dc34c77 1058
e29a8e05
AA
1059 if ((matches(*argv, "list-id") == 0)) {
1060 netns_map_init();
d652ccbf 1061 return netns_list_id(argc-1, argv+1);
e29a8e05 1062 }
d652ccbf 1063
0dc34c77 1064 if (matches(*argv, "help") == 0)
8e2d47dc 1065 return usage();
0dc34c77
EB
1066
1067 if (matches(*argv, "add") == 0)
e3dbcb2a 1068 return netns_add(argc-1, argv+1, true);
0dc34c77 1069
d182ee13
ND
1070 if (matches(*argv, "set") == 0)
1071 return netns_set(argc-1, argv+1);
1072
0dc34c77
EB
1073 if (matches(*argv, "delete") == 0)
1074 return netns_delete(argc-1, argv+1);
1075
9a7b3d91
EB
1076 if (matches(*argv, "identify") == 0)
1077 return netns_identify(argc-1, argv+1);
1078
1079 if (matches(*argv, "pids") == 0)
1080 return netns_pids(argc-1, argv+1);
1081
0dc34c77
EB
1082 if (matches(*argv, "exec") == 0)
1083 return netns_exec(argc-1, argv+1);
1084
1085 if (matches(*argv, "monitor") == 0)
1086 return netns_monitor(argc-1, argv+1);
1087
e3dbcb2a
MC
1088 if (matches(*argv, "attach") == 0)
1089 return netns_add(argc-1, argv+1, false);
1090
0dc34c77 1091 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
a05f6511 1092 exit(-1);
0dc34c77 1093}