文章

【笔记】网络虚拟化的数据路径与隔离边界

【笔记】网络虚拟化的数据路径与隔离边界

网络虚拟化的核心不是“再造一张虚拟网卡”,而是在不同隔离边界之间建立数据入口、转发规则和租户身份。VM 跨越两套内核,container 通常只跨 network namespace;二者都可以接入 bridge、OVS、route 或 overlay,但入口对象和数据路径不同。

1. 中心模型:先区分隔离边界,再看转发技术

flowchart LR
    subgraph VM[VM:两套 Kernel]
        GE[Guest eth0]
        VQ[VirtIO / virtqueue]
        TAP[Host TAP]
        GE --> VQ --> TAP
    end

    subgraph CT[Container:同一 Kernel]
        PE[Pod eth0]
        VH[Host veth peer]
        PE <--> VH
    end

    TAP --> DP[Host datapath]
    VH --> DP
    DP --> RT[Route / Bridge / OVS / eBPF]
    RT --> OL[VXLAN / Geneve / Physical Network]

分析网络路径时依次回答:

  1. 端点是否与 Host 共享内核?
  2. Host 侧接入点是 TAP、veth、IPVlan、PCI VF,还是其他设备?
  3. packet 进入 Host 后由 route、bridge、OVS、eBPF 还是用户态 datapath 转发?
  4. 跨主机时使用 underlay route,还是 VXLAN/Geneve 等 overlay?
  5. 租户身份由 IP、MAC、VLAN、VNI、ENI/VF 或其他 metadata 表示?

只画一条“虚拟网卡 → OVS → 物理网卡”的线,会丢掉最关键的内核与身份边界。

2. Linux net_device 是内核内对象

struct net_device 表示某个 Linux kernel 认识的网络设备。物理 NIC、loopback、veth、TAP、bridge、VXLAN device 都可以进入这套模型,但它们的驱动和数据来源不同。

network namespace 隔离的是同一内核中的网络对象视图。一个 net_device 在任一时刻属于某个 netns;把 veth 一端移动到 container netns,仍然是在同一个 kernel 中重组对象。

VM 则有独立 Guest kernel:

1
2
Guest kernel: eth0、Guest skb、Guest socket、Guest route
Host kernel:  tap0、Host skb、Host socket、Host route

Guest 的 eth0 与 Host 的 tap0 不是同一个 net_device,也不能用 ip link set ... netns 在两套 kernel 之间搬移。它们通过虚拟设备协议交换 packet data。

3. VM 网络:Guest eth0 如何接到 Host

3.1 VirtIO-net 在 Guest 中表现为一块设备

Guest 的 virtio-net driver 注册自己的 net_device。Guest 发包时,内核构造 Guest skb,driver 将 buffer descriptor 放入 virtqueue,再通知 Host 侧 device implementation。

1
2
3
4
5
Guest socket
  → Guest TCP/IP stack
  → Guest skb
  → virtio-net driver
  → virtqueue descriptor

跨过 virtqueue 后,Host 根据 descriptor 读取 packet data,并进入 Host 自己的 socket/SKB/netdevice 世界。两侧可能共享承载 packet 的 Guest memory page,但 Guest skb 与 Host skb 仍是两套 kernel 中的对象,不能把它们理解成同一个结构体穿越边界。

3.2 TAP 同时有字符设备接口和网络设备接口

Linux TUN/TAP driver 提供两个方向:

  • 用户态程序通过 /dev/net/tun 对 file descriptor 读写 packet;
  • Host kernel 中出现对应的 TUN/TAP network interface。

TUN 处理 IP packet,TAP 处理 Ethernet frame。对 VM 网卡后端而言,常见的是 TAP,因为 Guest 通常看到 Ethernet-like device。

方向要从 Host TAP 的视角理解:

1
2
3
4
5
6
7
用户态/VMM 向 TAP fd 写入 frame
  → Host 认为 frame 从 tap0 收到
  → 进入 Host RX/datapath

Host datapath 向 tap0 发送 frame
  → frame 排队到 TAP fd
  → 用户态/VMM 读取并交给 Guest

