cilium FRR 和 gobgp 的使用

5 阅读11分钟

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 内直接写入 daemonsbgpd=yesvtysh_enable=yes,并挂载到 /etc/frr/daemons/etc/frr/vtysh.confservice integrated-vtysh-config)。
        • Exec 入口:RunFRRCommand() 使用 vtysh 进入 FRR CLI。
        • 与 K8s 对象关联:创建 DaemonSet + ConfigMap(不涉及 Cilium BGP CRD,本质是测试桩/外部 peer)。
    • defaults.go
      • 功能点:固定 connectivity test 用的 FRR 镜像(quay.io/frrouting/frr:10.5.3...)。
    • 相关文档提及(CLI 使用侧)
  • 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 配置。
    • service/README.md
      • 功能点:验证侧大量用 docker exec ... vtysh -c 'sh bgp ...' 查看 Cilium 通告的路由与属性。

结论(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 查询)。
    • controller.go
      • 入口:agent 侧控制器 Controller.Run() 监听本地 CiliumNode 与 BGP 配置 store 触发 BGPMgr.ReconcileInstances(...)
      • 关键点:注释写明“可插拔后端(GoBGP/FRR/Bird等),但当前只实现 GoBGP”。
    • manager.go
      • 功能点:按 CiliumBGPClusterConfig 视角管理多个 BGP instance(虚拟路由器),并驱动一组 reconcilers 下发配置/状态。
      • 与 API 关联:实现 peers/routes 查询路径(文件顶部引入 api/v1/server/restapi/bgp,并对外提供聚合查询能力)。
  • GoBGP 后端封装(真正“起 BGP daemon”的地方:在进程内启动 gobgp server)

    • server.go
      • 入口:NewGoBGPServer(...)
      • 运行方式:server.NewBgpServer(...); go s.Serve(); s.StartBgp(...) —— GoBGP “daemon”是 cilium-agent 进程内 goroutine,不是独立 Pod/独立二进制。
      • 关键实现细节:
        • 下发 StartBgpRequest.GlobalAsn / RouterId / ListenPort,并可设置 RouteSelectionOptions.AdvertiseInactiveRoutes
        • 默认策略:全局 import policy 默认 REJECT,只允许 LOCAL 路由(allow-local policy + SetPolicyAssignment)。
        • Watch:WatchEvent(... WatchPeer, WatchPostUpdate...),peer state/route 变动通过 channel 通知上层触发状态 reconcile。
    • provider.go
      • 功能点:RouterProvider 工厂;当前唯一实现就是 GoBGP。
  • CRD/文档(配置模型与 K8s 对象关联)

    • 文档入口(资源与字段解释)
      • bgp-control-plane.rst
        • Helm/CLI 启用:bgpControlPlane.enabled=true
      • bgp-control-plane-configuration.rst
        • 关键 CRD:CiliumBGPClusterConfig / CiliumBGPPeerConfig / CiliumBGPAdvertisement / CiliumBGPNodeConfigOverride
        • 行为要点:默认 instance 不监听端口(只主动发起连接),如需入站则配置 localPort(并提示 179 需要 CAP_NET_BIND_SERVICE)。
    • CRD 定义(schema 层)
    • Helm/ConfigMap 到 daemon option 的落地
      • values.yaml
        • Helm 配置项:bgpControlPlane.enabledsecretsNamespacestatusReport.enabledrouterIDAllocation.mode/ipPoollegacyOriginAttribute.enabled
      • config.go
        • 关键 daemon flags:bgp-secrets-namespaceenable-bgp-control-planeenable-bgp-control-plane-status-reportbgp-router-id-allocation-*
  • “gobgp CLI/daemon”在本仓库中的体现

    • Cilium 不依赖/不部署独立的 gobgp CLI 或 gobgpd daemon;而是:
      • 在 agent 内嵌 github.com/osrg/gobgp/v4/pkg/server 作为 daemon(见 server.go)。
      • 用 Cilium 自己的 CLI/API 来查询 BGP 状态/路由:
        • routes.gocilium bgp routes 通过 exec 到各 cilium-agent Pod 内执行 cilium bgp routes ... -o json 聚合输出(并使用 github.com/osrg/gobgp/v4/pkg/packet/bgp 做属性解析/格式化)。
      • 测试脚本里存在“gobgp/*”命令,但那是 hive script 测试用的内存 GoBGP server 控制命令,不是外部 gobgp 二进制:
        • gobgp.go(例如 gobgp/add-servergobgp/add-peer 等)。
  • 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/验证工具
      • connectivity test 用 FRR DaemonSet + vtysh 执行检查(frr.go)。
      • containerlab 用 FRR 容器当“机架路由器/ToR”来验证通告与属性(topo.yaml)。
  • 互斥/兼容
    • 不互斥:FRR 可作为 Cilium(GoBGP 后端)对端路由器;这是仓库里默认的验证方式之一(文档/示例大量用 FRR)。

    • 后端层面当前互斥:代码层抽象允许未来替换后端(controller 注释提到 FRR/Bird),但当前 RouterProvider 只提供 GoBGP(cell.go),因此 “用 FRR 作为 Cilium 内部 BGP daemon”并未实现

总体结论

  • 在当前 Cilium 仓库里,GoBGP 是“Cilium BGP Control Plane 的真实后端”:运行在 cilium-agent 进程内,负责建邻、下发/撤回路由、策略与状态查询(核心入口见 cell.goserver.go)。
  • FRR 在本仓库中主要承担“外部路由器/对端 peer/验证工具”的角色:用于 connectivity test 和 containerlab 开发/演示环境里,作为 Cilium(BGP) 的 eBGP 对端,通过 vtysh 下发配置与读取状态(见 frr.gotopo.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)。
  • 用 ConfigMap 控制 FRR 启动哪些守护进程

    • 通过 ConfigMap 挂载 /etc/frr/daemons,明确开启 bgpd=yesvtysh_enable=yes,其它(ospf/rip/isis 等)默认关闭(见 NewFRRConfigMap)。
    • 同时写入 vtysh.conf: service integrated-vtysh-config(见同上),使得后续可以稳定用 vtysh -c ... 做自动化。
  • 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(见 WaitForFRRBGPPrefixesAssertFRRBGPCommunity)。
    • 故障时 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 原生”
    • sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons + /usr/lib/frr/frrinit.sh start(见 topo.yaml)。
    • vtysh 下发 router bgp 65000、peer-group、neighbor ... password ...、debug 等(见 topo.yaml)。
  • 体现了一个关键产品现实:示例里 server0/server1 明确写了静态路由,并备注“Cilium currently cannot import routes”(见 topo.yaml)。这和 GoBGP 侧的“默认全局 import reject”策略在行为上是一致的(下面会展开)。

GoBGP 在当前项目承载的功能与细节

1) 架构入口:Hive cell 组装 BGP CP(资源监听 + 控制循环 + API)

  • 模块入口是 cell.go
    • 注入 agent.NewControllermanager.NewBGPRouterManager、以及 gobgp.NewRouterProvider,并明确写了“GoBGP is currently the only supported router”(见 cell.go)。
    • 监听/存储的 Kubernetes 资源包含:
      • CiliumBGPNodeConfig / CiliumBGPPeerConfig / CiliumBGPAdvertisement(见 cell.go
      • Secret(用于 BGP auth secret namespace,未设置会 warn,见 cell.go
      • CiliumPodIPPool(与 MultiPool IPAM 场景下的 RouterID 等能力相关,见 cell.go
    • 同时提供 BGP REST API handlers:GetPeer / GetRoutes / GetRoutePolicies(见 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-observer job,处理 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 routesexec 到每个 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 jsonshow 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 主要是外部对端/测试环境依赖”。