如何从单个流程实例创建多个网络命名空间 [英] How to create multiple network namespace from a single process instance

查看:16
本文介绍了如何从单个流程实例创建多个网络命名空间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下 C 函数从一个单个进程实例创建多个网络命名空间:

I am using following C function to create multiple network namespaces from a single process instance:

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 命令)之后,然后我实际上在所有命名空间中都看到了这个接口(大概,这实际上是一个不同名称的命名空间).

After my process creates all the namspaces and I add a tap interface to any of the one network namespace (with ip link set tap1 netns ns1 command), then I actually see this interface in all of the namespaces (presumably, this is actually a single namespace that goes under different names).

但是,如果我使用多个进程创建多个命名空间,那么一切正常.

But, if I create multiple namespaces by using multiple processes, then everything is working just fine.

这里可能有什么问题?我是否必须将任何其他标志传递给 unshare() 才能使其从单个流程实例中工作?是否存在单个流程实例不能创建多个网络命名空间的限制?还是 mount() 调用有问题,因为 /proc/self/ns/net 实际上被挂载了多次?

What could be wrong here? Do I have to pass any additional flags to the unshare() to get this working from a single process instance? Is there a limitation that a single process instance can't create multiple network namespaces? Or is there a problem with mount() call, because /proc/self/ns/net is actually mounted multiple times?

更新:似乎 unshare() 函数正确创建了多个网络命名空间,但 /var/run/netns/ 中的所有挂载点实际上都引用了第一个挂载的网络命名空间在那个目录中.

Update: It seems that unshare() function creates multiple network namespaces correctly, but all the mount points in /var/run/netns/ actually reference to the first network namespace that was mounted in that direcotry.

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

Update2: It seems that the best approach is to fork() another process and execute create_namespace() function from there. Anyway, I would be glad to hear a better solution that does not involve fork() call or at least get a confirmation that would prove that it is impossible to create and manage multiple network namespaces from a single process.

更新3:我可以使用以下代码使用 unshare() 创建多个命名空间:

Update3: I am able to create multiple namespaces with unshare() by using the following code:

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 之后,似乎这两个命令都突然在命名空间中执行了一个.所以实际的问题是存储对命名空间的引用(或以正确的方式调用 mount().但我不确定这是否可能).

But after the process terminates and I execute ip netns exec a ifconfig -a and ip netns exec b ifconfig -a it seems that both commands were suddenly executed in namespace a. So the actual problem is storing the references to the namespaces (or calling mount() the right way. But I am not sure, if this is possible).

推荐答案

如果你需要从另一个进程访问这些命名空间,你只需要绑定 mount /proc/*/ns/*,或者需要处理才能在两者之间来回切换.不需要在单个进程中使用多个命名空间.

You only have to bind mount /proc/*/ns/* if you need to access these namespaces from another process, or need to get handle to be able to switch back and forth between the two. It is not needed to use multiple namespaces from a single process.

  • 取消共享创建新的命名空间.
  • 默认情况下,clone 和 fork 不会创建任何新的命名空间.
  • 每个进程都有一个当前"命名空间.可以通过 unshare 或 setns 更改.命名空间集(默认)由子进程继承.

无论何时打开(/proc/N/ns/net),它都会为这个文件创建inode,并且所有后续的 open()s 将返回绑定到相同的命名空间.细节丢失在内核目录缓存的深处.

Whenever you do open(/proc/N/ns/net), it creates inode for this file, and all subsequent open()s will return file that is bound to the same namespace. Details are lost in the depths of kernel dentry cache.

此外,每个进程只有一个 /proc/self/ns/net 文件条目,并且bind mount 不会创建此 proc 文件的新实例.打开那些挂载的文件完全一样打开/proc/self/ns/net 文件直接(它会一直指向首次打开时它指向的命名空间).

Also, each process has only one /proc/self/ns/net file entry, and bind mount does not create new instances of this proc file. Opening those mounted files are exactly the same as opening /proc/self/ns/net file directly (which will keep pointing to the namespace it pointed to when you first opened it).

/proc/*/ns"好像是这样半生不熟的.

It seems that "/proc/*/ns" is half-baked like this.

所以,如果你只需要 2 个命名空间,你可以:

So, if you only need 2 namespaces, you can:

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

并在两者之间切换.

对于超过 2 个,您可能需要 clone().似乎没有办法为每个进程创建多个 /proc/N/ns/net 文件.

For more that 2 you might have to clone(). There seems to be no way to create more than one /proc/N/ns/net file per process.

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

However, if you do not need to switch between namespaces at runtime, or to share them with other processes, you can use many namespaces like this:

  • 为主命名空间打开套接字并运行进程.
  • 取消分享
  • 为第二个命名空间(netlink、tcp 等)打开套接字并运行进程
  • 取消分享
  • ...
  • 取消分享
  • 为第 N 个命名空间(netlink、tcp 等)打开套接字并运行进程

打开的套接字保持对其网络命名空间的引用,因此在套接字关闭之前不会收集它们.

Open sockets keep reference to their network namespace, so they will not be collected until sockets are closed.

您还可以使用 netlink 在命名空间之间移动接口,方法是在源命名空间上发送 netlink 命令,并通过 PID 或命名空间 FD 指定 dst 命名空间(后者你没有).

You can also use netlink to move interfaces between namespaces, by sending netlink command on source namespace, and specifying dst namespace either by PID or namespace FD (the later you don't have).

在访问依赖于该命名空间的 /proc 条目之前,您需要切换进程命名空间.一旦proc"文件打开,它就会保持对命名空间的引用.

You need to switch process namespace before accessing /proc entries that depend on that namespace. Once "proc" file is open, it keeps reference to the namespace.

这篇关于如何从单个流程实例创建多个网络命名空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