所以 tap0 不是 Guest eth0,也不是“虚拟网线”本身;它是 Host 网络栈为该 VM 提供的接入端口。

3.3 vhost-net 把 VirtIO 数据面移入内核

不用 vhost-net 时,QEMU 可以在用户态处理 virtqueue 和 TAP fd,packet 会跨越用户态/内核态边界。

使用 vhost-net 时,QEMU 仍负责创建和配置 VM、VirtIO device、virtqueue 与 TAP backend,但把稳定运行的数据面交给 Host kernel 的 vhost-net。概念路径变为:

1
2
3
4
5
Guest TX:
virtio-net → virtqueue → vhost-net → TAP backend → Host datapath

Guest RX:
Host datapath → TAP backend → vhost-net → virtqueue → virtio-net

“没有 QEMU read()”不等于 TAP 消失,也不是 OVS “劫持”了 TAP。它表示负责消费 TAP/virtqueue 数据面的执行者从 QEMU 用户态换成了 vhost-net 内核路径。

具体 copy、zero-copy、XDP、offload 与通知路径会随内核、QEMU 和配置变化,不能从这张概念图直接推出固定函数调用链。

4. Container 网络:veth 跨 namespace,不跨 kernel

典型 container/Pod 网络使用 veth pair:

1
2
Pod netns                        Host root netns
eth0  <-------- veth pair --------> vethXXXX

两端都是同一个 Host kernel 中的 net_device。packet 从一端发送后,在另一端以接收方向进入;不需要 VirtIO、Guest memory 或 VM Exit。

CNI 规范定义 runtime 与 network plugin 的接口。常见流程是:

  1. runtime 创建 container network namespace;
  2. 调用 CNI plugin,并传入 CNI_NETNSCNI_IFNAME 等信息;
  3. plugin 创建或配置接口、地址和 route;
  4. IPAM plugin 可以独立负责地址分配。

CNI 只约束配置接口,不规定数据面必须是 veth、bridge、VXLAN 或 eBPF。Flannel、Calico、Cilium、云厂商 CNI 可以选择完全不同的 Host datapath。

5. Host datapath:接入点和转发器是两层

TAP 或 veth 解决“端点怎样进入 Host”。bridge、route、OVS、eBPF 等解决“Host 收到 packet 后怎样处理”。它们不能合并成一个概念。

5.1 Linux routing

三层方案根据 destination、policy rule 和 route table 选择下一跳/出接口。Calico 一类实现可以通过路由传播 Pod prefix,在部分模式下不使用 overlay。

5.2 Linux bridge

bridge 按 MAC learning/FDB 在二层端口间转发。TAP 或 veth 加入 bridge 后,就像接入一个软件交换机端口。

5.3 Open vSwitch

OVS datapath 对选定 network devices 做 flow-level packet processing。内核 datapath 为 packet 提取 flow key 并查 flow table:

  • 命中:在内核执行 actions;
  • 未命中:upcall 到用户态,由用户态决定处理并可安装后续 flow。

tap0 或 veth 加为 OVS port,表示它成为 datapath 的一个接入端口。不要把这个关系描述成“OVS 把 TAP 劫持成自己的设备”;TAP 仍是 Host network device,OVS 负责其 packet 的后续 flow processing。

OpenFlow 与 OVS 也不是同义词。OpenFlow 是控制器管理 OpenFlow switch pipeline 的南向协议;OVS 是一个具体虚拟交换机实现,可以接受 OpenFlow,也可以通过 OVSDB 管理 bridge、port 和 interface 等配置。OVS 用户态根据高层 pipeline 计算处理结果,内核 datapath 则缓存适合快速执行的 flow/actions。控制面规则、用户态分类器和内核 datapath flow 不是同一张表,排障时要区分:

1
2
3
ovs-ofctl dump-flows <bridge>   # OpenFlow pipeline
ovs-dpctl dump-flows            # datapath flows
ovs-vsctl show                   # OVSDB 中的拓扑配置

同一个 metadata-aware VXLAN port 可以由 flow action 动态设置 VNI 和 remote endpoint,因此不要求“每个 VPC 创建一个 VXLAN port”。这只是端口复用能力;VPC 与 VNI、VTEP 的映射仍要由控制面提供。

OVS 的内核接入细节会随 datapath 和版本变化。仅凭概念图不能断言一定经过某个 rx_handler、固定的 netif_receive_skb() 调用或某个 VXLAN 实现函数。

5.4 eBPF datapath

eBPF 可以挂在 tc、XDP、cgroup/socket 等 hook 上执行转发、策略、负载均衡和封装。它可能绕过部分传统 bridge/iptables 路径,但仍需明确 hook、map 状态和出接口,不能把“用了 eBPF”当成完整数据路径说明。

6. Overlay:在 Underlay 上携带虚拟网络身份

6.1 VXLAN 解决二层 segment 跨三层网络

VXLAN 把 inner Ethernet frame 封装在 UDP/IP 中。外层 IP 在物理 underlay 中路由,VNI 标识 inner frame 所属的 VXLAN segment。

1
2
3
4
5
Inner Ethernet frame
  → VXLAN header (VNI)
  → UDP
  → Outer IP
  → Physical Ethernet

VNI 是 24-bit 标识。它扩大了相对于传统 VLAN 的逻辑 segment 空间,并让同一组 tunnel endpoint 承载多个租户网络。

6.2 一个 tunnel interface 不必只对应一个租户

Linux/OVS 可以使用 metadata-aware tunnel port:flow action 根据 packet metadata 设置 VNI 和 remote endpoint。同一个逻辑 tunnel port 可以承载多个 VNI。

但这不是“一个 VXLAN device 天然知道所有 VPC”。控制面仍需建立:

1
2
3
4
端点/网络身份
  → VNI
  → remote VTEP
  → underlay route

VNI 提供 segment identity,不负责自动发现成员、分发 route、执行 security policy 或管理 endpoint 生命周期。

6.3 MTU 是 overlay 的直接代价

外层 Ethernet/IP/UDP/VXLAN header 增加封装开销。如果 underlay MTU 不变,inner network 必须缩小 MTU,或依赖分片/其他机制。遇到“小包通、大包不通”时,要沿 inner MTU、tunnel MTU、underlay MTU 和 PMTU discovery 检查。

7. 三条典型数据路径

7.1 VM + TAP + OVS + VXLAN

1
2
3
4
5
6
7
8
9
10
Guest app
  → Guest TCP/IP
  → Guest eth0 / virtio-net
  → virtqueue
  → vhost-net
  → Host tap0
  → OVS flow lookup/actions
  → set tunnel metadata/VNI
  → VXLAN encapsulation
  → Host physical NIC

反方向逐层解封装和查表,最终从 Host TAP/vhost 把 frame 放入 Guest RX virtqueue。

7.2 Pod + veth + route/VXLAN

1
2
3
4
5
6
7
Pod app
  → Pod TCP/IP
  → Pod eth0
  → veth peer in Host
  → Host route/policy
  → VXLAN device or eBPF tunnel action
  → Host physical NIC

全过程在同一个 Host kernel 中处理 net_deviceskb,没有 Guest/Host 两套内核对象的转换。

7.3 VM + SR-IOV VF

1
2
3
4
5
Guest app
  → Guest TCP/IP
  → Guest VF driver
  → assigned PCI VF
  → physical NIC datapath

这条路径可以绕开 TAP、vhost-net 和 Host software switch 的主数据面。IOMMU 限制 VF 的 DMA 范围,PF/设备硬件与 Host 控制面负责 VF 配置和资源切分。

路径更短不代表所有功能都免费保留。迁移、流量观测、策略执行、带宽控制和故障隔离可能需要 NIC hardware、representor、embedded switch 或额外控制面配合。

8. 网络身份与转发路径是两个问题

网络虚拟化经常同时处理多种身份:

标识主要作用域
netns同一 kernel 内隔离网络对象
MAC二层端点与 FDB lookup
IP/prefix三层端点与 route lookup
VLAN ID单条二层链路上的逻辑隔离
VXLAN VNIoverlay segment identity
PCI PF/VF设备 function 与资源分配
云 ENI 身份云平台的路由、安全组和生命周期主体

