blob: 019f954cc6f2a527b40ac4e4626dd5fea14c150c [file] [log] [blame]
Eric W. Biederman0dc34c72011-07-13 09:48:26 -07001#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/param.h>
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>
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +000016#include <ctype.h>
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020017#include <linux/limits.h>
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070018
Nicolas Dichteld182ee12015-02-17 17:30:37 +010019#include <linux/net_namespace.h>
20
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070021#include "utils.h"
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020022#include "hlist.h"
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070023#include "ip_common.h"
Vadim Kochaneb67e442014-12-24 23:04:08 +020024#include "namespace.h"
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070025
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +000026static int usage(void)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070027{
28 fprintf(stderr, "Usage: ip netns list\n");
29 fprintf(stderr, " ip netns add NAME\n");
Nicolas Dichteld182ee12015-02-17 17:30:37 +010030 fprintf(stderr, " ip netns set NAME NETNSID\n");
Vadim Kochan33724932015-01-18 16:10:19 +020031 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
vadimk0948adc2014-11-07 18:25:30 +020032 fprintf(stderr, " ip netns identify [PID]\n");
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +000033 fprintf(stderr, " ip netns pids NAME\n");
Vadim Kochanb13ba032015-01-18 16:10:18 +020034 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070035 fprintf(stderr, " ip netns monitor\n");
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020036 fprintf(stderr, " ip netns list-id\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -070037 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070038}
39
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020040/* This socket is used to get nsid */
41static struct rtnl_handle rtnsh = { .fd = -1 };
42
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020043static int have_rtnl_getnsid = -1;
44
45static int ipnetns_accept_msg(const struct sockaddr_nl *who,
Nicolas Dichtel0628cdd2015-05-20 16:19:58 +020046 struct rtnl_ctrl_data *ctrl,
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020047 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];
65 } req;
66 int fd;
67
68 if (have_rtnl_getnsid < 0) {
69 memset(&req, 0, sizeof(req));
70 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
71 req.n.nlmsg_flags = NLM_F_REQUEST;
72 req.n.nlmsg_type = RTM_GETNSID;
73 req.g.rtgen_family = AF_UNSPEC;
74
75 fd = open("/proc/self/ns/net", O_RDONLY);
76 if (fd < 0) {
77 perror("open(\"/proc/self/ns/net\")");
78 exit(1);
79 }
80
81 addattr32(&req.n, 1024, NETNSA_FD, fd);
82
83 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
84 perror("request send failed");
85 exit(1);
86 }
87 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
88 close(fd);
89 }
90
91 return have_rtnl_getnsid;
92}
93
Nicolas Dichteld182ee12015-02-17 17:30:37 +010094static int get_netnsid_from_name(const char *name)
95{
96 struct {
97 struct nlmsghdr n;
98 struct rtgenmsg g;
99 char buf[1024];
100 } req, answer;
101 struct rtattr *tb[NETNSA_MAX + 1];
102 struct rtgenmsg *rthdr;
103 int len, fd;
104
105 memset(&req, 0, sizeof(req));
106 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
107 req.n.nlmsg_flags = NLM_F_REQUEST;
108 req.n.nlmsg_type = RTM_GETNSID;
109 req.g.rtgen_family = AF_UNSPEC;
110
111 fd = netns_get_fd(name);
112 if (fd < 0)
113 return fd;
114
115 addattr32(&req.n, 1024, NETNSA_FD, fd);
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200116 if (rtnl_talk(&rtnsh, &req.n, 0, 0, &answer.n) < 0) {
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100117 close(fd);
118 return -2;
119 }
120 close(fd);
121
122 /* Validate message and parse attributes */
123 if (answer.n.nlmsg_type == NLMSG_ERROR)
124 return -1;
125
126 rthdr = NLMSG_DATA(&answer.n);
127 len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
128 if (len < 0)
129 return -1;
130
131 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
132
133 if (tb[NETNSA_NSID])
134 return rta_getattr_u32(tb[NETNSA_NSID]);
135
136 return -1;
137}
138
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200139struct nsid_cache {
140 struct hlist_node nsid_hash;
141 struct hlist_node name_hash;
142 int nsid;
143 char name[NAME_MAX];
144};
145
146#define NSIDMAP_SIZE 128
147#define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
148#define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
149
150static struct hlist_head nsid_head[NSIDMAP_SIZE];
151static struct hlist_head name_head[NSIDMAP_SIZE];
152
153static struct nsid_cache *netns_map_get_by_nsid(int nsid)
154{
155 uint32_t h = NSID_HASH_NSID(nsid);
156 struct hlist_node *n;
157
158 hlist_for_each(n, &nsid_head[h]) {
159 struct nsid_cache *c = container_of(n, struct nsid_cache,
160 nsid_hash);
161 if (c->nsid == nsid)
162 return c;
163 }
164
165 return NULL;
166}
167
168static int netns_map_add(int nsid, char *name)
169{
170 struct nsid_cache *c;
171 uint32_t h;
172
173 if (netns_map_get_by_nsid(nsid) != NULL)
174 return -EEXIST;
175
176 c = malloc(sizeof(*c));
177 if (c == NULL) {
178 perror("malloc");
179 return -ENOMEM;
180 }
181 c->nsid = nsid;
182 strcpy(c->name, name);
183
184 h = NSID_HASH_NSID(nsid);
185 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
186
187 h = NSID_HASH_NAME(name);
188 hlist_add_head(&c->name_hash, &name_head[h]);
189
190 return 0;
191}
192
193static void netns_map_del(struct nsid_cache *c)
194{
195 hlist_del(&c->name_hash);
196 hlist_del(&c->nsid_hash);
197 free(c);
198}
199
200void netns_map_init(void)
201{
202 static int initialized;
203 struct dirent *entry;
204 DIR *dir;
205 int nsid;
206
207 if (initialized || !ipnetns_have_nsid())
208 return;
209
210 if (rtnl_open(&rtnsh, 0) < 0) {
211 fprintf(stderr, "Cannot open rtnetlink\n");
212 exit(1);
213 }
214
215 dir = opendir(NETNS_RUN_DIR);
216 if (!dir)
217 return;
218
219 while ((entry = readdir(dir)) != NULL) {
220 if (strcmp(entry->d_name, ".") == 0)
221 continue;
222 if (strcmp(entry->d_name, "..") == 0)
223 continue;
224 nsid = get_netnsid_from_name(entry->d_name);
225
226 if (nsid >= 0)
227 netns_map_add(nsid, entry->d_name);
228 }
229 closedir(dir);
230 initialized = 1;
231}
232
233static int netns_get_name(int nsid, char *name)
234{
235 struct dirent *entry;
236 DIR *dir;
237 int id;
238
239 dir = opendir(NETNS_RUN_DIR);
240 if (!dir)
241 return -ENOENT;
242
243 while ((entry = readdir(dir)) != NULL) {
244 if (strcmp(entry->d_name, ".") == 0)
245 continue;
246 if (strcmp(entry->d_name, "..") == 0)
247 continue;
248 id = get_netnsid_from_name(entry->d_name);
249
250 if (nsid == id) {
251 strcpy(name, entry->d_name);
252 closedir(dir);
253 return 0;
254 }
255 }
256 closedir(dir);
257 return -ENOENT;
258}
259
260int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
261{
262 struct rtgenmsg *rthdr = NLMSG_DATA(n);
263 struct rtattr *tb[NETNSA_MAX+1];
264 int len = n->nlmsg_len;
265 FILE *fp = (FILE *)arg;
266 struct nsid_cache *c;
267 char name[NAME_MAX];
268 int nsid;
269
270 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
271 return 0;
272
273 len -= NLMSG_SPACE(sizeof(*rthdr));
274 if (len < 0) {
275 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
276 __func__);
277 return -1;
278 }
279
280 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
281 if (tb[NETNSA_NSID] == NULL) {
282 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
283 return -1;
284 }
285
286 if (n->nlmsg_type == RTM_DELNSID)
287 fprintf(fp, "Deleted ");
288
289 nsid = rta_getattr_u32(tb[NETNSA_NSID]);
290 fprintf(fp, "nsid %u ", nsid);
291
292 c = netns_map_get_by_nsid(nsid);
293 if (c != NULL) {
294 fprintf(fp, "(iproute2 netns name: %s)", c->name);
295 netns_map_del(c);
296 }
297
298 /* During 'ip monitor nsid', no chance to have new nsid in cache. */
299 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
300 if (netns_get_name(nsid, name) == 0) {
301 fprintf(fp, "(iproute2 netns name: %s)", name);
302 netns_map_add(nsid, name);
303 }
304
305 fprintf(fp, "\n");
306 fflush(fp);
307 return 0;
308}
309
310static int netns_list_id(int argc, char **argv)
311{
312 if (!ipnetns_have_nsid()) {
313 fprintf(stderr,
314 "RTM_GETNSID is not supported by the kernel.\n");
315 return -ENOTSUP;
316 }
317
318 if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETNSID) < 0) {
319 perror("Cannot send dump request");
320 exit(1);
321 }
322 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
323 fprintf(stderr, "Dump terminated\n");
324 exit(1);
325 }
326 return 0;
327}
328
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700329static int netns_list(int argc, char **argv)
330{
331 struct dirent *entry;
332 DIR *dir;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100333 int id;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700334
335 dir = opendir(NETNS_RUN_DIR);
336 if (!dir)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700337 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700338
339 while ((entry = readdir(dir)) != NULL) {
340 if (strcmp(entry->d_name, ".") == 0)
341 continue;
342 if (strcmp(entry->d_name, "..") == 0)
343 continue;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100344 printf("%s", entry->d_name);
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +0200345 if (ipnetns_have_nsid()) {
346 id = get_netnsid_from_name(entry->d_name);
347 if (id >= 0)
348 printf(" (id: %d)", id);
349 }
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100350 printf("\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700351 }
352 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700353 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700354}
355
Vadim Kochanb13ba032015-01-18 16:10:18 +0200356static int cmd_exec(const char *cmd, char **argv, bool do_fork)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700357{
JunweiZhang95592b42013-07-09 08:55:20 -0700358 fflush(stdout);
Vadim Kochanb13ba032015-01-18 16:10:18 +0200359 if (do_fork) {
JunweiZhang95592b42013-07-09 08:55:20 -0700360 int status;
361 pid_t pid;
362
363 pid = fork();
364 if (pid < 0) {
365 perror("fork");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700366 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700367 }
368
369 if (pid != 0) {
370 /* Parent */
371 if (waitpid(pid, &status, 0) < 0) {
372 perror("waitpid");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700373 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700374 }
375
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200376 if (WIFEXITED(status)) {
Vadim Kochanb13ba032015-01-18 16:10:18 +0200377 return WEXITSTATUS(status);
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200378 }
JunweiZhang95592b42013-07-09 08:55:20 -0700379
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200380 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700381 }
382 }
383
Vadim Kochanb13ba032015-01-18 16:10:18 +0200384 if (execvp(cmd, argv) < 0)
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000385 fprintf(stderr, "exec of \"%s\" failed: %s\n",
Vadim Kochanb13ba032015-01-18 16:10:18 +0200386 cmd, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700387 _exit(1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700388}
389
Vadim Kochanb13ba032015-01-18 16:10:18 +0200390static int on_netns_exec(char *nsname, void *arg)
391{
392 char **argv = arg;
393 cmd_exec(argv[1], argv + 1, true);
394 return 0;
395}
396
397static int netns_exec(int argc, char **argv)
398{
399 /* Setup the proper environment for apps that are not netns
400 * aware, and execute a program in that environment.
401 */
402 const char *cmd;
403
404 if (argc < 1 && !do_all) {
405 fprintf(stderr, "No netns name specified\n");
406 return -1;
407 }
408 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
409 fprintf(stderr, "No command specified\n");
410 return -1;
411 }
412
413 if (do_all)
414 return do_each_netns(on_netns_exec, --argv, 1);
415
416 if (netns_switch(argv[0]))
417 return -1;
418
419 /* ip must return the status of the child,
420 * but do_cmd() will add a minus to this,
421 * so let's add another one here to cancel it.
422 */
423 cmd = argv[1];
424 return -cmd_exec(cmd, argv + 1, !!batch_mode);
425}
426
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000427static int is_pid(const char *str)
428{
429 int ch;
430 for (; (ch = *str); str++) {
431 if (!isdigit(ch))
432 return 0;
433 }
434 return 1;
435}
436
437static int netns_pids(int argc, char **argv)
438{
439 const char *name;
440 char net_path[MAXPATHLEN];
441 int netns;
442 struct stat netst;
443 DIR *dir;
444 struct dirent *entry;
445
446 if (argc < 1) {
447 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700448 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000449 }
450 if (argc > 1) {
451 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700452 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000453 }
454
455 name = argv[0];
456 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
457 netns = open(net_path, O_RDONLY);
458 if (netns < 0) {
459 fprintf(stderr, "Cannot open network namespace: %s\n",
460 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700461 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000462 }
463 if (fstat(netns, &netst) < 0) {
464 fprintf(stderr, "Stat of netns failed: %s\n",
465 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700466 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000467 }
468 dir = opendir("/proc/");
469 if (!dir) {
470 fprintf(stderr, "Open of /proc failed: %s\n",
471 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700472 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000473 }
474 while((entry = readdir(dir))) {
475 char pid_net_path[MAXPATHLEN];
476 struct stat st;
477 if (!is_pid(entry->d_name))
478 continue;
479 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
480 entry->d_name);
481 if (stat(pid_net_path, &st) != 0)
482 continue;
483 if ((st.st_dev == netst.st_dev) &&
484 (st.st_ino == netst.st_ino)) {
485 printf("%s\n", entry->d_name);
486 }
487 }
488 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700489 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800490
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000491}
492
493static int netns_identify(int argc, char **argv)
494{
495 const char *pidstr;
496 char net_path[MAXPATHLEN];
497 int netns;
498 struct stat netst;
499 DIR *dir;
500 struct dirent *entry;
501
502 if (argc < 1) {
vadimk0948adc2014-11-07 18:25:30 +0200503 pidstr = "self";
504 } else if (argc > 1) {
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000505 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700506 return -1;
vadimk0948adc2014-11-07 18:25:30 +0200507 } else {
508 pidstr = argv[0];
509 if (!is_pid(pidstr)) {
510 fprintf(stderr, "Specified string '%s' is not a pid\n",
511 pidstr);
512 return -1;
513 }
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000514 }
515
516 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
517 netns = open(net_path, O_RDONLY);
518 if (netns < 0) {
519 fprintf(stderr, "Cannot open network namespace: %s\n",
520 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700521 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000522 }
523 if (fstat(netns, &netst) < 0) {
524 fprintf(stderr, "Stat of netns failed: %s\n",
525 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700526 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000527 }
528 dir = opendir(NETNS_RUN_DIR);
529 if (!dir) {
530 /* Succeed treat a missing directory as an empty directory */
531 if (errno == ENOENT)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700532 return 0;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000533
534 fprintf(stderr, "Failed to open directory %s:%s\n",
535 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700536 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000537 }
538
539 while((entry = readdir(dir))) {
540 char name_path[MAXPATHLEN];
541 struct stat st;
542
543 if (strcmp(entry->d_name, ".") == 0)
544 continue;
545 if (strcmp(entry->d_name, "..") == 0)
546 continue;
547
548 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
549 entry->d_name);
550
551 if (stat(name_path, &st) != 0)
552 continue;
553
554 if ((st.st_dev == netst.st_dev) &&
555 (st.st_ino == netst.st_ino)) {
556 printf("%s\n", entry->d_name);
557 }
558 }
559 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700560 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800561
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000562}
563
Vadim Kochan33724932015-01-18 16:10:19 +0200564static int on_netns_del(char *nsname, void *arg)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700565{
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700566 char netns_path[MAXPATHLEN];
567
Vadim Kochan33724932015-01-18 16:10:19 +0200568 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700569 umount2(netns_path, MNT_DETACH);
570 if (unlink(netns_path) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000571 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700572 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700573 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700574 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700575 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700576}
577
Vadim Kochan33724932015-01-18 16:10:19 +0200578static int netns_delete(int argc, char **argv)
579{
580 if (argc < 1 && !do_all) {
581 fprintf(stderr, "No netns name specified\n");
582 return -1;
583 }
584
585 if (do_all)
586 return netns_foreach(on_netns_del, NULL);
587
588 return on_netns_del(argv[0], NULL);
589}
590
vadimkc1cbb182014-08-31 22:45:29 +0300591static int create_netns_dir(void)
592{
593 /* Create the base netns directory if it doesn't exist */
594 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
595 if (errno != EEXIST) {
596 fprintf(stderr, "mkdir %s failed: %s\n",
597 NETNS_RUN_DIR, strerror(errno));
598 return -1;
599 }
600 }
601
602 return 0;
603}
604
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700605static int netns_add(int argc, char **argv)
606{
607 /* This function creates a new network namespace and
608 * a new mount namespace and bind them into a well known
609 * location in the filesystem based on the name provided.
610 *
611 * The mount namespace is created so that any necessary
612 * userspace tweaks like remounting /sys, or bind mounting
613 * a new /etc/resolv.conf can be shared between uers.
614 */
615 char netns_path[MAXPATHLEN];
616 const char *name;
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000617 int fd;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000618 int made_netns_run_dir_mount = 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700619
620 if (argc < 1) {
621 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700622 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700623 }
624 name = argv[0];
625
626 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
627
vadimkc1cbb182014-08-31 22:45:29 +0300628 if (create_netns_dir())
629 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700630
Stephen Hemmingerd259f032013-08-04 15:00:56 -0700631 /* Make it possible for network namespace mounts to propagate between
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000632 * mount namespaces. This makes it likely that a unmounting a network
633 * namespace file in one namespace will unmount the network namespace
634 * file in all namespaces allowing the network namespace to be freed
635 * sooner.
636 */
637 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
638 /* Fail unless we need to make the mount point */
639 if (errno != EINVAL || made_netns_run_dir_mount) {
640 fprintf(stderr, "mount --make-shared %s failed: %s\n",
641 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700642 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000643 }
644
645 /* Upgrade NETNS_RUN_DIR to a mount point */
646 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) {
647 fprintf(stderr, "mount --bind %s %s failed: %s\n",
648 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700649 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000650 }
651 made_netns_run_dir_mount = 1;
652 }
653
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700654 /* Create the filesystem state */
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000655 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
656 if (fd < 0) {
Mike Rapoport55713c82014-05-11 12:21:26 +0300657 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700658 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700659 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700660 }
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000661 close(fd);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700662 if (unshare(CLONE_NEWNET) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000663 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
664 name, strerror(errno));
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700665 goto out_delete;
666 }
667
668 /* Bind the netns last so I can watch for it */
669 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
670 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
671 netns_path, strerror(errno));
672 goto out_delete;
673 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700674 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700675out_delete:
676 netns_delete(argc, argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700677 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700678}
679
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100680static int set_netnsid_from_name(const char *name, int nsid)
681{
682 struct {
683 struct nlmsghdr n;
684 struct rtgenmsg g;
685 char buf[1024];
686 } req;
687 int fd, err = 0;
688
689 memset(&req, 0, sizeof(req));
690 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
691 req.n.nlmsg_flags = NLM_F_REQUEST;
692 req.n.nlmsg_type = RTM_NEWNSID;
693 req.g.rtgen_family = AF_UNSPEC;
694
695 fd = netns_get_fd(name);
696 if (fd < 0)
697 return fd;
698
699 addattr32(&req.n, 1024, NETNSA_FD, fd);
700 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
701 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
702 err = -2;
703
704 close(fd);
705 return err;
706}
707
708static int netns_set(int argc, char **argv)
709{
710 char netns_path[MAXPATHLEN];
711 const char *name;
712 int netns, nsid;
713
714 if (argc < 1) {
715 fprintf(stderr, "No netns name specified\n");
716 return -1;
717 }
718 if (argc < 2) {
719 fprintf(stderr, "No nsid specified\n");
720 return -1;
721 }
722 name = argv[0];
723 nsid = atoi(argv[1]);
724
725 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
726 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
727 if (netns < 0) {
728 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
729 name, strerror(errno));
730 return -1;
731 }
732
733 return set_netnsid_from_name(name, nsid);
734}
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700735
736static int netns_monitor(int argc, char **argv)
737{
738 char buf[4096];
739 struct inotify_event *event;
740 int fd;
741 fd = inotify_init();
742 if (fd < 0) {
743 fprintf(stderr, "inotify_init failed: %s\n",
744 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700745 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700746 }
vadimkc1cbb182014-08-31 22:45:29 +0300747
748 if (create_netns_dir())
749 return -1;
750
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700751 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
752 fprintf(stderr, "inotify_add_watch failed: %s\n",
753 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700754 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700755 }
756 for(;;) {
757 ssize_t len = read(fd, buf, sizeof(buf));
758 if (len < 0) {
759 fprintf(stderr, "read failed: %s\n",
760 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700761 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700762 }
763 for (event = (struct inotify_event *)buf;
764 (char *)event < &buf[len];
765 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
766 if (event->mask & IN_CREATE)
767 printf("add %s\n", event->name);
768 if (event->mask & IN_DELETE)
769 printf("delete %s\n", event->name);
770 }
771 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700772 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700773}
774
775int do_netns(int argc, char **argv)
776{
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200777 netns_map_init();
778
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700779 if (argc < 1)
780 return netns_list(0, NULL);
781
782 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
783 (matches(*argv, "lst") == 0))
784 return netns_list(argc-1, argv+1);
785
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200786 if ((matches(*argv, "list-id") == 0))
787 return netns_list_id(argc-1, argv+1);
788
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700789 if (matches(*argv, "help") == 0)
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +0000790 return usage();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700791
792 if (matches(*argv, "add") == 0)
793 return netns_add(argc-1, argv+1);
794
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100795 if (matches(*argv, "set") == 0)
796 return netns_set(argc-1, argv+1);
797
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700798 if (matches(*argv, "delete") == 0)
799 return netns_delete(argc-1, argv+1);
800
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000801 if (matches(*argv, "identify") == 0)
802 return netns_identify(argc-1, argv+1);
803
804 if (matches(*argv, "pids") == 0)
805 return netns_pids(argc-1, argv+1);
806
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700807 if (matches(*argv, "exec") == 0)
808 return netns_exec(argc-1, argv+1);
809
810 if (matches(*argv, "monitor") == 0)
811 return netns_monitor(argc-1, argv+1);
812
813 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700814 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700815}