mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-08-14 20:51:26 +00:00
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: Vadim Kochan <vadim4j@gmail.com> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
This commit is contained in:
parent
486ccd99a0
commit
eb67e4498a
46
include/namespace.h
Normal file
46
include/namespace.h
Normal file
@ -0,0 +1,46 @@
|
||||
#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__ */
|
106
ip/ipnetns.c
106
ip/ipnetns.c
@ -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));
|
||||
if (netns_switch(argv[0]))
|
||||
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);
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
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
|
||||
|
||||
|
86
lib/namespace.c
Normal file
86
lib/namespace.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user