一尘不染

如何从单个流程实例创建多个网络名称空间

linux

我正在使用以下C函数从 单个流程实例* 创建 多个网络名称空间*

void create_namespace(const char *ns_name)
{
    char ns_path[100];

    snprintf(ns_path, 100, "%s/%s", "/var/run/netns", ns_name);
    close(open(ns_path, O_RDONLY|O_CREAT|O_EXCL, 0));
    unshare(CLONE_NEWNET);
    mount("/proc/self/ns/net", ns_path, "none", MS_BIND , NULL);
}

在我的过程创建了所有命名空间之后,我向一个网络名称空间中的任何一个添加了 tap 接口(使用ip link set tap1 netns ns1命令),然后我实际上在所有名称空间中看到了该接口(大概这实际上是一个使用不同名称的单个名称空间) )。

但是,如果我通过使用多个进程创建多个名称空间,那么一切工作都很好。

这有什么问题吗?我是否必须传递任何其他标志到unshare()才能从单个流程实例开始工作?是否存在单个流程实例不能创建多个网络名称空间的限制?还是mount()因为/proc/self/ns/net实际安装多次而导致通话出现问题?

更新:
似乎该unshare()函数正确创建了多个网络名称空间,但/var/run/netns/实际上所有安装点都引用该目录中已安装的第一个网络名称空间。

Update2:
似乎最好的方法是对另一个进程进行fork()并从那里执行create_namespace()函数。无论如何,我将很高兴听到一个更好的解决方案,该解决方案不涉及fork()调用,或者至少得到一个确认,该确认将证明不可能从单个进程创建和管理多个网络名称空间。

Update3: 通过使用以下代码,我可以使用unshare()创建多个名称空间:

int  main() {
    create_namespace("a");
    system("ip tuntap add mode tap tapa");
    system("ifconfig -a");//shows lo and tapA interface
    create_namespace("b");
    system("ip tuntap add mode tap tapb");
    system("ifconfig -a");//show lo and tapB interface, but does not show tapA. So this is second namespace created.
}

但是在进程终止并执行后ip netns exec a ifconfig -aip netns exec b ifconfig -a似乎两个命令都突然在命名空间 a中 执行
。因此,实际的问题是存储对名称空间的引用(或以正确的方式调用mount()。但是我不确定,如果可以的话)。


阅读 317

收藏
2020-06-07

共1个答案

一尘不染

/proc/*/ns/*当您需要从另一个进程访问这些名称空间,或者需要获取能够在两者之间来回切换的句柄时,才需要绑定mount
。不需要在单个进程中使用多个名称空间。

  • 取消共享 创建新的名称空间。
  • 默认情况下,clone和fork不创建任何新的名称空间。
  • 有一个分配给一个流程的每种“当前”名称空间。可以通过取消共享或设置来更改它。命名空间集(默认情况下)由子进程继承。

每当您执行open(/proc/N/ns/net)时,它都会为此文件创建inode,所有后续open()都将返回绑定到相同名称空间的文件。内核dentry缓存的深度丢失了详细信息。

同样,每个进程只有一个/proc/self/ns/net文件条目,并且绑定安装不会创建此proc文件的新实例。打开这些已挂载的文件
/proc/self/ns/net直接打开 文件 完全相同 (它将始终指向您首次打开文件时指向的名称空间)。

似乎/proc/*/ns像这样“半生不熟”。

因此,如果仅需要2个名称空间,则可以:

  • 打开 /proc/1/ns/net
  • 取消分享
  • 打开 /proc/self/ns/net

并在两者之间切换。

可能需要多于2个clone()/proc/N/ns/net每个进程似乎无法创建多个文件。

但是,如果您不需要在运行时在名称空间之间切换,也不需要与其他进程共享它们,则可以使用许多这样的名称空间:

  • 打开套接字并为主要名称空间运行进程。
  • 取消分享
  • 打开套接字并运行第二个名称空间(netlink,tcp等)的进程
  • 取消分享
  • 取消分享
  • 打开套接字并运行第N个名称空间(netlink,tcp等)的进程

打开的套接字会引用其网络名称空间,因此只有在套接字关闭后才能收集它们。

您还可以使用netlink通过在源名称空间上发送netlink命令,并通过PID或名称空间FD(您没有后者)来指定dst名称空间,从而在名称空间之间移动接口。

您需要在访问/proc依赖于该名称空间的条目之前切换进程名称空间。打开“ proc”文件后,它将继续引用命名空间。

2020-06-07