主题
OVN 是什么
这一章没有实验,是一次收束:把前面十九章的零件拼起来,看看一个完整的虚拟网络系统长什么样。
前面十九章缺了什么
你现在会的东西已经不少了:
- 建网桥、接端口、配 VLAN
- 写流表实现任意转发策略
- 建 VXLAN 隧道做 Overlay
- 用 conntrack 做有状态防火墙
- 接外部控制器
但如果真要用这些搭一个云平台的网络,会遇到一个很现实的问题:
500 台宿主机、3000 个虚拟机、200 个租户,每个租户有自己的子网、路由器、安全组。 这些流表谁来生成?虚拟机迁移了谁来更新?
手写不可能。实验 18 的反应式控制器也不行(延迟高、缓存爆炸)。
你需要的不是一个 OpenFlow 控制器,而是一个能把"我想要什么样的网络"翻译成流表的系统。 这就是 OVN。
OVN 的核心思想:声明式
对比一下两种描述方式:
text
命令式(前面十九章在做的事)
"在 br-int 的 table 20 加一条规则:
匹配 dl_vlan=100,dl_dst=fa:16:3e:xx,
动作 strip_vlan,set_field:100->tun_id,output:3"
声明式(OVN 的方式)
"有一个逻辑交换机 ls1
上面有三个逻辑端口 vm1、vm2、vm3
ls1 连到逻辑路由器 lr1
vm1 的安全组允许出站、拒绝入站"你描述网络应该是什么样,OVN 负责把它翻译成每台宿主机上的流表。 虚拟机迁移了、新宿主机加进来了,OVN 自动重新计算并下发。
架构
四个组件,各司其职:
| 组件 | 在哪 | 干什么 |
|---|---|---|
| Northbound DB | 中心 | 存逻辑网络定义:逻辑交换机、路由器、端口、ACL。这是用户/云平台写入的 |
| ovn-northd | 中心 | 翻译器。把逻辑定义编译成"逻辑流表" |
| Southbound DB | 中心 | 存逻辑流表和物理拓扑(哪个端口在哪台宿主机上) |
| ovn-controller | 每台宿主机 | 订阅 SB DB,把逻辑流表翻译成本机的 OpenFlow 流表下发给 ovs-vswitchd |
两次翻译是关键设计
第一次(northd):逻辑定义 → 逻辑流表。这一步和物理拓扑无关,全局只做一次。
第二次(ovn-controller):逻辑流表 → 物理流表。每台宿主机只关心"和我有关的部分",本地完成。
这样中心节点的计算量不随宿主机数量增长,扩展性好得多。这是纯主动式(proactive)的,运行时不需要 packet-in。
它用到了你学过的每一个特性
OVN 不是另起炉灶,它就是把前面十九章的东西组合起来:
| 你学过的 | OVN 拿它做什么 |
|---|---|
| OVSDB 数据模型 | NB/SB 数据库用的就是 OVSDB |
external_ids | 把 OVS 端口关联到逻辑端口 |
| patch 端口 | 连接 br-int 和 br-ex |
| 多级流表 | 逻辑流水线有二十多张表 |
resubmit | 实现逻辑端口之间的跳转 |
| VLAN tag | 本机内标识逻辑交换机 |
| Geneve 隧道 | 跨宿主机传输,用可变元数据携带逻辑端口 ID |
options:key=flow | 一个隧道端口承载所有逻辑网络 |
| conntrack + zone | 实现安全组,每个逻辑端口一个 zone |
fail_mode=secure | 保证控制面故障时不泄露 |
你已经理解了 OVN 的每一块砖。
为什么 OVN 选 Geneve 而不是 VXLAN
实验 13 提过 Geneve 支持可变长度的元数据选项。OVN 需要在隧道头里携带:
- 源逻辑端口 ID
- 目的逻辑端口 ID
- 逻辑数据路径 ID
VXLAN 的头是固定的,只有 24 位 VNI,塞不下这些。Geneve 的 TLV 选项正好合适。
逻辑流水线
OVN 把转发拆成两条流水线:
text
入口流水线(在源宿主机上执行)
┌─────────────────────────────────────────┐
│ 0 端口安全(反 MAC/IP 欺骗) │
│ 1 ACL 前处理(送 conntrack) │
│ 2 ACL(安全组规则) │
│ 3 ARP/ND 应答(本地代答,不广播) │
│ 4 逻辑交换机转发(查逻辑 MAC 表) │
│ 5 逻辑路由器(三层转发、NAT) │
│ ... │
└─────────────────────────────────────────┘
│ Geneve 隧道
┌────────────────▼────────────────────────┐
│ 出口流水线(在目的宿主机上执行) │
│ 0 ACL(入站安全组) │
│ 1 端口安全 │
│ 2 交付到逻辑端口 │
└─────────────────────────────────────────┘ARP 本地代答很值得注意
传统二层网络里 ARP 是广播。OVN 知道每个逻辑端口的 IP 和 MAC,所以直接在源宿主机上构造 ARP 应答返回,广播根本不出宿主机。
几千个虚拟机的环境里,这一条就消灭了绝大部分广播流量。
看真实环境里的逻辑流表:
bash
ovn-sbctl lflow-list会看到几百上千条,每条形如:
text
table=8 (ls_in_l2_lkup), priority=50,
match=(eth.dst == fa:16:3e:11:22:33),
action=(outport = "vm1"; output;)这是一种中间语言,不是 OpenFlow。ovn-controller 会把它翻译成本机真实的 OpenFlow 规则。
常用命令
bash
# 逻辑网络定义(写 NB DB)
ovn-nbctl ls-add ls1 # 建逻辑交换机
ovn-nbctl lsp-add ls1 vm1 # 加逻辑端口
ovn-nbctl lsp-set-addresses vm1 "fa:16:3e:00:00:01 10.0.0.11"
ovn-nbctl lr-add lr1 # 建逻辑路由器
ovn-nbctl acl-add ls1 to-lport 1000 "ip4.src == 10.0.0.0/24" allow
ovn-nbctl show # 看逻辑拓扑
# 看编译结果(读 SB DB)
ovn-sbctl show # 物理拓扑:哪个端口在哪台机器
ovn-sbctl lflow-list # 逻辑流表
# 排错
ovn-trace ls1 'inport=="vm1" && eth.dst==...' # 逻辑层面的 trace
ovs-appctl ofproto/trace br-int '<流>' # 物理层面的 traceovn-trace 和 ofproto/trace 是两个层面
ovn-trace 走的是逻辑流水线,告诉你"按逻辑网络定义,这个包该怎么走"。
ofproto/trace(实验 8)走的是物理流表,告诉你"这台机器上实际会怎么处理"。
排错时先用 ovn-trace 确认逻辑对不对,再用 ofproto/trace 确认翻译对不对。
谁在用
| 平台 | 怎么用 OVN |
|---|---|
| OpenStack Neutron | ovn 驱动已经是默认,取代了老的 ovs + agent 方案 |
| ovn-kubernetes | Kubernetes CNI,Red Hat OpenShift 的默认网络 |
| oVirt / RHV | 虚拟化平台的网络层 |
Antrea 是另一个 Kubernetes CNI,直接用 OVS 而不经过 OVN,自己实现控制面。
该不该用 OVN
该用:
- 要做多租户虚拟网络(逻辑交换机、路由器、安全组、浮动 IP)
- 规模在几十台宿主机以上
- 已经在用 OpenStack 或 Kubernetes
不该用:
- 单机或几台机器 —— 直接用 OVS 更简单
- 只需要固定的、不常变的网络策略 —— 手写流表或脚本生成就够
- 网络需求很特殊,OVN 的逻辑模型表达不了
OVN 引入了不小的复杂度
两个数据库、两次翻译、几十张逻辑表。排错时你可能要同时看 NB DB、SB DB、逻辑流表、物理流表四个层面。
没有多租户需求就别上 OVN。 前面十九章的东西足够解决绝大多数问题。
小结
- OVN 解决的是**"流表谁来生成、谁来维护"**,而不是"怎么转发"
- 核心是声明式:描述逻辑网络,OVN 翻译成流表
- 四个组件:NB DB(逻辑定义)→ northd(翻译)→ SB DB(逻辑流表)→ ovn-controller(每机翻译成 OpenFlow)
- 两次翻译让中心节点的计算量不随宿主机数量增长,且是纯主动式
- OVN 用到了你学过的每一个特性:OVSDB、patch、多级流表、Geneve、conntrack zone、fail_mode
- 选 Geneve 是因为要在隧道头里携带逻辑端口 ID,VXLAN 的固定头塞不下
- ARP 本地代答消灭了绝大部分广播
- 排错要分层:
ovn-trace看逻辑,ofproto/trace看物理 - 规模不够就别上 OVN,复杂度不是免费的
第 5 部分到此结束。最后一部分是排错与实践 —— 把前面所有工具串成一套可执行的方法论。