AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 441876
Accepted
TheDiveO
TheDiveO
Asked: 2018-05-05 12:41:43 +0800 CST2018-05-05 12:41:43 +0800 CST 2018-05-05 12:41:43 +0800 CST

如何找到 veth 对等体 ifindex 的网络命名空间?

  • 772

任务

我需要明确且没有“整体”猜测的情况下在另一个网络命名空间中找到veth 端的对等网络接口。

理论 。/。现实

尽管有很多文档和关于 SO 的答案都假设网络接口的 ifindex 索引在网络名称空间中每个主机都是全局唯一的,但这在许多情况下并不成立:ifindex/iflink 是模棱两可的。甚至环回也已经表明相反的情况,在任何网络命名空间中的 ifindex 都是 1。此外,根据容器环境,ifindex数字会在不同的命名空间中重用。这使得跟踪 veth 布线成为一场噩梦,尤其是有很多容器和一个带有 veth 对等点的主机桥都以 @if3 左右结尾......

示例:link-netnsid是0

启动一个 Docker 容器实例,只是为了获得一个veth从主机网络命名空间连接到新容器网络命名空间的新对......

$ sudo docker run -it debian /bin/bash

现在,在主机网络命名空间列表中的网络接口(我忽略了那些对这个问题不感兴趣的接口):

$ ip链接显示
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    链接/环回 00:00:00:00:00:00 brd 00:00:00:00:00:00
...
4:docker0:mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    链接/以太 02:42:34:23:81:f0 brd ff:ff:ff:ff:ff:ff
...
16: vethfc8d91e@if15: mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    链接/以太 da:4c:f7:50:09:e2 brd ff:ff:ff:ff:ff:ff 链接-netnsid 0

如您所见,虽然iflink是明确的,但link-netnsid是 0,尽管对等端位于不同的网络命名空间中。

作为参考,请检查容器的未命名网络命名空间中的 netnsid:

$ sudo lsns -t 网络
        NS 类型 NPROCS PID 用户命令
...
...
4026532469 网络 1 29616 根 /bin/bash

$ sudo nsenter -t 29616 -n ip 链接显示
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    链接/环回 00:00:00:00:00:00 brd 00:00:00:00:00:00
15: eth0@if16: mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    链接/以太 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff 链接-netnsid 0

因此,对于两个 veth 端ip link show(和 RTNETLINK fwif)都告诉我们它们与 netnsid 0 在同一个网络命名空间中。在 link-netnsids 是本地而不是全局的假设下,这是错误的或正确的。我找不到任何文档来明确说明 link-netnsids 应该具有的范围。

/sys/class/net/...不去救援?

我查看了 /sys/class/net/ if /... 但只能找到 ifindex 和 iflink 元素;这些都有据可查。“ip link show”似乎也只以(in)著名的“@if#”符号的形式显示对等 ifindex。还是我错过了一些额外的网络命名空间元素?

底线/问题

是否有任何系统调用允许检索 veth 对的对等端丢失的网络命名空间信息?

networking network-namespaces
  • 3 3 个回答
  • 14182 Views

