
Ciliumcilium-dbg bpf socknat list详解查看 Socket-LB 反向 NAT 表项【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium导读socknat list是 Cilium 命令行工具cilium-dbg提供的 BPF 地图查看命令之一用于列出内核中 Socket LoadBalancerSocket-LB为每个已建立的 TCP 连接记录的反向 NATreverse NAT表项。本文以 Cilium 官方命令参考 Documentation/cmdref/cilium-dbg_bpf_socknat_list.md 为核心结合cilium-dbg/cmd/bpf_socknat.go的命令实现、pkg/loadbalancer/maps/types.go中的地图键值结构定义、bpf/lib/sock.h中的 BPF 地图定义以及cilium-dbg/cmd/bpf_socknat_test.go中的单元测试完整讲解该命令的用途、用法、输出格式、底层数据结构与故障排查思路。读完本文你将能够熟练查看并解读 Cilium 节点上的 Socket-LB 反向 NAT 表并理解其与 ClusterIP、NodePort 服务负载均衡路径的关系。命令背景Socket-LB 与反向 NAT 表Cilium 的 Socket LoadBalancerSocket-LB是构建在 eBPF 之上的高性能负载均衡机制它通过cgroup/sock类型的 BPF 程序在应用进程发起connect()、sendmsg()等 socket 系统调用时直接在内核 socket 层完成 ClusterIP / NodePort 服务地址到后端地址的翻译从而避免流量绕行到节点级 DNAT显著降低转发路径的复杂度与延迟。当 Socket-LB 把一个**前端地址Frontend即服务地址翻译到后端地址Backend**时为了让应答流量能够原路返回即把后端的源地址再翻译回服务地址内核需要记录一份反向映射。这份映射正是socknat list命令所查看的对象——Socket-LB 反向 NAT 表Reverse NAT entries。在 BPF 层面Cilium 使用两张 LRU 哈希表来保存这些表项IPv4 反向表cilium_lb4_reverse_skIPv6 反向表cilium_lb6_reverse_sk这两张表在 bpf/lib/sock.h 中定义为BPF_MAP_TYPE_LRU_HASHLRU 哈希支持内存淘汰并使用LIBBPF_PIN_BY_NAME钉在 BPF 文件系统中因此用户态工具可以直接访问。在 Go 侧对应的地图名常量定义在 pkg/loadbalancer/maps/types.goSockRevNat4MapName cilium_lb4_reverse_sk SockRevNat6MapName cilium_lb6_reverse_sk SockRevNat4MapSize 256 * 1024 SockRevNat6MapSize 256 * 1024两张表默认容量均为 256 * 1024262144条可容纳大量并发连接的反向映射。命令用法语法与位置socknat命令位于cilium-dbg bpf子命令之下其完整层级为cilium-dbg bpf socknat list [flags]cilium-dbg bpf直接访问节点上本地 BPF 地图的入口socknatSocket NAT 操作分组参见 Documentation/cmdref/cilium-dbg_bpf_socknat.mdlist列出 Socket-LB 反向 NAT 表项。list还提供了别名ls即cilium-dbg bpf socknat ls与cilium-dbg bpf socknat list等价这一别名在 cilium-dbg/cmd/bpf_socknat.go 中通过 Cobra 的Aliases: []string{ls}定义。前置条件命令的实现第一行即调用common.RequireRootPrivilege(cilium bpf socknat list)见 cilium-dbg/cmd/bpf_socknat.go这意味着必须以 root 权限运行否则命令会直接报错退出。原因是读取 BPF 地图需要足够的权限访问 BPF 文件系统。在实际 Kubernetes 集群中该命令通常在 Cilium agent 所在的节点上通过kubectl exec进入cilium-dbg容器内执行。参数一览命令参考文档给出的参数如下-h, --help help for list -o, --output string json| yaml| jsonpath{}-h, --help查看list子命令的帮助信息-o, --output指定输出格式支持json、yaml以及jsonpath{}表达式用于与脚本、jq、kubectl 式 JSONPath 等工具联动做自动化解析。继承自父命令的通用选项与cilium-dbg其他子命令一致socknat list同样继承以下通用选项--config string Config file (default is $HOME/.cilium.yaml) -D, --debug Enable debug messages -H, --host string URI to server-side API --log-driver strings Logging endpoints to use (example: syslog) --log-opt map Log driver options (example: formatjson)--config指定配置文件默认读取$HOME/.cilium.yaml-D, --debug开启调试日志-H, --host指定连接的服务端 API URI--log-driver/--log-opt配置日志输出端点与选项。输出格式与字段解读表格输出不带-o参数时命令使用TablePrinter打印两列表格见 cilium-dbg/cmd/bpf_socknat.goSocket Cookie Backend - Frontend列名含义Socket Cookie触发 Socket-LB 翻译的 socket 的内核 cookie__sock_cookie由bpf_get_socket_cookie()获得用于唯一标识一个 socket是反向表项的查找依据之一Backend - Frontend一条反向映射记录格式为后端地址:端口 - 前端地址:端口 (revnat索引)表示来自该后端连接的回答流量应翻译回该前端地址其中revnat是RevNatIndex字段即反向 NAT 索引用于在数据路径上定位对应的前端服务条目。单条记录的完整格式结合 cilium-dbg/cmd/bpf_socknat.go 中的dumpReverseSKEntries解析逻辑两条地址族的记录格式分别为IPv410.0.2.100:80 - 10.0.0.1:8080 (revnat1)IPv6[2001:db8::1]:443 - [fd00::1]:8443 (revnat2)IPv6 地址使用方括号包裹与 URL 端口写法保持一致。JSON / YAML 输出指定-o json或-o yaml时命令会先把表项聚合成map[string][]string以 Socket Cookie 为键、该 cookie 下的多条Backend - Frontend记录为值的映射再交给command.PrintOutput序列化输出见 cilium-dbg/cmd/bpf_socknat.go。因此 JSON 输出大致形如{ 1234: [ 10.0.2.100:80 - 10.0.0.1:8080 (revnat1) ], 2345: [ [2001:db8::1]:443 - [fd00::1]:8443 (revnat2) ] }该结构便于使用jq等工具按 cookie 或后端地址做过滤统计。空表输出如果两张反向表都不存在任何条目命令会正常结束并输出一个空表无数据行不会报错。在低流量或未启用 Socket-LB 的场景下这是常见现象。底层数据结构从 Go 到 BPF地图键值结构cilium-dbg bpf socknat list之所以能打印出 cookie、地址、端口与 revnat 索引是因为它按 pkg/loadbalancer/maps/types.go 中定义的键值结构解析地图条目IPv4 键SockRevNat4Keytype SockRevNat4Key struct { Cookie uint64 // socket cookie Address types.IPv4 // 前端地址 Port int16 // 前端端口 }IPv4 值SockRevNat4Valuetype SockRevNat4Value struct { Address types.IPv4 // 后端地址 Port int16 // 后端端口 RevNatIndex uint16 // 反向 NAT 索引 }IPv6 键SockRevNat6Key与值SockRevNat6Value结构完全对应只是把types.IPv4换成了types.IPv6。可以看到键是前端服务地址 socket cookie值是后端真实工作负载地址 revnat 索引。这印证了dumpReverseSKEntries的输出方向Backend - Frontend打印时键中的前端地址被当作值值中的后端地址被当作键从而直观呈现后端在左、前端在右的反向映射语义。BPF 侧定义在数据路径侧bpf/lib/sock.h 定义了与 Go 结构内存布局对齐的两张地图struct ipv4_revnat_tuple { __sock_cookie cookie; __be32 address; // 前端地址 __be16 port; __u16 pad; }; struct ipv4_revnat_entry { __be32 address; // 后端地址 __be16 port; __u16 rev_nat_index; };地图类型为BPF_MAP_TYPE_LRU_HASH使用 LRU 语义自动淘汰冷条目保证在高并发下反向表不会无限膨胀LIBBPF_PIN_BY_NAME则使表项可被用户态按固定路径访问。表项写入的触发点反向表项的增删查统一封装在BPFLBMaps实现LBMaps接口见 pkg/loadbalancer/maps/lbmaps.go中UpdateSockRevNat(cookie, addr, port, revNatIndex)在 Socket-LB 为 socket 完成前端到后端翻译时写入反向表DeleteSockRevNat(...)在 socket 关闭、映射关系失效时删除ExistsSockRevNat(...)供数据路径或诊断逻辑查询。命令socknat list并不依赖 agent 的 API 服务而是直接打开并遍历这两张钉在 BPF 文件系统中的地图通过lbmap.NewSockRevNat4Map(256*1024)与NewSockRevNat6Map(256*1024)创建地图句柄后调用DumpWithCallbackIfExists见 cilium-dbg/cmd/bpf_socknat.go。这也是它需要 root 权限、且可以在 agent 数据面异常时仍能独立查看内核状态的原因。实战场景与排查技巧场景一验证 Socket-LB 是否生效在部署了 ClusterIP 服务的节点上持续发起业务连接然后执行cilium-dbg bpf socknat list若 Socket-LB 正常工作应能看到与连接数对应的反向表项。若服务在转发但表中始终没有该服务相关的条目则需要检查节点是否启用了 Socket-LB例如 Helm 的socketLB.enabled、bpfSocketLB相关配置以及 cgroup sock 程序是否加载成功。场景二定位请求成功但回包丢失问题当出现客户端发请求能到后端但响应丢失的现象时可先确认反向表是否缺失对应条目# 查看指定 socket cookie 下的反向映射 cilium-dbg bpf socknat list -o json | jq .cookie若缺少该 cookie 的反向条目说明 Socket-LB 未成功记录映射回包无法被翻译回前端地址是典型的数据面写入缺失若存在但指向的Backend与预期不符说明翻译结果异常需要结合服务端点endpoints与后端选择逻辑进一步排查。注意Socket Cookie在内核中由bpf_get_socket_cookie()生成每个 socket 唯一重新建立连接后 cookie 会变化因此排查时应在连接保持期间抓取。场景三观察 IPv6 双栈流量使用-o yaml输出IPv6 表项会以[addr]:port形式展示cilium-dbg bpf socknat list -o yaml可通过过滤包含[的记录快速了解 IPv6 服务的 Socket-LB 覆盖情况验证双栈服务的前端地址翻译是否正常。场景四脚本化监控表项规模反向表容量上限为 256 * 1024 条/族SockRevNat4MapSize/SockRevNat6MapSize见 pkg/loadbalancer/maps/types.go。由于地图是 LRU 类型接近上限时会淘汰冷条目一般不会 OOM但可用以下命令监控规模变化趋势cilium-dbg bpf socknat list -o json | jq length若条目数长期逼近上限说明并发连接数极大或存在连接泄漏可结合cilium-dbg bpf ct list、cilium-dbg metrics list进一步评估。与单元测试的印证仓库中的 cilium-dbg/cmd/bpf_socknat_test.go 直接验证了反向表的数据模型与本文描述一致测试通过mockMap.UpdateSockRevNat(1234, net.ParseIP(10.0.2.100), 80, 1)写入一条 IPv4 表项cookie1234后端 10.0.2.100:80revnat1通过mockMap.UpdateSockRevNat(2345, net.ParseIP(2001:db8::1), 443, 2)写入一条 IPv6 表项cookie2345后端 2001:db8::1:443revnat2随后用ExistsSockRevNat断言这两条存在、不存在的条目如 cookie9999 的 192.168.1.1:8080返回不存在。这组用例确认了UpdateSockRevNat的四个参数cookie、地址、端口、revnat 索引与键值结构的对应关系也印证了dumpReverseSKEntries解析出的 Backend - Frontend 格式正是由键前端与值后端拼接而成。测试中的 mock 地图实现位于 pkg/loadbalancer/maps/lbmaps.go其中的FakeLBMaps.UpdateSockRevNat与真实BPFLBMaps的写入逻辑保持一致方便在不依赖内核 BPF 的情况下复现和验证行为。常见问题FAQQ为什么执行cilium-dbg bpf socknat list会提示权限不足A该命令需要 root 权限直接读取 BPF 地图见 cilium-dbg/cmd/bpf_socknat.go。请使用 root 用户执行或在 Pod 中确保以特权模式运行。Qlist和ls有什么区别A没有区别ls是list的命令别名见 cilium-dbg/cmd/bpf_socknat.go。Q为什么表里没有数据A可能原因包括未启用 Socket-LB 功能、当前节点没有活跃的 socket 级负载均衡流量、或流量走了其他数据路径如 tc/xdp 层的 DNAT。可先确认服务流量确实经过 Socket-LB 后再查看。Qrevnat数值代表什么A它是RevNatIndex即反向 NAT 索引见 pkg/loadbalancer/maps/types.go用于数据路径在回包方向上定位对应的前端服务条目。Q该命令是否需要 agent 正常运行A不需要。它直接遍历钉在 BPF 文件系统中的地图cilium_lb4_reverse_sk/cilium_lb6_reverse_sk即便 agent 控制面异常只要内核地图仍在就能查看当前内核中的真实状态。参考链接命令参考文档Documentation/cmdref/cilium-dbg_bpf_socknat_list.md、Documentation/cmdref/cilium-dbg_bpf_socknat.md命令实现cilium-dbg/cmd/bpf_socknat.go命令单元测试cilium-dbg/cmd/bpf_socknat_test.go键值结构定义pkg/loadbalancer/maps/types.go地图管理与写入接口pkg/loadbalancer/maps/lbmaps.goBPF 地图定义bpf/lib/sock.h【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考