blob: bd1e9013706c417c2dae0171c2ec181e7f93fde7 [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];
Phil Sutterd17b1362016-07-18 16:48:42 +020064 } req = {
65 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
66 .n.nlmsg_flags = NLM_F_REQUEST,
67 .n.nlmsg_type = RTM_GETNSID,
68 .g.rtgen_family = AF_UNSPEC,
69 };
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020070 int fd;
71
72 if (have_rtnl_getnsid < 0) {
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020073 fd = open("/proc/self/ns/net", O_RDONLY);
74 if (fd < 0) {
Liping Zhangc44003f2016-09-20 02:09:02 -070075 have_rtnl_getnsid = 0;
76 return 0;
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020077 }
78
79 addattr32(&req.n, 1024, NETNSA_FD, fd);
80
81 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
82 perror("request send failed");
83 exit(1);
84 }
85 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
86 close(fd);
87 }
88
89 return have_rtnl_getnsid;
90}
91
Nicolas Dichteld182ee12015-02-17 17:30:37 +010092static int get_netnsid_from_name(const char *name)
93{
94 struct {
95 struct nlmsghdr n;
96 struct rtgenmsg g;
97 char buf[1024];
Phil Sutterd17b1362016-07-18 16:48:42 +020098 } answer, req = {
99 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
100 .n.nlmsg_flags = NLM_F_REQUEST,
101 .n.nlmsg_type = RTM_GETNSID,
102 .g.rtgen_family = AF_UNSPEC,
103 };
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100104 struct rtattr *tb[NETNSA_MAX + 1];
105 struct rtgenmsg *rthdr;
106 int len, fd;
107
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100108 fd = netns_get_fd(name);
109 if (fd < 0)
110 return fd;
111
112 addattr32(&req.n, 1024, NETNSA_FD, fd);
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700113 if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100114 close(fd);
115 return -2;
116 }
117 close(fd);
118
119 /* Validate message and parse attributes */
120 if (answer.n.nlmsg_type == NLMSG_ERROR)
121 return -1;
122
123 rthdr = NLMSG_DATA(&answer.n);
124 len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
125 if (len < 0)
126 return -1;
127
128 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
129
130 if (tb[NETNSA_NSID])
131 return rta_getattr_u32(tb[NETNSA_NSID]);
132
133 return -1;
134}
135
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200136struct nsid_cache {
137 struct hlist_node nsid_hash;
138 struct hlist_node name_hash;
139 int nsid;
Stephen Hemminger2f29d6b2015-08-12 08:35:54 -0700140 char name[0];
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200141};
142
143#define NSIDMAP_SIZE 128
144#define NSID_HASH_NSID(nsid) (nsid & (NSIDMAP_SIZE - 1))
145#define NSID_HASH_NAME(name) (namehash(name) & (NSIDMAP_SIZE - 1))
146
147static struct hlist_head nsid_head[NSIDMAP_SIZE];
148static struct hlist_head name_head[NSIDMAP_SIZE];
149
150static struct nsid_cache *netns_map_get_by_nsid(int nsid)
151{
152 uint32_t h = NSID_HASH_NSID(nsid);
153 struct hlist_node *n;
154
155 hlist_for_each(n, &nsid_head[h]) {
156 struct nsid_cache *c = container_of(n, struct nsid_cache,
157 nsid_hash);
158 if (c->nsid == nsid)
159 return c;
160 }
161
162 return NULL;
163}
164
Stephen Hemminger2f29d6b2015-08-12 08:35:54 -0700165static int netns_map_add(int nsid, const char *name)
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200166{
167 struct nsid_cache *c;
168 uint32_t h;
169
170 if (netns_map_get_by_nsid(nsid) != NULL)
171 return -EEXIST;
172
Nicolas Cavallaria1b4a272016-02-12 14:47:39 +0100173 c = malloc(sizeof(*c) + strlen(name) + 1);
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200174 if (c == NULL) {
175 perror("malloc");
176 return -ENOMEM;
177 }
178 c->nsid = nsid;
179 strcpy(c->name, name);
180
181 h = NSID_HASH_NSID(nsid);
182 hlist_add_head(&c->nsid_hash, &nsid_head[h]);
183
184 h = NSID_HASH_NAME(name);
185 hlist_add_head(&c->name_hash, &name_head[h]);
186
187 return 0;
188}
189
190static void netns_map_del(struct nsid_cache *c)
191{
192 hlist_del(&c->name_hash);
193 hlist_del(&c->nsid_hash);
194 free(c);
195}
196
Anton Aksolae29a8e02016-09-20 06:01:27 +0000197void netns_nsid_socket_init(void)
198{
199 if (rtnsh.fd > -1 || !ipnetns_have_nsid())
200 return;
201
202 if (rtnl_open(&rtnsh, 0) < 0) {
203 fprintf(stderr, "Cannot open rtnetlink\n");
204 exit(1);
205 }
206
207}
208
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200209void netns_map_init(void)
210{
211 static int initialized;
212 struct dirent *entry;
213 DIR *dir;
214 int nsid;
215
216 if (initialized || !ipnetns_have_nsid())
217 return;
218
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200219 dir = opendir(NETNS_RUN_DIR);
220 if (!dir)
221 return;
222
223 while ((entry = readdir(dir)) != NULL) {
224 if (strcmp(entry->d_name, ".") == 0)
225 continue;
226 if (strcmp(entry->d_name, "..") == 0)
227 continue;
228 nsid = get_netnsid_from_name(entry->d_name);
229
230 if (nsid >= 0)
231 netns_map_add(nsid, entry->d_name);
232 }
233 closedir(dir);
234 initialized = 1;
235}
236
237static int netns_get_name(int nsid, char *name)
238{
239 struct dirent *entry;
240 DIR *dir;
241 int id;
242
243 dir = opendir(NETNS_RUN_DIR);
244 if (!dir)
245 return -ENOENT;
246
247 while ((entry = readdir(dir)) != NULL) {
248 if (strcmp(entry->d_name, ".") == 0)
249 continue;
250 if (strcmp(entry->d_name, "..") == 0)
251 continue;
252 id = get_netnsid_from_name(entry->d_name);
253
254 if (nsid == id) {
255 strcpy(name, entry->d_name);
256 closedir(dir);
257 return 0;
258 }
259 }
260 closedir(dir);
261 return -ENOENT;
262}
263
264int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
265{
266 struct rtgenmsg *rthdr = NLMSG_DATA(n);
267 struct rtattr *tb[NETNSA_MAX+1];
268 int len = n->nlmsg_len;
269 FILE *fp = (FILE *)arg;
270 struct nsid_cache *c;
271 char name[NAME_MAX];
272 int nsid;
273
274 if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
275 return 0;
276
277 len -= NLMSG_SPACE(sizeof(*rthdr));
278 if (len < 0) {
279 fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
280 __func__);
281 return -1;
282 }
283
284 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
285 if (tb[NETNSA_NSID] == NULL) {
286 fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
287 return -1;
288 }
289
290 if (n->nlmsg_type == RTM_DELNSID)
291 fprintf(fp, "Deleted ");
292
293 nsid = rta_getattr_u32(tb[NETNSA_NSID]);
294 fprintf(fp, "nsid %u ", nsid);
295
296 c = netns_map_get_by_nsid(nsid);
297 if (c != NULL) {
298 fprintf(fp, "(iproute2 netns name: %s)", c->name);
299 netns_map_del(c);
300 }
301
302 /* During 'ip monitor nsid', no chance to have new nsid in cache. */
303 if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
304 if (netns_get_name(nsid, name) == 0) {
305 fprintf(fp, "(iproute2 netns name: %s)", name);
306 netns_map_add(nsid, name);
307 }
308
309 fprintf(fp, "\n");
310 fflush(fp);
311 return 0;
312}
313
314static int netns_list_id(int argc, char **argv)
315{
316 if (!ipnetns_have_nsid()) {
317 fprintf(stderr,
318 "RTM_GETNSID is not supported by the kernel.\n");
319 return -ENOTSUP;
320 }
321
322 if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETNSID) < 0) {
323 perror("Cannot send dump request");
324 exit(1);
325 }
326 if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
327 fprintf(stderr, "Dump terminated\n");
328 exit(1);
329 }
330 return 0;
331}
332
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700333static int netns_list(int argc, char **argv)
334{
335 struct dirent *entry;
336 DIR *dir;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100337 int id;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700338
339 dir = opendir(NETNS_RUN_DIR);
340 if (!dir)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700341 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700342
343 while ((entry = readdir(dir)) != NULL) {
344 if (strcmp(entry->d_name, ".") == 0)
345 continue;
346 if (strcmp(entry->d_name, "..") == 0)
347 continue;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100348 printf("%s", entry->d_name);
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +0200349 if (ipnetns_have_nsid()) {
350 id = get_netnsid_from_name(entry->d_name);
351 if (id >= 0)
352 printf(" (id: %d)", id);
353 }
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100354 printf("\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700355 }
356 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700357 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700358}
359
Vadim Kochanb13ba032015-01-18 16:10:18 +0200360static int cmd_exec(const char *cmd, char **argv, bool do_fork)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700361{
JunweiZhang95592b42013-07-09 08:55:20 -0700362 fflush(stdout);
Vadim Kochanb13ba032015-01-18 16:10:18 +0200363 if (do_fork) {
JunweiZhang95592b42013-07-09 08:55:20 -0700364 int status;
365 pid_t pid;
366
367 pid = fork();
368 if (pid < 0) {
369 perror("fork");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700370 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700371 }
372
373 if (pid != 0) {
374 /* Parent */
375 if (waitpid(pid, &status, 0) < 0) {
376 perror("waitpid");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700377 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700378 }
379
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200380 if (WIFEXITED(status)) {
Vadim Kochanb13ba032015-01-18 16:10:18 +0200381 return WEXITSTATUS(status);
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200382 }
JunweiZhang95592b42013-07-09 08:55:20 -0700383
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200384 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700385 }
386 }
387
Vadim Kochanb13ba032015-01-18 16:10:18 +0200388 if (execvp(cmd, argv) < 0)
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000389 fprintf(stderr, "exec of \"%s\" failed: %s\n",
Vadim Kochanb13ba032015-01-18 16:10:18 +0200390 cmd, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700391 _exit(1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700392}
393
Vadim Kochanb13ba032015-01-18 16:10:18 +0200394static int on_netns_exec(char *nsname, void *arg)
395{
396 char **argv = arg;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700397
Vadim Kochanb13ba032015-01-18 16:10:18 +0200398 cmd_exec(argv[1], argv + 1, true);
399 return 0;
400}
401
402static int netns_exec(int argc, char **argv)
403{
404 /* Setup the proper environment for apps that are not netns
405 * aware, and execute a program in that environment.
406 */
407 const char *cmd;
408
409 if (argc < 1 && !do_all) {
410 fprintf(stderr, "No netns name specified\n");
411 return -1;
412 }
413 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
414 fprintf(stderr, "No command specified\n");
415 return -1;
416 }
417
418 if (do_all)
419 return do_each_netns(on_netns_exec, --argv, 1);
420
421 if (netns_switch(argv[0]))
422 return -1;
423
424 /* ip must return the status of the child,
425 * but do_cmd() will add a minus to this,
426 * so let's add another one here to cancel it.
427 */
428 cmd = argv[1];
429 return -cmd_exec(cmd, argv + 1, !!batch_mode);
430}
431
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000432static int is_pid(const char *str)
433{
434 int ch;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700435
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000436 for (; (ch = *str); str++) {
437 if (!isdigit(ch))
438 return 0;
439 }
440 return 1;
441}
442
443static int netns_pids(int argc, char **argv)
444{
445 const char *name;
Felix Jandaea343662015-07-26 21:25:32 +0200446 char net_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000447 int netns;
448 struct stat netst;
449 DIR *dir;
450 struct dirent *entry;
451
452 if (argc < 1) {
453 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700454 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000455 }
456 if (argc > 1) {
457 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700458 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000459 }
460
461 name = argv[0];
462 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
463 netns = open(net_path, O_RDONLY);
464 if (netns < 0) {
465 fprintf(stderr, "Cannot open network namespace: %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 if (fstat(netns, &netst) < 0) {
470 fprintf(stderr, "Stat of netns 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 dir = opendir("/proc/");
475 if (!dir) {
476 fprintf(stderr, "Open of /proc failed: %s\n",
477 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700478 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000479 }
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700480 while ((entry = readdir(dir))) {
Felix Jandaea343662015-07-26 21:25:32 +0200481 char pid_net_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000482 struct stat st;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700483
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000484 if (!is_pid(entry->d_name))
485 continue;
486 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
487 entry->d_name);
488 if (stat(pid_net_path, &st) != 0)
489 continue;
490 if ((st.st_dev == netst.st_dev) &&
491 (st.st_ino == netst.st_ino)) {
492 printf("%s\n", entry->d_name);
493 }
494 }
495 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700496 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800497
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000498}
499
500static int netns_identify(int argc, char **argv)
501{
502 const char *pidstr;
Felix Jandaea343662015-07-26 21:25:32 +0200503 char net_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000504 int netns;
505 struct stat netst;
506 DIR *dir;
507 struct dirent *entry;
508
509 if (argc < 1) {
vadimk0948adc2014-11-07 18:25:30 +0200510 pidstr = "self";
511 } else if (argc > 1) {
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000512 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700513 return -1;
vadimk0948adc2014-11-07 18:25:30 +0200514 } else {
515 pidstr = argv[0];
516 if (!is_pid(pidstr)) {
517 fprintf(stderr, "Specified string '%s' is not a pid\n",
518 pidstr);
519 return -1;
520 }
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000521 }
522
523 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
524 netns = open(net_path, O_RDONLY);
525 if (netns < 0) {
526 fprintf(stderr, "Cannot open network namespace: %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 if (fstat(netns, &netst) < 0) {
531 fprintf(stderr, "Stat of netns failed: %s\n",
532 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700533 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000534 }
535 dir = opendir(NETNS_RUN_DIR);
536 if (!dir) {
537 /* Succeed treat a missing directory as an empty directory */
538 if (errno == ENOENT)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700539 return 0;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000540
541 fprintf(stderr, "Failed to open directory %s:%s\n",
542 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700543 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000544 }
545
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700546 while ((entry = readdir(dir))) {
Felix Jandaea343662015-07-26 21:25:32 +0200547 char name_path[PATH_MAX];
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000548 struct stat st;
549
550 if (strcmp(entry->d_name, ".") == 0)
551 continue;
552 if (strcmp(entry->d_name, "..") == 0)
553 continue;
554
555 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
556 entry->d_name);
557
558 if (stat(name_path, &st) != 0)
559 continue;
560
561 if ((st.st_dev == netst.st_dev) &&
562 (st.st_ino == netst.st_ino)) {
563 printf("%s\n", entry->d_name);
564 }
565 }
566 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700567 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800568
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000569}
570
Vadim Kochan33724932015-01-18 16:10:19 +0200571static int on_netns_del(char *nsname, void *arg)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700572{
Felix Jandaea343662015-07-26 21:25:32 +0200573 char netns_path[PATH_MAX];
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700574
Vadim Kochan33724932015-01-18 16:10:19 +0200575 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700576 umount2(netns_path, MNT_DETACH);
577 if (unlink(netns_path) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000578 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700579 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700580 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700581 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700582 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700583}
584
Vadim Kochan33724932015-01-18 16:10:19 +0200585static int netns_delete(int argc, char **argv)
586{
587 if (argc < 1 && !do_all) {
588 fprintf(stderr, "No netns name specified\n");
589 return -1;
590 }
591
592 if (do_all)
593 return netns_foreach(on_netns_del, NULL);
594
595 return on_netns_del(argv[0], NULL);
596}
597
vadimkc1cbb182014-08-31 22:45:29 +0300598static int create_netns_dir(void)
599{
600 /* Create the base netns directory if it doesn't exist */
601 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
602 if (errno != EEXIST) {
603 fprintf(stderr, "mkdir %s failed: %s\n",
604 NETNS_RUN_DIR, strerror(errno));
605 return -1;
606 }
607 }
608
609 return 0;
610}
611
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700612static int netns_add(int argc, char **argv)
613{
614 /* This function creates a new network namespace and
615 * a new mount namespace and bind them into a well known
616 * location in the filesystem based on the name provided.
617 *
618 * The mount namespace is created so that any necessary
619 * userspace tweaks like remounting /sys, or bind mounting
620 * a new /etc/resolv.conf can be shared between uers.
621 */
Felix Jandaea343662015-07-26 21:25:32 +0200622 char netns_path[PATH_MAX];
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700623 const char *name;
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000624 int fd;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000625 int made_netns_run_dir_mount = 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700626
627 if (argc < 1) {
628 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700629 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700630 }
631 name = argv[0];
632
633 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
634
vadimkc1cbb182014-08-31 22:45:29 +0300635 if (create_netns_dir())
636 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700637
Stephen Hemmingerd259f032013-08-04 15:00:56 -0700638 /* Make it possible for network namespace mounts to propagate between
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000639 * mount namespaces. This makes it likely that a unmounting a network
640 * namespace file in one namespace will unmount the network namespace
641 * file in all namespaces allowing the network namespace to be freed
642 * sooner.
643 */
644 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
645 /* Fail unless we need to make the mount point */
646 if (errno != EINVAL || made_netns_run_dir_mount) {
647 fprintf(stderr, "mount --make-shared %s failed: %s\n",
648 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
652 /* Upgrade NETNS_RUN_DIR to a mount point */
653 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) {
654 fprintf(stderr, "mount --bind %s %s failed: %s\n",
655 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700656 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000657 }
658 made_netns_run_dir_mount = 1;
659 }
660
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700661 /* Create the filesystem state */
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000662 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
663 if (fd < 0) {
Mike Rapoport55713c82014-05-11 12:21:26 +0300664 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700665 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700666 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700667 }
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000668 close(fd);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700669 if (unshare(CLONE_NEWNET) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000670 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
671 name, strerror(errno));
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700672 goto out_delete;
673 }
674
675 /* Bind the netns last so I can watch for it */
676 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
677 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
678 netns_path, strerror(errno));
679 goto out_delete;
680 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700681 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700682out_delete:
683 netns_delete(argc, argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700684 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700685}
686
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100687static int set_netnsid_from_name(const char *name, int nsid)
688{
689 struct {
690 struct nlmsghdr n;
691 struct rtgenmsg g;
692 char buf[1024];
Phil Sutterd17b1362016-07-18 16:48:42 +0200693 } req = {
694 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
695 .n.nlmsg_flags = NLM_F_REQUEST,
696 .n.nlmsg_type = RTM_NEWNSID,
697 .g.rtgen_family = AF_UNSPEC,
698 };
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100699 int fd, err = 0;
700
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100701 fd = netns_get_fd(name);
702 if (fd < 0)
703 return fd;
704
705 addattr32(&req.n, 1024, NETNSA_FD, fd);
706 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700707 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100708 err = -2;
709
710 close(fd);
711 return err;
712}
713
714static int netns_set(int argc, char **argv)
715{
Felix Jandaea343662015-07-26 21:25:32 +0200716 char netns_path[PATH_MAX];
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100717 const char *name;
718 int netns, nsid;
719
720 if (argc < 1) {
721 fprintf(stderr, "No netns name specified\n");
722 return -1;
723 }
724 if (argc < 2) {
725 fprintf(stderr, "No nsid specified\n");
726 return -1;
727 }
728 name = argv[0];
729 nsid = atoi(argv[1]);
730
731 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
732 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
733 if (netns < 0) {
734 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
735 name, strerror(errno));
736 return -1;
737 }
738
739 return set_netnsid_from_name(name, nsid);
740}
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700741
742static int netns_monitor(int argc, char **argv)
743{
744 char buf[4096];
745 struct inotify_event *event;
746 int fd;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700747
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700748 fd = inotify_init();
749 if (fd < 0) {
750 fprintf(stderr, "inotify_init failed: %s\n",
751 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700752 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700753 }
vadimkc1cbb182014-08-31 22:45:29 +0300754
755 if (create_netns_dir())
756 return -1;
757
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700758 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
759 fprintf(stderr, "inotify_add_watch 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 }
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700763 for (;;) {
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700764 ssize_t len = read(fd, buf, sizeof(buf));
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700765
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700766 if (len < 0) {
767 fprintf(stderr, "read failed: %s\n",
768 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700769 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700770 }
771 for (event = (struct inotify_event *)buf;
772 (char *)event < &buf[len];
773 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
774 if (event->mask & IN_CREATE)
775 printf("add %s\n", event->name);
776 if (event->mask & IN_DELETE)
777 printf("delete %s\n", event->name);
778 }
779 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700780 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700781}
782
783int do_netns(int argc, char **argv)
784{
Anton Aksolae29a8e02016-09-20 06:01:27 +0000785 netns_nsid_socket_init();
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200786
Anton Aksolae29a8e02016-09-20 06:01:27 +0000787 if (argc < 1) {
788 netns_map_init();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700789 return netns_list(0, NULL);
Anton Aksolae29a8e02016-09-20 06:01:27 +0000790 }
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700791
792 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
Anton Aksolae29a8e02016-09-20 06:01:27 +0000793 (matches(*argv, "lst") == 0)) {
794 netns_map_init();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700795 return netns_list(argc-1, argv+1);
Anton Aksolae29a8e02016-09-20 06:01:27 +0000796 }
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700797
Anton Aksolae29a8e02016-09-20 06:01:27 +0000798 if ((matches(*argv, "list-id") == 0)) {
799 netns_map_init();
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200800 return netns_list_id(argc-1, argv+1);
Anton Aksolae29a8e02016-09-20 06:01:27 +0000801 }
Nicolas Dichteld652ccb2015-04-15 14:23:22 +0200802
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700803 if (matches(*argv, "help") == 0)
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +0000804 return usage();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700805
806 if (matches(*argv, "add") == 0)
807 return netns_add(argc-1, argv+1);
808
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100809 if (matches(*argv, "set") == 0)
810 return netns_set(argc-1, argv+1);
811
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700812 if (matches(*argv, "delete") == 0)
813 return netns_delete(argc-1, argv+1);
814
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000815 if (matches(*argv, "identify") == 0)
816 return netns_identify(argc-1, argv+1);
817
818 if (matches(*argv, "pids") == 0)
819 return netns_pids(argc-1, argv+1);
820
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700821 if (matches(*argv, "exec") == 0)
822 return netns_exec(argc-1, argv+1);
823
824 if (matches(*argv, "monitor") == 0)
825 return netns_monitor(argc-1, argv+1);
826
827 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700828 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700829}