packet “从哪张 Linux interface 发出”不一定等于云平台认为它“属于哪个租户/ENI”。阿里云 ENI Trunking 等方案会用 VLAN 和 Member ENI 关联,在一条 Trunk ENI 上恢复不同 Pod 的云网络身份;这属于具体产品控制面与数据面,应放在独立产品笔记中,不反推为所有网络虚拟化的通用实现。

9. 排障时沿边界逐层观测

9.1 VM 内

1
2
3
4
ip -d link show
ip route show table all
ethtool -i eth0
ethtool -k eth0

确认 Guest 看到的 device model、地址、route 和 offload,不要从 Guest interface 名字猜 Host 接入点。

9.2 Host 接入点

1
2
3
ip -d link show
bridge link
bridge fdb show

确认 TAP/veth/VXLAN device 的 namespace、master、state 和 MTU。Host 看不到 Guest 内部 eth0 是正常现象。

9.3 OVS

1
2
3
4
5
ovs-vsctl show
ovs-ofctl dump-ports-desc <bridge>
ovs-ofctl dump-flows <bridge>
ovs-dpctl show
ovs-dpctl dump-flows

区分 OpenFlow 控制视图与 datapath flow/cache 视图。一个 port 出现在配置中,不代表 packet 一定命中预期 flow。

9.4 Tunnel 与物理网络

1
2
3
ip -d link show type vxlan
ip route get <remote-vtep-ip>
tcpdump -ni <underlay-iface> udp port 4789

同时检查 VNI、remote VTEP、underlay route、MTU 和防火墙。只看到外层 UDP packet,不能证明 inner endpoint/segment 映射正确。

10. 易混点

说法更准确的理解
TAP 就是 Guest 网卡TAP 是 Host 侧接入点,Guest eth0 在另一套 kernel 中
Guest skb 直接变成 Host skb跨 VirtIO 传输的是 packet buffer/descriptor;两侧 skb 属于不同 kernel
TAP 必须由 QEMU read()用户态模式会读写 TAP fd;vhost-net 可把稳定数据面移入内核
使用 vhost-net 就没有 TAPvhost-net 与 TAP 解决不同边界,常共同组成数据路径
OVS 是 TAP backendTAP 是接入端口,OVS 是 Host datapath
OVS 一定通过某个 rx handler 接管需要结合具体 datapath、内核和版本核验
VM eth0 可以像 veth 一样移入 netnsVM 与 Host 是两套 kernel,不能用 Host netns 操作 Guest net_device
CNI 就是 veth + bridgeCNI 规定 runtime/plugin 接口,不规定唯一 datapath
VXLAN port 一租户一个metadata-aware tunnel port 可以承载多个 VNI
VNI 等于完整租户控制面VNI 只标识 segment,成员、route、policy 和生命周期仍需控制面
SR-IOV VF 完全绕过所有虚拟化它缩短设备数据面,但仍依赖 IOMMU、PF/control plane 和 Guest driver

11. 复习索引

  1. VM 网络跨越 Guest/Host 两套 kernel,container 网络通常只跨同一 kernel 的 netns;
  2. Guest eth0 与 Host TAP 是两个 net_device,VirtIO/virtqueue/vhost 连接两边;
  3. veth pair 是同一 Host kernel 中的两个端点,可以分属不同 netns;
  4. TAP/veth 是 Host 接入点,route/bridge/OVS/eBPF 是转发 datapath;
  5. OVS 用 flow key/table/action 处理 packet,miss 可以 upcall 用户态;
  6. VXLAN 在 underlay 上封装 inner Ethernet,VNI 标识 overlay segment;
  7. SR-IOV VF 可以绕开 Host software switch 主路径,但不能省略 DMA 隔离和控制面;
  8. 排障必须同时确认隔离边界、接入对象、datapath、tunnel 和租户身份。

12. 核验入口

本文由作者按照 CC BY 4.0 进行授权