三云主机节点部署OVN与验证报告

8 阅读5分钟

OVN 使用3云主机节点部署与验证报告

1. 环境概述

1.1 节点信息

节点角色公网 IP (EIP)内网 IP运营商主机名
node1Central27.152.182.118172.20.2.2电信i-grtdkmrwgiygkztb-xmmp02
node2Chassis27.152.182.117172.20.2.3电信i-gu2timrtgnqtozbt-xmmp02
node3Chassis112.51.122.81172.20.2.8移动i-g42taojwgq2tgmjy-xmmp02

1.2 软件版本

组件版本
OVN24.03.6
OVS3.3.4
DB Schema7.3.0
OSUbuntu 24.04 (kernel 6.8.0-53-generic)

1.3 双网段设计

本环境每个节点拥有两个 IP 地址,承担不同职责:

┌─────────────────────────────────────────────────────────┐
│                    公网 (EIP)                           │
│    用于操作机 SSH 远程连接,执行部署和运维命令           │
│                                                         │
│  node1 EIP ←──SSH──→ 操作机 ←──SSH──→ node2 EIP       │
│                                   ←──SSH──→ node3 EIP   │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│                    内网 (Underlay)                       │
│    用于 OVN 组件间通信和隧道封装                         │
│                                                         │
│  node2 ──Geneve/VXLAN──→ node3                         │
│    (172.20.2.3)              (172.20.2.8)               │
│         ↑                         ↑                     │
│         │    ovn-remote            │                     │
│         └─────── tcp:172.20.2.2:6642 ───────┘           │
│                        node1                            │
│                     (172.20.2.2)                         │
└─────────────────────────────────────────────────────────┘
用途使用的 IP说明
SSH 远程执行EIP所有 ssh / scp 操作
ovn-remote (SB 连接)NODE1 内网 IPChassis 通过内网连接 Central SB
ovn-encap-ip (隧道源)本节点内网 IPGeneve/VXLAN 隧道封装使用内网 IP
NB/SB 监听地址0.0.0.0监听所有网卡,由防火墙控制访问

2. 组件分布

2.1 Central 节点 (node1)

运行服务:

服务systemd 单元监听端口职责
OVN NB DBovn-ovsdb-server-nbTCP 6641北向数据库,存储逻辑拓扑定义
OVN SB DBovn-ovsdb-server-sbTCP 6642南向数据库,Chassis 注册与端口绑定
ovn-northdovn-northd将 NB 逻辑翻译为 SB 流表,下发至 Chassis

核心配置文件:

文件用途当前内容/状态
/etc/default/ovn-centralCentral 三个服务共用此文件,通过 $OVN_CTL_OPTS 传参OVN_CTL_OPTS="--db-nb-create-insecure-yes --db-sb-create-insecure-yes"
/usr/lib/systemd/system/ovn-ovsdb-server-nb.serviceNB DB systemd 单元(包管理,不建议直接改)EnvironmentFile=-/etc/default/ovn-centralExecStart=/usr/share/ovn/scripts/ovn-ctl run_nb_ovsdb $OVN_CTL_OPTS
/usr/lib/systemd/system/ovn-ovsdb-server-sb.serviceSB DB systemd 单元(包管理,不建议直接改)EnvironmentFile=-/etc/default/ovn-centralExecStart=/usr/share/ovn/scripts/ovn-ctl run_sb_ovsdb $OVN_CTL_OPTS
/usr/lib/systemd/system/ovn-northd.servicenorthd systemd 单元(包管理,不建议直接改)EnvironmentFile=-/etc/default/ovn-centralExecStart=/usr/share/ovn/scripts/ovn-ctl start_northd --ovn-manage-ovsdb=no $OVN_CTL_OPTS
/usr/lib/systemd/system/ovn-central.service总控服务(oneshot),拉起上面三个Wants=ovn-ovsdb-server-nb.service ovn-ovsdb-server-sb.service ovn-northd.service
/usr/share/ovn/scripts/ovn-ctl启停脚本,所有 Central 服务统一经它拉起解析 $OVN_CTL_OPTS,控制 DB 路径/PID/socket 等
/var/lib/ovn/ovnnb_db.dbNB 数据库文件(持久化逻辑拓扑定义)OVSDB 文件,ovn-nbctl 操作的对象
/var/lib/ovn/ovnsb_db.dbSB 数据库文件(持久化 Chassis/绑定/逻辑流表)OVSDB 文件,ovn-sbctl 操作的对象
/var/run/ovn/ovnnb_db.sockNB DB Unix socket(本地 ovn-nbctl 默认连此)运行时生成
/var/run/ovn/ovnsb_db.sockSB DB Unix socket(本地 ovn-sbctl 默认连此)运行时生成
/var/run/ovn/ovnnb_db.pidNB DB PID 文件运行时生成
/var/run/ovn/ovnsb_db.pidSB DB PID 文件运行时生成
/var/run/ovn/ovn-northd.pidnorthd PID 文件运行时生成
/var/log/ovn/ovsdb-server-nb.logNB DB 日志
/var/log/ovn/ovsdb-server-sb.logSB DB 日志
/var/log/ovn/ovn-northd.lognorthd 日志

运行时数据库连接配置(存储在 OVSDB connection 表中,非独立文件):

