From a6ee3b0933ea7ac30e744cf9f84edb3908752236 Mon Sep 17 00:00:00 2001 From: Rastislav Szabo Date: Fri, 19 Jul 2024 11:27:38 +0200 Subject: [PATCH] connectivity: Assert BGP timer intervals in BGP connectivity tests This change asserts that BGP peering connections used in the BGP connectivity tests use the BGP timer intervals as configured via Cilium. Signed-off-by: Rastislav Szabo --- connectivity/check/frr.go | 54 +++++++++++++++++++++++++++------------ connectivity/tests/bgp.go | 19 +++++++++----- 2 files changed, 50 insertions(+), 23 deletions(-) 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{ {