blob: e4038ea72d7161d205b041344a5c0e405dcf79e2 [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
18#include "utils.h"
19#include "ip_common.h"
Vadim Kochaneb67e442014-12-24 23:04:08 +020020#include "namespace.h"
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070021
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +000022static int usage(void)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070023{
24 fprintf(stderr, "Usage: ip netns list\n");
25 fprintf(stderr, " ip netns add NAME\n");
Vadim Kochan33724932015-01-18 16:10:19 +020026 fprintf(stderr, " ip [-all] netns delete [NAME]\n");
vadimk0948adc2014-11-07 18:25:30 +020027 fprintf(stderr, " ip netns identify [PID]\n");
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +000028 fprintf(stderr, " ip netns pids NAME\n");
Vadim Kochanb13ba032015-01-18 16:10:18 +020029 fprintf(stderr, " ip [-all] netns exec [NAME] cmd ...\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070030 fprintf(stderr, " ip netns monitor\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -070031 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070032}
33
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070034static int netns_list(int argc, char **argv)
35{
36 struct dirent *entry;
37 DIR *dir;
38
39 dir = opendir(NETNS_RUN_DIR);
40 if (!dir)
Stephen Hemmingera05f6512013-07-12 08:43:23 -070041 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070042
43 while ((entry = readdir(dir)) != NULL) {
44 if (strcmp(entry->d_name, ".") == 0)
45 continue;
46 if (strcmp(entry->d_name, "..") == 0)
47 continue;
48 printf("%s\n", entry->d_name);
49 }
50 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -070051 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070052}
53
Vadim Kochanb13ba032015-01-18 16:10:18 +020054static int cmd_exec(const char *cmd, char **argv, bool do_fork)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070055{
JunweiZhang95592b42013-07-09 08:55:20 -070056 fflush(stdout);
Vadim Kochanb13ba032015-01-18 16:10:18 +020057 if (do_fork) {
JunweiZhang95592b42013-07-09 08:55:20 -070058 int status;
59 pid_t pid;
60
61 pid = fork();
62 if (pid < 0) {
63 perror("fork");
Stephen Hemmingera05f6512013-07-12 08:43:23 -070064 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -070065 }
66
67 if (pid != 0) {
68 /* Parent */
69 if (waitpid(pid, &status, 0) < 0) {
70 perror("waitpid");
Stephen Hemmingera05f6512013-07-12 08:43:23 -070071 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -070072 }
73
Nicolas Dichtel3c61c012013-08-29 14:29:07 +020074 if (WIFEXITED(status)) {
Vadim Kochanb13ba032015-01-18 16:10:18 +020075 return WEXITSTATUS(status);
Nicolas Dichtel3c61c012013-08-29 14:29:07 +020076 }
JunweiZhang95592b42013-07-09 08:55:20 -070077
Nicolas Dichtel3c61c012013-08-29 14:29:07 +020078 exit(1);
JunweiZhang95592b42013-07-09 08:55:20 -070079 }
80 }
81
Vadim Kochanb13ba032015-01-18 16:10:18 +020082 if (execvp(cmd, argv) < 0)
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +000083 fprintf(stderr, "exec of \"%s\" failed: %s\n",
Vadim Kochanb13ba032015-01-18 16:10:18 +020084 cmd, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -070085 _exit(1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070086}
87
Vadim Kochanb13ba032015-01-18 16:10:18 +020088static int on_netns_exec(char *nsname, void *arg)
89{
90 char **argv = arg;
91 cmd_exec(argv[1], argv + 1, true);
92 return 0;
93}
94
95static int netns_exec(int argc, char **argv)
96{
97 /* Setup the proper environment for apps that are not netns
98 * aware, and execute a program in that environment.
99 */
100 const char *cmd;
101
102 if (argc < 1 && !do_all) {
103 fprintf(stderr, "No netns name specified\n");
104 return -1;
105 }
106 if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
107 fprintf(stderr, "No command specified\n");
108 return -1;
109 }
110
111 if (do_all)
112 return do_each_netns(on_netns_exec, --argv, 1);
113
114 if (netns_switch(argv[0]))
115 return -1;
116
117 /* ip must return the status of the child,
118 * but do_cmd() will add a minus to this,
119 * so let's add another one here to cancel it.
120 */
121 cmd = argv[1];
122 return -cmd_exec(cmd, argv + 1, !!batch_mode);
123}
124
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000125static int is_pid(const char *str)
126{
127 int ch;
128 for (; (ch = *str); str++) {
129 if (!isdigit(ch))
130 return 0;
131 }
132 return 1;
133}
134
135static int netns_pids(int argc, char **argv)
136{
137 const char *name;
138 char net_path[MAXPATHLEN];
139 int netns;
140 struct stat netst;
141 DIR *dir;
142 struct dirent *entry;
143
144 if (argc < 1) {
145 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700146 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000147 }
148 if (argc > 1) {
149 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700150 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000151 }
152
153 name = argv[0];
154 snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
155 netns = open(net_path, O_RDONLY);
156 if (netns < 0) {
157 fprintf(stderr, "Cannot open network namespace: %s\n",
158 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700159 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000160 }
161 if (fstat(netns, &netst) < 0) {
162 fprintf(stderr, "Stat of netns failed: %s\n",
163 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700164 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000165 }
166 dir = opendir("/proc/");
167 if (!dir) {
168 fprintf(stderr, "Open of /proc failed: %s\n",
169 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700170 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000171 }
172 while((entry = readdir(dir))) {
173 char pid_net_path[MAXPATHLEN];
174 struct stat st;
175 if (!is_pid(entry->d_name))
176 continue;
177 snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
178 entry->d_name);
179 if (stat(pid_net_path, &st) != 0)
180 continue;
181 if ((st.st_dev == netst.st_dev) &&
182 (st.st_ino == netst.st_ino)) {
183 printf("%s\n", entry->d_name);
184 }
185 }
186 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700187 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800188
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000189}
190
191static int netns_identify(int argc, char **argv)
192{
193 const char *pidstr;
194 char net_path[MAXPATHLEN];
195 int netns;
196 struct stat netst;
197 DIR *dir;
198 struct dirent *entry;
199
200 if (argc < 1) {
vadimk0948adc2014-11-07 18:25:30 +0200201 pidstr = "self";
202 } else if (argc > 1) {
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000203 fprintf(stderr, "extra arguments specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700204 return -1;
vadimk0948adc2014-11-07 18:25:30 +0200205 } else {
206 pidstr = argv[0];
207 if (!is_pid(pidstr)) {
208 fprintf(stderr, "Specified string '%s' is not a pid\n",
209 pidstr);
210 return -1;
211 }
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000212 }
213
214 snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
215 netns = open(net_path, O_RDONLY);
216 if (netns < 0) {
217 fprintf(stderr, "Cannot open network namespace: %s\n",
218 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700219 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000220 }
221 if (fstat(netns, &netst) < 0) {
222 fprintf(stderr, "Stat of netns failed: %s\n",
223 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700224 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000225 }
226 dir = opendir(NETNS_RUN_DIR);
227 if (!dir) {
228 /* Succeed treat a missing directory as an empty directory */
229 if (errno == ENOENT)
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700230 return 0;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000231
232 fprintf(stderr, "Failed to open directory %s:%s\n",
233 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700234 return -1;
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000235 }
236
237 while((entry = readdir(dir))) {
238 char name_path[MAXPATHLEN];
239 struct stat st;
240
241 if (strcmp(entry->d_name, ".") == 0)
242 continue;
243 if (strcmp(entry->d_name, "..") == 0)
244 continue;
245
246 snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
247 entry->d_name);
248
249 if (stat(name_path, &st) != 0)
250 continue;
251
252 if ((st.st_dev == netst.st_dev) &&
253 (st.st_ino == netst.st_ino)) {
254 printf("%s\n", entry->d_name);
255 }
256 }
257 closedir(dir);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700258 return 0;
Stephen Hemminger06125192014-02-17 10:55:31 -0800259
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000260}
261
Vadim Kochan33724932015-01-18 16:10:19 +0200262static int on_netns_del(char *nsname, void *arg)
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700263{
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700264 char netns_path[MAXPATHLEN];
265
Vadim Kochan33724932015-01-18 16:10:19 +0200266 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700267 umount2(netns_path, MNT_DETACH);
268 if (unlink(netns_path) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000269 fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700270 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700271 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700272 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700273 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700274}
275
Vadim Kochan33724932015-01-18 16:10:19 +0200276static int netns_delete(int argc, char **argv)
277{
278 if (argc < 1 && !do_all) {
279 fprintf(stderr, "No netns name specified\n");
280 return -1;
281 }
282
283 if (do_all)
284 return netns_foreach(on_netns_del, NULL);
285
286 return on_netns_del(argv[0], NULL);
287}
288
vadimkc1cbb182014-08-31 22:45:29 +0300289static int create_netns_dir(void)
290{
291 /* Create the base netns directory if it doesn't exist */
292 if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
293 if (errno != EEXIST) {
294 fprintf(stderr, "mkdir %s failed: %s\n",
295 NETNS_RUN_DIR, strerror(errno));
296 return -1;
297 }
298 }
299
300 return 0;
301}
302
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700303static int netns_add(int argc, char **argv)
304{
305 /* This function creates a new network namespace and
306 * a new mount namespace and bind them into a well known
307 * location in the filesystem based on the name provided.
308 *
309 * The mount namespace is created so that any necessary
310 * userspace tweaks like remounting /sys, or bind mounting
311 * a new /etc/resolv.conf can be shared between uers.
312 */
313 char netns_path[MAXPATHLEN];
314 const char *name;
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000315 int fd;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000316 int made_netns_run_dir_mount = 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700317
318 if (argc < 1) {
319 fprintf(stderr, "No netns name specified\n");
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700320 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700321 }
322 name = argv[0];
323
324 snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
325
vadimkc1cbb182014-08-31 22:45:29 +0300326 if (create_netns_dir())
327 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700328
Stephen Hemmingerd259f032013-08-04 15:00:56 -0700329 /* Make it possible for network namespace mounts to propagate between
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000330 * mount namespaces. This makes it likely that a unmounting a network
331 * namespace file in one namespace will unmount the network namespace
332 * file in all namespaces allowing the network namespace to be freed
333 * sooner.
334 */
335 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
336 /* Fail unless we need to make the mount point */
337 if (errno != EINVAL || made_netns_run_dir_mount) {
338 fprintf(stderr, "mount --make-shared %s failed: %s\n",
339 NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700340 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000341 }
342
343 /* Upgrade NETNS_RUN_DIR to a mount point */
344 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) {
345 fprintf(stderr, "mount --bind %s %s failed: %s\n",
346 NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700347 return -1;
Eric W. Biederman58a3e822013-01-17 14:47:18 +0000348 }
349 made_netns_run_dir_mount = 1;
350 }
351
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700352 /* Create the filesystem state */
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000353 fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
354 if (fd < 0) {
Mike Rapoport55713c82014-05-11 12:21:26 +0300355 fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700356 netns_path, strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700357 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700358 }
Eric W. Biederman223f4d82011-07-15 14:29:41 +0000359 close(fd);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700360 if (unshare(CLONE_NEWNET) < 0) {
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000361 fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
362 name, strerror(errno));
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700363 goto out_delete;
364 }
365
366 /* Bind the netns last so I can watch for it */
367 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
368 fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
369 netns_path, strerror(errno));
370 goto out_delete;
371 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700372 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700373out_delete:
374 netns_delete(argc, argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700375 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700376}
377
378
379static int netns_monitor(int argc, char **argv)
380{
381 char buf[4096];
382 struct inotify_event *event;
383 int fd;
384 fd = inotify_init();
385 if (fd < 0) {
386 fprintf(stderr, "inotify_init failed: %s\n",
387 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700388 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700389 }
vadimkc1cbb182014-08-31 22:45:29 +0300390
391 if (create_netns_dir())
392 return -1;
393
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700394 if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
395 fprintf(stderr, "inotify_add_watch failed: %s\n",
396 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700397 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700398 }
399 for(;;) {
400 ssize_t len = read(fd, buf, sizeof(buf));
401 if (len < 0) {
402 fprintf(stderr, "read failed: %s\n",
403 strerror(errno));
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700404 return -1;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700405 }
406 for (event = (struct inotify_event *)buf;
407 (char *)event < &buf[len];
408 event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
409 if (event->mask & IN_CREATE)
410 printf("add %s\n", event->name);
411 if (event->mask & IN_DELETE)
412 printf("delete %s\n", event->name);
413 }
414 }
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700415 return 0;
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700416}
417
418int do_netns(int argc, char **argv)
419{
420 if (argc < 1)
421 return netns_list(0, NULL);
422
423 if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
424 (matches(*argv, "lst") == 0))
425 return netns_list(argc-1, argv+1);
426
427 if (matches(*argv, "help") == 0)
Eric W. Biederman8e2d47d2013-01-17 14:46:09 +0000428 return usage();
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700429
430 if (matches(*argv, "add") == 0)
431 return netns_add(argc-1, argv+1);
432
433 if (matches(*argv, "delete") == 0)
434 return netns_delete(argc-1, argv+1);
435
Eric W. Biederman9a7b3d92013-01-17 14:48:15 +0000436 if (matches(*argv, "identify") == 0)
437 return netns_identify(argc-1, argv+1);
438
439 if (matches(*argv, "pids") == 0)
440 return netns_pids(argc-1, argv+1);
441
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700442 if (matches(*argv, "exec") == 0)
443 return netns_exec(argc-1, argv+1);
444
445 if (matches(*argv, "monitor") == 0)
446 return netns_monitor(argc-1, argv+1);
447
448 fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
Stephen Hemmingera05f6512013-07-12 08:43:23 -0700449 exit(-1);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700450}