在 Linux 上,我可以使用 C 语言创建一个新的 tun/tap 设备,例如:
int fd = open("/dev/net/tun", O_RDWR);
ioctl(fd, TUNSETIFF, (void *)&ifr);
这将在当前网络命名空间中创建一个新的网络接口。之后我可以使用类似的方法ip link set tap0 netns foo
将其从 shell 移动到另一个命名空间。
首先在正确的命名空间中创建它的正确方法是什么,或者至少将其从我的 C 代码移动到该命名空间?
答案1
如果您正在尝试创建一个tun
在现存的命名空间,您应该能够setns()
在创建 tun 设备之前使用系统调用来设置进程的网络命名空间。例如,假设存在一个名为“blue”的命名空间:
# ip netns
blue
以下代码将在该命名空间中打开一个 tun 设备:
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/if.h>
#include <linux/if_tun.h>
int main() {
int nsfd;
int tunfd;
struct ifreq ifr;
nsfd = open("/run/netns/blue", O_RDONLY);
if (setns(nsfd, CLONE_NEWNET) == -1) {
perror("setns");
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN;
tunfd = open("/dev/net/tun", O_RDWR);
if (ioctl(tunfd, TUNSETIFF, (void *)&ifr) < 0) {
perror("ioctl");
exit(1);
}
// this is just here to prevent the code from exiting, which
sleep(300);
}
当上面的代码运行时,我们可以验证设备是否tun
已在适当的命名空间中创建:
# ip netns exec blue ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500
link/none