blob: 24df167e9262406399471519522d2bd04b38fc54 [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>
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"
21#include "ip_common.h"
Vadim Kochaneb67e442014-12-24 23:04:08 +020022#include "namespace.h"
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070023
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +000024static int usage(void)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070025{
26 fprintf(stderr, "Usage: ip netns list\n");
27 fprintf(stderr, " ip netns add NAME\n");
Nicolas Dichteld182ee12015-02-17 17:30:37 +010028 fprintf(stderr, " ip netns set NAME NETNSID\n");
Vadim Kochan33724932015-01-18 16:10:19 +020029 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
vadimk0948adc2014-11-07 18:25:30 +020030 fprintf(stderr, " ip netns identify [PID]\n");
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +000031 fprintf(stderr, " ip netns pids NAME\n");
Vadim Kochanb13ba032015-01-18 16:10:18 +020032 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070033 fprintf(stderr, " ip netns monitor\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -070034 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070035}
36
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +020037static int have_rtnl_getnsid = -1;
38
39static int ipnetns_accept_msg(const struct sockaddr_nl *who,
40 struct nlmsghdr *n, void *arg)
41{
42 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
43
44 if (n->nlmsg_type == NLMSG_ERROR &&
45 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
46 have_rtnl_getnsid = 0;
47 else
48 have_rtnl_getnsid = 1;
49 return -1;
50}
51
52static int ipnetns_have_nsid(void)
53{
54 struct {
55 struct nlmsghdr n;
56 struct rtgenmsg g;
57 char buf[1024];
58 } req;
59 int fd;
60
61 if (have_rtnl_getnsid < 0) {
62 memset(&req, 0, sizeof(req));
63 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
64 req.n.nlmsg_flags = NLM_F_REQUEST;
65 req.n.nlmsg_type = RTM_GETNSID;
66 req.g.rtgen_family = AF_UNSPEC;
67
68 fd = open("/proc/self/ns/net", O_RDONLY);
69 if (fd < 0) {
70 perror("open(\"/proc/self/ns/net\")");
71 exit(1);
72 }
73
74 addattr32(&req.n, 1024, NETNSA_FD, fd);
75
76 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
77 perror("request send failed");
78 exit(1);
79 }
80 rtnl_listen(&rth, ipnetns_accept_msg, NULL);
81 close(fd);
82 }
83
84 return have_rtnl_getnsid;
85}
86
Nicolas Dichteld182ee12015-02-17 17:30:37 +010087static int get_netnsid_from_name(const char *name)
88{
89 struct {
90 struct nlmsghdr n;
91 struct rtgenmsg g;
92 char buf[1024];
93 } req, answer;
94 struct rtattr *tb[NETNSA_MAX + 1];
95 struct rtgenmsg *rthdr;
96 int len, fd;
97
98 memset(&req, 0, sizeof(req));
99 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
100 req.n.nlmsg_flags = NLM_F_REQUEST;
101 req.n.nlmsg_type = RTM_GETNSID;
102 req.g.rtgen_family = AF_UNSPEC;
103
104 fd = netns_get_fd(name);
105 if (fd < 0)
106 return fd;
107
108 addattr32(&req.n, 1024, NETNSA_FD, fd);
109 if (rtnl_talk(&rth, &req.n, 0, 0, &answer.n) < 0) {
110 close(fd);
111 return -2;
112 }
113 close(fd);
114
115 /* Validate message and parse attributes */
116 if (answer.n.nlmsg_type == NLMSG_ERROR)
117 return -1;
118
119 rthdr = NLMSG_DATA(&answer.n);
120 len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
121 if (len < 0)
122 return -1;
123
124 parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
125
126 if (tb[NETNSA_NSID])
127 return rta_getattr_u32(tb[NETNSA_NSID]);
128
129 return -1;
130}
131
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700132static int netns_list(int argc, char **argv)
133{
134 struct dirent *entry;
135 DIR *dir;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100136 int id;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700137
138 dir = opendir(NETNS_RUN_DIR);
139 if (!dir)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700140 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700141
142 while ((entry = readdir(dir)) != NULL) {
143 if (strcmp(entry->d_name, ".") == 0)
144 continue;
145 if (strcmp(entry->d_name, "..") == 0)
146 continue;
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100147 printf("%s", entry->d_name);
Nicolas Dichtel4c7d9a52015-04-13 10:34:26 +0200148 if (ipnetns_have_nsid()) {
149 id = get_netnsid_from_name(entry->d_name);
150 if (id >= 0)
151 printf(" (id: %d)", id);
152 }
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100153 printf("\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700154 }
155 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700156 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700157}
158
Vadim Kochanb13ba032015-01-18 16:10:18 +0200159static int cmd_exec(const char *cmd, char **argv, bool do_fork)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700160{
JunweiZhang95592b42013-07-09 08:55:20 -0700161 fflush(stdout);
Vadim Kochanb13ba032015-01-18 16:10:18 +0200162 if (do_fork) {
JunweiZhang95592b42013-07-09 08:55:20 -0700163 int status;
164 pid_t pid;
165
166 pid = fork();
167 if (pid < 0) {
168 perror("fork");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700169 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700170 }
171
172 if (pid != 0) {
173 /* Parent */
174 if (waitpid(pid, &status, 0) < 0) {
175 perror("waitpid");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700176 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700177 }
178
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200179 if (WIFEXITED(status)) {
Vadim Kochanb13ba032015-01-18 16:10:18 +0200180 return WEXITSTATUS(status);
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200181 }
JunweiZhang95592b42013-07-09 08:55:20 -0700182
Nicolas Dichtel3c61c012013-08-29 14:29:07 +0200183 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -0700184 }
185 }
186
Vadim Kochanb13ba032015-01-18 16:10:18 +0200187 if (execvp(cmd, argv) < 0)
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000188 fprintf(stderr, "exec of \"%s\" failed: %s\n",
Vadim Kochanb13ba032015-01-18 16:10:18 +0200189 cmd, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700190 _exit(1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700191}
192
Vadim Kochanb13ba032015-01-18 16:10:18 +0200193static int on_netns_exec(char *nsname, void *arg)
194{
195 char **argv = arg;
196 cmd_exec(argv[1], argv + 1, true);
197 return 0;
198}
199
200static int netns_exec(int argc, char **argv)
201{
202 /* Setup the proper environment for apps that are not netns
203 * aware, and execute a program in that environment.
204 */
205 const char *cmd;
206
207 if (argc < 1 && !do_all) {
208 fprintf(stderr, "No netns name specified\n");
209 return -1;
210 }
211 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
212 fprintf(stderr, "No command specified\n");
213 return -1;
214 }
215
216 if (do_all)
217 return do_each_netns(on_netns_exec, --argv, 1);
218
219 if (netns_switch(argv[0]))
220 return -1;
221
222 /* ip must return the status of the child,
223 * but do_cmd() will add a minus to this,
224 * so let's add another one here to cancel it.
225 */
226 cmd = argv[1];
227 return -cmd_exec(cmd, argv + 1, !!batch_mode);
228}
229
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000230static int is_pid(const char *str)
231{
232 int ch;
233 for (; (ch = *str); str++) {
234 if (!isdigit(ch))
235 return 0;
236 }
237 return 1;
238}
239
240static int netns_pids(int argc, char **argv)
241{
242 const char *name;
243 char net_path[MAXPATHLEN];
244 int netns;
245 struct stat netst;
246 DIR *dir;
247 struct dirent *entry;
248
249 if (argc < 1) {
250 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700251 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000252 }
253 if (argc > 1) {
254 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700255 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000256 }
257
258 name = argv[0];
259 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
260 netns = open(net_path, O_RDONLY);
261 if (netns < 0) {
262 fprintf(stderr, "Cannot open network namespace: %s\n",
263 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700264 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000265 }
266 if (fstat(netns, &netst) < 0) {
267 fprintf(stderr, "Stat of netns failed: %s\n",
268 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700269 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000270 }
271 dir = opendir("/proc/");
272 if (!dir) {
273 fprintf(stderr, "Open of /proc failed: %s\n",
274 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700275 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000276 }
277 while((entry = readdir(dir))) {
278 char pid_net_path[MAXPATHLEN];
279 struct stat st;
280 if (!is_pid(entry->d_name))
281 continue;
282 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
283 entry->d_name);
284 if (stat(pid_net_path, &st) != 0)
285 continue;
286 if ((st.st_dev == netst.st_dev) &&
287 (st.st_ino == netst.st_ino)) {
288 printf("%s\n", entry->d_name);
289 }
290 }
291 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700292 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800293
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000294}
295
296static int netns_identify(int argc, char **argv)
297{
298 const char *pidstr;
299 char net_path[MAXPATHLEN];
300 int netns;
301 struct stat netst;
302 DIR *dir;
303 struct dirent *entry;
304
305 if (argc < 1) {
vadimk0948adc2014-11-07 18:25:30 +0200306 pidstr = "self";
307 } else if (argc > 1) {
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000308 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700309 return -1;
vadimk0948adc2014-11-07 18:25:30 +0200310 } else {
311 pidstr = argv[0];
312 if (!is_pid(pidstr)) {
313 fprintf(stderr, "Specified string '%s' is not a pid\n",
314 pidstr);
315 return -1;
316 }
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000317 }
318
319 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
320 netns = open(net_path, O_RDONLY);
321 if (netns < 0) {
322 fprintf(stderr, "Cannot open network namespace: %s\n",
323 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700324 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000325 }
326 if (fstat(netns, &netst) < 0) {
327 fprintf(stderr, "Stat of netns failed: %s\n",
328 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700329 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000330 }
331 dir = opendir(NETNS_RUN_DIR);
332 if (!dir) {
333 /* Succeed treat a missing directory as an empty directory */
334 if (errno == ENOENT)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700335 return 0;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000336
337 fprintf(stderr, "Failed to open directory %s:%s\n",
338 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700339 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000340 }
341
342 while((entry = readdir(dir))) {
343 char name_path[MAXPATHLEN];
344 struct stat st;
345
346 if (strcmp(entry->d_name, ".") == 0)
347 continue;
348 if (strcmp(entry->d_name, "..") == 0)
349 continue;
350
351 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
352 entry->d_name);
353
354 if (stat(name_path, &st) != 0)
355 continue;
356
357 if ((st.st_dev == netst.st_dev) &&
358 (st.st_ino == netst.st_ino)) {
359 printf("%s\n", entry->d_name);
360 }
361 }
362 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700363 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800364
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000365}
366
Vadim Kochan33724932015-01-18 16:10:19 +0200367static int on_netns_del(char *nsname, void *arg)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700368{
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700369 char netns_path[MAXPATHLEN];
370
Vadim Kochan33724932015-01-18 16:10:19 +0200371 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700372 umount2(netns_path, MNT_DETACH);
373 if (unlink(netns_path) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000374 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700375 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700376 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700377 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700378 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700379}
380
Vadim Kochan33724932015-01-18 16:10:19 +0200381static int netns_delete(int argc, char **argv)
382{
383 if (argc < 1 && !do_all) {
384 fprintf(stderr, "No netns name specified\n");
385 return -1;
386 }
387
388 if (do_all)
389 return netns_foreach(on_netns_del, NULL);
390
391 return on_netns_del(argv[0], NULL);
392}
393
vadimkc1cbb182014-08-31 22:45:29 +0300394static int create_netns_dir(void)
395{
396 /* Create the base netns directory if it doesn't exist */
397 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
398 if (errno != EEXIST) {
399 fprintf(stderr, "mkdir %s failed: %s\n",
400 NETNS_RUN_DIR, strerror(errno));
401 return -1;
402 }
403 }
404
405 return 0;
406}
407
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700408static int netns_add(int argc, char **argv)
409{
410 /* This function creates a new network namespace and
411 * a new mount namespace and bind them into a well known
412 * location in the filesystem based on the name provided.
413 *
414 * The mount namespace is created so that any necessary
415 * userspace tweaks like remounting /sys, or bind mounting
416 * a new /etc/resolv.conf can be shared between uers.
417 */
418 char netns_path[MAXPATHLEN];
419 const char *name;
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000420 int fd;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000421 int made_netns_run_dir_mount = 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700422
423 if (argc < 1) {
424 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700425 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700426 }
427 name = argv[0];
428
429 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
430
vadimkc1cbb182014-08-31 22:45:29 +0300431 if (create_netns_dir())
432 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700433
Stephen Hemmingerd259f032013-08-04 15:00:56 -0700434 /* Make it possible for network namespace mounts to propagate between
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000435 * mount namespaces. This makes it likely that a unmounting a network
436 * namespace file in one namespace will unmount the network namespace
437 * file in all namespaces allowing the network namespace to be freed
438 * sooner.
439 */
440 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
441 /* Fail unless we need to make the mount point */
442 if (errno != EINVAL || made_netns_run_dir_mount) {
443 fprintf(stderr, "mount --make-shared %s failed: %s\n",
444 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700445 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000446 }
447
448 /* Upgrade NETNS_RUN_DIR to a mount point */
449 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) {
450 fprintf(stderr, "mount --bind %s %s failed: %s\n",
451 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700452 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000453 }
454 made_netns_run_dir_mount = 1;
455 }
456
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700457 /* Create the filesystem state */
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000458 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
459 if (fd < 0) {
Mike Rapoport55713c82014-05-11 12:21:26 +0300460 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700461 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700462 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700463 }
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000464 close(fd);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700465 if (unshare(CLONE_NEWNET) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000466 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
467 name, strerror(errno));
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700468 goto out_delete;
469 }
470
471 /* Bind the netns last so I can watch for it */
472 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
473 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
474 netns_path, strerror(errno));
475 goto out_delete;
476 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700477 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700478out_delete:
479 netns_delete(argc, argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700480 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700481}
482
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100483static int set_netnsid_from_name(const char *name, int nsid)
484{
485 struct {
486 struct nlmsghdr n;
487 struct rtgenmsg g;
488 char buf[1024];
489 } req;
490 int fd, err = 0;
491
492 memset(&req, 0, sizeof(req));
493 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
494 req.n.nlmsg_flags = NLM_F_REQUEST;
495 req.n.nlmsg_type = RTM_NEWNSID;
496 req.g.rtgen_family = AF_UNSPEC;
497
498 fd = netns_get_fd(name);
499 if (fd < 0)
500 return fd;
501
502 addattr32(&req.n, 1024, NETNSA_FD, fd);
503 addattr32(&req.n, 1024, NETNSA_NSID, nsid);
504 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
505 err = -2;
506
507 close(fd);
508 return err;
509}
510
511static int netns_set(int argc, char **argv)
512{
513 char netns_path[MAXPATHLEN];
514 const char *name;
515 int netns, nsid;
516
517 if (argc < 1) {
518 fprintf(stderr, "No netns name specified\n");
519 return -1;
520 }
521 if (argc < 2) {
522 fprintf(stderr, "No nsid specified\n");
523 return -1;
524 }
525 name = argv[0];
526 nsid = atoi(argv[1]);
527
528 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
529 netns = open(netns_path, O_RDONLY | O_CLOEXEC);
530 if (netns < 0) {
531 fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
532 name, strerror(errno));
533 return -1;
534 }
535
536 return set_netnsid_from_name(name, nsid);
537}
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700538
539static int netns_monitor(int argc, char **argv)
540{
541 char buf[4096];
542 struct inotify_event *event;
543 int fd;
544 fd = inotify_init();
545 if (fd < 0) {
546 fprintf(stderr, "inotify_init failed: %s\n",
547 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700548 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700549 }
vadimkc1cbb182014-08-31 22:45:29 +0300550
551 if (create_netns_dir())
552 return -1;
553
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700554 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
555 fprintf(stderr, "inotify_add_watch failed: %s\n",
556 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700557 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700558 }
559 for(;;) {
560 ssize_t len = read(fd, buf, sizeof(buf));
561 if (len < 0) {
562 fprintf(stderr, "read failed: %s\n",
563 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700564 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700565 }
566 for (event = (struct inotify_event *)buf;
567 (char *)event < &buf[len];
568 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
569 if (event->mask & IN_CREATE)
570 printf("add %s\n", event->name);
571 if (event->mask & IN_DELETE)
572 printf("delete %s\n", event->name);
573 }
574 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700575 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700576}
577
578int do_netns(int argc, char **argv)
579{
580 if (argc < 1)
581 return netns_list(0, NULL);
582
583 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
584 (matches(*argv, "lst") == 0))
585 return netns_list(argc-1, argv+1);
586
587 if (matches(*argv, "help") == 0)
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +0000588 return usage();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700589
590 if (matches(*argv, "add") == 0)
591 return netns_add(argc-1, argv+1);
592
Nicolas Dichteld182ee12015-02-17 17:30:37 +0100593 if (matches(*argv, "set") == 0)
594 return netns_set(argc-1, argv+1);
595
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700596 if (matches(*argv, "delete") == 0)
597 return netns_delete(argc-1, argv+1);
598
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000599 if (matches(*argv, "identify") == 0)
600 return netns_identify(argc-1, argv+1);
601
602 if (matches(*argv, "pids") == 0)
603 return netns_pids(argc-1, argv+1);
604
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700605 if (matches(*argv, "exec") == 0)
606 return netns_exec(argc-1, argv+1);
607
608 if (matches(*argv, "monitor") == 0)
609 return netns_monitor(argc-1, argv+1);
610
611 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700612 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700613}