使用 cilium-dbg bpf srv6 sid 排查 Cilium SRv6 SID 映射表
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
cilium-dbg bpf srv6 sid是 Cilium 数据面排障工具cilium-dbg中用于直接查看内核 BPF 哈希表cilium_srv6_sid的命令,该表记录着 SRv6(Segment Routing over IPv6)SID(Segment Identifier)到 VRF ID 的映射关系。本文以 Documentation/cmdref/cilium-dbg_bpf_srv6_sid.md 为骨架,结合仓库内命令实现(cilium-dbg/cmd/bpf_srv6_sid.go)、BPF map 定义(pkg/maps/srv6map/sid.go、bpf/lib/srv6_maps.h)及数据面查询逻辑(bpf/lib/srv6.h),完整讲解该命令的语法、输出格式、底层数据结构与数据面消费路径,帮助你快速定位 SRv6 路由不生效的根因。
命令定位:SRv6 子命令家族中的一员
cilium-dbg bpf srv6 sid是cilium-dbg bpf srv6命令族的三个叶子命令之一,父命令srv6的职责是 "Manage the SRv6 routing rules"(见 Documentation/cmdref/cilium-dbg_bpf_srv6.md),其完整子命令树为:
cilium-dbg bpf srv6 policy— List SRv6 policy entries(查看 SRv6 出向策略映射)cilium-dbg bpf srv6 sid— List SRv6 SID entries(查看本文主题,SID→VRF ID 映射)cilium-dbg bpf srv6 vrf— List SRv6 VRF mappings(查看源地址/目的 CIDR 到 VRF ID 的映射)
在命令实现中,srv6子命令由 cilium-dbg/cmd/bpf_srv6.go 中的BPFSRv6Cmd定义并挂载到BPFCmd(即cilium-dbg bpf)之下,三个叶子命令分别对应三张不同的 BPF map。
命令语法与全部选项
根据官方 cmdref 文档,命令用法如下:
cilium-dbg bpf srv6 sid [flags]专属选项
| 选项 | 说明 |
|---|---|
-h, --help | 显示sid子命令的帮助信息 |
-o, --output string | 指定输出格式,取值范围为json、yaml、jsonpath='{}' |
--output选项由command.AddOutputOption(bpfSRv6SIDListCmd)注册(见 cilium-dbg/cmd/bpf_srv6_sid.go),执行时会走command.PrintOutput(bpfSIDList)路径,将切片结构序列化为指定格式。
继承自父命令的选项
这些选项由cilium-dbg的根命令统一提供,sid子命令同样适用:
| 选项 | 说明 |
|---|---|
--config string | 配置文件路径(默认$HOME/.cilium.yaml) |
-D, --debug | 启用调试消息输出 |
-H, --host string | 服务端 API 的 URI |
--log-driver strings | 日志端点(示例:syslog) |
--log-opt map | 日志驱动选项(示例:format=json) |
默认输出:表格化的 SID 与 VRF ID 列表
不带-o参数执行时,命令将遍历 SID map 的全部条目并以 tabwriter 对齐的表格打印。表头固定为SID与VRF ID(见 cilium-dbg/cmd/bpf_srv6_sid.go),每个条目一行,SID 以 IPv6 地址字符串形式展示,VRF ID 以十进制无符号整数展示。示例输出:
SID VRF ID fd00::1 1 fd00::2 2当 map 中没有任何条目时,命令向 stderr 输出No entries found.;当 map 文件本身不存在(例如节点未启用 SRv6)时,输出Cannot find SRv6 SID map并提前返回(见 cilium-dbg/cmd/bpf_srv6_sid.go)。
机器可读输出:JSON / YAML / jsonpath
通过-o参数可以将结果导出为结构化格式,便于与jq、yq或脚本管道配合做自动化巡检:
cilium-dbg bpf srv6 sid -o json cilium-dbg bpf srv6 sid -o yaml cilium-dbg bpf srv6 sid -o jsonpath='{.items[*].SID}'命令内部构造的条目结构体为(见 cilium-dbg/cmd/bpf_srv6_sid.go):
type srv6SID struct { SID string VRFID uint32 }因此 JSON 输出的每一条目形如{"SID": "fd00::1", "VRFID": 1}。
底层原理:cilium_srv6_sidBPF 哈希表
sid子命令读取的内核 map 名为cilium_srv6_sid,其完整定义在 Go 侧 pkg/maps/srv6map/sid.go 与 BPF C 侧 bpf/lib/srv6_maps.h 中保持一致:
| 属性 | 值 | 说明 |
|---|---|---|
| map 名称 | cilium_srv6_sid | 按名称 pin 在 bpffs 上(LIBBPF_PIN_BY_NAME) |
| map 类型 | BPF_MAP_TYPE_HASH | 普通哈希表 |
| key | union v6addr(128 位 IPv6 地址) | 即 SID 本身 |
| value | __u32 | 对应的 VRF ID |
| 最大条目数 | SRV6_SID_MAP_SIZE= 16384 | 常量在 pkg/maps/srv6map/sid.go 与 bpf/node_config.h 中定义 |
| map flags | BPF_F_NO_PREALLOC \| BPF_F_RDONLY_PROG_COND | 不预分配内存;条件性对 BPF 程序只读 |
Go 侧的 key/value 类型分别为SIDKey{SID types.IPv6}与SIDValue{VRFID uint32}(见 pkg/maps/srv6map/sid.go),Go map 打开方式为OpenSIDMap(logger)(同文件 pkg/maps/srv6map/sid.go),该 map 仅在节点启用 SRv6(DaemonConfig.EnableSRv6)时创建,并通过 Hive 生命周期钩子在OnStart时OpenOrCreate、OnStop时关闭(见 pkg/maps/srv6map/sid.go)。
数据面如何消费这张表
SID map 在数据面中的角色是"解封装判定":当内核收到一个内层协议为 IPIP/IPv6 或携带 SRH 的 IPv6 报文时,数据面会以报文目的地址(SID)为 key 查询cilium_srv6_sid,命中则说明本节点是该 SID 的终点,应执行 SRv6 解封装并将流量送入对应 VRF。核心查询函数为 bpf/lib/srv6.h 中的srv6_lookup_sid():
static __always_inline __u32 srv6_lookup_sid(const struct in6_addr *sid) { const __u32 *vrf_id; vrf_id = map_lookup_elem(&cilium_srv6_sid, sid); if (vrf_id) return *vrf_id; return 0; }可以看到,map 的 value(VRF ID)正是解封装后报文所属 VRF 的标识;未命中时返回 0,意味着该报文不会被当作 SRv6 终止处理。因此,当你发现 SRv6 解封装没有按预期生效时,第一步就是用cilium-dbg bpf srv6 sid确认目标 SID 是否已写入表中、其绑定的 VRF ID 是否符合预期。
一张表,三类子命令配合排障
SRv6 数据面依赖三张 map 协作:cilium_srv6_vrf_v4/v6(LPM Trie,源 IP+目的 CIDR → VRF ID)、cilium_srv6_policy_v4/v6(LPM Trie,VRF ID+目的 CIDR → SID)以及本文的cilium_srv6_sid(哈希,SID → VRF ID)。完整的排查链路是:用cilium-dbg bpf srv6 vrf确认入站报文能否映射到正确的 VRF,用cilium-dbg bpf srv6 policy确认出向流量应封装的 SID,再用cilium-dbg bpf srv6 sid确认该 SID 在对端节点是否已注册。三者定义分别见 pkg/maps/srv6map/vrf.go 与 pkg/maps/srv6map/policy.go。
权限与运行环境要求
命令在Run函数入口调用了common.RequireRootPrivilege("cilium bpf srv6 sid")(见 cilium-dbg/cmd/bpf_srv6_sid.go),因此必须以 root 权限(或在支持非 root 读取 BPF map 的环境下具备相应能力)执行。它读取的是本节点 bpffs 上 pin 的 map 文件,属于对本地数据面的直接访问,无需经由 API server。
源码级验证:测试用例
仓库中的单元测试 pkg/maps/srv6map/sid_test.go(TestPrivilegedSIDMapsHive)验证了该 map 从创建到迭代的完整流程:通过 Hive 注入newSIDMap,断言SRV6_SID_MAP_SIZE宏被导出、map 文件存在于 bpffs、插入SID=fd00::1, VRFID=1后能通过IterateWithCallback读回。数据面侧的集成测试 bpf/tests/tc_srv6_decap.c 则直接调用map_update_elem(&cilium_srv6_sid, &sid, &vrf_id, 0)预置 SID 条目后验证解封装路径——这正对应了本命令所列举的条目类型。
进一步阅读
- 父命令参考:cilium-dbg bpf srv6
- 兄弟命令:cilium-dbg bpf srv6 policy、cilium-dbg bpf srv6 vrf
- 命令实现:cilium-dbg/cmd/bpf_srv6_sid.go
- BPF map 定义:bpf/lib/srv6_maps.h、pkg/maps/srv6map/sid.go
- 数据面查询逻辑:bpf/lib/srv6.h
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考