NB: target="ptcp:6641:0.0.0.0"  inactivity_probe=0
SB: target="ptcp:6642:0.0.0.0"  inactivity_probe=0

通过 ovn-nbctl set-connection / ovn-sbctl set-connection 写入,重启后持久化在 DB 文件中。

TCP 明文模式下必须设置 --db-*-create-insecure-yes,否则 NB/SB 仅监听 Unix socket,Chassis 无法远程连接。

2.2 Chassis 节点 (node2, node3)

运行服务:

服务systemd 单元职责
openvswitch-switchopenvswitch-switchOVS 数据面,维护 br-int 网桥和 OpenFlow 流表
ovn-controllerovn-controller从 SB 获取逻辑流表,翻译为 OpenFlow 规则下发给 OVS

核心配置文件:

文件用途当前内容/状态
/etc/default/ovn-hostovn-controller 启动参数默认空(OVN_CTL_OPTS 注释掉),未自定义
/usr/lib/systemd/system/ovn-controller.serviceovn-controller systemd 单元(包管理,不建议直接改)EnvironmentFile=-/etc/default/ovn-hostExecStart=/usr/share/ovn/scripts/ovn-ctl start_controller --ovn-manage-ovsdb=no $OVN_CTL_OPTS
/usr/lib/systemd/system/ovn-host.service总控服务(oneshot),拉起 ovn-controllerWants=ovn-controller.service
/etc/default/openvswitch-switchOVS 启动参数(DPDK 等)默认全注释,未自定义
/usr/lib/systemd/system/openvswitch-switch.serviceOVS 总控,拉起 ovsdb-server + ovs-vswitchdRequires=ovsdb-server.service ovs-vswitchd.service
/usr/lib/systemd/system/ovsdb-server.serviceOVS 本地配置数据库服务ExecStart=/usr/share/openvswitch/scripts/ovs-ctl --no-mlockall start_db
/usr/lib/systemd/system/ovs-vswitchd.serviceOVS 数据面转发守护进程ExecStart=/usr/share/openvswitch/scripts/ovs-ctl --no-mlockall start
/var/lib/openvswitch/conf.dbOVS 配置数据库文件(持久化网桥/端口/external_ids 等)包含 br-int 定义、隧道端口、veth 端口等
/var/run/openvswitch/db.sockOVS DB Unix socket(ovn-controller 连此获取 OVN 配置)运行时生成
/var/run/ovn/ovn-controller.pidovn-controller PID 文件运行时生成
/var/log/ovn/ovn-controller.logovn-controller 日志
/var/log/openvswitch/ovsdb-server.logOVS DB 日志
/var/log/openvswitch/ovs-vswitchd.logOVS 转发日志

运行时 OVN 连接配置(存储在 OVS conf.db external_ids 中,非独立文件):

ovn-remote    = "tcp:172.20.2.2:6642"     # SB 连接地址(内网 IP)
ovn-encap-type = "geneve,vxlan"          # 隧道封装类型
ovn-encap-ip   = "172.20.2.3"             # 本节点隧道源 IP(内网 IP)
system-id     = "2636c4cc-..."            # Chassis UUID

通过 ovs-vsctl set Open_vSwitch . external_ids:xxx 写入,持久化在 conf.db 中,重启不丢失。

OVS external_ids 配置命令(以 node2 为例):

ovs-vsctl set Open_vSwitch . \
    external_ids:ovn-remote="tcp:172.20.2.2:6642" \
    external_ids:ovn-encap-type="geneve,vxlan" \
    external_ids:ovn-encap-ip="172.20.2.3"

2.3 组件交互关系

                    ┌──────────────────────┐
                    │  管理员 (操作机)      │
                    │  通过 EIP SSH 执行    │
                    └──────────┬───────────┘
                               │ ovn-nbctl (via SSH)
                               ▼
┌─────────────────────────────────────────────────────────┐
│                    node1 (Central)                       │
│  ┌──────────┐    ┌──────────┐    ┌───────────┐         │
│  │  NB DB   │───▶│ovn-northd│───▶│  SB DB    │         │
│  │ :6641    │    │          │    │ :6642     │         │
│  └──────────┘    └──────────┘    └─────┬─────┘         │
│                                        │                │
└────────────────────────────────────────┼────────────────┘
                                         │ tcp:172.20.2.2:6642
                              ┌──────────┴──────────┐
                              │                     │
                    ┌─────────▼──────┐    ┌─────────▼──────┐
                    │ node2 (Chassis) │    │ node3 (Chassis) │
                    │ ovn-controller  │    │ ovn-controller  │
                    │     │           │    │     │           │
                    │  ┌──▼──┐        │    │  ┌──▼──┐        │
                    │  │br-int│        │    │  │br-int│        │
                    │  └──┬──┘        │    │  └──┬──┘        │
                    └─────┼───────────┘    └─────┼───────────┘
                          │ Geneve/VXLAN          │
                          └───────────────────────┘
                               172.20.2.3172.20.2.8

2.4 配置文件关系图

