diff --git a/connectivity/check/frr.go b/connectivity/check/frr.go index 1f60b05888..5c9e861f74 100644 --- a/connectivity/check/frr.go +++ b/connectivity/check/frr.go @@ -54,12 +54,16 @@ type FRRBGPPeeringParams struct { // FRRBGPNeighborInfo holds FRR BGP neighbor information equivalent to "show bgp neighbor json" CLI output entry. type FRRBGPNeighborInfo struct { - RemoteAS int `json:"remoteAs"` - LocalAS int `json:"localAs"` - Hostname string `json:"hostname"` - RemoteRouterID string `json:"remoteRouterId"` - LocalRouterID string `json:"localRouterId"` - BGPState string `json:"bgpState"` + RemoteAS int `json:"remoteAs"` + LocalAS int `json:"localAs"` + Hostname string `json:"hostname"` + RemoteRouterID string `json:"remoteRouterId"` + LocalRouterID string `json:"localRouterId"` + BGPState string `json:"bgpState"` + BgpTimerUpMsec int `json:"bgpTimerUpMsec"` + BgpTimerUpEstablishedEpoch int `json:"bgpTimerUpEstablishedEpoch"` + BgpTimerHoldTimeMsecs int `json:"bgpTimerHoldTimeMsecs"` + BgpTimerKeepAliveIntervalMsecs int `json:"bgpTimerKeepAliveIntervalMsecs"` } // FRRBGPPrefixMap is a map of BGP route information indexed by prefix. @@ -250,41 +254,59 @@ func RenderFRRBGPPeeringConfig(t *Test, params FRRBGPPeeringParams) string { } // WaitForFRRBGPNeighborsState waits until provided list of BGP peers reach the provided state -// on the provided FRR pod. -func WaitForFRRBGPNeighborsState(ctx context.Context, t *Test, frrPod *Pod, expPeers []netip.Addr, expState string) { +// on the provided FRR pod and returns detailed state information of all peers. +func WaitForFRRBGPNeighborsState(ctx context.Context, t *Test, frrPod *Pod, expPeers []netip.Addr, expState string) map[string]FRRBGPNeighborInfo { w := wait.NewObserver(ctx, wait.Parameters{Timeout: 30 * time.Second}) defer w.Cancel() - ensureBGPNeighborsState := func() error { + ensureBGPNeighborsState := func() (map[string]FRRBGPNeighborInfo, error) { stdout := RunFRRCommand(ctx, t, frrPod, "show bgp neighbor json") entries := map[string]FRRBGPNeighborInfo{} err := json.Unmarshal(stdout, &entries) if err != nil { - return err + return nil, err } if len(entries) < len(expPeers) { - return fmt.Errorf("expected %d peers, got %d", len(expPeers), len(entries)) + return nil, fmt.Errorf("expected %d peers, got %d", len(expPeers), len(entries)) } for _, peer := range expPeers { frrPeer, exists := entries[peer.String()] if !exists { - return fmt.Errorf("missing peer %s", peer.String()) + return nil, fmt.Errorf("missing peer %s", peer.String()) } if frrPeer.BGPState != expState { - return fmt.Errorf("peer %s: expected %s state, got %s", peer, expState, entries[peer.String()].BGPState) + return nil, fmt.Errorf("peer %s: expected %s state, got %s", peer, expState, entries[peer.String()].BGPState) } } - return nil + return entries, nil } for { - if err := ensureBGPNeighborsState(); err != nil { + entries, err := ensureBGPNeighborsState() + if err != nil { if err := w.Retry(err); err != nil { t.Fatalf("Failed to ensure FRR BGP neighbor states: %v", err) } continue } - return + return entries + } +} + +// AssertFRRBGPNeighborTimers asserts that peering connections of the provided neighbors filtered by checkNeighbors +// use the provided BGP timer intervals. +func AssertFRRBGPNeighborTimers(t *Test, neighbors map[string]FRRBGPNeighborInfo, checkNeighbors []netip.Addr, keepAliveSeconds, holdTimeSeconds int32) { + for _, addr := range checkNeighbors { + neighbor, ok := neighbors[addr.String()] + if !ok { + t.Fatalf("neighbor %s missing in FRR neighbors map", addr) + } + if neighbor.BgpTimerKeepAliveIntervalMsecs != int(keepAliveSeconds*1000) { + t.Fatalf("neighbor %s: expected BGP KeepAlive '%d', got '%d'", addr, keepAliveSeconds, neighbor.BgpTimerKeepAliveIntervalMsecs/1000) + } + if neighbor.BgpTimerHoldTimeMsecs != int(holdTimeSeconds*1000) { + t.Fatalf("neighbor %s: expected BGP HoldTime '%d', got '%d'", addr, holdTimeSeconds, neighbor.BgpTimerHoldTimeMsecs/1000) + } } } diff --git a/connectivity/tests/bgp.go b/connectivity/tests/bgp.go index 02261a821f..7d6c1ae378 100644 --- a/connectivity/tests/bgp.go +++ b/connectivity/tests/bgp.go @@ -27,6 +27,10 @@ const ( bgpCommunityPodCIDR = "65001:100" bgpCommunityService = "65001:200" + + bgpConnectRetryTimeSeconds = 1 + bgpKeepAliveTimeSeconds = 1 + bgpHoldTimeSeconds = 3 ) func BGPAdvertisements(bgpAPIVersion uint8) check.Scenario { @@ -72,7 +76,8 @@ func (s *bgpAdvertisements) Run(ctx context.Context, t *check.Test) { podCIDRPrefixes := ct.PodCIDRPrefixes(ipFamily) svcPrefixes := ct.EchoServicePrefixes(ipFamily) for _, frr := range ct.FRRPods() { - check.WaitForFRRBGPNeighborsState(ctx, t, &frr, frrPeers, "Established") + neighbors := check.WaitForFRRBGPNeighborsState(ctx, t, &frr, frrPeers, "Established") + check.AssertFRRBGPNeighborTimers(t, neighbors, frrPeers, bgpKeepAliveTimeSeconds, bgpHoldTimeSeconds) frrPrefixes := check.WaitForFRRBGPPrefixes(ctx, t, &frr, podCIDRPrefixes, ipFamily) check.AssertFRRBGPCommunity(t, frrPrefixes, podCIDRPrefixes, bgpCommunityPodCIDR) @@ -167,9 +172,9 @@ func (s *bgpAdvertisements) configureBGPv1Peering(ctx context.Context, t *check. ciliumv2alpha1.CiliumBGPNeighbor{ PeerAddress: frr.Address(ipFamily) + prefix, PeerASN: bgpFRRASN, - ConnectRetryTimeSeconds: ptr.To[int32](1), - KeepAliveTimeSeconds: ptr.To[int32](1), - HoldTimeSeconds: ptr.To[int32](3), + ConnectRetryTimeSeconds: ptr.To[int32](bgpConnectRetryTimeSeconds), + KeepAliveTimeSeconds: ptr.To[int32](bgpKeepAliveTimeSeconds), + HoldTimeSeconds: ptr.To[int32](bgpHoldTimeSeconds), AdvertisedPathAttributes: []ciliumv2alpha1.CiliumBGPPathAttributes{ { SelectorType: ciliumv2alpha1.PodCIDRSelectorName, @@ -236,9 +241,9 @@ func (s *bgpAdvertisements) configureBGPv2Peering(ctx context.Context, t *check. }, Spec: ciliumv2alpha1.CiliumBGPPeerConfigSpec{ Timers: &ciliumv2alpha1.CiliumBGPTimers{ - ConnectRetryTimeSeconds: ptr.To[int32](1), - KeepAliveTimeSeconds: ptr.To[int32](1), - HoldTimeSeconds: ptr.To[int32](3), + ConnectRetryTimeSeconds: ptr.To[int32](bgpConnectRetryTimeSeconds), + KeepAliveTimeSeconds: ptr.To[int32](bgpKeepAliveTimeSeconds), + HoldTimeSeconds: ptr.To[int32](bgpHoldTimeSeconds), }, Families: []ciliumv2alpha1.CiliumBGPFamilyWithAdverts{ {