4、OVS 流表入门:流表概念、匹配域与动作

好,咱们进入正题。前面几章我们聊了怎么装 OVS、怎么建网桥、怎么配端口。但说实话,那些都只是热身。真正让 OVS 变得强大的,是它的流表机制。

流表是什么?我打个比方你就明白了。你想想看,一个交换机收到一个数据包,它得决定怎么处理——是转发、丢弃、还是修改?传统交换机靠 MAC 地址表,OVS 呢?它靠流表。流表就是一张规则表,每条规则告诉你:什么样的包,该做什么动作。

我个人习惯把流表理解成「交通规则」。数据包就像路上的车,流表就是红绿灯和指示牌。没有流表,数据包就乱跑;有了流表,一切井然有序。

4.1 流表的核心概念

先看一个最简单的流表条目长什么样。我用 ovs-ofctl dump-flows 命令,能看到当前网桥上的流表:

# ovs-ofctl dump-flows br0
 cookie=0x0, duration=10.001s, table=0, n_packets=0, n_bytes=0, priority=0,ip,in_port="eth0",nw_src=10.0.0.1 actions=output:"eth1"

这一行信息量很大。我拆开给你看:

  • cookie:就是个标识符,方便你管理流表条目,不影响转发逻辑。
  • duration:这条规则活了多久。10 秒前刚加的。
  • table:流表编号。OVS 支持多级流表,默认是 table 0。
  • priority:优先级。数字越大越优先。默认是 0。
  • 匹配域ip,in_port="eth0",nw_src=10.0.0.1 这部分就是匹配条件。
  • actions:匹配成功后要执行的动作,这里是转发到 eth1。

嗯,这里要注意:流表是精确匹配 + 通配符匹配的混合体。你可以指定一个具体的 IP,也可以用 nw_src=10.0.0.0/24 匹配一个网段。

核心要点:流表由三部分组成——匹配域、优先级、动作。匹配域决定「谁符合条件」,优先级决定「多条规则冲突时听谁的」,动作决定「符合条件后怎么办」。

4.2 匹配域详解

匹配域是流表最灵活的部分。说白了,你可以根据数据包的任何字段来做匹配。我整理了一份常用匹配域清单,你在项目里肯定用得上:

匹配域 含义 示例
in_port 入端口 in_port="eth0"
dl_src 源 MAC 地址 dl_src=00:11:22:33:44:55
dl_dst 目的 MAC 地址 dl_dst=ff:ff:ff:ff:ff:ff
dl_type 以太网类型 dl_type=0x0800 (IPv4)
nw_src 源 IP 地址 nw_src=192.168.1.0/24
nw_dst 目的 IP 地址 nw_dst=10.0.0.1
nw_proto IP 协议号 nw_proto=6 (TCP)
tp_src TCP/UDP 源端口 tp_src=80
tp_dst TCP/UDP 目的端口 tp_dst=443
vlan_vid VLAN ID vlan_vid=100

我记得有一次排查一个网络故障,流量就是不通。我查了半天,最后发现是 dl_type 写错了——我配的是 0x0800(IPv4),但实际流量是 IPv6(0x86DD)。这种坑,你遇到了就知道有多头疼。

小技巧:如果你不确定某个字段的值,可以用 ovs-ofctl dump-portsovs-ofctl show 查看端口信息。匹配域写错了,流表是不会报错的,它只会默默不匹配。

4.3 动作详解

匹配到了,然后呢?动作决定了数据包的命运。OVS 支持的动作非常多,我挑几个最常用的讲:

4.3.1 output:转发到端口

最基础的动作,没有之一。

actions=output:"eth1"

也可以转发到多个端口:

actions=output:"eth1",output:"eth2"

4.3.2 drop:丢弃

没有动作就是丢弃。但为了明确,我建议你显式写出来:

actions=drop

4.3.3 normal:传统二层转发

让 OVS 像普通交换机一样工作,基于 MAC 地址表转发。

actions=normal

4.3.4 mod_vlan_vid:修改 VLAN

这个我在做 VLAN 隔离项目时经常用:

actions=mod_vlan_vid:100,output:"eth1"

4.3.5 resubmit:重入流表

这是多级流表的核心动作。把数据包重新提交到指定流表继续处理。

actions=resubmit(,1)

上面这个意思是:提交到 table 1 继续匹配。

避坑指南:我曾经在项目里用 resubmit 写了一个循环——table 0 提交到 table 1,table 1 又提交回 table 0。结果 OVS 直接卡死,CPU 飙到 100%。后来我加了 resubmit 次数限制才解决。记住,resubmit 一定要有出口,别让它无限循环。

4.4 实战:写一条完整的流表规则

光说不练假把式。咱们来写一条真实的流表规则。假设场景是这样的:

  • 网桥 br0 上有两个端口:eth0eth1
  • 我想把来自 eth0、源 IP 是 10.0.0.0/24 的 TCP 流量,转发到 eth1
  • 同时把 VLAN 标签改成 200

命令如下:

ovs-ofctl add-flow br0 \
  "priority=100,ip,in_port=\"eth0\",nw_src=10.0.0.0/24,nw_proto=6 \
   actions=mod_vlan_vid:200,output:\"eth1\""

验证一下:

# ovs-ofctl dump-flows br0
 cookie=0x0, duration=5.123s, table=0, n_packets=0, n_bytes=0, priority=100,ip,in_port="eth0",nw_src=10.0.0.0/24,nw_proto=6 actions=mod_vlan_vid:200,output:"eth1"

看到没?流表已经生效了。虽然现在 n_packets=0,但只要符合条件的流量进来,它就会自动匹配并执行动作。

重要提醒:流表规则是立即生效的。你加完规则,下一个数据包就会按新规则处理。所以生产环境里加规则要小心,最好先在测试环境验证。

4.5 流表的优先级与匹配顺序

你可能会问:如果多条规则都能匹配同一个包,怎么办?

答案是:优先级高的先匹配。优先级数字越大,优先级越高。如果优先级相同,那就看谁先添加的——但我不建议依赖这个顺序,太容易出问题。

举个例子:

# 规则1:优先级 100,匹配所有 IP 流量,转发到 eth1
ovs-ofctl add-flow br0 "priority=100,ip actions=output:\"eth1\""

# 规则2:优先级 200,匹配来自 10.0.0.1 的流量,转发到 eth2
ovs-ofctl add-flow br0 "priority=200,ip,nw_src=10.0.0.1 actions=output:\"eth2\""

这时候,来自 10.0.0.1 的包会匹配规则2(优先级 200),其他 IP 包匹配规则1(优先级 100)。

我个人习惯是:通用规则给低优先级,特殊规则给高优先级。这样既保证了灵活性,又不会漏掉流量。

4.6 流表的默认行为

如果没有任何规则匹配呢?OVS 会怎么做?

答案是:默认丢弃。没错,OVS 的流表默认是「白名单」机制——你没写规则,我就当没看见这个包,直接丢掉。

所以,很多新手第一次配 OVS 时,发现流量不通,就是因为忘了加默认转发规则。我建议你至少加一条兜底规则:

ovs-ofctl add-flow br0 "priority=0,actions=normal"

这条规则优先级最低(0),匹配所有包,执行 normal 动作——让 OVS 像普通交换机一样工作。这样至少不会丢包。

我的经验:在调试阶段,我通常先加一条 priority=0,actions=normal 兜底,然后逐步加高优先级的精确规则。等所有规则都验证通过了,再把兜底规则删掉。这样能避免「一加规则就断网」的尴尬。

4.7 本章小结

好了,流表入门就讲到这里。你记住三件事就行:

  1. 流表 = 匹配域 + 优先级 + 动作,缺一不可
  2. 匹配域可以精确到 MAC、IP、端口、VLAN 等任意字段
  3. 动作决定了数据包的命运——转发、丢弃、修改、重入流表

下一章,我会带你深入多级流表,看看怎么用流水线的方式处理复杂流量。到时候你会发现,流表的威力远不止于此。

公众号:蓝海资料掘金营,微信deep3321