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