3. veth pair原理与创建

在 Linux 网络命名空间的世界里,命名空间把网络协议栈、网卡、路由表、ARP 表、iptables 规则等资源彼此隔离。隔离之后立刻出现一个新问题:两个命名空间之间怎么通信?答案不是把物理网卡搬来搬去,而是使用一对成对出现的虚拟以太网设备——veth pair。理解 veth pair,是理解容器网络、网桥、隧道和后续所有虚拟网络拓扑的起点。

一、veth pair 的本质:一根虚拟网线的两端

veth(virtual Ethernet)不是一块普通的虚拟网卡,它天生就是“成对”的。创建时会同时生成两个网络接口,习惯上称为 veth0 和 veth1,或者 vethA 和 vethB。这两个接口构成一个整体,数据从一端进入,就会从另一端出来,中间没有交换机、没有路由决策,行为上非常像一根两端带水晶头的网线。

关键点在于:veth pair 的两端可以分别放在不同的网络命名空间中。把一端留在宿主机(或某个命名空间),把另一端放进另一个命名空间,这根“虚拟网线”就跨越了隔离边界,把两个原本互不可见的网络栈连接起来。这正是容器网络最基础的连接方式。

需要特别强调的是,veth pair 本身不提供路由、不提供 NAT、也不自动分配 IP。它只负责“把帧从一端送到另一端”。要让两端真正能通信,还需要给两端配置 IP 地址、设置接口为 UP 状态,并处理好路由。理解这一点,可以避免把 veth 误当成“能自动联网的网卡”。

可以把 veth pair 想象成一根两端固定的网线:一端插在 A 房间的墙上插座,另一端插在 B 房间的墙上插座。网线本身不会决定谁和谁说话,它只负责把电信号从一端传到另一端。IP 地址和路由才是决定“谁能找到谁”的规则。

二、veth pair 的数据流向与状态联动

veth pair 有一个非常重要的特性:一端的状态会影响另一端。当一端被设置为 DOWN 时,另一端即使显示 UP,也无法正常收发数据;当一端被删除时,另一端也会随之消失。这种“同生共死”的联动关系,是判断 veth 是否正常工作的关键依据。

数据流向方面,假设 veth0 在命名空间 ns1,veth1 在命名空间 ns2。当 ns1 中的进程向 veth0 发送一个以太网帧时,内核并不会把这个帧交给本机的协议栈处理,而是直接把它“推”到 veth1 的接收队列。veth1 收到后,再交给它所在的 ns2 协议栈处理。反向亦然。整个过程不经过物理网卡,也不依赖外部网络。

下面这张图展示了 veth pair 连接两个命名空间时的结构关系、数据流向以及状态联动。图中左侧为命名空间 ns1,右侧为命名空间 ns2,中间由一对 veth 接口相连,箭头表示帧的传递方向。

网络命名空间 ns1 TCP/IP 协议栈 路由表 / ARP / iptables veth0 10.0.0.1/24 UP 网络命名空间 ns2 TCP/IP 协议栈 路由表 / ARP / iptables veth1 10.0.0.2/24 UP veth pair(虚拟网线) 帧从 veth0 进入 → 从 veth1 出来 帧从 veth1 进入 → 从 veth0 出来 一端 DOWN / 删除 → 另一端同步失效

三、使用 ip link 创建 veth pair

创建 veth pair 最直接的工具是 ip link。基本语法如下:

ip link add <名称A> type veth peer name <名称B>

例如,在宿主机上创建一对名为 veth-host 和 veth-ns 的 veth 设备:

ip link add veth-host type veth peer name veth-ns

执行后可以用 ip link show 查看结果。此时两个接口都还在当前命名空间中,默认状态为 DOWN,且没有 IP 地址。输出中会看到类似下面的内容:

5: veth-ns@veth-host: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 8a:3f:1c:2b:9d:01 brd ff:ff:ff:ff:ff:ff
6: veth-host@veth-ns: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 9c:2e:4a:7d:11:02 brd ff:ff:ff:ff:ff:ff

注意接口名后面的 @veth-host 和 @veth-ns,这是内核在提示你“它的对端是谁”。这是判断 veth 配对关系最直观的方式之一。

四、把一端放入另一个命名空间

要让 veth pair 真正跨越隔离边界,需要先创建一个网络命名空间,再把其中一端移进去。示例流程如下:

# 1. 创建命名空间
ip netns add ns1

# 2. 创建 veth pair
ip link add veth0 type veth peer name veth1

# 3. 把 veth1 移入 ns1
ip link set veth1 netns ns1

# 4. 在宿主机侧配置 veth0
ip addr add 10.0.0.1/24 dev veth0
ip link set veth0 up

# 5. 在 ns1 内配置 veth1
ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth1
ip netns exec ns1 ip link set veth1 up
ip netns exec ns1 ip link set lo up

执行完成后,在宿主机执行 ip link show,只会看到 veth0,看不到 veth1;而在 ip netns exec ns1 ip link show 中,只会看到 veth1 和 lo。这说明 veth1 已经彻底属于 ns1 的网络栈,宿主机默认无法直接访问它。

此时从宿主机 ping 10.0.0.2,应该能收到回复;在 ns1 内 ping 10.0.0.1,同样应该通。如果 ping 不通,优先检查三件事:两端是否都 UP、IP 是否在同一网段、对端是否真的在目标命名空间中。可以用 ip netns exec ns1 ip addr 和 ip netns exec ns1 ip route 分别确认地址和路由。

五、观察与验证的关键命令

下面这张表汇总了本节最常用的观察命令及其判断依据,便于在实际操作中快速定位问题。

命令 作用 关键判断依据
ip link show 查看当前命名空间所有接口 接口名后的 @peer 表示对端名称
ip link show veth0 查看指定接口详情 state UP/DOWN、MTU、MAC 地址
ip netns exec ns1 ip link show 查看 ns1 内接口 确认 veth1 是否已移入
ip netns exec ns1 ip addr 查看 ns1 内地址 确认 IP 是否配置成功
ip netns exec ns1 ip route 查看 ns1 路由表 确认是否有到对端的路由
ping -c 2 10.0.0.2 从宿主机测试连通性 有回包说明链路与地址均正常

六、常见误区与排障思路

第一个误区是“创建完 veth 就能通”。实际上,刚创建出来的 veth pair 两端都是 DOWN,也没有 IP,必须手动配置。第二个误区是“把一端移入命名空间后,宿主机还能用原名访问它”。移入之后,该接口只存在于目标命名空间,宿主机侧只能用对端接口操作。

第三个误区是忽略 lo 接口。在新建的命名空间里,lo 默认是 DOWN 的。虽然 veth 通信不一定依赖 lo,但很多本地服务和路由行为会受影响,建议养成 ip netns exec ns1 ip link set lo up 的习惯。

删除 veth pair 时,只需删除任意一端,另一端会自动消失。例如 ip link del veth0 会同时删除 veth1。如果 veth1 已经在 ns1 中,删除后 ns1 内也会同步消失。不要试图分别删除两端,否则会报“Cannot find device”之类的错误。

掌握 veth pair 之后,下一步自然就是把它接入网桥,让多个命名空间通过一个虚拟交换机互相通信。veth pair 是容器网络、Kubernetes Pod 网络、网络命名空间实验中最基础也最不可替代的构件。理解它的成对机制、状态联动和跨命名空间能力,后续所有虚拟网络拓扑都会变得有迹可循。