blob: b3ee23c23aaa22d337266f800e2168ea2961d4a0 [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>
Eric W. Biederman0dc34c72011-07-13 09:48:26 -07007#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>
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +000015#include <ctype.h>
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020016#include <linux/limits.h>
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070017
Nicolas Dichteld182ee12015-02-17 17:30:37 +010018#include <linux/net_namespace.h>
19
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070020#include "utils.h"
Jiri Pirko4952b452016-03-22 10:02:20 +010021#include "list.h"
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070022#include "ip_common.h"
Vadim Kochaneb67e442014-12-24 23:04:08 +020023#include "namespace.h"
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070024
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +000025static int usage(void)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070026{
27 fprintf(stderr, "Usage: ip netns list\n");
28 fprintf(stderr, " ip netns add NAME\n");
Nicolas Dichteld182ee12015-02-17 17:30:37 +010029 fprintf(stderr, " ip netns set NAME NETNSID\n");
Vadim Kochan33724932015-01-18 16:10:19 +020030 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
vadimk0948adc2014-11-07 18:25:30 +020031 fprintf(stderr, " ip netns identify [PID]\n");
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +000032 fprintf(stderr, " ip netns pids NAME\n");
Vadim Kochanb13ba032015-01-18 16:10:18 +020033 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070034 fprintf(stderr, " ip netns monitor\n");
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020035 fprintf(stderr, " ip netns list-id\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -070036 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070037}
38
Nicolas Dichteld652ccb2015-04-15 14:23:22 +020039/* This socket is used to get nsid */
40static struct rtnl_handle rtnsh = { .fd = -1 };
41
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020042static int have_rtnl_getnsid = -1;
43
44static int ipnetns_accept_msg(const struct sockaddr_nl *who,
Nicolas Dichtel0628cdd2015-05-20 16:19:58 +020045 struct rtnl_ctrl_data *ctrl,
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020046 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
58static 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
Nicolas Dichteld182ee12015-02-17 17:30:37 +010093static 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);
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700115 if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100116 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
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200138struct nsid_cache {
139 struct hlist_node nsid_hash;
140 struct hlist_node name_hash;
141 int nsid;
Stephen Hemminger2f29d6b2015-08-12 08:35:54 -0700142 char name[0];
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200143};
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
149static struct hlist_head nsid_head[NSIDMAP_SIZE];
150static struct hlist_head name_head[NSIDMAP_SIZE];
151
152static 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
Stephen Hemminger2f29d6b2015-08-12 08:35:54 -0700167static int netns_map_add(int nsid, const char *name)
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200168{
169 struct nsid_cache *c;
170 uint32_t h;
171
172 if (netns_map_get_by_nsid(nsid) != NULL)
173 return -EEXIST;
174
Nicolas Cavallaria1b4a272016-02-12 14:47:39 +0100175 c = malloc(sizeof(*c) + strlen(name) + 1);
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200176 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
192static 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
199void 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
232static 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
259int 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
309static 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
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700328static int netns_list(int argc, char **argv)
329{
330 struct dirent *entry;
331 DIR *dir;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100332 int id;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700333
334 dir = opendir(NETNS_RUN_DIR);
335 if (!dir)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700336 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700337
338 while ((entry = readdir(dir)) != NULL) {
339 if (strcmp(entry->d_name, ".") == 0)
340 continue;
341 if (strcmp(entry->d_name, "..") == 0)
342 continue;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100343 printf("%s", entry->d_name);
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +0200344 if (ipnetns_have_nsid()) {
345 id = get_netnsid_from_name(entry->d_name);
346 if (id >= 0)
347 printf(" (id: %d)", id);
348 }
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100349 printf("\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700350 }
351 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700352 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700353}
354
Vadim Kochanb13ba032015-01-18 16:10:18 +0200355static int cmd_exec(const char *cmd, char **argv, bool do_fork)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700356{
JunweiZhang95592b42013-07-09 08:55:20 -0700357 fflush(stdout);
Vadim Kochanb13ba032015-01-18 16:10:18 +0200358 if (do_fork) {
JunweiZhang95592b42013-07-09 08:55:20 -0700359 int status;
360 pid_t pid;
361
362 pid = fork();
363 if (pid < 0) {
364 perror("fork");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700365 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700366 }
367
368 if (pid != 0) {
369 /* Parent */
370 if (waitpid(pid, &status, 0) < 0) {
371 perror("waitpid");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700372 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700373 }
374
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200375 if (WIFEXITED(status)) {
Vadim Kochanb13ba032015-01-18 16:10:18 +0200376 return WEXITSTATUS(status);
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200377 }
JunweiZhang95592b42013-07-09 08:55:20 -0700378
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200379 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700380 }
381 }
382
Vadim Kochanb13ba032015-01-18 16:10:18 +0200383 if (execvp(cmd, argv) < 0)
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000384 fprintf(stderr, "exec of \"%s\" failed: %s\n",
Vadim Kochanb13ba032015-01-18 16:10:18 +0200385 cmd, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700386 _exit(1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700387}
388
Vadim Kochanb13ba032015-01-18 16:10:18 +0200389static int on_netns_exec(char *nsname, void *arg)
390{
391 char **argv = arg;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700392
Vadim Kochanb13ba032015-01-18 16:10:18 +0200393 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;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700430
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000431 for (; (ch = *str); str++) {
432 if (!isdigit(ch))
433 return 0;
434 }
435 return 1;
436}
437
438static int netns_pids(int argc, char **argv)
439{
440 const char *name;
Felix Jandaea343662015-07-26 21:25:32 +0200441 char net_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000442 int netns;
443 struct stat netst;
444 DIR *dir;
445 struct dirent *entry;
446
447 if (argc < 1) {
448 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700449 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000450 }
451 if (argc > 1) {
452 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700453 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000454 }
455
456 name = argv[0];
457 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
458 netns = open(net_path, O_RDONLY);
459 if (netns < 0) {
460 fprintf(stderr, "Cannot open network namespace: %s\n",
461 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700462 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000463 }
464 if (fstat(netns, &netst) < 0) {
465 fprintf(stderr, "Stat of netns failed: %s\n",
466 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700467 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000468 }
469 dir = opendir("/proc/");
470 if (!dir) {
471 fprintf(stderr, "Open of /proc failed: %s\n",
472 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700473 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000474 }
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700475 while ((entry = readdir(dir))) {
Felix Jandaea343662015-07-26 21:25:32 +0200476 char pid_net_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000477 struct stat st;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700478
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000479 if (!is_pid(entry->d_name))
480 continue;
481 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
482 entry->d_name);
483 if (stat(pid_net_path, &st) != 0)
484 continue;
485 if ((st.st_dev == netst.st_dev) &&
486 (st.st_ino == netst.st_ino)) {
487 printf("%s\n", entry->d_name);
488 }
489 }
490 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700491 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800492
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000493}
494
495static int netns_identify(int argc, char **argv)
496{
497 const char *pidstr;
Felix Jandaea343662015-07-26 21:25:32 +0200498 char net_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000499 int netns;
500 struct stat netst;
501 DIR *dir;
502 struct dirent *entry;
503
504 if (argc < 1) {
vadimk0948adc2014-11-07 18:25:30 +0200505 pidstr = "self";
506 } else if (argc > 1) {
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000507 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700508 return -1;
vadimk0948adc2014-11-07 18:25:30 +0200509 } else {
510 pidstr = argv[0];
511 if (!is_pid(pidstr)) {
512 fprintf(stderr, "Specified string '%s' is not a pid\n",
513 pidstr);
514 return -1;
515 }
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000516 }
517
518 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
519 netns = open(net_path, O_RDONLY);
520 if (netns < 0) {
521 fprintf(stderr, "Cannot open network namespace: %s\n",
522 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700523 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000524 }
525 if (fstat(netns, &netst) < 0) {
526 fprintf(stderr, "Stat of netns failed: %s\n",
527 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700528 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000529 }
530 dir = opendir(NETNS_RUN_DIR);
531 if (!dir) {
532 /* Succeed treat a missing directory as an empty directory */
533 if (errno == ENOENT)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700534 return 0;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000535
536 fprintf(stderr, "Failed to open directory %s:%s\n",
537 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700538 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000539 }
540
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700541 while ((entry = readdir(dir))) {
Felix Jandaea343662015-07-26 21:25:32 +0200542 char name_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000543 struct stat st;
544
545 if (strcmp(entry->d_name, ".") == 0)
546 continue;
547 if (strcmp(entry->d_name, "..") == 0)
548 continue;
549
550 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
551 entry->d_name);
552
553 if (stat(name_path, &st) != 0)
554 continue;
555
556 if ((st.st_dev == netst.st_dev) &&
557 (st.st_ino == netst.st_ino)) {
558 printf("%s\n", entry->d_name);
559 }
560 }
561 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700562 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800563
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000564}
565
Vadim Kochan33724932015-01-18 16:10:19 +0200566static int on_netns_del(char *nsname, void *arg)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700567{
Felix Jandaea343662015-07-26 21:25:32 +0200568 char netns_path[PATH_MAX];
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700569
Vadim Kochan33724932015-01-18 16:10:19 +0200570 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700571 umount2(netns_path, MNT_DETACH);
572 if (unlink(netns_path) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000573 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700574 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700575 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700576 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700577 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700578}
579
Vadim Kochan33724932015-01-18 16:10:19 +0200580static int netns_delete(int argc, char **argv)
581{
582 if (argc < 1 && !do_all) {
583 fprintf(stderr, "No netns name specified\n");
584 return -1;
585 }
586
587 if (do_all)
588 return netns_foreach(on_netns_del, NULL);
589
590 return on_netns_del(argv[0], NULL);
591}
592
vadimkc1cbb182014-08-31 22:45:29 +0300593static int create_netns_dir(void)
594{
595 /* Create the base netns directory if it doesn't exist */
596 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
597 if (errno != EEXIST) {
598 fprintf(stderr, "mkdir %s failed: %s\n",
599 NETNS_RUN_DIR, strerror(errno));
600 return -1;
601 }
602 }
603
604 return 0;
605}
606
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700607static int netns_add(int argc, char **argv)
608{
609 /* This function creates a new network namespace and
610 * a new mount namespace and bind them into a well known
611 * location in the filesystem based on the name provided.
612 *
613 * The mount namespace is created so that any necessary
614 * userspace tweaks like remounting /sys, or bind mounting
615 * a new /etc/resolv.conf can be shared between uers.
616 */
Felix Jandaea343662015-07-26 21:25:32 +0200617 char netns_path[PATH_MAX];
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700618 const char *name;
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000619 int fd;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000620 int made_netns_run_dir_mount = 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700621
622 if (argc < 1) {
623 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700624 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700625 }
626 name = argv[0];
627
628 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
629
vadimkc1cbb182014-08-31 22:45:29 +0300630 if (create_netns_dir())
631 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700632
Stephen Hemmingerd259f032013-08-04 15:00:56 -0700633 /* Make it possible for network namespace mounts to propagate between
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000634 * mount namespaces. This makes it likely that a unmounting a network
635 * namespace file in one namespace will unmount the network namespace
636 * file in all namespaces allowing the network namespace to be freed
637 * sooner.
638 */
639 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
640 /* Fail unless we need to make the mount point */
641 if (errno != EINVAL || made_netns_run_dir_mount) {
642 fprintf(stderr, "mount --make-shared %s failed: %s\n",
643 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700644 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000645 }
646
647 /* Upgrade NETNS_RUN_DIR to a mount point */
648 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) {
649 fprintf(stderr, "mount --bind %s %s failed: %s\n",
650 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700651 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000652 }
653 made_netns_run_dir_mount = 1;
654 }
655
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700656 /* Create the filesystem state */
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000657 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
658 if (fd < 0) {
Mike Rapoport55713c82014-05-11 12:21:26 +0300659 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700660 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700661 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700662 }
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000663 close(fd);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700664 if (unshare(CLONE_NEWNET) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000665 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
666 name, strerror(errno));
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700667 goto out_delete;
668 }
669
670 /* Bind the netns last so I can watch for it */
671 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
672 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
673 netns_path, strerror(errno));
674 goto out_delete;
675 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700676 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700677out_delete:
678 netns_delete(argc, argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700679 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700680}
681
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100682static int set_netnsid_from_name(const char *name, int nsid)
683{
684 struct {
685 struct nlmsghdr n;
686 struct rtgenmsg g;
687 char buf[1024];
688 } req;
689 int fd, err = 0;
690
691 memset(&req, 0, sizeof(req));
692 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
693 req.n.nlmsg_flags = NLM_F_REQUEST;
694 req.n.nlmsg_type = RTM_NEWNSID;
695 req.g.rtgen_family = AF_UNSPEC;
696
697 fd = netns_get_fd(name);
698 if (fd < 0)
699 return fd;
700
701 addattr32(&req.n, 1024, NETNSA_FD, fd);
702 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700703 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100704 err = -2;
705
706 close(fd);
707 return err;
708}
709
710static int netns_set(int argc, char **argv)
711{
Felix Jandaea343662015-07-26 21:25:32 +0200712 char netns_path[PATH_MAX];
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100713 const char *name;
714 int netns, nsid;
715
716 if (argc < 1) {
717 fprintf(stderr, "No netns name specified\n");
718 return -1;
719 }
720 if (argc < 2) {
721 fprintf(stderr, "No nsid specified\n");
722 return -1;
723 }
724 name = argv[0];
725 nsid = atoi(argv[1]);
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}
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700737
738static int netns_monitor(int argc, char **argv)
739{
740 char buf[4096];
741 struct inotify_event *event;
742 int fd;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700743
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700744 fd = inotify_init();
745 if (fd < 0) {
746 fprintf(stderr, "inotify_init failed: %s\n",
747 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700748 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700749 }
vadimkc1cbb182014-08-31 22:45:29 +0300750
751 if (create_netns_dir())
752 return -1;
753
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700754 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));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700757 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700758 }
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700759 for (;;) {
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700760 ssize_t len = read(fd, buf, sizeof(buf));
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700761
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700762 if (len < 0) {
763 fprintf(stderr, "read failed: %s\n",
764 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700765 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700766 }
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 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700776 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700777}
778
779int do_netns(int argc, char **argv)
780{
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200781 netns_map_init();
782
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700783 if (argc < 1)
784 return netns_list(0, NULL);
785
786 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
787 (matches(*argv, "lst") == 0))
788 return netns_list(argc-1, argv+1);
789
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200790 if ((matches(*argv, "list-id") == 0))
791 return netns_list_id(argc-1, argv+1);
792
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700793 if (matches(*argv, "help") == 0)
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +0000794 return usage();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700795
796 if (matches(*argv, "add") == 0)
797 return netns_add(argc-1, argv+1);
798
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100799 if (matches(*argv, "set") == 0)
800 return netns_set(argc-1, argv+1);
801
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700802 if (matches(*argv, "delete") == 0)
803 return netns_delete(argc-1, argv+1);
804
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000805 if (matches(*argv, "identify") == 0)
806 return netns_identify(argc-1, argv+1);
807
808 if (matches(*argv, "pids") == 0)
809 return netns_pids(argc-1, argv+1);
810
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700811 if (matches(*argv, "exec") == 0)
812 return netns_exec(argc-1, argv+1);
813
814 if (matches(*argv, "monitor") == 0)
815 return netns_monitor(argc-1, argv+1);
816
817 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700818 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700819}