Skip to content

bgpstatus: replace netlink collector with gNMI Get#3674

Open
juan-malbeclabs wants to merge 2 commits intomainfrom
jo/bgpstatus_gnmi
Open

bgpstatus: replace netlink collector with gNMI Get#3674
juan-malbeclabs wants to merge 2 commits intomainfrom
jo/bgpstatus_gnmi

Conversation

@juan-malbeclabs
Copy link
Copy Markdown
Contributor

@juan-malbeclabs juan-malbeclabs commented May 5, 2026

Summary of Changes

  • Replace the Linux-specific netlink BGP socket collector with a gNMI Get call to Arista's local gNMI server (/var/run/gnmiServer.sock), querying all BGP neighbor state across all network instances in a single request
  • Remove per-VRF namespace switching (vrfNamespaces, setns) and tunnel interface discovery (FindLocalTunnel); simplify peer IP matching to checking both IPs in the user's /31 tunnel net
  • Remove //go:build linux build tag and BGPNamespace config field; consolidate platform-specific test file into a single cross-platform submitter_test.go

Diff Breakdown

Category Files Lines (+/-) Net
Core logic 2 +132 / -170 -38
Scaffolding 1 +23 / -5 +18
Tests 2 +341 / -393 -52
Total 5 +496 / -568 -72

Net deletion branch: removes more complexity than it adds — namespace switching, netlink, and tunnel discovery logic replaced by a single gNMI call.

Key files (click to expand)
  • controlplane/telemetry/internal/bgpstatus/submitter.go — removes DefaultCollector and namespace loop; adds GNMIClient interface, GNMICollector, parseEstablished, neighborAddress; simplifies tick() to a single collector call
  • controlplane/telemetry/internal/bgpstatus/bgpstatus.go — replaces NamespaceCollector with BGPCollector (no namespace param, no ifaces return); removes vrfNamespaces, bgpSocket, buildEstablishedIPSet, rootNamespace; adds peerIPsFor31
  • controlplane/telemetry/internal/bgpstatus/submitter_test.go — consolidates two test files; adds tests for parseEstablished, neighborAddress, peerIPsFor31, and tick() with gNMI mocks
  • controlplane/telemetry/cmd/telemetry/main.go — wires gRPC connection to /var/run/gnmiServer.sock (namespace-aware) and passes GNMICollector to the submitter

Testing Verification

  • All 47 unit tests pass (go test ./controlplane/telemetry/internal/bgpstatus/...)
  • parseEstablished tested against all BGP session states (ESTABLISHED, IDLE, ACTIVE, CONNECT, OPENSENT, OPENCONFIRM), multiple neighbors, and neighbor-address in prefix vs. update path

Replace the Linux-specific netlink-based BGP session collector with a
gNMI Get call to Arista's local gNMI server (/var/run/gnmiServer.sock).

- Remove NamespaceCollector, vrfNamespaces(), and namespace switching
  logic; add BGPCollector interface (no namespace parameter)
- Add GNMIClient interface and GNMICollector() that queries all BGP
  neighbors across all network-instances in a single Get request
- Simplify per-user peer IP matching: check both IPs in the /31 tunnel
  net instead of finding the local tunnel interface first
- Remove //go:build linux build tag; code is now platform-agnostic
- Consolidate submitter_linux_test.go into submitter_test.go; add tests
  for parseEstablished, neighborAddress, and tick() with gNMI collector
@juan-malbeclabs juan-malbeclabs marked this pull request as ready for review May 7, 2026 16:03
// whose session-state is ESTABLISHED across every network instance.
func GNMICollector(client GNMIClient) BGPCollector {
return func(ctx context.Context) (map[string]struct{}, error) {
resp, err := client.Get(ctx, bgpNeighborsGetRequest)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if this call hangs or is very slow? Probably need to set a timeout on the Get call

continue
}
var state bgpStateJSON
if err := json.Unmarshal(jsonVal, &state); err != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No error handling needed here?

// peerIPsFor31 returns both host IPs in a /31 network. Since tunnel IPs are
// globally unique (onchain-allocated), exactly one of the two will be the
// BGP neighbor address for a given user on this device.
func peerIPsFor31(tunnelNet *net.IPNet) (net.IP, net.IP) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the caller sends something other than a /31?

) <-chan error {
executor := serviceability.NewExecutor(log, rpcClient, &keypair, serviceabilityProgramID)

const gnmiSocketPath = "/var/run/gnmiServer.sock"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also hard-coded on line 549 below. Share the constant?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants