Cilium 连接跟踪排查指南cilium-dbg bpf ct list命令详解与 BPF CT Map 底层原理【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/ciliumcilium-dbg bpf ct list是 Cilium 数据面排障的核心命令用于直接读取内核中 eBPF 连接跟踪Connection TrackingCT映射表列出每一条活动的连接状态。本文以该命令的官方命令参考文档Documentation/cmdref/cilium-dbg_bpf_ct_list.md为主线结合仓库中命令实现cilium-dbg/cmd/bpf_ct_list.go与 CT Map 底层源码pkg/maps/ctmap/ctmap.go讲解命令的每个参数、输出字段含义、四种 CT Map 的组织方式以及时钟源clock source换算原理帮助你读懂连接跟踪数据、快速定位连接异常。命令概览列出连接跟踪条目该命令归属于cilium-dbg bpf ctConnection tracking tables见 cilium-dbg/cmd/bpf_ct.go其完整语法为cilium-dbg bpf ct list [cluster identifier] [flags]命令的Short描述为 List connection tracking entries即列出连接跟踪表中的全部条目。从源码看它还注册了别名lscilium-dbg/cmd/bpf_ct_list.go因此以下两种写法等价cilium-dbg bpf ct list cilium-dbg bpf ct ls执行前会调用common.RequireRootPrivilege(cilium bpf ct list)即该命令需要 root 权限因为它要直接访问/sys/fs/bpf下的内核 BPF Map。位置参数[cluster identifier]命令接受一个可选的位置参数源码中的parseArgs逻辑cilium-dbg/cmd/bpf_ct_list.go将其分为两种模式global默认不传任何参数时默认读取全局连接跟踪表即本节点所有网络命名空间共享的 CT Map。为保持向后兼容显式传入global关键字同样有效。cluster identifier在启用 Cluster-aware Addressing集群感知寻址的多集群场景下读取指定集群 ID 的每集群per-clusterCT Map。identifier会被解析为无符号 32 位整数并通过cmtypes.ValidateClusterID校验合法性缺省或非法时命令会报错Invalid argument。之所以需要 per-cluster CT Map是因为现有全局 CT Map 的 key 结构无法在不破坏存量连接的前提下扩展出 ClusterID 字段因此 Cilium 采用一个集群一张内层 map的方案外层以 array-of-maps数组内嵌 map索引即 ClusterID形式组织见 pkg/maps/ctmap/per_cluster_ctmap.go 中的设计说明。若不指定该参数而直接使用全局模式命令会给出提示Unable to open ...: please try using cilium bpf ct list。参数详解list 子命令专属参数参数简写类型默认值说明--help-hbool—显示 list 子命令帮助--output-ostring空纯文本输出格式支持json、yaml、jsonpath{}--time-diff-dboolfalse为每条条目打印剩余存活时间time difference--time-diff-clocksource-hz—int250手动指定时钟源频率HZ仅配合 jiffies 模式使用--time-diff-clocksource-mode—string空手动指定时钟源模式ktime/jiffies默认改为联系 agent 查询其中--output由command.AddOutputOption(bpfCtListCmd)统一注册cilium-dbg/cmd/bpf_ct_list.go是 Cilium CLI 各命令共用的输出选项。从父命令继承的参数cilium-dbg bpf ct list还继承了cilium-dbg根命令的全局参数参数简写说明--config string—配置文件路径默认$HOME/.cilium.yaml--debug-D开启调试消息--host string-H服务器端 API 的 URI用于连接 cilium-agent--log-driver strings—日志端点例如syslog--log-opt map—日志驱动选项例如formatjson纯文本输出格式解读默认不带-o时命令将每个 CT Map 的条目逐行打印。每条输出的关键部分由两个结构拼成key 描述来自 pkg/maps/ctmap/types.go 中CtKey4Global/CtKey6Global的Dump方法与value 详情来自CtEntry.StringWithTimeDiff。以 IPv4 TCP 条目为例实际输出形态为TCP OUT 10.10.10.2:13579 - 10.10.10.1:80 expires12345 Packets5 Bytes2560 RxFlagsSeen0x63 LastRxReport7777 TxFlagsSeen0x58 LastTxReport0 Flags0x0003 [ ... ] RevNAT27 SourceSecurityID6789 BackendID0 NatPort0方向与 key 字段Key 部分由TCP/UDP等协议、方向标记和五元组构成。方向标记pkg/maps/ctmap/ctmap.go有四种OUTTUPLE_F_OUT 0出方向条目INTUPLE_F_IN 1入方向条目relatedTUPLE_F_RELATED 2表示该条目属于相关连接如 FTP 数据连接、ICMP 错误回报SVCTUPLE_F_SERVICE 4表示服务相关的条目其打印格式为协议 SVC 源IP:目的端口 - 目的IP:源端口。注意源码注释pkg/maps/ctmap/types.go指出由于历史 issue #5848CT 条目 key 中记录的源地址实际上是数据包的目的地址因此在 dump 时地址做了对调展示OUT 10.10.10.2:13579 - 10.10.10.1:80表示从 10.10.10.2 的 13579 端口发往 10.10.10.1 的 80 端口这一连接。value 字段含义CtEntry结构体定义于 pkg/maps/ctmap/types.go其打印字段与含义对应如下格式化逻辑见StringWithTimeDiff输出字段对应结构体字段含义expiresLifetime条目的剩余存活时间单位取决于时钟源ktime 模式下为秒Packets/BytesPackets/Bytes该连接累计的数据包数与字节数RxFlagsSeen/TxFlagsSeenRxFlagsSeen/TxFlagsSeen接收 / 发送方向观察到的 TCP 标志位十六进制LastRxReport/LastTxReportLastRxReport/LastTxReport最近一次接收 / 发送上报时间戳FlagsFlagsrx_closing条目的内部标志位详见下文RevNATRevNAT反向 NAT 索引用于服务负载均衡时还原 Service IPSourceSecurityIDSourceSecurityID源端的安全身份标识Security IdentityBackendIDUnion0[1]后端backendID与Union0联合体相关NatPortNatPortNAT 端口网络字节序打印时转为主机序Flags位域定义于 pkg/maps/ctmap/types.go可同时出现多个标记RxClosing收到 FIN/RST、TxClosing发出 FIN/RST、Nat64NAT64 转换、LBLoopback负载均衡回环、SeenNonSyn观察到非 SYN 报文、NodePortNodePort 服务流量、ProxyRedirect经过代理重定向、DSRInternalDSR 内部条目、FromL7LB来自 L7 负载均衡、FromTunnel来自隧道封装。解析函数flagsString会逐位还原这些标记。结构化输出JSON / YAML / jsonpath使用-o json、-o yaml或-o jsonpath{...}时命令行为发生改变。源码中的dumpCt函数cilium-dbg/cmd/bpf_ct_list.go注释明确说明纯文本模式边遍历边打印而结构化模式会先收集所有 map 的条目最后输出一个统一的对象。收集时每个条目被封装为ctmap.CtMapRecord{Key, Value}pkg/maps/ctmap/ctmap.go随后通过command.PrintOutput(entries)统一输出。JSON 输出的典型结构为键值对数组其中 key 为五元组信息、value 为CtEntry的字段展开。示例cilium-dbg bpf ct list -o json cilium-dbg bpf ct list -o yaml cilium-dbg bpf ct list -o jsonpath{range .items[*]}{.key.dest_addr}{\n}{end}从测试代码 cilium-dbg/cmd/bpf_ct_list_test.go 可以看到JSON 反序列化时使用的记录类型为{Key: tuple.TupleKey4/TupleKey6, Value: ctmap.CtEntry}即 key 直接暴露五元组字段dest_addr、source_addr、dest_port、source_port、next_header、flagsvalue 则包含packets、bytes、lifetime、rev_nat、source_security_id等字段方便后续脚本化处理或与jq管道配合。计算剩余存活时间-d与时钟源-d, --time-diff会在每条条目后追加remaining: N sec(s)即该连接还剩多少秒被回收。要完成换算必须知道 CT 条目时间戳所用的时钟源其获取优先级由getClockSourcecilium-dbg/cmd/bpf_ct_list.go决定未指定--time-diff-clocksource-mode时优先通过 API 调用timestamp.GetClockSourceFromAgent即 agent 的 healthz 接口见 pkg/maps/timestamp/timestamp.go获取 agent 当前时钟源若 agent 不可达则回退读取运行时配置文件agent-runtime-config.jsonGetClockSourceFromRuntimeConfig。手动指定--time-diff-clocksource-mode ktime直接使用 ktime 模式无需 HZ 参数。手动指定--time-diff-clocksource-mode jiffies必须同时提供合法的--time-diff-clocksource-hz默认 250若 HZ 为 0 会报错invalid HZ value。传入其他值则报invalid clocksource。时钟源换算的核心逻辑在 pkg/maps/timestamp/timestamp.goktime 模式当前时间取bpf.GetMtime()纳秒除以 10 亿得到秒条目Lifetime本身就是秒直接做差即可。jiffies 模式datapath 将 jiffies 右移BPF_MONO_SCALER 8位后存入 CT 条目对应 eBPF 侧BPF_MONO_SCALER常量换算时先左移 8 位还原 jiffies再除以 HZ 得到秒数(timestamp 8) / Hertz。因此remaining: N sec(s)的计算式为条目时间戳换算成秒 - 当前时间换算成秒。当Lifetime小于当前时间时该值可能为负数表示条目已过期、等待 GC 回收。底层原理四种全局 CT Map 与数据来源命令默认展示的全局连接跟踪表并非单张 map而是按IPv4/IPv6 × TCP/非TCP拆分的四张 map命名沿用 Cilium 1.0 时代的约定以保证升级不中断存量连接pkg/maps/ctmap/ctmap.goMap 名称类型说明cilium_ct4_globalIPv4 TCP全局 IPv4 TCP 连接跟踪表cilium_ct_any4_globalIPv4 非 TCP全局 IPv4 非 TCPUDP/ICMP 等连接跟踪表cilium_ct6_globalIPv6 TCP全局 IPv6 TCP 连接跟踪表cilium_ct_any6_globalIPv6 非 TCP全局 IPv6 非 TCP 连接跟踪表这些 map 均为LRU_HASH类型newMap中指定ebpf.LRUHash容量上限由maxEntries决定TCP map 默认取option.CTMapEntriesGlobalTCPDefault非 TCP map 默认取option.CTMapEntriesGlobalAnyDefault且均可用配置项覆盖pkg/maps/ctmap/types.go。getMapscilium-dbg/cmd/bpf_ct_list.go决定实际遍历哪些 mapglobal模式调用ctmap.Maps(ipv4, ipv6)返回当前节点启用的协议族对应的全局 map 列表cluster模式调用ctmap.GetClusterCTMaps(id, ipv4, ipv6)返回该集群 ID 对应的 per-cluster 内层 map。而 IPv4/IPv6 是否启用则由getIpEnableStatusescilium-dbg/cmd/helpers.go确定优先向 agent 查询 healthz 与ConfigGet接口拿到实际启用的地址族agent 不在时读取agent-runtime-config.json两者均失败时回退到编译期默认值。遍历时命令通过ctmap.OpenCTMap打开每一张 map调用方负责Close。若某张 map 不存在例如节点只启用了 IPv4命令会打印Unable to open ... Skipping.并继续处理其余 map而不会整体失败。纯文本输出调用DumpEntriesWithTimeDiffpkg/maps/ctmap/ctmap.go它先通过批量迭代器DumpWithCallback遍历全部条目再拼接 key 与 value 字符串结构化输出则走DumpWithCallback收集CtMapRecord后统一序列化。实战示例# 列出本节点全部全局连接跟踪条目纯文本 cilium-dbg bpf ct list # 使用 ls 别名并展示每条目的剩余存活时间 cilium-dbg bpf ct ls -d # 仅列出 TCP 相关的条目用 grep 过滤输出即可 cilium-dbg bpf ct list | grep ^TCP # 输出 JSON 供脚本处理 cilium-dbg bpf ct list -o json # 指定集群 ID 查看某远程集群的每集群连接跟踪表 cilium-dbg bpf ct list cluster 5 # 手动指定 jiffies 时钟源HZ1000计算剩余时间 cilium-dbg bpf ct list -d --time-diff-clocksource-mode jiffies --time-diff-clocksource-hz 1000典型排障场景当某个 Service 的连接出现RevNAT与期望后端不符、或者出现大量expires0的过期条目时可通过cilium-dbg bpf ct list | grep 目标IP快速定位相关连接并结合Flags中的NodePort、DSRInternal、ProxyRedirect等标记判断流量路径。相关命令父命令cilium-dbg bpf ctConnection tracking tables的参考文档见 Documentation/cmdref/cilium-dbg_bpf_ct.md配套的清空命令cilium-dbg bpf ct flushFlush all connection tracking entries用于一次性删除全部连接跟踪条目其实现cilium-dbg/cmd/bpf_ct_flush.go在刷新 CT map 的同时会联动清理对应的 NAT map参考文档见 Documentation/cmdref/cilium-dbg_bpf_ct_flush.md若需验证本命令的行为可运行单测go test ./cilium-dbg/cmd/ -run TestDumpCt测试代码见 cilium-dbg/cmd/bpf_ct_list_test.go它通过 mock map 分别构造 IPv4 与 IPv6 条目验证dumpCt在 JSON 模式下的输出能够被正确反序列化且与原始记录一致可作为理解输出结构的参考样例。【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考