2367 字
12 分钟
ovs-ofctl中的action之ct
ovs-ofctl 流表中的 ct 动作 (actions=ct(...)) 是 Open vSwitch (OVS) 连接追踪 (Connection Tracking, conntrack) 功能的核心指令。它的核心作用是 将数据包交给内核的连接追踪子系统进行处理 。ct 动作不仅允许 OVS 感知连接状态(通过后续规则匹配 ct_state),还允许修改连接状态和属性(如执行 NAT),是实现有状态防火墙、NAT、负载均衡等高级网络功能的基础。
ct 动作的核心作用
- 启用连接追踪: 触发内核连接追踪模块检查该数据包。
- 建立/更新连接状态: 对于新连接,
commit参数会创建一个新的连接追踪条目;对于现有连接的后续包,会更新该连接的状态(如超时、序列号、状态标志等)。 - 提供状态信息: 连接追踪子系统处理后的结果(
ct_state,ct_mark,ct_label,ct_zone,ct_nw_proto等)会设置到数据包的元数据中,供后续的流表规则匹配和决策。 - 执行有状态操作: 直接执行 NAT 操作(源 NAT/SNAT、目的 NAT/DNAT、同时 DNAT 和 SNAT)。
- 强制策略检查:(
commit, exec(allow/block)) 强制对连接的第一个数据包应用策略(通常是防火墙的“默认拒绝”策略的例外)。
ct 动作的主要参数及用法详解
ct 动作接受多个参数,通过括号 () 内逗号分隔指定。主要参数如下:
1. commit(提交连接)
- 作用: 对于
+new状态的数据包(即新连接的第一个包),commit指示连接追踪子系统 创建 一个持久化的连接追踪条目记录这条连接。连接建立后,后续属于该连接的包(+est,+rel)都会自动匹配和更新这个条目。 对于+new的包,commit是必须的,否则追踪状态不会被保存。 - 用法:
actions=ct(commit, ...其他参数...) # 创建/提交连接actions=ct(...) # 不带 commit 通常只做检查,不持久化新连接(适用于 `+est`/`+rel` 包)- 典型场景:
- 放行并记录内部客户端发起的新出站连接。
- 在 DNAT 规则后提交转换后的连接,确保回包能正确匹配。
2. zone[=](连接追踪域)
- 作用: 指定连接追踪发生的 域(Zone)。每个
zone拥有独立的连接追踪表。这允许 逻辑隔离 不同的网络策略或租户(例如 VRF 或租户隔离)。zone参数对ct动作的行为至关重要。 - 用法:
actions=ct(zone=5, commit) # 在 zone 5 中追踪并提交连接actions=ct(zone=10) # 在 zone 10 中检查连接状态actions=ct(zone=0) # 在默认 zone 0 中操作(与不指定 zone 等效)actions=ct() # 隐含在默认 zone 0 中操作- 典型场景:
- 多租户云环境中,不同租户或不同逻辑网络的流量在不同
zone中追踪,避免冲突。 - 需要在不同策略点(如物理网卡入口和虚拟机 vNIC 入口)独立跟踪连接状态。
- 多租户云环境中,不同租户或不同逻辑网络的流量在不同
3. NAT 参数(nat)
-
作用: 直接在
ct动作内部执行网络地址转换 (NAT)。这是ct动作执行有状态操作的关键。 -
子参数:
-
src[=]: 执行 源 NAT (SNAT)。将匹配数据包的 源 IP 地址 替换为指定的 IP 地址或 IP 范围/端口范围。
Terminal window actions=ct(commit, nat(src=203.0.113.1)) # SNAT 到单个 IP (端口自动分配)actions=ct(commit, nat(src=203.0.113.2:1024-2048)) # SNAT 到指定 IP 和端口范围actions=ct(commit, nat(src=192.168.1.0/24)) # SNAT 到 IP 范围(通常配合哈希)-
dst[=]: 执行 目的 NAT (DNAT)。将匹配数据包的 目标 IP 地址(和可选的端口) 替换为指定的 IP 地址(和端口)。
Terminal window actions=ct(commit, nat(dst=192.168.1.100)) # DNAT 目标 IP (端口不变)actions=ct(commit, nat(dst=192.168.1.100:8080)) # DNAT 目标 IP 和端口-
dst[=]:+src[=](组合): 执行 同时进行的 DNAT 和 SNAT(有时也称为 Full NAT)。先做 DNAT,再做 SNAT。
Terminal window actions=ct(commit, nat(dst=192.168.1.100, src=10.0.0.1)) # DNAT + SNATactions=ct(commit, nat(dst=192.168.1.100:80, src=203.0.113.1:1000-2000)) # 详细地址/端口-
persistent: 用于 NAT 网关多出口 IP 的场景,使得同一个内部连接的 不同会话 尽可能使用同一个外部 IP(对于特定协议如 FTP/PASV)。通常和src=范围一起使用。
Terminal window actions=ct(commit, nat(src=203.0.113.10-203.0.113.20, persistent)) -
-
典型场景:
- 使内部私有 IP (
192.168.1.x) 访问互联网时共享一个或多个公共 IP (SNAT)。 - 将外部访问 VIP (
203.0.113.10) 的流量重定向到内部真实服务器 (192.168.1.100) (DNAT)。 - 在 DNAT 后,进一步修改源地址以确保回包路径(
DNAT + SNAT)。
- 使内部私有 IP (
4. force(强制进入连接追踪)
- 作用: 强制 重新进行 连接追踪处理,即使该数据包之前可能已经过
ct处理。 使用需谨慎,常见于特殊转发路径或调试。 - 用法:
actions=ct(force, ...其他参数...)5. table=(跳转到指定流表)
- 作用: 在连接追踪处理(包括可能的 NAT) 完成后 ,将数据包 重新注入 到 OVS 的指定编号的流表 (
table=N) 的 起始处 ,进行新一轮匹配。 这是ct动作与流表形成“环回”或“迭代”处理的关键。 - 用法:
actions=ct(table=1, zone=5, commit, nat(src=203.0.113.1)) # 提交连接、执行 SNAT 后跳转到 table 1actions=ct(table=2) # 检查连接状态后跳转到 table 2- 典型场景:
- 多阶段策略处理: 例如,在
table=0提交连接并执行 DNAT,然后跳转到table=1匹配ct_state并应用防火墙规则。 - 复杂路径: 在同一个流表中使用
ct+goto_table可能导致处理顺序不清;ct(table=N)使逻辑更清晰。 - 处理回包方向: 在 DNAT 后的
table中匹配ct_state=+trk+est允许已建立连接的回包通过防火墙。
- 多阶段策略处理: 例如,在
6. exec(ACTION) (执行元数据动作)
-
作用: 在连接追踪处理 之后 (可能创建了新连接条目), 对连接 (而非当前数据包) 执行一个指定的动作 (ACTION)。
ACTION的结果会影响当前连接以及所有属于该连接的后续数据包。 -
支持的
ACTION:-
exec(allow)/exec(allow_src)/exec(allow_dst): 为 整个连接 (或仅源端/目标端) 添加允许策略标记 。这通常在配置了--default-deny的有状态防火墙中用于明确放行匹配+new的有效连接。exec(allow)通常 需要配合commit一起使用在+new的数据包上 。
Terminal window priority=100, tcp, ct_state=+new, actions=ct(commit, exec(allow)) # 提交新连接并允许它及其后续/回包-
exec(drop)/exec(reject): 为连接添加拒绝或拒绝并发送 TCP RST / ICMP 不可达的策略标记(不常用)。 -
exec(set_field:FIELD=VALUE): 设置连接的ct_mark或ct_label。ct_mark/ct_label是连接追踪条目的元数据,可以被后续规则匹配或修改(即使 IP/Port 转换了!)。
Terminal window actions=ct(commit, exec(set_field:ct_mark=0x10)) # 设置连接的 ct_mark 为 0x10actions=ct(exec(set_field:ct_label=0x123/0x123)) # 设置连接的 ct_label 位 (0x123 是值,0x123 是掩码) -
-
典型场景:
- 有状态防火墙: 在提交新连接时执行
exec(allow)允许其通信。 - 基于连接的标记: 设置
ct_mark/ct_label来标记连接属性(如 QoS 等级、来自哪个租户),后续基于这些标记应用策略(限速、计费、ACL)。
- 有状态防火墙: 在提交新连接时执行
7. alg= (指定应用层网关协议)
-
作用: 为 特定复杂协议 (如
ftp,tftp,sip) 显式启用应用层网关 (ALG)。ALG 会深度解析协议内容,发现协议内部协商的 IP/Port,并为这些协商出的衍生连接动态打开端口或修改其地址信息(通常需要配合helper内核模块)。 -
用法:
actions=ct(commit, alg=ftp) # 提交 FTP 控制连接,并启用 FTP ALGactions=ct(commit, alg=sip) # 提交 SIP 连接,启用 SIP ALG- 典型场景:
- 允许被动 FTP (
PASV/PORT) 或支持 FTP 穿越 NAT 时自动打开数据连接端口。 - 解析 SIP 信令中的
SDP媒体地址,确保 RTP 媒体流能正确建立。
- 允许被动 FTP (
ct 动作使用的关键点总结
-
ct_state的依赖: 所有基于ct_state(如+new,+est,+trk)的匹配规则, 其数据包必须已经经过至少一次ct动作的处理 。 - Stateful 与 Stateless:
ct动作是 OVS 实现有状态功能的触发点和执行者。没有ct,流表只能做无状态操作。 - NAT 的最佳实践: 必须在同一个
ct动作中结合commit和nat参数执行 (如ct(commit, nat(src=IP)))。分离nat动作(如过时的mod_nw_src)会导致 NAT 失效或无状态。 -
zone隔离: 正确使用zone是实现复杂网络策略或多租户隔离的基础。不同物理接口、不同 VRF 或不同虚拟机(vNIC)的流量应尽量使用不同zone追踪。 - 多阶段处理 (
table=): 使用ct(table=N)将流量在流表之间跳转是构建 多阶段、清晰逻辑 的防火墙/NAT 规则的推荐方式。 - 安全策略 (
exec(allow)): 在有状态防火墙设计中,在+new数据包上使用ct(commit, exec(allow))是告诉防火墙“允许这个新连接”的标准做法。 -
ct_mark/ct_label的威力: 它们是连接级别的标记, 在 IP/Port 转换后依然有效 ,为高级策略提供了强大的锚点。
简单来说:ct 动作是 OVS 连接追踪机制的“门户”。它让无状态的 SDN 交换机拥有了感知和管理网络连接状态的能力,是实现生产级、安全、可靠的网络基础设施的关键组件。