github.com/cilium/cilium@v1.16.2/pkg/bgpv1/manager/manager_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package manager
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/netip"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"k8s.io/utils/ptr"
    14  
    15  	restapi "github.com/cilium/cilium/api/v1/server/restapi/bgp"
    16  	"github.com/cilium/cilium/pkg/bgpv1/agent/mode"
    17  	"github.com/cilium/cilium/pkg/bgpv1/manager/instance"
    18  	"github.com/cilium/cilium/pkg/bgpv1/types"
    19  	v2alpha1api "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2alpha1"
    20  )
    21  
    22  var (
    23  	testSingleIPv4Prefix = []netip.Prefix{
    24  		netip.MustParsePrefix("192.168.0.0/24"),
    25  	}
    26  	testSingleIPv6Prefix = []netip.Prefix{
    27  		netip.MustParsePrefix("2001:DB8::/32"),
    28  	}
    29  
    30  	testRouterASN         = 64125
    31  	testInvalidRouterASN  = 4126
    32  	testNeighborIP        = "5.6.7.8"
    33  	testInvalidNeighborIP = "1.2.3.4"
    34  
    35  	tableTypeLocRib       = "loc-rib"
    36  	tableTypeLocAdjRibOut = "adj-rib-out"
    37  	afiIPv4               = "ipv4"
    38  	afiIPv6               = "ipv6"
    39  	safiUnicast           = "unicast"
    40  )
    41  
    42  // TestGetRoutes tests GetRoutes API of the Manager.
    43  func TestGetRoutes(t *testing.T) {
    44  
    45  	var table = []struct {
    46  		// name of the test case
    47  		name string
    48  
    49  		// advertised prefixes
    50  		advertisedPrefixes []netip.Prefix
    51  		// expected prefixes
    52  		expectedPrefixes []netip.Prefix
    53  
    54  		// GetRoutes params
    55  		routerASN *int64
    56  		tableType string
    57  		afi       string
    58  		safi      string
    59  		neighbor  *string
    60  
    61  		// non-nil if error is expected, nil if not
    62  		expectedErr error
    63  	}{
    64  		{
    65  			name:               "single IPv4 prefix - retrieve IPv4",
    66  			advertisedPrefixes: testSingleIPv4Prefix,
    67  			expectedPrefixes:   testSingleIPv4Prefix,
    68  			routerASN:          ptr.To[int64](int64(testRouterASN)),
    69  			tableType:          tableTypeLocRib,
    70  			afi:                afiIPv4,
    71  			safi:               safiUnicast,
    72  			neighbor:           nil,
    73  			expectedErr:        nil,
    74  		},
    75  		{
    76  			name:               "single IPv4 prefix - retrieve IPv6",
    77  			advertisedPrefixes: testSingleIPv4Prefix,
    78  			expectedPrefixes:   nil,
    79  			routerASN:          ptr.To[int64](int64(testRouterASN)),
    80  			tableType:          tableTypeLocRib,
    81  			afi:                afiIPv6,
    82  			safi:               safiUnicast,
    83  			neighbor:           nil,
    84  			expectedErr:        nil,
    85  		},
    86  		{
    87  			name:               "single IPv6 prefix - retrieve IPv6",
    88  			advertisedPrefixes: testSingleIPv6Prefix,
    89  			expectedPrefixes:   testSingleIPv6Prefix,
    90  			routerASN:          nil,
    91  			tableType:          tableTypeLocRib,
    92  			afi:                afiIPv6,
    93  			safi:               safiUnicast,
    94  			neighbor:           nil,
    95  			expectedErr:        nil,
    96  		},
    97  		{
    98  			name:               "mixed IPv4 & IPv6 prefixes - retrieve IPv6",
    99  			advertisedPrefixes: []netip.Prefix{testSingleIPv4Prefix[0], testSingleIPv6Prefix[0]},
   100  			routerASN:          nil,
   101  			expectedPrefixes:   testSingleIPv6Prefix,
   102  			tableType:          tableTypeLocRib,
   103  			afi:                afiIPv6,
   104  			safi:               safiUnicast,
   105  			neighbor:           nil,
   106  			expectedErr:        nil,
   107  		},
   108  		{
   109  			name:               "incorrect ASN",
   110  			advertisedPrefixes: testSingleIPv4Prefix,
   111  			expectedPrefixes:   nil,
   112  			routerASN:          ptr.To[int64](int64(testInvalidRouterASN)),
   113  			tableType:          tableTypeLocRib,
   114  			afi:                afiIPv4,
   115  			safi:               safiUnicast,
   116  			neighbor:           nil,
   117  			expectedErr:        fmt.Errorf(""),
   118  		},
   119  		{
   120  			name:               "unspecified neighbor for adj-rib-out",
   121  			advertisedPrefixes: testSingleIPv4Prefix,
   122  			expectedPrefixes:   nil, // nil as the neighbor never goes UP
   123  			routerASN:          nil,
   124  			tableType:          tableTypeLocAdjRibOut,
   125  			afi:                afiIPv4,
   126  			safi:               safiUnicast,
   127  			neighbor:           nil,
   128  			expectedErr:        nil,
   129  		},
   130  		{
   131  			name:               "valid neighbor",
   132  			advertisedPrefixes: testSingleIPv4Prefix,
   133  			expectedPrefixes:   nil, // nil as the neighbor never goes UP
   134  			routerASN:          nil,
   135  			tableType:          tableTypeLocAdjRibOut,
   136  			afi:                afiIPv4,
   137  			safi:               safiUnicast,
   138  			neighbor:           ptr.To[string](testNeighborIP),
   139  			expectedErr:        nil,
   140  		},
   141  		{
   142  			name:               "non-existing neighbor",
   143  			advertisedPrefixes: testSingleIPv4Prefix,
   144  			expectedPrefixes:   nil,
   145  			routerASN:          nil,
   146  			tableType:          tableTypeLocAdjRibOut,
   147  			afi:                afiIPv4,
   148  			safi:               safiUnicast,
   149  			neighbor:           ptr.To[string](testInvalidNeighborIP),
   150  			expectedErr:        fmt.Errorf(""),
   151  		},
   152  	}
   153  
   154  	for _, tt := range table {
   155  		t.Run(tt.name, func(t *testing.T) {
   156  			// set up BGPRouterManager with one BGP server
   157  			srvParams := types.ServerParameters{
   158  				Global: types.BGPGlobal{
   159  					ASN:        uint32(testRouterASN),
   160  					RouterID:   "127.0.0.1",
   161  					ListenPort: -1,
   162  				},
   163  			}
   164  			testSC, err := instance.NewServerWithConfig(context.Background(), log, srvParams)
   165  			require.NoError(t, err)
   166  
   167  			testSC.Config = &v2alpha1api.CiliumBGPVirtualRouter{
   168  				LocalASN:  int64(testRouterASN),
   169  				Neighbors: []v2alpha1api.CiliumBGPNeighbor{},
   170  			}
   171  			cm := mode.NewConfigMode()
   172  			cm.Set(mode.BGPv1)
   173  
   174  			brm := &BGPRouterManager{
   175  				ConfigMode: cm,
   176  				Servers: map[int64]*instance.ServerWithConfig{
   177  					int64(testRouterASN): testSC,
   178  				},
   179  				running: true,
   180  			}
   181  
   182  			// add a neighbor
   183  			n := &v2alpha1api.CiliumBGPNeighbor{
   184  				PeerAddress: testNeighborIP + "/32",
   185  				PeerASN:     64100,
   186  			}
   187  			n.SetDefaults()
   188  			err = testSC.Server.AddNeighbor(context.Background(), types.NeighborRequest{
   189  				Neighbor: n,
   190  			})
   191  			require.NoError(t, err)
   192  
   193  			// advertise test-provided prefixes
   194  			for _, cidr := range tt.advertisedPrefixes {
   195  				_, err := testSC.Server.AdvertisePath(context.Background(), types.PathRequest{
   196  					Path: types.NewPathForPrefix(cidr),
   197  				})
   198  				require.NoError(t, err)
   199  			}
   200  
   201  			// retrieve routes from server's local RIB and
   202  			routes, err := brm.GetRoutes(context.Background(), restapi.GetBgpRoutesParams{
   203  				RouterAsn: tt.routerASN,
   204  				TableType: tt.tableType,
   205  				Afi:       tt.afi,
   206  				Safi:      tt.safi,
   207  				Neighbor:  tt.neighbor,
   208  			})
   209  			if tt.expectedErr == nil {
   210  				require.NoError(t, err)
   211  			} else {
   212  				require.Error(t, err)
   213  			}
   214  
   215  			// ensure retrieved routes match expected prefixes
   216  			var retrievedPrefixes []netip.Prefix
   217  			for _, r := range routes {
   218  				retrievedPrefixes = append(retrievedPrefixes, netip.MustParsePrefix(r.Prefix))
   219  			}
   220  			require.EqualValues(t, tt.expectedPrefixes, retrievedPrefixes)
   221  		})
   222  	}
   223  }