3 个回答

  • Voted
  1. A.B
    2018-05-05T17:21:59+08:002018-05-05T17:21:59+08:00

    这是我遵循的方法来了解如何理解这个问题。可用的工具似乎可以用于命名空间部分(带有一些卷积),并且(已更新)使用 /sys/ 可以轻松获取对等点的索引。所以它很长,请耐心等待。它分为两部分(不按逻辑顺序,但命名空间首先有助于解释索引命名),使用通用工具,而不是任何自定义程序:

    • 网络命名空间
    • 接口索引

    网络命名空间

    此信息可通过link-netnsid的输出中的属性获得,ip link并且可以与 的输出中的 id 匹配ip netns。可以将容器的网络命名空间“关联”到ip netns,从而将ip netns其用作专用工具。当然为此做一个特定的程序会更好(每个部分末尾有关系统调用的一些信息)。

    关于 nsid 的描述,以下是man ip netns说明(强调我的):

    ip netns set NAME NETNSID - 将 id 分配给对等网络命名空间

    此命令将 id 分配给对等网络命名空间。此 id 仅在当前网络命名空间中有效。这个 id 将被内核在一些 netlink 消息中使用。如果内核需要的时候没有分配id,就会由内核自动分配。一旦分配,就无法更改它。

    虽然创建命名空间ip netns不会立即创建 netnsid,但只要将 veth half 设置为另一个命名空间,就会创建它(在当前命名空间上,可能是“主机”)。所以它总是为一个典型的容器设置。

    这是一个使用 LXC 容器的示例:

    # lxc-start -n stretch-amd64
    

    出现了一个新的 veth 链接veth9RPX4M(可以用 跟踪ip monitor link)。以下是详细信息:

    # ip -o link show veth9RPX4M
    44: veth9RPX4M@if43: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master lxcbr0 state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether fe:25:13:8a:00:f8 brd ff:ff:ff:ff:ff:ff link-netnsid 4
    

    这个链接有属性link-netnsid 4,告诉对方在网络命名空间中,nsid 4。如何验证它是 LXC 容器?获取此信息的最简单方法是通过执行 manpage 中提示的操作ip netns来相信它创建了容器的网络命名空间。

    # mkdir -p /var/run/netns
    # touch /var/run/netns/stretch-amd64
    # mount -o bind /proc/$(lxc-info -H -p -n stretch-amd64)/ns/net /var/run/netns/stretch-amd64
    

    UPDATE3:我不明白找回全局名称是个问题。这里是:

    # ls -l /proc/$(lxc-info -H -p -n stretch-amd64)/ns/net
    lrwxrwxrwx. 1 root root 0 mai    5 20:40 /proc/17855/ns/net -> net:[4026532831]
    
    # stat -c %i /var/run/netns/stretch-amd64 
    4026532831
    

    现在通过以下方式检索信息:

    # ip netns | grep stretch-amd64
    stretch-amd64 (id: 4)
    

    它确认 veth 的对等点位于具有相同 nsid = 4 = link-netnsid 的网络命名空间中。

    可以删除容器/ ip netns“关联”(只要容器正在运行,就无需删除命名空间):

    # ip netns del stretch-amd64
    

    注意:nsid 命名是每个网络命名空间,通常第一个容器以 0 开头,可用的最低值与新命名空间一起回收。

    关于使用系统调用,以下是从 strace 猜测的信息:

    • 对于链接部分:它需要一个AF_NETLINK套接字(打开socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)),询问(sendmsg())带有消息类型的链接信息RTM_GETLINK并检索(recvmsg())带有消息类型的回复RTM_NEWLINK。

    • 对于 netns nsid 部分:同样的方法,查询消息是 type RTM_GETNSIDwith reply type RTM_NEWNSID。

    我认为处理这个问题的稍微更高级别的库在那里:libnl。无论如何,这是SO的主题。

    接口索引

    现在更容易理解为什么索引似乎具有随机行为。让我们做一个实验:

    首先输入一个新的网络命名空间以获得一个干净的(索引)石板:

    # ip netns add test
    # ip netns exec test bash
    # ip netns id
    test
    # ip -o link 
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    

    正如 OP 所指出的, lo 从索引 1 开始。

    让我们添加 5 个网络命名空间,创建 veth 对,然后在它们上添加一个 veth 结尾:

    # for i in {0..4}; do ip netns add test$i; ip link add type veth peer netns test$i ; done
    # ip -o link|sed 's/^/    /'
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: veth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:83:4f:60:5a:30 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    3: veth1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 22:a7:75:8e:3c:95 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    4: veth2@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 72:94:6e:e4:2c:fc brd ff:ff:ff:ff:ff:ff link-netnsid 2
    5: veth3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether ee:b5:96:63:62:de brd ff:ff:ff:ff:ff:ff link-netnsid 3
    6: veth4@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:7d:e2:9a:3f:6d brd ff:ff:ff:ff:ff:ff link-netnsid 4
    

    当它为它们中的每一个显示@if2 时,很明显它是对等的命名空间接口索引和索引不是全局的,而是每个命名空间的。当它显示一个实际的接口名称时,它是与同一名称空间中的一个接口的关系(无论是 veth 的对等点、网桥、键...)。那么为什么 veth0 没有显示对等点呢?ip link当索引与自身相同时,我相信这是一个错误。只需移动两次对等链接就可以在这里“解决”它,因为它会强制更改索引。我也确定有时ip link会造成其他混淆,而不是显示@ifXX,而是在当前命名空间中显示一个具有相同索引的接口。

    # ip -n test0 link set veth0 name veth0b netns test
    # ip link set veth0b netns test0
    # ip -o link
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: veth0@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:83:4f:60:5a:30 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    3: veth1@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 22:a7:75:8e:3c:95 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    4: veth2@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether 72:94:6e:e4:2c:fc brd ff:ff:ff:ff:ff:ff link-netnsid 2
    5: veth3@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether ee:b5:96:63:62:de brd ff:ff:ff:ff:ff:ff link-netnsid 3
    6: veth4@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000\    link/ether e2:7d:e2:9a:3f:6d brd ff:ff:ff:ff:ff:ff link-netnsid 4
    

    更新:再次阅读 OP 问题中的信息,同行的索引(但不是 nsid)很容易且明确地可用.cat /sys/class/net/ interface /iflink

    更新2:

    所有这些 iflink 2 可能看起来模棱两可,但独特的是 nsid 和 iflink 的组合,而不是单独的 iflink。对于上面的例子是:

    interface    nsid:iflink
    veth0        0:7
    veth1        1:2
    veth2        2:2
    veth3        3:2
    veth4        4:2
    

    在这个命名空间(即命名空间test)中,永远不会有两个相同的 nsid:pair 。

    如果要从每个对等网络中查看相反的信息:

    namespace    interface    nsid:iflink
    test0        veth0        0:2
    test1        veth0        0:3
    test2        veth0        0:4
    test3        veth0        0:5
    test4        veth0        0:6
    

    但请记住,0:每一个都有一个单独的 0,它恰好映射到同一个对等命名空间(即:命名空间test,甚至不是主机)。它们无法直接比较,因为它们与它们的命名空间相关联。因此,整个可比较且唯一的信息应该是:

    test0:0:2
    test1:0:3
    test2:0:4
    test3:0:5
    test4:0:6
    

    一旦确认 "test0:0" == "test1:0" 等(在这个例子中是真的,都映射到由 调用的网络命名空间test),ip netns那么它们就可以真正进行比较。

    关于系统调用,仍然查看 strace 结果,信息如上从RTM_GETLINK. 现在应该有所有可用的信息:

    本地:带有SIOCGIFINDEX/ 对等的接口索引:nsid 和带有 . 的接口索引。if_nametoindex
    RTM_GETLINK

    所有这些都应该与libnl一起使用。

    • 9
  2. Best Answer
    TheDiveO
    2018-05-06T09:26:35+08:002018-05-06T09:26:35+08:00

    非常感谢@AB,他为我填补了一些缺失的部分,特别是关于netnsids 的语义。他的 PoC 很有启发性。然而,他的 PoC 中关键缺失的部分是如何将本地netnsid与其全局唯一的网络命名空间 inode 编号相关联,因为只有这样我们才能明确地连接正确的veth对应对。

    总结并给出一个小的 Python 示例,如何以编程方式收集信息而无需依赖ip netns和挂载事物:RTNETLINK 在查询网络接口时实际上返回 netnsid。它是IFLA_LINK_NETNSID属性,仅在需要时出现在链接的信息中。如果它不存在,那么就不需要它——我们必须假设对等索引指的是命名空间本地网络接口。

    要带回家的重要教训是,netnsid/IFLA_LINK_NETSID仅在您向 RTNETLINK 请求链接信息时获得的网络命名空间内本地定义。在不同的网络名称空间中获得相同值的 Anetnsid可能会标识不同的对等名称空间,因此请注意不要使用netnsid其名称空间之外的名称。但是哪个唯一可识别的网络命名空间(inode编号)映射到哪个netnsid?

    事实证明,lsns截至 2018 年 3 月的最新版本能够很好地netnsid在其网络命名空间 inode 编号旁边显示正确!所以有一种方法可以将 local 映射netnsid到命名空间 inode,但实际上是倒退的!它更像是一个 oracle(带有小写 ell)而不是查找:RTM_GETNSID 需要一个网络名称空间标识符作为 PID 或 FD(到网络名称空间),然后返回netnsid. 有关如何询问 Linux 网络命名空间 oracle 的示例,请参阅https://stackoverflow.com/questions/50196902/retrieving-the-netnsid-of-a-network-namespace-in-python 。

    因此,您需要枚举可用的网络命名空间(通过/proc和/或/var/run/netns),然后对于给定的veth网络接口附加到您找到它的网络命名空间,询问netnsid您在开始时枚举的所有网络命名空间的 s(因为您永远不会事先知道哪个是哪个),最后根据您在第 3 步中创建的本地映射,在附加到 的命名空间后netnsid,将对等节点映射到命名空间 inode 编号。vethveth

    import psutil
    import os
    import pyroute2
    from pyroute2.netlink import rtnl, NLM_F_REQUEST
    from pyroute2.netlink.rtnl import nsidmsg
    from nsenter import Namespace
    
    # phase I: gather network namespaces from /proc/[0-9]*/ns/net
    netns = dict()
    for proc in psutil.process_iter():
        netnsref= '/proc/{}/ns/net'.format(proc.pid)
        netnsid = os.stat(netnsref).st_ino
        if netnsid not in netns:
            netns[netnsid] = netnsref
    
    # phase II: ask kernel "oracle" about the local IDs for the
    # network namespaces we've discovered in phase I, doing this
    # from all discovered network namespaces
    for id, ref in netns.items():
        with Namespace(ref, 'net'):
            print('inside net:[{}]...'.format(id))
            ipr = pyroute2.IPRoute()
            for netnsid, netnsref in netns.items():
                with open(netnsref, 'r') as netnsf:
                    req = nsidmsg.nsidmsg()
                    req['attrs'] = [('NETNSA_FD', netnsf.fileno())]
                    resp = ipr.nlm_request(req, rtnl.RTM_GETNSID, NLM_F_REQUEST)
                    local_nsid = dict(resp[0]['attrs'])['NETNSA_NSID']
                if local_nsid != 2**32-1:
                    print('  net:[{}] <--> nsid {}'.format(netnsid, local_nsid))
    
    • 7
  3. Sam Stoelinga
    2019-12-31T15:24:23+08:002019-12-31T15:24:23+08:00

    我创建了一个简单的脚本,列出了所有具有关联 veth 接口的容器:https ://github.com/samos123/docker-veth/blob/master/docker-veth.sh

    让我解释一下它是如何工作的:

    1. 查找容器的PID
    pid=$(docker inspect --format '{{.State.Pid}}' $containerID)
    
    1. 使用输入网络命名空间nsenter
    nsenter -t $pid -n ip a
    

    您会注意到eth0@ifX容器网络命名空间内有一个接口。X 告诉您主机网络上的接口索引。然后可以使用该索引来确定哪个 veth 属于容器。

    运行以下命令找到 veth 接口:

    ifindex=$(nsenter -t $pid -n ip link | sed -n -e 's/.*eth0@if\([0-9]*\):.*/\1/p')
    veth=$(ip -o link | grep ^$ifindex | sed -n -e 's/.*\(veth[[:alnum:]]*@if[[:digit:]]*\).*/\1/p')
    echo $veth
    

    包含更多详细信息的博客文章:http: //samos-it.com/posts/enter-namespace-of-other-containers-from-a-pod.html

    • 2

相关问题

  • 查找与端口关联的线程/脚本?

  • 关于网络挂载文件的问题

  • IP地址可以以255结尾而不是广播IP地址吗?

  • 无法识别arp命令或ip命令哪个MAC地址输出正确

  • 奇怪的路由器与centos 6一起工作[关闭]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve