mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-08-15 09:33:17 +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 "utils.h"
|
||||||
#include "ip_common.h"
|
#include "ip_common.h"
|
||||||
|
#include "namespace.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 */
|
|
||||||
|
|
||||||
static int usage(void)
|
static int usage(void)
|
||||||
{
|
{
|
||||||
@ -101,42 +66,12 @@ static int netns_list(int argc, char **argv)
|
|||||||
return 0;
|
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)
|
static int netns_exec(int argc, char **argv)
|
||||||
{
|
{
|
||||||
/* Setup the proper environment for apps that are not netns
|
/* Setup the proper environment for apps that are not netns
|
||||||
* aware, and execute a program in that environment.
|
* aware, and execute a program in that environment.
|
||||||
*/
|
*/
|
||||||
const char *name, *cmd;
|
const char *cmd;
|
||||||
char net_path[MAXPATHLEN];
|
|
||||||
int netns;
|
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
fprintf(stderr, "No netns name specified\n");
|
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");
|
fprintf(stderr, "No command specified\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = argv[0];
|
|
||||||
cmd = argv[1];
|
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) {
|
if (netns_switch(argv[0]))
|
||||||
fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
|
|
||||||
name, strerror(errno));
|
|
||||||
return -1;
|
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);
|
fflush(stdout);
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
include ../Config
|
include ../Config
|
||||||
|
|
||||||
|
ifeq ($(IP_CONFIG_SETNS),y)
|
||||||
|
CFLAGS += -DHAVE_SETNS
|
||||||
|
endif
|
||||||
|
|
||||||
CFLAGS += -fPIC
|
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
|
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