主题
为什么需要虚拟交换机
从一个具体问题开始
你有一台物理服务器,上面跑着 30 个虚拟机。每个虚拟机都要能上网,也要能互相通信。
服务器只有 2 块物理网卡。
text
┌──────────────────────────────────────────┐
│ 物理服务器 │
│ │
│ VM1 VM2 VM3 ... VM29 VM30 │
│ │ │ │ │ │ │
│ └────┴────┴──── ? ───┴─────┘ │
│ │
│ eth0 eth1 │
└──────────────┬───────┬───────────────────┘
│ │
─────┴───────┴───── 物理网络中间那个问号该放什么?
最朴素的两个答案
答案一:给每个虚拟机一块物理网卡。 30 个虚拟机就插 30 块网卡。PCIe 插槽不够,成本也荒谬。排除。
答案二:在软件里做一个交换机。 每个虚拟机分一个虚拟网口,全都接到这个软件交换机上,交换机再从 eth0 出去。
这就是虚拟交换机(virtual switch)要解决的问题 —— 它是服务器内部的接入层交换机。
Linux 内核早就自带了一个:Linux bridge。
text
┌──────────────────────────────────────────┐
│ VM1 VM2 VM3 ... VM30 │
│ │ │ │ │ │
│ tap1 tap2 tap3 tap30 │
│ └───────┴───────┴─────┬──────┘ │
│ ┌────┴────┐ │
│ │ br0 │ Linux │
│ │ │ bridge │
│ └────┬────┘ │
│ eth0 │
└────────────────────────┬─────────────────┘
物理网络Linux bridge 已经够用的场景
先说清楚:很多时候 Linux bridge 完全够用。
你现在跑 Docker,默认的 docker0 就是一个 Linux bridge。容器之间二层互通、出网做 NAT,这套组合支撑了海量的生产负载。不要因为学了 OVS 就觉得 Linux bridge 是落后的东西。
Linux bridge 该干的事都干得挺好:
- 学习 MAC 地址,维护转发表
- 未知目的地址泛洪,已知地址单播转发
- STP 防环
- VLAN 过滤(内核 3.8 以后支持,用
bridge vlan配置)
那什么时候不够?
四个 Linux bridge 接不住的需求
需求一:按 IP 或端口号做转发决策
"去 80 端口的流量走这条链路,去 443 的走那条。"
Linux bridge 的转发逻辑写死在内核 C 代码里,只做一件事:查目的 MAC,找出口。它不看 IP,不看 TCP 端口 —— 二层交换机本来就不该看。
你可以拿 nftables 或 tc 在旁边打补丁,但那是在网桥之外另做一套东西,两套配置各管一半,很快就没人能说清一个包到底怎么走的。
需求二:跨物理机的二层网络
"机器 A 上的 VM1 和机器 B 上的 VM2,我要它们在同一个广播域里。"
这需要 Overlay:把二层帧封装进 UDP,跨过三层网络送到对面再解开。
内核有 vxlan 设备,你可以:
bash
ip link add vxlan10 type vxlan id 10 remote 192.0.2.2 dstport 4789
ip link set vxlan10 master br0单条隧道能跑。但真实场景是几十个租户、每个租户一个 VNI、几百台宿主机两两之间的隧道 —— 用 ip link 一条条建,还要自己维护对端列表和租户到 VNI 的映射。规模一上来就没法管了。
需求三:从控制中心统一下发策略
"我要在一个地方定义整个集群的网络策略,自动同步到 500 台宿主机。"
Linux bridge 的配置接口只有本机的 ip、bridge 命令。要远程管理,你得自己写 agent、自己定义协议、自己做状态同步和一致性。
需求四:知道每条流的流量
"这个虚拟机到那个数据库的流量有多大?"
Linux bridge 有每个端口的收发计数,但没有每条流的粒度。想要 per-flow 统计、端口镜像、流量采样,都得另外搭。
逐项对比
| 能力 | Linux bridge | Open vSwitch |
|---|---|---|
| MAC 学习、泛洪、单播转发 | 内置 | 内置(NORMAL 动作) |
| STP | 支持 | 支持,另有 RSTP |
| VLAN access / trunk | 支持(bridge vlan) | 支持,且能被流表任意改写 |
| 按 IP / 协议 / 端口号转发 | 不支持,需要 nftables/tc 旁路 | 原生支持,流表可匹配几十个字段 |
| 多级流表 pipeline | 无此概念 | 支持,resubmit / goto_table |
| 改写报文字段(NAT、改 MAC/VLAN) | 需要 nftables/tc | 流表动作原生支持 |
| VXLAN / GRE / Geneve 隧道 | 手工建隧道设备再桥接 | 端口就是隧道,配置项里声明即可 |
| 远程集中配置 | 无,只有本机命令 | OVSDB 协议,可远程读写 |
| 外部控制器接管转发 | 无 | OpenFlow 协议 |
| 每条流的统计 | 无,只有端口级 | 每条流表项自带包数/字节数 |
| 端口镜像 | 需要 tc mirred | 内置 mirror |
| sFlow / NetFlow / IPFIX | 无 | 内置 |
| 有状态防火墙(连接跟踪) | 需要 nftables | ct 动作,集成进流表 |
| 逐包转发路径追踪 | 无 | ofproto/trace |
看这张表容易得出"OVS 全面胜出"的结论,但真正该记住的是最后一行之外的那个规律:多出来的能力,全都来自同一个设计选择。
OVS 的核心思路:把转发决策变成数据
Linux bridge 和 OVS 最本质的区别在这里:
text
Linux bridge
包 ──▶ ┌──────────────────────────┐ ──▶ 出口
│ 内核里编译好的转发逻辑 │
│ 查 MAC 表 → 单播 / 泛洪 │
└──────────────────────────┘
行为固定。想改,得改内核代码。
Open vSwitch
包 ──▶ ┌──────────────────────────┐ ──▶ 出口
│ 一张流表(数据,不是代码) │
│ 匹配任意字段 → 执行动作 │
└──────────────────────────┘
行为由表内容决定。想改,改表。转发逻辑从代码变成了数据。数据可以远程下发、可以版本化、可以由控制器统一生成 —— 上面那些能力全是这一步的自然结果。
一张流表长这样(这就是第 2 部分的主要内容):
text
优先级 匹配条件 动作
200 tcp, tp_dst=80 output:3
200 tcp, tp_dst=443 output:4
150 dl_vlan=100 pop_vlan, output:5
100 ip, nw_src=10.0.0.0/8 mod_nw_src:203.0.113.1, output:2
0 (匹配所有包) NORMAL最后那条 NORMAL 值得注意
NORMAL 这个动作的含义是"按传统二层交换机的方式处理这个包" —— 查 MAC 表、该泛洪就泛洪。
也就是说 Linux bridge 的全部行为,在 OVS 里只是流表中的一条特例。你新建一个 OVS 网桥,里面默认就有这一条 priority=0 actions=NORMAL,所以它开箱就是个普通交换机。你在实验 1 里会亲眼看到这条流表项。
可编程是有代价的
每个包都去查一张可能上万条、每条都能匹配几十个字段的表 —— 这比"查一下 MAC 表"慢太多了。如果 OVS 真这么干,性能会崩。
OVS 的解法是把自己拆成两层:
text
┌────────────────────────────────────────┐
│ 用户态:完整的流表,慢,但什么都能表达 │
│ 只处理"没见过的包" │
└───────────────┬────────────────────────┘
│ 处理完把结论缓存下去
▼
┌────────────────────────────────────────┐
│ 内核态:简单的精确匹配缓存,极快 │
│ 处理绝大多数包 │
└────────────────────────────────────────┘一条连接的第一个包走上面那条慢路,OVS 把"这类包该怎么处理"的结论装进下面的缓存;后续的包全部在内核里命中缓存直接转发。
这个两级结构是理解 OVS 的关键,下一章会把它拆开讲,实验 1 里你会亲手验证它 —— 清空缓存后 ping 五个包,第一个包的 RTT 明显更高,因为只有它跑了完整的一趟。
OVS 现在跑在哪
不是实验室玩具:
- OpenStack 的 Neutron 默认用 OVS 做计算节点的虚拟交换
- OVN(Open Virtual Network)是 OVS 项目自己的上层控制面,
ovn-kubernetes、Antrea这些 Kubernetes CNI 建立在它之上 - 电信云 / NFV 大量使用 OVS-DPDK 做高性能转发
- 内核里的
openvswitch模块在 Linux 主线中,从 3.3 版本进入
小结
- 虚拟交换机解决的是"服务器内部几十个虚拟网口怎么接入网络"
- Linux bridge 把转发逻辑写死在内核里,够用、但只能按 MAC 转发
- OVS 把转发逻辑变成一张可编程的流表,由此获得了 L3/L4 转发、报文改写、隧道、集中管理、per-flow 观测这些能力
- 代价是可编程带来的性能开销,OVS 用"用户态决策 + 内核态缓存"的两级结构来抵消
NORMAL动作让 OVS 可以完全退化成一个 Linux bridge
下一章:OVS 的三个进程 —— 把这个两级结构落到具体的进程和命令上。