Cilium 连接跟踪(Connection Tracking)排查实战:cilium-dbg bpf ct 命令族完全指南
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
导读
本文围绕 Cilium 数据面最核心的状态机制——eBPF 连接跟踪(Connection Tracking, CT)展开,以官方命令参考文档 Documentation/cmdref/cilium-dbg_bpf_ct.md 为主体,结合仓库源码深入剖析cilium-dbg bpf ct命令族的实现原理。读完本文,你将掌握如何列出并解读节点上 TCP/UDP 等连接跟踪表中的条目、如何按集群维度查看 CT 状态、如何用时钟源换算条目存活时间,以及如何安全地清空全部连接跟踪条目,并理解这些操作在 BPF 层面对应哪张 map、走的是哪条调用链。
1. 连接跟踪(CT)在 Cilium 中的地位
Cilium 基于 eBPF 实现网络、安全与可观测性,而连接跟踪是这一切的基石:数据路径(datapath)中的 BPF 程序需要为每个流维护"谁发起、谁响应、属于哪个安全身份"的状态,才能完成 NAT(网络地址转换)、反向 NAT、状态化防火墙策略判定以及按连接维度统计流量。这些状态被持久化在位于/sys/fs/bpf/tc/globals/下的多个 BPF map 中。
从源码 pkg/maps/ctmap/types.go 可以看到,Cilium 将 CT map 按两个维度划分为四类:
- 协议族维度:IPv4 与 IPv6;
- 协议类型维度:TCP(有状态协议,需要精细的流转状态机)与非 TCP(Any,涵盖 UDP、ICMP 等)。
对应关系如下:
| mapType | 说明 |
|---|---|
mapTypeIPv4TCPGlobal | 全局 IPv4 TCP CT map |
mapTypeIPv6TCPGlobal | 全局 IPv6 TCP CT map |
mapTypeIPv4AnyGlobal | 全局 IPv4 非 TCP CT map |
mapTypeIPv6AnyGlobal | 全局 IPv6 非 TCP CT map |
在 pkg/maps/ctmap/ctmap.go 中定义了四个全局 map 的实际名称:tcp4global、tcp6global、any4global、any6global。cilium-dbg bpf ct系列命令正是这些 map 的用户态操作入口。
2. 命令族总览:cilium-dbg bpf ct
2.1 命令定义
cilium-dbg bpf ct描述:Connection tracking tables(连接跟踪表),即访问 Cilium 节点本地连接跟踪 BPF map 的总入口。
选项:
-h, --help help for ct该命令本身不执行具体操作,仅作为list(列表)与flush(清空)两个子命令的父命令容器。在源码中,它对应 cilium-dbg/cmd/bpf_ct.go 里定义的BPFCtCmd:
// BPFCtCmd represents the bpf_ct command var BPFCtCmd = &cobra.Command{ Use: "ct", Short: "Connection tracking tables", } func init() { BPFCmd.AddCommand(BPFCtCmd) }可以看到它挂载在BPFCmd(即cilium-dbg bpf,对应文档 Documentation/cmdref/cilium-dbg_bpf.md)之下,与bpf nat、bpf lb等命令平级,遵循 Cilium 统一的 "Direct access to local BPF maps" 设计。
2.2 全局父命令继承选项
ct、ct list、ct flush均继承自cilium-dbg根命令的通用选项:
--config string 配置文件(默认 $HOME/.cilium.yaml) -D, --debug 启用调试消息 -H, --host string 服务端 API 的 URI --log-driver strings 日志端点(示例:syslog) --log-opt map 日志驱动选项(示例:format=json)其中-H/--host用于指定 Cilium agent 的 API 地址,调试与日志选项用于输出诊断信息,这些选项在所有cilium-dbg bpf *子命令中保持一致,方便脚本化调用与故障排查。
2.3 子命令一览
* cilium-dbg bpf ct flush - 清空所有连接跟踪条目 * cilium-dbg bpf ct list - 列出连接跟踪条目3. 列出连接跟踪条目:cilium-dbg bpf ct list
3.1 语法与输出格式选项
cilium-dbg bpf ct list [cluster <identifier>] [flags]该命令列出节点上的连接跟踪条目,是排查连接建立失败、NAT 异常、流表堆积等问题的第一入口。参数与选项如下:
| 参数/选项 | 说明 |
|---|---|
[cluster <identifier>] | 可选,指定要查看的集群 ID(ClusterMesh 多集群场景),省略时默认查看global本节点全局 map |
-o, --output string | 输出格式,支持json、yaml、jsonpath='{}' |
-d, --time-diff | 打印条目的剩余存活时间差(time difference),便于判断条目何时过期 |
--time-diff-clocksource-hz int | 手动指定时钟源频率 Hz(默认 250),仅在 jiffies 模式且不向服务端查询时使用 |
--time-diff-clocksource-mode string | 手动指定时钟源模式(ktime/jiffies),而不是向服务端查询 |
从源码 cilium-dbg/cmd/bpf_ct_list.go 可以看到命令别名ls与三个 flag 的注册:
var bpfCtListCmd = &cobra.Command{ Use: "list [cluster <identifier>]", Aliases: []string{"ls"}, Short: "List connection tracking entries", Run: func(cmd *cobra.Command, args []string) { t, id, err := parseArgs(args) ... }, }3.2 参数解析:global 与 cluster 两种视图
parseArgs(cilium-dbg/cmd/bpf_ct_list.go)实现了参数校验:
- 不带参数:等价于传入
global,读取本节点全局 CT map(向后兼容旧行为); cluster <identifier>:解析集群 ID,并通过cmtypes.ValidateClusterID校验其取值范围,随后调用ctmap.GetClusterCTMaps(id, ipv4, ipv6)读取该集群维度的 CT map(对应 pkg/maps/ctmap/per_cluster_ctmap.go 中的 per-cluster CT map 实现);- 其他参数:报错
unknown type。
getMaps(cilium-dbg/cmd/bpf_ct_list.go)会根据getIpEnableStatuses()探测当前节点是否启用了 IPv4/IPv6,再决定实际读取哪几张 map。对于global视图,调用 pkg/maps/ctmap/ctmap.go 中的ctmap.Maps(ipv4, ipv6):
// Maps returns a slice of all CT maps that are used. func Maps(ipv4, ipv6 bool) []*Map { result := make([]*Map, 0, mapCount) if ipv4 { result = append(result, newMap(MapNameTCP4Global, mapTypeIPv4TCPGlobal)) result = append(result, newMap(MapNameAny4Global, mapTypeIPv4AnyGlobal)) } if ipv6 { result = append(result, newMap(MapNameTCP6Global, mapTypeIPv6TCPGlobal)) result = append(result, newMap(MapNameAny6Global, mapTypeIPv6AnyGlobal)) } return result }即最多遍历tcp4global、any4global、tcp6global、any6global四张 map。每张 map 通过ctmap.OpenCTMap(pkg/maps/ctmap/ctmap.go)打开;若某张 map 不存在(例如未启用 IPv6),会打印Unable to open <path>: <err>. Skipping.并跳过,而不会中断整个命令。
3.3 条目内容:五元组 Key 与 CT Entry Value
list输出的每条记录由一个 Key 和一个 Value 组成。测试用例 cilium-dbg/cmd/bpf_ct_list_test.go 给出了直观的样例:
- Key(五元组):目的地址
DestAddr、源地址SourceAddr、目的端口DestPort、源端口SourcePort、下一层协议号NextHeader(6 为 TCP、17 为 UDP)以及标志位Flags; - Value(CtEntry):包含
Packets/Bytes(该方向累计的包数与字节数)、Lifetime(剩余存活时间)、Flags、RevNAT(反向 NAT 端口)、TxFlagsSeen/RxFlagsSeen(观测到的 TCP 收发标志位)、SourceSecurityID(源安全身份,对应 Cilium 的 identity 机制)以及LastTxReport/LastRxReport(最近一次收发的时间戳,用于计算 time-diff)。
这些字段定义在 pkg/maps/ctmap 与 pkg/tuple 中,是解读流状态的关键依据。
3.4 文本输出与结构化输出(JSON/YAML/jsonpath)
dumpCt(cilium-dbg/cmd/bpf_ct_list.go)实现了两种输出路径:
- 文本模式(默认):对每张 map 调用
doDumpEntries,最终走m.DumpEntriesWithTimeDiff(clockSource)(pkg/maps/ctmap/ctmap.go),逐条打印五元组与状态信息,立即输出,适合人工阅读; - 结构化模式(指定
-o json|yaml|jsonpath):通过command.AddOutputOption注册的 output 选项触发。此时命令会先通过DumpWithCallback把四张 map 的条目统一收集到内存,待全部读取完毕后再输出一份一致的完整对象,避免 JSON/YAML 被多张 map 的输出切碎,方便jq或yq进一步加工。
常用示例:
# 文本方式查看本节点全部 CT 条目 cilium-dbg bpf ct list # 以 JSON 输出,交给 jq 过滤(例如只看 TCP 条目) cilium-dbg bpf ct list -o json | jq '.[] | select(.key.NextHeader == 6)' # 查看指定集群 ID 的 CT 条目(ClusterMesh 场景) cilium-dbg bpf ct list cluster 1 # 打印每条目剩余存活时间(依赖时钟源换算) cilium-dbg bpf ct list -dls是list的别名,两者等价。
3.5 深入解析-d/--time-diff:时钟源(ClockSource)换算
CT 条目中记录的Lifetime与时间戳不是墙上时钟,而是 BPF 侧单调时钟的"tick"计数,直接打印对用户不友好。因此-d选项需要先确定时钟源模式,再换算为秒:
getClockSource(cilium-dbg/cmd/bpf_ct_list.go)的优先级如下:
- 未指定
--time-diff-clocksource-mode时,调用timestamp.GetClockSourceFromAgent(client.Daemon)(pkg/maps/timestamp/timestamp.go)向 Cilium agent 查询真实时钟源;查询失败则回退到GetClockSourceFromRuntimeConfig()读取本地运行配置; - 指定
ktime模式时,直接构造ClockSource{Mode: ktime},tick 与纳秒一一对应; - 指定
jiffies模式时,必须提供非零的--time-diff-clocksource-hz(即内核 HZ,默认 250),否则报错invalid HZ value;换算时用 tick 除以 Hz 得到秒数(见 pkg/maps/timestamp/timestamp.go 中 ktime/jiffies 两种换算分支); - 其他模式字符串直接报错
invalid clocksource。
因此,若 agent 不可达但你又需要-d输出,可以手动指定模式与频率,例如在 HZ=100 的内核上:
cilium-dbg bpf ct list -d --time-diff-clocksource-mode jiffies --time-diff-clocksource-hz 1004. 清空连接跟踪条目:cilium-dbg bpf ct flush
4.1 语法与选项
cilium-dbg bpf ct flush [flags]描述:Flush all connection tracking entries(清空所有连接跟踪条目)。该命令只有-h/--help一个选项。
4.2 实现原理:一次基于 GC 机制的批量清理
与直觉不同,flush并非简单地逐条Delete,而是复用了 CT map 的垃圾回收(GC)机制。源码 cilium-dbg/cmd/bpf_ct_flush.go 的流程如下:
- 通过
getIpEnableStatuses()判断 IPv4/IPv6 启用状态; - 打开 NAT 全局 map(
nat.GlobalMaps),调用ctmap.InitMapInfo初始化 map 信息——因为 flush 需要同步清理与 CT 条目关联的 NAT 映射; - 通过
stream.Multicast建立 GC 事件广播通道,用于在清理过程中联动 NAT map 的条目回收; - 对
ctmap.Maps(ipv4, ipv6)返回的每张 CT map 调用m.Flush(next4, next6); - 每张 map 清理完毕后打印
Flushed <N> entries from <path>。
Map.Flush的实现位于 pkg/maps/ctmap/ctmap.go:
// Flush runs garbage collection for map m with the name mapType, deleting all // entries. The specified map must be already opened using bpf.OpenMap(). func (m *Map) Flush(next4, next6 func(GCEvent)) int { d, _ := m.doGC(GCFilter{ RemoveExpired: true, Time: MaxTime, }, next4, next6) return d }它构造一个GCFilter{RemoveExpired: true, Time: MaxTime},即把"所有条目都视为已过期",从而让 GC 路径删除全部条目,同时联动删除关联的 NAT 条目。这样做既保证了 CT 与 NAT 的一致性,也复用了经过测试的成熟清理逻辑。
4.3 使用注意
flush需要 root 权限(命令内部调用common.RequireRootPrivilege,与list一致);- 该操作会清空该节点上的全部连接跟踪状态,所有在途连接都需要重新建立跟踪,可能影响现存长连接并产生短暂的数据面开销;在排查 NAT/CT 表异常或需要从零观测流表增长时使用,生产环境应谨慎评估影响窗口。
5. 源码级验证:list 的测试用例
仓库为ct list的输出逻辑提供了完整的单元测试:cilium-dbg/cmd/bpf_ct_list_test.go。
TestDumpCt4与TestDumpCt6分别使用mockmaps.NewCtMockMap构造包含 IPv4(TCP,NextHeader=6)与 IPv6(UDP,NextHeader=17)条目的 mock CT map;- 测试将标准输出重定向到管道,强制 JSON 输出模式后调用
dumpCt,再反序列化校验输出内容与预期条目一致; - 这验证了两点实现事实:结构化输出会把多张 map 的条目聚合成一个对象,且 JSON 输出中条目的 Key/Value 字段与 mock 数据完全对应。
此外,pkg/maps/ctmap 包还包含 GC 相关的gc/子包、per_cluster_ctmap.go(ClusterMesh 场景的按集群 CT map)与ctmap_privileged_test.go(需要特权环境的 map 级测试),感兴趣的读者可以沿这些路径继续深入。
6. 实战场景小结
| 场景 | 推荐命令 |
|---|---|
| 查看节点当前所有连接跟踪条目 | cilium-dbg bpf ct list |
| 用机器可读格式分析流表(配合 jq/yq) | cilium-dbg bpf ct list -o json/-o yaml |
| 判断条目何时过期、排查流表堆积 | cilium-dbg bpf ct list -d |
| 多集群场景下查看指定集群的 CT 状态 | cilium-dbg bpf ct list cluster <identifier> |
| 清理全部连接跟踪状态(谨慎) | cilium-dbg bpf ct flush |
| 快速查看命令用法 | cilium-dbg bpf ct list --help/cilium-dbg bpf ct flush --help |
通过cilium-dbg bpf ct命令族,运维与开发者可以在不进入 Pod、不依赖监控面板的情况下,直接审视 eBPF 数据面的连接跟踪状态,并结合 Documentation/cmdref/cilium-dbg_bpf.md 中的其他 BPF map 查看命令(如bpf nat、bpf lb)交叉定位网络问题。
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考