cilium FRR 和 gobgp 的使用
已对 /Users/ftwhmg/g/cilium 做了全库检索(含文档/Helm/示例实验/CLI/核心实现/CRD/依赖 vendor),下面汇总所有与 FRR/frr/bgpd/vtysh 以及 GoBGP/gobgp/github.com/osrg/gobgp(含 CLI/daemon 概念) 相关的路径与功能承载点,并说明二者在 Cilium 中的关系/分工。
FRR / frr / bgpd / vtysh(集成/部署/文档/配置/代码)
-
Connectivity Test 中的 FRR “外部路由器”部署与交互(K8s DaemonSet + vtysh)
- frr.go
- 功能点:为
cilium connectivity test动态创建一个运行 FRR 的 DaemonSet(frr-external-node)作为外部 BGP peer;通过vtysh -c ...执行命令采集邻居/路由(JSON 输出)。 - 关键实现细节:
- ConfigMap 内直接写入
daemons:bgpd=yes、vtysh_enable=yes,并挂载到/etc/frr/daemons、/etc/frr/vtysh.conf(service integrated-vtysh-config)。 - Exec 入口:
RunFRRCommand()使用vtysh进入 FRR CLI。 - 与 K8s 对象关联:创建
DaemonSet+ConfigMap(不涉及 Cilium BGP CRD,本质是测试桩/外部 peer)。
- ConfigMap 内直接写入
- 功能点:为
- defaults.go
- 功能点:固定 connectivity test 用的 FRR 镜像(
quay.io/frrouting/frr:10.5.3...)。
- 功能点:固定 connectivity test 用的 FRR 镜像(
- 相关文档提及(CLI 使用侧)
- cilium_connectivity_test.md(包含 FRR image/测试说明的上下文引用点)
- frr.go
-
Containerlab 开发/演示环境中的 FRR 路由器(linux 容器 + bgpd + vtysh 配置)
- bgp_cplane.rst
- 功能点:贡献者开发环境说明:
router0是 FRR,作为 Cilium BGP Control Plane 的 peer。
- 功能点:贡献者开发环境说明:
- topo.yaml
- 功能点:containerlab 拓扑里显式启动
frrouting/frr,用vtysh -c写入router bgp ...、peer-group、password、debug 等。 - 关键实现细节:
- 启动 FRR:
/usr/lib/frr/frrinit.sh start - 开启 bgpd:
sed -i 's/bgpd=no/bgpd=yes/g' /etc/frr/daemons - 通过
vtysh下发 BGP 配置。
- 启动 FRR:
- 功能点:containerlab 拓扑里显式启动
- service/README.md
- 功能点:验证侧大量用
docker exec ... vtysh -c 'sh bgp ...'查看 Cilium 通告的路由与属性。
- 功能点:验证侧大量用
- bgp_cplane.rst
结论(FRR 在本仓库中的定位):FRR/bgpd/vtysh 主要作为“外部 BGP 路由器/peer”出现在测试与实验环境(connectivity test、containerlab),用于验证 Cilium 的 BGP Control Plane 行为;不是 Cilium agent 内部的 BGP 后端实现。
GoBGP / gobgp / github.com/osrg/gobgp(代码路径、入口、配置项、运行方式、CRD 关联)
-
Cilium BGP Control Plane 主实现(嵌入式 GoBGP server,运行在 cilium-agent 内)
- cell.go
- 入口:Hive module
bgp-control-plane。 - 关键点:
- 组装
agent.Controller+manager.BGPRouterManager+gobgp.NewRouterProvider()(明确注释:目前只支持 GoBGP)。 - 绑定 K8s 资源流(Resource/Store):
CiliumBGPNodeConfig / CiliumBGPPeerConfig / CiliumBGPAdvertisement / Secret / CiliumPodIPPool等,并在事件时触发控制面 reconcile。 - 提供 BGP Rest API handlers:
api.NewGetPeerHandler / NewGetRoutesHandler / NewGetRoutePoliciesHandler(供cilium bgp ...与 API 查询)。
- 组装
- 入口:Hive module
- controller.go
- 入口:agent 侧控制器
Controller.Run()监听本地CiliumNode与 BGP 配置 store 触发BGPMgr.ReconcileInstances(...)。 - 关键点:注释写明“可插拔后端(GoBGP/FRR/Bird等),但当前只实现 GoBGP”。
- 入口:agent 侧控制器
- manager.go
- 功能点:按
CiliumBGPClusterConfig视角管理多个 BGP instance(虚拟路由器),并驱动一组 reconcilers 下发配置/状态。 - 与 API 关联:实现 peers/routes 查询路径(文件顶部引入
api/v1/server/restapi/bgp,并对外提供聚合查询能力)。
- 功能点:按
- cell.go
-
GoBGP 后端封装(真正“起 BGP daemon”的地方:在进程内启动 gobgp server)
- server.go
- 入口:
NewGoBGPServer(...)。 - 运行方式:
server.NewBgpServer(...); go s.Serve(); s.StartBgp(...)—— GoBGP “daemon”是 cilium-agent 进程内 goroutine,不是独立 Pod/独立二进制。 - 关键实现细节:
- 下发
StartBgpRequest.Global:Asn / RouterId / ListenPort,并可设置RouteSelectionOptions.AdvertiseInactiveRoutes。 - 默认策略:全局 import policy 默认 REJECT,只允许 LOCAL 路由(
allow-localpolicy +SetPolicyAssignment)。 - Watch:
WatchEvent(... WatchPeer, WatchPostUpdate...),peer state/route 变动通过 channel 通知上层触发状态 reconcile。
- 下发
- 入口:
- provider.go
- 功能点:RouterProvider 工厂;当前唯一实现就是 GoBGP。
- server.go
-
CRD/文档(配置模型与 K8s 对象关联)
- 文档入口(资源与字段解释)
- bgp-control-plane.rst
- Helm/CLI 启用:
bgpControlPlane.enabled=true。
- Helm/CLI 启用:
- bgp-control-plane-configuration.rst
- 关键 CRD:
CiliumBGPClusterConfig / CiliumBGPPeerConfig / CiliumBGPAdvertisement / CiliumBGPNodeConfigOverride。 - 行为要点:默认 instance 不监听端口(只主动发起连接),如需入站则配置
localPort(并提示 179 需要CAP_NET_BIND_SERVICE)。
- 关键 CRD:
- bgp-control-plane.rst
- CRD 定义(schema 层)
- ciliumbgpclusterconfigs.yaml
- 关键字段:
spec.bgpInstances[].localASN / localPort / peers[] / peers[].autoDiscovery...等。
- 关键字段:
- ciliumbgpclusterconfigs.yaml
- Helm/ConfigMap 到 daemon option 的落地
- values.yaml
- Helm 配置项:
bgpControlPlane.enabled、secretsNamespace、statusReport.enabled、routerIDAllocation.mode/ipPool、legacyOriginAttribute.enabled。
- Helm 配置项:
- config.go
- 关键 daemon flags:
bgp-secrets-namespace、enable-bgp-control-plane、enable-bgp-control-plane-status-report、bgp-router-id-allocation-*。
- 关键 daemon flags:
- values.yaml
- 文档入口(资源与字段解释)
-
“gobgp CLI/daemon”在本仓库中的体现
- Cilium 不依赖/不部署独立的
gobgpCLI 或gobgpddaemon;而是:- 在 agent 内嵌
github.com/osrg/gobgp/v4/pkg/server作为 daemon(见 server.go)。 - 用 Cilium 自己的 CLI/API 来查询 BGP 状态/路由:
- routes.go:
cilium bgp routes通过 exec 到各 cilium-agent Pod 内执行cilium bgp routes ... -o json聚合输出(并使用github.com/osrg/gobgp/v4/pkg/packet/bgp做属性解析/格式化)。
- routes.go:
- 测试脚本里存在“gobgp/*”命令,但那是 hive script 测试用的内存 GoBGP server 控制命令,不是外部 gobgp 二进制:
- gobgp.go(例如
gobgp/add-server、gobgp/add-peer等)。
- gobgp.go(例如
- 在 agent 内嵌
- Cilium 不依赖/不部署独立的
-
vendor 依赖路径(github.com/osrg/gobgp)
vendor/github.com/osrg/gobgp/v4/...:完整 GoBGP API、server、zebra 等依赖实现(例如pkg/server/*、api/*.pb.go等,供 Cilium 内嵌调用)。- 该目录承载第三方实现本体;Cilium 自身的 glue/抽象在
pkg/bgp/gobgp/*与pkg/bgp/*。
二者关系 / 分工 / 互斥或兼容
- 分工
- GoBGP:Cilium BGP Control Plane 的实际后端(当前唯一实现),在
cilium-agent内运行,负责建立 BGP session、注入/撤回路由、策略等(入口见 NewGoBGPServer)。 - FRR:在本仓库中主要是外部 peer/验证工具:
- GoBGP:Cilium BGP Control Plane 的实际后端(当前唯一实现),在
- 互斥/兼容
-
不互斥:FRR 可作为 Cilium(GoBGP 后端)对端路由器;这是仓库里默认的验证方式之一(文档/示例大量用 FRR)。
-
后端层面当前互斥:代码层抽象允许未来替换后端(controller 注释提到 FRR/Bird),但当前
RouterProvider只提供 GoBGP(cell.go),因此 “用 FRR 作为 Cilium 内部 BGP daemon”并未实现。
-
总体结论
- 在当前 Cilium 仓库里,GoBGP 是“Cilium BGP Control Plane 的真实后端”:运行在
cilium-agent进程内,负责建邻、下发/撤回路由、策略与状态查询(核心入口见 cell.go、server.go)。 - FRR 在本仓库中主要承担“外部路由器/对端 peer/验证工具”的角色:用于 connectivity test 和 containerlab 开发/演示环境里,作为 Cilium(BGP) 的 eBGP 对端,通过
vtysh下发配置与读取状态(见 frr.go、topo.yaml)。
FRR 在当前项目承载的功能与细节
1) cilium connectivity test 里的“外部 FRR 节点”(测试桩 / 外部 Peer)
对应实现集中在 frr.go:
-
以 DaemonSet 形式部署 FRR
- DaemonSet 名称固定为
frr-external-node,通过HostNetwork: true+ 高权限能力(NET_ADMIN/NET_RAW/SYS_ADMIN)运行(见 NewFRRDaemonSet)。 - 节点选择器是
cilium.io/no-schedule=true(见 NewFRRDaemonSet),表示把 FRR 放到“没有 Cilium 的外部节点”/或模拟外部网络侧节点上。 - FRR 镜像在 CLI defaults 固定:
quay.io/frrouting/frr:10.5.3...(见 defaults.go)。
- DaemonSet 名称固定为
-
用 ConfigMap 控制 FRR 启动哪些守护进程
- 通过 ConfigMap 挂载
/etc/frr/daemons,明确开启bgpd=yes与vtysh_enable=yes,其它(ospf/rip/isis 等)默认关闭(见 NewFRRConfigMap)。 - 同时写入
vtysh.conf: service integrated-vtysh-config(见同上),使得后续可以稳定用vtysh -c ...做自动化。
- 通过 ConfigMap 挂载
-
用
vtysh作为 FRR 的“查询/配置 API”- 执行入口是
RunFRRCommand():vtysh -c <cmd>,并要求 stderr 为空,否则直接 fail(见 RunFRRCommand)。 - 配置下发方式是把
frr.conf写入 Pod 后执行/usr/lib/frr/frr-reload(见 ApplyFRRConfig)。
- 执行入口是
-
测试断言覆盖的“BGP 细节项”
- 邻居状态收敛:轮询
show bgp neighbor json并解析成结构体FRRBGPNeighborInfo,检查每个 peer 的bgpState达到期望(见 WaitForFRRBGPNeighborsState)。 - Timer 校验:断言 KeepAlive/HoldTime 是否符合预期(见 AssertFRRBGPNeighborTimers)。
- 路由学习与属性校验:轮询
show bgp ipv4/ipv6 detail json,确认前缀出现,并可断言 community(见 WaitForFRRBGPPrefixes、AssertFRRBGPCommunity)。 - 故障时 dump:直接 dump
show bgp neighbors / show bgp ipv4 detail / show bgp ipv6 detail(见 DumpFRRBGPState)。
- 邻居状态收敛:轮询
这里 FRR 的定位非常清晰:它不是 Cilium 内部 BGP 的实现,而是被 CLI 拉起来的“对端 BGP 路由器”,用于验证 Cilium 的通告、属性、会话与计时器行为。
2) containerlab 里的 FRR “router0”(开发/演示拓扑中的 ToR/外部路由器)
对应拓扑是 topo.yaml:
- router0 就是 FRR 容器:
image: frrouting/frr:v8.4.0(见 topo.yaml)。 - 启动步骤非常“FRR 原生”:
- 体现了一个关键产品现实:示例里
server0/server1明确写了静态路由,并备注“Cilium currently cannot import routes”(见 topo.yaml)。这和 GoBGP 侧的“默认全局 import reject”策略在行为上是一致的(下面会展开)。
GoBGP 在当前项目承载的功能与细节
1) 架构入口:Hive cell 组装 BGP CP(资源监听 + 控制循环 + API)
- 模块入口是 cell.go:
2) 控制循环:Controller 用“事件信号”触发 reconcile
- Controller 的核心行为在 controller.go:
- 它监听本节点
CiliumNode的 Upsert 事件,更新LocalCiliumNode并触发信号(见 Controller.Run)。 - 收到信号后,读取
CiliumBGPNodeConfig(按本节点名取),然后调用BGPMgr.ReconcileInstances(...)(见 Controller.Reconcile)。 - 代码注释层面明确“抽象上可支持 GoBGP/FRR/Bird 等,但当前只实现 GoBGP”(见 NewController 注释)。
- 它监听本节点
3) BGP 实例管理:BGPRouterManager 管多实例 + reconcilers + 状态观测
- Manager 的入口在 manager.go:
- 它把
CiliumBGPClusterConfig里的每个 instance 视为“本机一个 BGP router 实例”(见注释 manager.go)。 - 注入
types.RouterProvider(当前就是 GoBGP provider)+ 一组 ConfigReconcilers / StateReconcilers(见 manager.go)。 - 它单独起了
bgp-state-observerjob,处理 GoBGP server 的状态通知(peer state change、路由变化)并触发 state reconcile(见 manager.go)。
- 它把
4) 真正的“BGP daemon”:GoBGP server 以内嵌方式运行在 agent 进程里
- 核心在 server.go:
server.NewBgpServer(...)后直接go s.Serve(),说明 没有外部 gobgpd 容器/进程,就是 agent 内 goroutine(见 server.go)。StartBgpRequest.Global里设置Asn / RouterId / ListenPort(见 server.go),并支持 RouteSelectionOptions(见 server.go)。- 一个非常关键的默认安全/行为策略:全局 import policy 默认 REJECT(拒绝从外部 peer 学到的路由),只额外允许 local route(
allow-local)通过,以免误伤本地路由(见 server.go)。 - Watch 机制:peer state change 和 route event 会往
params.StateNotification发信号,驱动上层 state reconcile(见 server.go)。
5) CLI/可观测:通过 Cilium 自己的命令查询,必要时用 GoBGP 库解析属性
cilium-cli侧的cilium bgp routes是exec 到每个 cilium-agent Pod 内跑cilium bgp routes ... -o json,并发聚合输出(见 routes.go)。- 该命令直接引入
github.com/osrg/gobgp/v4/pkg/packet/bgp用于解析 BGP 属性/字段展示(见 routes.go imports)。
FRR 与 GoBGP 在“使用关系”上的对应与耦合点
1) 数据面/协议层:FRR 作为对端,验证 GoBGP(Cilium)通告是否正确
- connectivity test 里,FRR 通过
show bgp neighbor json、show bgp ipv4/ipv6 detail json来判断:- 会话是否 Established、timer 是否匹配、前缀是否学习、community 是否符合预期(见 frr.go)。
- containerlab 里,router0(FRR) 按 ToR 模式配置 peer-group、password,与 Cilium 建 eBGP(见 topo.yaml)。
2) 控制面/产品行为:Cilium(GoBGP) 默认“不导入外部路由”,FRR 示例因此需要静态路由或额外设计
- GoBGP 后端在初始化时把 global import 默认动作设为 REJECT(见 server.go),这意味着:
- Cilium 的 BGP CP 更偏向“对外通告(announce)”,而不是“学路由做转发决策的通用路由器”。
- containerlab 示例里明确写了 “These static routes are needed because Cilium cannot import routes currently.”(见 topo.yaml),正好呼应这一点。
3) 代码层后端分工:抽象上可替换,但当前实现只落地了 GoBGP
- Controller 注释提到后端可为 GoBGP/FRR/Bird 等,但标注 only GoBGP implemented(见 controller.go)。
- Hive 注入处也写明当前只提供
gobgp.NewRouterProvider(见 cell.go)。 - 所以在“Cilium 内部跑哪个 BGP daemon”这个维度上:GoBGP 与 FRR 不是并行使用,而是“GoBGP 是实现,FRR 主要是外部对端/测试环境依赖”。