【笔记】网络虚拟化的数据路径与隔离边界
网络虚拟化的核心不是“再造一张虚拟网卡”,而是在不同隔离边界之间建立数据入口、转发规则和租户身份。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]
分析网络路径时依次回答:
- 端点是否与 Host 共享内核?
- Host 侧接入点是 TAP、veth、IPVlan、PCI VF,还是其他设备?
- packet 进入 Host 后由 route、bridge、OVS、eBPF 还是用户态 datapath 转发?
- 跨主机时使用 underlay route,还是 VXLAN/Geneve 等 overlay?
- 租户身份由 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 的接口。常见流程是:
- runtime 创建 container network namespace;
- 调用 CNI plugin,并传入
CNI_NETNS、CNI_IFNAME等信息; - plugin 创建或配置接口、地址和 route;
- 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_device 和 skb,没有 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 VNI | overlay 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 就没有 TAP | vhost-net 与 TAP 解决不同边界,常共同组成数据路径 |
| OVS 是 TAP backend | TAP 是接入端口,OVS 是 Host datapath |
| OVS 一定通过某个 rx handler 接管 | 需要结合具体 datapath、内核和版本核验 |
| VM eth0 可以像 veth 一样移入 netns | VM 与 Host 是两套 kernel,不能用 Host netns 操作 Guest net_device |
| CNI 就是 veth + bridge | CNI 规定 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. 复习索引
- VM 网络跨越 Guest/Host 两套 kernel,container 网络通常只跨同一 kernel 的 netns;
- Guest eth0 与 Host TAP 是两个
net_device,VirtIO/virtqueue/vhost 连接两边; - veth pair 是同一 Host kernel 中的两个端点,可以分属不同 netns;
- TAP/veth 是 Host 接入点,route/bridge/OVS/eBPF 是转发 datapath;
- OVS 用 flow key/table/action 处理 packet,miss 可以 upcall 用户态;
- VXLAN 在 underlay 上封装 inner Ethernet,VNI 标识 overlay segment;
- SR-IOV VF 可以绕开 Host software switch 主路径,但不能省略 DMA 隔离和控制面;
- 排障必须同时确认隔离边界、接入对象、datapath、tunnel 和租户身份。
12. 核验入口
- Linux Universal TUN/TAP device driver:TUN/TAP 字符设备与 network interface 双侧模型;
- VirtIO 1.2 Specification:virtio-net、virtqueue、transport 与通知;
- QEMU System Emulation Introduction:设备模型、KVM accelerator、VirtIO 与 device passthrough;
- Open vSwitch Datapath Development Guide:datapath、flow key、flow table、action 与 upcall;
- RFC 7348: VXLAN:VNI、VTEP、inner/outer frame 和典型数据路径;
- CNI Specification:runtime、plugin、network namespace、interface 与 IPAM 边界;
- Linux VFIO:device assignment、IOMMU isolation 与 group;
- Linux PCI SR-IOV HOWTO:PF/VF 与 VF 生命周期。