当前位置: 首页 > 面试题库 >

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

萧星火
2023-03-14
问题内容

我正在使用以下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()。但是我不确定,如果可以的话)。


问题答案:

/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”文件后,它将继续引用命名空间。



 类似资料:
  • 问题内容: 我有一个自动相互连接的Spring bean图。大大简化了图示: 所有这些bean都没有指定范围,这暗示它们是单例(使它们成为显式单例不会改变任何东西,我已经尝试过)。 问题在于,在实例化 单个应用程序上下文之后 ,的实例和包含的 不同 实例。怎么会这样 我试图为它创建public no args构造函数,并且调试已确认创建了多次。所有这些创建的堆栈跟踪都在这里。 我还尝试过为Spri

  • 我有一张相互自动连线的Spring豆图。高度简化的插图: 所有这些bean都没有指定作用域,这意味着它们是单例(我已经尝试过了,让它们显式单例不会改变任何东西)。 问题是,在实例化单个应用程序上下文之后,Bar和Baz的实例包含不同的Foo实例。这怎么会发生? 我尝试为创建公共no args构造函数,并且调试已确认已多次创建。所有这些创建的堆栈跟踪都在这里。 我还尝试为Spring启用调试日志记录

  • 我正在研究NFC应用程序。当我打开应用程序并从NFC标签读取信息时,活动打开哪个注册了意图过滤器,这将打开一个已经打开的应用程序的新实例。如何关闭应用程序的上一个实例或打开应用程序的上一个实例。 请帮帮我,抱歉英语不好。。提前谢谢。

  • 我在名称空间方面有问题。我需要从一个公共api (Prestashop)解组。该api使用xml作为xlink类型,如下所示: 每种产品的 API 为: 我为每个XML生成了两个包含pojo类的包。我想从产品列表中获取给定id的任何产品的属性。 我有一个产品,其中包含@XMLSchema命名空间,但这个命名空间仅针对一个路径是静态的。我知道这不是这样做的方法。 下面,我的客户类。 这里有代码:ht

  • 本文向大家介绍创建一个Docker网络,包括了创建一个Docker网络的使用技巧和注意事项,需要的朋友参考一下 示例 此命令将创建一个名为的简单桥接网络appBackend。默认情况下,没有容器连接到该网络。

  • 问题内容: 我正在使用MVC创建一个基本的计算器。到目前为止,我正在改编一个教程,该教程仅将两个用户输入的值加在一起。 目前,我要添加到视图中的每个按钮都有其自己的侦听器,可以。但是,根据教程的控制器每个按钮只有一个ActionListener内部类。这重复了大量代码。 如何为所有按下的按钮创建一个ActionListener类,并在按下的按钮的ID上使用case语句? 在视图中注册oneButt