]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipnetns.c
5 #include <sys/inotify.h>
8 #include <sys/syscall.h>
18 #include "ip_common.h"
20 #define NETNS_RUN_DIR "/var/run/netns"
21 #define NETNS_ETC_DIR "/etc/netns"
24 #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
28 #define MNT_DETACH 0x00000002 /* Just detach from the tree */
29 #endif /* MNT_DETACH */
32 static int setns(int fd
, int nstype
)
35 return syscall(__NR_setns
, fd
, nstype
);
41 #endif /* HAVE_SETNS */
43 static int usage(void)
45 fprintf(stderr
, "Usage: ip netns list\n");
46 fprintf(stderr
, " ip netns add NAME\n");
47 fprintf(stderr
, " ip netns delete NAME\n");
48 fprintf(stderr
, " ip netns exec NAME cmd ...\n");
49 fprintf(stderr
, " ip netns monitor\n");
53 int get_netns_fd(const char *name
)
55 char pathbuf
[MAXPATHLEN
];
56 const char *path
, *ptr
;
59 ptr
= strchr(name
, '/');
61 snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
62 NETNS_RUN_DIR
, name
);
65 return open(path
, O_RDONLY
);
68 static int netns_list(int argc
, char **argv
)
73 dir
= opendir(NETNS_RUN_DIR
);
77 while ((entry
= readdir(dir
)) != NULL
) {
78 if (strcmp(entry
->d_name
, ".") == 0)
80 if (strcmp(entry
->d_name
, "..") == 0)
82 printf("%s\n", entry
->d_name
);
88 static void bind_etc(const char *name
)
90 char etc_netns_path
[MAXPATHLEN
];
91 char netns_name
[MAXPATHLEN
];
92 char etc_name
[MAXPATHLEN
];
96 snprintf(etc_netns_path
, sizeof(etc_netns_path
), "%s/%s", NETNS_ETC_DIR
, name
);
97 dir
= opendir(etc_netns_path
);
101 while ((entry
= readdir(dir
)) != NULL
) {
102 if (strcmp(entry
->d_name
, ".") == 0)
104 if (strcmp(entry
->d_name
, "..") == 0)
106 snprintf(netns_name
, sizeof(netns_name
), "%s/%s", etc_netns_path
, entry
->d_name
);
107 snprintf(etc_name
, sizeof(etc_name
), "/etc/%s", entry
->d_name
);
108 if (mount(netns_name
, etc_name
, "none", MS_BIND
, NULL
) < 0) {
109 fprintf(stderr
, "Bind %s -> %s failed: %s\n",
110 netns_name
, etc_name
, strerror(errno
));
116 static int netns_exec(int argc
, char **argv
)
118 /* Setup the proper environment for apps that are not netns
119 * aware, and execute a program in that environment.
121 const char *name
, *cmd
;
122 char net_path
[MAXPATHLEN
];
126 fprintf(stderr
, "No netns name specified\n");
130 fprintf(stderr
, "No cmd specified\n");
135 snprintf(net_path
, sizeof(net_path
), "%s/%s", NETNS_RUN_DIR
, name
);
136 netns
= open(net_path
, O_RDONLY
);
138 fprintf(stderr
, "Cannot open network namespace %s: %s\n",
139 name
, strerror(errno
));
142 if (setns(netns
, CLONE_NEWNET
) < 0) {
143 fprintf(stderr
, "seting the network namespace failed: %s\n",
148 if (unshare(CLONE_NEWNS
) < 0) {
149 fprintf(stderr
, "unshare failed: %s\n", strerror(errno
));
152 /* Don't let any mounts propogate back to the parent */
153 if (mount("", "/", "none", MS_SLAVE
| MS_REC
, NULL
)) {
154 fprintf(stderr
, "mount --make-rslave / failed: %s\n",
158 /* Mount a version of /sys that describes the network namespace */
159 if (umount2("/sys", MNT_DETACH
) < 0) {
160 fprintf(stderr
, "umount of /sys failed: %s\n", strerror(errno
));
163 if (mount(name
, "/sys", "sysfs", 0, NULL
) < 0) {
164 fprintf(stderr
, "mount of /sys failed: %s\n",strerror(errno
));
168 /* Setup bind mounts for config files in /etc */
171 if (execvp(cmd
, argv
+ 1) < 0)
172 fprintf(stderr
, "exec of %s failed: %s\n",
173 cmd
, strerror(errno
));
177 static int netns_delete(int argc
, char **argv
)
180 char netns_path
[MAXPATHLEN
];
183 fprintf(stderr
, "No netns name specified\n");
188 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, name
);
189 umount2(netns_path
, MNT_DETACH
);
190 if (unlink(netns_path
) < 0) {
191 fprintf(stderr
, "Cannot remove %s: %s\n",
192 netns_path
, strerror(errno
));
198 static int netns_add(int argc
, char **argv
)
200 /* This function creates a new network namespace and
201 * a new mount namespace and bind them into a well known
202 * location in the filesystem based on the name provided.
204 * The mount namespace is created so that any necessary
205 * userspace tweaks like remounting /sys, or bind mounting
206 * a new /etc/resolv.conf can be shared between uers.
208 char netns_path
[MAXPATHLEN
];
213 fprintf(stderr
, "No netns name specified\n");
218 snprintf(netns_path
, sizeof(netns_path
), "%s/%s", NETNS_RUN_DIR
, name
);
220 /* Create the base netns directory if it doesn't exist */
221 mkdir(NETNS_RUN_DIR
, S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
223 /* Create the filesystem state */
224 fd
= open(netns_path
, O_RDONLY
|O_CREAT
|O_EXCL
, 0);
226 fprintf(stderr
, "Could not create %s: %s\n",
227 netns_path
, strerror(errno
));
231 if (unshare(CLONE_NEWNET
) < 0) {
232 fprintf(stderr
, "Failed to create a new network namespace: %s\n",
237 /* Bind the netns last so I can watch for it */
238 if (mount("/proc/self/ns/net", netns_path
, "none", MS_BIND
, NULL
) < 0) {
239 fprintf(stderr
, "Bind /proc/self/ns/net -> %s failed: %s\n",
240 netns_path
, strerror(errno
));
245 netns_delete(argc
, argv
);
250 static int netns_monitor(int argc
, char **argv
)
253 struct inotify_event
*event
;
257 fprintf(stderr
, "inotify_init failed: %s\n",
261 if (inotify_add_watch(fd
, NETNS_RUN_DIR
, IN_CREATE
| IN_DELETE
) < 0) {
262 fprintf(stderr
, "inotify_add_watch failed: %s\n",
267 ssize_t len
= read(fd
, buf
, sizeof(buf
));
269 fprintf(stderr
, "read failed: %s\n",
273 for (event
= (struct inotify_event
*)buf
;
274 (char *)event
< &buf
[len
];
275 event
= (struct inotify_event
*)((char *)event
+ sizeof(*event
) + event
->len
)) {
276 if (event
->mask
& IN_CREATE
)
277 printf("add %s\n", event
->name
);
278 if (event
->mask
& IN_DELETE
)
279 printf("delete %s\n", event
->name
);
285 int do_netns(int argc
, char **argv
)
288 return netns_list(0, NULL
);
290 if ((matches(*argv
, "list") == 0) || (matches(*argv
, "show") == 0) ||
291 (matches(*argv
, "lst") == 0))
292 return netns_list(argc
-1, argv
+1);
294 if (matches(*argv
, "help") == 0)
297 if (matches(*argv
, "add") == 0)
298 return netns_add(argc
-1, argv
+1);
300 if (matches(*argv
, "delete") == 0)
301 return netns_delete(argc
-1, argv
+1);
303 if (matches(*argv
, "exec") == 0)
304 return netns_exec(argc
-1, argv
+1);
306 if (matches(*argv
, "monitor") == 0)
307 return netns_monitor(argc
-1, argv
+1);
309 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv
);