Central 节点 (node1):
  /etc/default/ovn-central          ←─ 唯一需要编辑的配置文件
       │
       ▼ $OVN_CTL_OPTS
  ovn-ctl run_nb_ovsdb / run_sb_ovsdb / start_northd
       │
       ├── /var/lib/ovn/ovnnb_db.db   ←─ NB 持久化数据(含 connection 表)
       ├── /var/lib/ovn/ovnsb_db.db   ←─ SB 持久化数据(含 Chassis/Port_Binding)
       └── /var/run/ovn/*.sock        ←─ 本地管理 socket

Chassis 节点 (node2/node3):
  /etc/default/ovn-host              ←─ 默认空,一般不改
  /etc/default/openvswitch-switch     ←─ 默认空,一般不改
       │
       ▼
  ovs-ctl start_db / start
       │
       ├── /var/lib/openvswitch/conf.db  ←─ OVS 配置 DB(含 external_ids)
       │     └── external_ids:            ←─ OVN 连接三件套
       │           ovn-remote    = tcp:172.20.2.2:6642
       │           ovn-encap-type = geneve,vxlan
       │           ovn-encap-ip   = 172.20.2.3
       │
       ▼
  ovn-controller unix:/var/run/openvswitch/db.sock
       │
       └── 连接 SB DB → 获取逻辑流表 → 下发 OpenFlow 到 br-int

3. 部署过程

3.1 部署 Central (node1)

# 1. 安装软件包
apt-get install -y ovn-central

# 2. 配置 TCP 明文模式
cat > /etc/default/ovn-central <<EOF
OVN_CTL_OPTS="--db-nb-create-insecure-yes --db-sb-create-insecure-yes"
EOF

# 3. 清除旧数据库,重启服务
rm -f /var/lib/ovn/ovn-nb.db /var/lib/ovn/ovn-sb.db
systemctl restart ovn-central

# 4. 设置 NB/SDB 监听所有网卡
ovn-nbctl set-connection ptcp:6641:0.0.0.0 -- set connection . inactivity_probe=0
ovn-sbctl set-connection ptcp:6642:0.0.0.0 -- set connection . inactivity_probe=0

部署验证结果:

  [OK] ovn-ovsdb-server-nb is active
  [OK] ovn-ovsdb-server-sb is active
  [OK] ovn-northd is active
  [OK] Port 6641 is listening
  [OK] Port 6642 is listening

踩坑记录: Ubuntu 24.04 的 OVN 包中 NB/SB 数据库服务名不是 ovn-nb / ovn-sb,而是 ovn-ovsdb-server-nb / ovn-ovsdb-server-sb,总控服务为 ovn-central(exited 状态)。包名 ovn-tool 在 24.04 仓库中不存在,已从安装列表移除。

3.2 部署 Chassis (node2, node3)

# 1. 安装软件包
apt-get install -y openvswitch-switch ovn-host

# 2. 启动 OVS
systemctl restart openvswitch-switch

# 3. 配置 OVN 连接(内网 IP)
ovs-vsctl set Open_vSwitch . \
    external_ids:ovn-remote="tcp:172.20.2.2:6642" \
    external_ids:ovn-encap-type="geneve,vxlan" \
    external_ids:ovn-encap-ip="<本节点内网IP>"

# 4. 重启 ovn-controller
systemctl restart ovn-controller

部署验证结果:

node2:  [OK] ovn-controller is active, ovn-remote = tcp:172.20.2.2:6642
node3:  [OK] ovn-controller is active, ovn-remote = tcp:172.20.2.2:6642

Chassis 注册确认(在 node1 上执行 ovn-sbctl show):

Chassis "2636c4cc-cb6e-4db3-a7fc-3335a01e273c"
    hostname: i-gu2timrtgnqtozbt-xmmp02     # node2
    Encap geneve
        ip: "172.20.2.3"
    Encap vxlan
        ip: "172.20.2.3"
    Port_Binding lsp-node1

Chassis "7f756ca5-c9ee-4cde-b5bc-f9d5c9f6869b"
    hostname: i-g42taojwgq2tgmjy-xmmp02     # node3
    Encap geneve
        ip: "172.20.2.8"
    Encap vxlan
        ip: "172.20.2.8"
    Port_Binding lsp-node2

4. 逻辑网络拓扑

4.1 拓扑结构

                      lr1 (逻辑路由器)
                   10.10.0.1/24  10.20.0.1/24
                   00:00:00:00:01:01  00:00:00:00:02:01
                      │                │
              lsp-lr1-ls1          lsp-lr1-ls2
              (type:router)        (type:router)
                      │                │
                 ┌────┴────┐      ┌────┴────┐
                 │   ls1   │      │   ls2   │
                 │10.10.0.0│      │10.20.0.0│
                 │  /24    │      │  /24    │
                 └────┬────┘      └────┬────┘
                      │                │
              lsp-node1           lsp-node2
              00:00:00:00:01:11   00:00:00:00:02:21
              10.10.0.11          10.20.0.21
                      │                │
              ┌───────┴───────┐  ┌──────┴────────┐
              │   node2       │  │   node3        │
              │ (Chassis)     │  │ (Chassis)      │
              │ veth-node1    │  │ veth-node2     │
              └───────────────┘  └────────────────┘

4.2 创建命令

以下命令均在 Central 节点 (node1) 上执行,按顺序逐步构建完整拓扑。

1) 创建逻辑交换机

ovn-nbctl ls-add ls1
ovn-nbctl ls-add ls2

2) 创建逻辑路由器

ovn-nbctl lr-add lr1

3) 连接路由器与交换机(ls1 侧)

# 在 lr1 上添加面向 ls1 的路由器端口
ovn-nbctl lrp-add lr1 lrp-lr1-ls1 00:00:00:00:01:01 10.10.0.1/24

# 在 ls1 上添加面向 lr1 的交换机端口,并与路由器端口 peer
ovn-nbctl lsp-add ls1 lsp-lr1-ls1
ovn-nbctl lsp-set-type lsp-lr1-ls1 router
ovn-nbctl lsp-set-addresses lsp-lr1-ls1 router
ovn-nbctl lsp-set-options lsp-lr1-ls1 router-port=lrp-lr1-ls1

4) 连接路由器与交换机(ls2 侧)

# 在 lr1 上添加面向 ls2 的路由器端口
ovn-nbctl lrp-add lr1 lrp-lr1-ls2 00:00:00:00:02:01 10.20.0.1/24

# 在 ls2 上添加面向 lr1 的交换机端口,并与路由器端口 peer
ovn-nbctl lsp-add ls2 lsp-lr1-ls2
ovn-nbctl lsp-set-type lsp-lr1-ls2 router
ovn-nbctl lsp-set-addresses lsp-lr1-ls2 router
ovn-nbctl lsp-set-options lsp-lr1-ls2 router-port=lrp-lr1-ls2

要点:路由器端口(lrp)和交换机端口(lsp)必须通过 lsp-set-options router-port=<lrp名> 互相配对,OVN 才会在二者之间建立 patch port 实现跨管道转发。

5) 添加 VM 逻辑端口

# node2 上的 VM 接入 ls1
ovn-nbctl lsp-add ls1 lsp-node1
ovn-nbctl lsp-set-addresses lsp-node1 "00:00:00:00:01:11 10.10.0.11"

# node3 上的 VM 接入 ls2
ovn-nbctl lsp-add ls2 lsp-node2
ovn-nbctl lsp-set-addresses lsp-node2 "00:00:00:00:02:21 10.20.0.21"

要点lsp-set-addresses 同时绑定 MAC 和 IP,OVN 据此生成端口安全规则(只允许该 MAC/IP 的报文进出)和 L2 转发表项。

6) 配置 ACL 规则

# ls2 → ls1 方向
ovn-nbctl acl-add ls2 from-lport 1002 "ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && icmp" allow
ovn-nbctl acl-add ls2 from-lport 1002 "ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && tcp && tcp.dst==80" allow
ovn-nbctl acl-add ls2 from-lport 1002 "ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && tcp && tcp.dst==443" allow
ovn-nbctl acl-add ls2 from-lport 1001 "ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && udp && udp.dst==5000" drop

# ls1 → ls2 方向
ovn-nbctl acl-add ls1 from-lport 1002 "ip4.src==10.10.0.0/24 && ip4.dst==10.20.0.0/24 && icmp" allow
ovn-nbctl acl-add ls1 from-lport 1002 "ip4.src==10.10.0.0/24 && ip4.dst==10.20.0.0/24 && tcp && tcp.dst==80" allow
ovn-nbctl acl-add ls1 from-lport 1002 "ip4.src==10.10.0.0/24 && ip4.dst==10.20.0.0/24 && tcp && tcp.dst==443" allow

# 入向默认放行
ovn-nbctl acl-add ls1 from-lport 0 "inport==\"lsp-node1\"" allow
ovn-nbctl acl-add ls2 from-lport 0 "inport==\"lsp-node2\"" allow

要点acl-add 参数依次为 交换机名、方向、优先级、匹配条件、动作。优先级数值越大越优先,所以 1002 的 allow 优先于 1001 的 drop,ICMP/TCP:80/TCP:443 被放行,而 UDP:5000 被丢弃。

7) 在 Chassis 节点上创建 veth pair 模拟 VM 接入

# 在 node2 (Chassis) 上执行
ip link add veth-node1 type veth peer name veth-node1-br
ip link set veth-node1 addr 00:00:00:00:01:11
ip link set veth-node1 up
ip addr add 10.10.0.11/24 dev veth-node1
ip route add 10.20.0.0/24 via 10.10.0.1 dev veth-node1
ovs-vsctl add-port br-int veth-node1-br \
    -- set interface veth-node1-br external_ids:iface-id=lsp-node1
ip link set veth-node1-br up

# 在 node3 (Chassis) 上执行
ip link add veth-node2 type veth peer name veth-node2-br
ip link set veth-node2 addr 00:00:00:00:02:21
ip link set veth-node2 up
ip addr add 10.20.0.21/24 dev veth-node2
ip route add 10.10.0.0/24 via 10.20.0.1 dev veth-node2
ovs-vsctl add-port br-int veth-node2-br \
    -- set interface veth-node2-br external_ids:iface-id=lsp-node2
ip link set veth-node2-br up

要点external_ids:iface-id=<LSP名> 是 veth 端口与 OVN 逻辑端口关联的唯一纽带。ovn-controller 读取此字段后向 SB 注册 Port_Binding,逻辑流表才能正确下发到此端口。

4.3 逻辑端口清单

逻辑端口所属类型MACIP
lrp-lr1-ls1lr1路由器端口00:00:00:00:01:0110.10.0.1/24
lrp-lr1-ls2lr1路由器端口00:00:00:00:02:0110.20.0.1/24
lsp-lr1-ls1ls1router (peer: lrp-lr1-ls1)
lsp-lr1-ls2ls2router (peer: lrp-lr1-ls2)
lsp-node1ls1普通00:00:00:00:01:1110.10.0.11
lsp-node2ls2普通00:00:00:00:02:2110.20.0.21

4.4 ACL 规则

方向交换机优先级匹配条件动作说明
from-lportls11002ip4.src==10.10.0.0/24 && ip4.dst==10.20.0.0/24 && icmpallow允许 ICMP ls1->ls2
from-lportls11002ip4.src==10.10.0.0/24 && ip4.dst==10.20.0.0/24 && tcp.dst==80allow允许 TCP:80 ls1->ls2
from-lportls11002ip4.src==10.10.0.0/24 && ip4.dst==10.20.0.0/24 && tcp.dst==443allow允许 TCP:443 ls1->ls2
from-lportls10inport=="lsp-node1"allow允许 node1 入向
from-lportls21002ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && icmpallow允许 ICMP ls2->ls1
from-lportls21002ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && tcp.dst==80allow允许 TCP:80 ls2->ls1
from-lportls21002ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && tcp.dst==443allow允许 TCP:443 ls2->ls1
from-lportls21001ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && udp.dst==5000drop拒绝 UDP:5000 ls2->ls1
from-lportls20inport=="lsp-node2"allow允许 node2 入向

5. 数据面链路详解

5.1 VM 模拟方式

在 Chassis 节点上通过 veth pair 模拟 VM 接入:

┌──────────────────────────────────────────┐
│              Chassis 节点                │
│                                          │
│  ┌─────────┐     ┌──────────────┐       │
│  │ Namespace│     │   OVS br-int │       │
│  │ (模拟VM) │     │              │       │
│  │         │     │  veth-XX-br ─┤──┐    │
│  │ veth-XX ├─────┤              │  │    │
│  │         │     │  ovn-XX-0 ───┤──┤    │
│  │ IP/MAC  │     │  (Geneve)    │  │    │
│  │ 路由    │     │              │  │    │
│  └─────────┘     └──────────────┘  │    │
│        │                 │         │    │
│        │          iface-id=LSP名   │    │
│        │                            │    │
└────────┼────────────────────────────┼────┘
         │                            │
    VM 侧接口                   OVS 侧接口
  (配置IP/MAC/路由)         (挂入br-int, 设置iface-id)

实际配置:

节点veth VM 侧veth OVS 侧iface-idIP/路由
node2veth-node1veth-node1-brlsp-node110.10.0.11/24, 默认经 10.10.0.1 到 10.20.0.0/24
node3veth-node2veth-node2-brlsp-node210.20.0.21/24, 默认经 10.20.0.1 到 10.10.0.0/24

5.2 跨子网数据包完整路径 (10.10.0.11 → 10.20.0.21)

以 node2 上的 VM (10.10.0.11) ping node3 上的 VM (10.20.0.21) 为例:

步骤1: VM发出ICMP请求
  源: 10.10.0.11 (MAC: 00:00:00:00:01:11)
  目的: 10.20.0.21 (跨子网,需查路由表)
  路由: 经 10.10.0.1 (lr1 端口 MAC: 00:00:00:00:01:01)
  封装: Eth dst=00:00:00:00:01:01, IP dst=10.20.0.21
  ↓ veth-node1 → veth-node1-br

步骤2: OVS br-int (node2) — ls1 ingress 管道
  ls_in_check_port_sec:  校验端口安全
  ls_in_acl_eval:        匹配ACL规则 (icmp, priority 2002, reg8[16]=1 → allow)
  ls_in_acl_action:      执行 allow 动作
  ls_in_l2_lkup:         目的MAC=00:00:00:00:01:01 → outport="lsp-lr1-ls1"
  ↓ output → patch port

步骤3: lr1 ingress 管道
  lr_in_admission:       校验 eth.dst==00:00:00:00:01:01, inport=="lrp-lr1-ls1"
  lr_in_ip_input:        IP路由查找: 10.20.0.0/24 经 lrp-lr1-ls2
                         TTL递减, 源MAC改为 00:00:00:00:02:01
  ↓ output → patch port

步骤4: ls2 ingress/egress 管道
  ls_in_l2_lkup:         目的MAC=00:00:00:00:02:21 → outport="lsp-node2"
  ls_out_apply_port_sec: 输出

步骤5: Geneve隧道封装
  node2 (172.20.2.3) ──Geneve──→ node3 (172.20.2.8)
  外层: UDP dst=6081, VNI=逻辑网络标识
  内层: 原始以太帧

步骤6: OVS br-int (node3) 收到后解封装
  根据 VNI 和目的 MAC 转发到 veth-node2-br → veth-node2
  VM (10.20.0.21) 收到 ICMP Echo Request

5.3 隧道端口映射

node2 br-int:
  Port ovn-7f756c-0          # Geneve隧道端口,remote_ip=172.20.2.8 (node3)
  Port veth-node1-br         # VM接入端口,iface-id=lsp-node1

node3 br-int:
  Port ovn-2636c4-0          # Geneve隧道端口,remote_ip=172.20.2.3 (node2)
  Port veth-node2-br         # VM接入端口,iface-id=lsp-node2

6. 验证结果

6.1 服务状态

节点服务状态
node1ovn-ovsdb-server-nbactive
node1ovn-ovsdb-server-sbactive
node1ovn-northdactive
node2openvswitch-switchactive
node2ovn-controlleractive
node3openvswitch-switchactive
node3ovn-controlleractive

6.2 Chassis 注册

ChassisEncap 类型Encap IPPort_Binding
node2 (2636c4cc...)geneve, vxlan172.20.2.3lsp-node1
node3 (7f756ca5...)geneve, vxlan172.20.2.8lsp-node2

6.3 L3 连通性

node2 VM → node3 VM (10.10.0.11 → 10.20.0.21)

PING 10.20.0.21 (10.20.0.21) 56(84) bytes of data.
64 bytes from 10.20.0.21: icmp_seq=1 ttl=63 time=2.41 ms
64 bytes from 10.20.0.21: icmp_seq=2 ttl=63 time=0.439 ms
64 bytes from 10.20.0.21: icmp_seq=3 ttl=63 time=0.429 ms
64 bytes from 10.20.0.21: icmp_seq=4 ttl=63 time=0.389 ms
64 bytes from 10.20.0.21: icmp_seq=5 ttl=63 time=0.386 ms

5 packets transmitted, 5 received, 0% packet loss, time 4096ms
rtt min/avg/max/mdev = 0.386/0.811/2.412/0.800 ms

node3 VM → node2 VM (10.20.0.21 → 10.10.0.11)

PING 10.10.0.11 (10.10.0.11) 56(84) bytes of data.
64 bytes from 10.10.0.11: icmp_seq=1 ttl=63 time=0.975 ms
64 bytes from 10.10.0.11: icmp_seq=2 ttl=63 time=0.533 ms
64 bytes from 10.10.0.11: icmp_seq=3 ttl=63 time=0.500 ms
64 bytes from 10.10.0.11: icmp_seq=4 ttl=63 time=0.455 ms
64 bytes from 10.10.0.11: icmp_seq=5 ttl=63 time=0.426 ms

5 packets transmitted, 5 received, 0% packet loss, time 4064ms
rtt min/avg/max/mdev = 0.426/0.577/0.975/0.201 ms

注:node2 和 node3 分属电信/移动不同运营商,跨运营商 Geneve 隧道仍可正常工作,首包 RTT 约 1-2ms(ARP 学习开销),后续包稳定在 0.4-0.5ms。

6.4 ACL 规则验证 (ovn-trace)

OVN 使用 reg8 寄存器位标记 ACL 判定结果:

  • reg8[16] = 1allow(允许通过)
  • reg8[17] = 1drop(直接丢弃)
  • reg8[18] = 1reject(拒绝并回复)
流量类型方向ACL 优先级reg8 判定实际结果
ICMPls2→ls12002reg8[16]=1 (allow)允许通过
TCP:80ls2→ls12002reg8[16]=1 (allow)允许通过
TCP:443ls2→ls12002reg8[16]=1 (allow)允许通过
UDP:5000ls2→ls12001reg8[17]=1 (drop)被丢弃

ICMP allow 的完整 trace 片段:

 8. ls_in_acl_eval: (ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && icmp), priority 2002
    reg8[16] = 1;              ← 标记为 allow
    next;
 9. ls_in_acl_action: reg8[16] == 1, priority 1000
    reg8[16] = 0;              ← 清除标记,继续处理
    reg8[17] = 0;
    reg8[18] = 0;
    next;                       ← 放行,进入后续管道

UDP:5000 drop 的完整 trace 片段:

 8. ls_in_acl_eval: (ip4.src==10.20.0.0/24 && ip4.dst==10.10.0.0/24 && udp && udp.dst==5000), priority 2001
    reg8[17] = 1;              ← 标记为 drop
    next;
 9. ls_in_acl_action: reg8[17] == 1, priority 1000
    reg8[16] = 0;
    reg8[17] = 0;
    reg8[18] = 0;              ← 不执行 next,包在此被丢弃

6.5 OpenFlow 流表

节点流表条目数
node2499
node3499

7. 部署踩坑记录

问题原因解决方案
ovn-tool 包安装失败Ubuntu 24.04 仓库中无此包从安装列表移除,ovn-nbctl/ovn-sbctl 已包含在 ovn-common
ovn-nb.service not foundUbuntu 24.04 中 NB/SB DB 服务名变更使用 ovn-ovsdb-server-nb / ovn-ovsdb-server-sb 或通过 ovn-central 总控服务管理
ovn-sbctl show 中 Chassis 名为 UUID系统主机名非 node1/node2 格式通过 encap IP 匹配确认 Chassis 归属
nc 测试 UDP:5000 未被阻断nc UDP 模式发送不受 OVS 管道约束(内网直接可达)ovn-trace 作为 ACL 验证的权威手段

8. 逻辑网络拓扑查询命令

以下命令用于日常排查和确认逻辑网络状态,按查询对象分为三大类。

8.1 ovn-nbctl — 北向数据库查询(逻辑拓扑定义)

在 Central 节点 (node1) 上执行,查看管理员定义的逻辑资源。

# ===== 全局概览 =====

# 查看完整逻辑拓扑(交换机、路由器、端口、地址绑定)
ovn-nbctl show

# ===== 逻辑交换机 =====

# 列出所有逻辑交换机
ovn-nbctl ls-list

# 查看指定交换机的所有端口及 MAC/IP 绑定
ovn-nbctl lsp-list ls1
ovn-nbctl lsp-list ls2

# 查看指定端口的详细属性(类型、地址、选项)
ovn-nbctl lsp-get-type lsp-node1
ovn-nbctl lsp-get-addresses lsp-node1
ovn-nbctl lsp-get-options lsp-lr1-ls1

# ===== 逻辑路由器 =====

# 列出所有逻辑路由器
ovn-nbctl lr-list

# 查看路由器上的所有端口及 IP
ovn-nbctl lrp-list lr1

# 查看路由器的路由表(静态路由 + 直连路由)
ovn-nbctl lr-route-list lr1

# ===== ACL 规则 =====

# 查看指定交换机上的所有 ACL 规则
ovn-nbctl acl-list ls1
ovn-nbctl acl-list ls2

# ===== 地址映射 =====

# 查看 MAC-IP 绑定(端口安全 / DHCP 静态分配)
ovn-nbctl list Logical_Switch_Port

# ===== 连接配置 =====

# 查看 NB 数据库的远程连接配置
ovn-nbctl get-connection

# 查看数据库本身的运行状态
ovn-nbctl status

ovn-nbctl show 实际输出示例:

switch 3d8ec12a-124e-4264-ac5a-1427d37b2bb2 (ls2)
    port lsp-lr1-ls2
        type: router
        router-port: lrp-lr1-ls2
    port lsp-node2
        addresses: ["00:00:00:00:02:21 10.20.0.21"]
switch 3c40ca53-8be8-474a-8b54-db0679575b4f (ls1)
    port lsp-lr1-ls1
        type: router
        router-port: lrp-lr1-ls1
    port lsp-node1
        addresses: ["00:00:00:00:01:11 10.10.0.11"]
router d5b59209-d5ef-48ea-8069-465448abd2cd (lr1)
    port lrp-lr1-ls2
        mac: "00:00:00:00:02:01"
        networks: ["10.20.0.1/24"]
    port lrp-lr1-ls1
        mac: "00:00:00:00:01:01"
        networks: ["10.10.0.1/24"]

8.2 ovn-sbctl — 南向数据库查询(运行时状态)

在 Central 节点 (node1) 上执行,查看 Chassis 注册、端口绑定等运行时信息。

# ===== Chassis 注册 =====

# 查看所有已注册 Chassis 及其隧道封装 IP
ovn-sbctl show

# 列出所有 Chassis 及其封装配置
ovn-sbctl list Chassis

# 查看指定 Chassis 的封装类型和 IP
ovn-sbctl list Encap

# ===== 端口绑定 =====

# 查看所有逻辑端口的绑定状态(绑定到哪个 Chassis)
ovn-sbctl list Port_Binding

# 查看指定端口绑定详情
ovn-sbctl get Port_Binding lsp-node1 chassis

# ===== 逻辑流表 =====

# 查看指定逻辑交换机的 ingress/egress 逻辑流表
ovn-sbctl lflow-list ls1
ovn-sbctl lflow-list ls2

# 查看指定逻辑路由器的逻辑流表
ovn-sbctl lflow-list lr1

# ===== 数据包追踪 =====

# 追踪从 lsp-node2 发出的 ICMP 包(ls2 → ls1,预期 allow)
ovn-trace ls2 'inport=="lsp-node2" && eth.src==00:00:00:00:02:21 && eth.dst==00:00:00:00:02:01 && ip4.src==10.20.0.21 && ip4.dst==10.10.0.11 && icmp'

# 追踪从 lsp-node2 发出的 UDP:5000 包(预期 drop)
ovn-trace ls2 'inport=="lsp-node2" && eth.src==00:00:00:00:02:21 && eth.dst==00:00:00:00:02:01 && ip4.src==10.20.0.21 && ip4.dst==10.10.0.11 && udp.dst==5000'

# 追踪从 lsp-node2 发出的 TCP:80 SYN 包(预期 allow)
ovn-trace ls2 'inport=="lsp-node2" && eth.src==00:00:00:00:02:21 && eth.dst==00:00:00:00:02:01 && ip4.src==10.20.0.21 && ip4.dst==10.10.0.11 && tcp.dst==80 && tcp.flags==0x02'

# ===== 连接配置 =====

# 查看 SB 数据库的远程连接配置
ovn-sbctl get-connection

ovn-sbctl show 实际输出示例:

Chassis "2636c4cc-cb6e-4db3-a7fc-3335a01e273c"
    hostname: i-gu2timrtgnqtozbt-xmmp02     # node2
    Encap geneve
        ip: "172.20.2.3"
    Encap vxlan
        ip: "172.20.2.3"
    Port_Binding lsp-node1

Chassis "7f756ca5-c9ee-4cde-b5bc-f9d5c9f6869b"
    hostname: i-g42taojwgq2tgmjy-xmmp02     # node3
    Encap geneve
        ip: "172.20.2.8"
    Encap vxlan
        ip: "172.20.2.8"
    Port_Binding lsp-node2

ovn-sbctl list Port_Binding 关键字段说明:

字段含义示例
logical_port逻辑端口名lsp-node1
chassis绑定的 Chassis UUID2636c4cc-...
mac绑定的 MAC 地址["00:00:00:00:01:11"]
type端口类型(空=普通, router=路由端口)"" / "router"

8.3 ovs-vsctl / ovs-ofctl — OVS 数据面查询

在 Chassis 节点 (node2/node3) 上执行,查看本地 OVS 网桥和 OpenFlow 流表。

# ===== OVS 网桥与端口 =====

# 查看本节点所有网桥及端口配置
ovs-vsctl show

# 查看指定端口的 OVN 关联信息(iface-id 是端口绑定的核心)
ovs-vsctl get Interface veth-node1-br external_ids:iface-id
# 输出: "lsp-node1"

# 查看指定端口的链路状态
ovs-vsctl get Interface veth-node1-br link_state
# 输出: up

# 查看 OVN 相关的 external_ids(SB 连接地址、隧道类型、隧道源 IP)
ovs-vsctl get Open_vSwitch . external_ids:ovn-remote
# 输出: "tcp:172.20.2.2:6642"

ovs-vsctl get Open_vSwitch . external_ids:ovn-encap-type
# 输出: "geneve,vxlan"

ovs-vsctl get Open_vSwitch . external_ids:ovn-encap-ip
# 输出: "172.20.2.3"

# ===== OpenFlow 流表 =====

# 查看 br-int 上所有 OpenFlow 流规则
ovs-ofctl dump-flows br-int

# 按表号分类统计流表条目
ovs-ofctl dump-flows br-int | awk -F'table=' '{print $2}' | awk -F' ' '{print $1}' | sort | uniq -c | sort -rn

# 查看指定表号的流规则(如 table=8 即 ls_in_acl_eval)
ovs-ofctl dump-flows br-int table=8

# 查看指定端口相关的流规则
ovs-ofctl dump-flows br-int | grep "in_port=veth-node1-br"

# ===== 隧道端口 =====

# 查看 Geneve 隧道端口配置(remote_ip 指向对端 Chassis 内网 IP)
ovs-vsctl get Interface ovn-7f756c-0 options
# 输出: {csum="true", key=flow, remote_ip="172.20.2.8"}

# ===== 连通性诊断 =====

# 从 VM 侧发 ping(在 veth 接口上)
ping -I veth-node1 10.20.0.21

# 查看 ARP 表(确认是否学到对端 MAC)
ip neigh show dev veth-node1

# 查看 veth 接口的路由表
ip route show dev veth-node1
# 输出: 10.10.0.0/24 proto kernel scope link src 10.10.0.11
#        10.20.0.0/24 via 10.10.0.1

# 抓包:在 OVS 侧查看进入 br-int 的原始报文
tcpdump -i veth-node1-br -nn -e icmp

ovs-vsctl show 实际输出示例(node2):

a6010e53-fba5-412b-be0b-15ffd4fe16c5
    Bridge br-int
        fail_mode: secure
        datapath_type: system
        Port ovn-7f756c-0
            Interface ovn-7f756c-0
                type: geneve
                options: {csum="true", key=flow, remote_ip="172.20.2.8"}
        Port br-int
            Interface br-int
                type: internal
        Port veth-node1-br
            Interface veth-node1-br
    ovs_version: "3.3.4"

8.4 命令速查对照表

按排查场景快速索引:

排查场景命令执行位置
逻辑拓扑长什么样ovn-nbctl shownode1
某交换机有哪些端口ovn-nbctl lsp-list ls1node1
某端口绑定了什么 MAC/IPovn-nbctl lsp-get-addresses lsp-node1node1
ACL 规则是否配了ovn-nbctl acl-list ls2node1
Chassis 有没有注册上来ovn-sbctl shownode1
端口有没有绑定到 Chassisovn-sbctl list Port_Bindingnode1
包走到哪一步被丢/被放ovn-trace ls2 '...'node1
OVS 上 VM 端口是否挂进去了ovs-vsctl shownode2/node3
iface-id 有没有设对ovs-vsctl get Interface veth-node1-br external_ids:iface-idnode2/node3
SB 连接地址是否正确ovs-vsctl get Open_vSwitch . external_ids:ovn-remotenode2/node3
隧道有没有建起来ovs-vsctl get Interface ovn-7f756c-0 optionsnode2/node3
OpenFlow 流表有多少条ovs-ofctl dump-flows br-int | wc -lnode2/node3
ACL 在 OpenFlow 层怎么生效ovs-ofctl dump-flows br-int table=8node2/node3
VM 侧是否能 ping 通对端ping -I veth-node1 10.20.0.21node2/node3

9. 清理方式

# 完整清理(拓扑 + 服务 + veth)
export NODE0_IP=172.20.2.2 NODE0_EIP=27.152.182.118
export NODE1_IP=172.20.2.3 NODE1_EIP=27.152.182.117
export NODE2_IP=172.20.2.8 NODE2_EIP=112.51.122.81

cd ovn-deploy
./cleanup.sh all

# 或按范围清理
./cleanup.sh topology   # 仅删除逻辑拓扑和 veth
./cleanup.sh services   # 仅停止并卸载 OVN/OVS 服务