Commit eb67e449 authored by Vadim Kochan's avatar Vadim Kochan Committed by Stephen Hemminger

lib: Add netns_switch func for change network namespace

New netns_switch func moved to the lib/namespace.c from ip/ipnetns.c
so it can be used from the other tools for fast switching
network namespace.
Signed-off-by: default avatarVadim Kochan <vadim4j@gmail.com>
Signed-off-by: default avatarJiri Pirko <jiri@resnulli.us>
parent 486ccd99
#ifndef __NAMESPACE_H__
#define __NAMESPACE_H__ 1
#include <sched.h>
#include <sys/mount.h>
#include <errno.h>
#define NETNS_RUN_DIR "/var/run/netns"
#define NETNS_ETC_DIR "/etc/netns"
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
#endif
#ifndef MNT_DETACH
#define MNT_DETACH 0x00000002 /* Just detach from the tree */
#endif /* MNT_DETACH */
/* sys/mount.h may be out too old to have these */
#ifndef MS_REC
#define MS_REC 16384
#endif
#ifndef MS_SLAVE
#define MS_SLAVE (1 << 19)
#endif
#ifndef MS_SHARED
#define MS_SHARED (1 << 20)
#endif
#ifndef HAVE_SETNS
static int setns(int fd, int nstype)
{
#ifdef __NR_setns
return syscall(__NR_setns, fd, nstype);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif /* HAVE_SETNS */
extern int netns_switch(char *netns);
#endif /* __NAMESPACE_H__ */
......@@ -17,42 +17,7 @@
#include "utils.h"
#include "ip_common.h"
#define NETNS_RUN_DIR "/var/run/netns"
#define NETNS_ETC_DIR "/etc/netns"
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
#endif
#ifndef MNT_DETACH
#define MNT_DETACH 0x00000002 /* Just detach from the tree */
#endif /* MNT_DETACH */
/* sys/mount.h may be out too old to have these */
#ifndef MS_REC
#define MS_REC 16384
#endif
#ifndef MS_SLAVE
#define MS_SLAVE (1 << 19)
#endif
#ifndef MS_SHARED
#define MS_SHARED (1 << 20)
#endif
#ifndef HAVE_SETNS
static int setns(int fd, int nstype)
{
#ifdef __NR_setns
return syscall(__NR_setns, fd, nstype);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif /* HAVE_SETNS */
#include "namespace.h"
static int usage(void)
{
......@@ -101,42 +66,12 @@ static int netns_list(int argc, char **argv)
return 0;
}
static void bind_etc(const char *name)
{
char etc_netns_path[MAXPATHLEN];
char netns_name[MAXPATHLEN];
char etc_name[MAXPATHLEN];
struct dirent *entry;
DIR *dir;
snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
dir = opendir(etc_netns_path);
if (!dir)
return;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
fprintf(stderr, "Bind %s -> %s failed: %s\n",
netns_name, etc_name, strerror(errno));
}
}
closedir(dir);
}
static int netns_exec(int argc, char **argv)
{
/* Setup the proper environment for apps that are not netns
* aware, and execute a program in that environment.
*/
const char *name, *cmd;
char net_path[MAXPATHLEN];
int netns;
const char *cmd;
if (argc < 1) {
fprintf(stderr, "No netns name specified\n");
......@@ -146,45 +81,10 @@ static int netns_exec(int argc, char **argv)
fprintf(stderr, "No command specified\n");
return -1;
}
name = argv[0];
cmd = argv[1];
snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
netns = open(net_path, O_RDONLY | O_CLOEXEC);
if (netns < 0) {
fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
name, strerror(errno));
return -1;
}
if (setns(netns, CLONE_NEWNET) < 0) {
fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
name, strerror(errno));
return -1;
}
if (unshare(CLONE_NEWNS) < 0) {
fprintf(stderr, "unshare failed: %s\n", strerror(errno));
return -1;
}
/* Don't let any mounts propagate back to the parent */
if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
strerror(errno));
if (netns_switch(argv[0]))
return -1;
}
/* Mount a version of /sys that describes the network namespace */
if (umount2("/sys", MNT_DETACH) < 0) {
fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
return -1;
}
if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
return -1;
}
/* Setup bind mounts for config files in /etc */
bind_etc(name);
fflush(stdout);
......
include ../Config
ifeq ($(IP_CONFIG_SETNS),y)
CFLAGS += -DHAVE_SETNS
endif
CFLAGS += -fPIC
UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o
UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o
NLOBJ=libgenl.o ll_map.o libnetlink.o
......
/*
* namespace.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <fcntl.h>
#include <dirent.h>
#include "utils.h"
#include "namespace.h"
static void bind_etc(const char *name)
{
char etc_netns_path[MAXPATHLEN];
char netns_name[MAXPATHLEN];
char etc_name[MAXPATHLEN];
struct dirent *entry;
DIR *dir;
snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
dir = opendir(etc_netns_path);
if (!dir)
return;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
fprintf(stderr, "Bind %s -> %s failed: %s\n",
netns_name, etc_name, strerror(errno));
}
}
closedir(dir);
}
int netns_switch(char *name)
{
char net_path[MAXPATHLEN];
int netns;
snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
netns = open(net_path, O_RDONLY | O_CLOEXEC);
if (netns < 0) {
fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
name, strerror(errno));
return -1;
}
if (setns(netns, CLONE_NEWNET) < 0) {
fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
name, strerror(errno));
return -1;
}
if (unshare(CLONE_NEWNS) < 0) {
fprintf(stderr, "unshare failed: %s\n", strerror(errno));
return -1;
}
/* Don't let any mounts propagate back to the parent */
if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
strerror(errno));
return -1;
}
/* Mount a version of /sys that describes the network namespace */
if (umount2("/sys", MNT_DETACH) < 0) {
fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
return -1;
}
if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
return -1;
}
/* Setup bind mounts for config files in /etc */
bind_etc(name);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment