Skip to content
Snippets Groups Projects
bgp_api_test.go 8.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • package server
    
    import (
    	"context"
    	"log"
    	"net"
    	"testing"
    	"time"
    
    	"github.com/bio-routing/bio-rd/protocols/bgp/api"
    	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
    	"github.com/bio-routing/bio-rd/protocols/bgp/types"
    	"github.com/bio-routing/bio-rd/route"
    	routeapi "github.com/bio-routing/bio-rd/route/api"
    	"github.com/bio-routing/bio-rd/routingtable"
    	"github.com/bio-routing/bio-rd/routingtable/adjRIBIn"
    	"github.com/bio-routing/bio-rd/routingtable/adjRIBOut"
    	"github.com/bio-routing/bio-rd/routingtable/filter"
    	"github.com/stretchr/testify/assert"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/test/bufconn"
    
    	bnet "github.com/bio-routing/bio-rd/net"
    )
    
    func TestDumpRIBInOut(t *testing.T) {
    	tests := []struct {
    		name      string
    		apisrv    *BGPAPIServer
    		addRoutes []*route.Route
    		req       *api.DumpRIBRequest
    		expected  []*routeapi.Route
    		wantFail  bool
    	}{
    		{
    			name: "Test #0: Non existent peer",
    			apisrv: &BGPAPIServer{
    				srv: &bgpServer{
    					peers: &peerManager{
    						peers: map[bnet.IP]*peer{},
    					},
    				},
    			},
    			addRoutes: []*route.Route{},
    			req: &api.DumpRIBRequest{
    				Peer: bnet.IPv4FromOctets(10, 0, 0, 0).ToProto(),
    				Afi:  packet.IPv4AFI,
    				Safi: packet.UnicastSAFI,
    			},
    			expected: []*routeapi.Route{},
    			wantFail: false,
    		},
    		{
    			name: "Test #1: No routes given",
    			apisrv: &BGPAPIServer{
    				srv: &bgpServer{
    					peers: &peerManager{
    						peers: map[bnet.IP]*peer{
    							bnet.IPv4FromOctets(10, 0, 0, 0): {
    								fsms: []*FSM{
    									0: {
    										ipv4Unicast: &fsmAddressFamily{
    											adjRIBIn:  adjRIBIn.New(filter.NewAcceptAllFilter(), nil, 0, 0, true),
    											adjRIBOut: adjRIBOut.New(&routingtable.Neighbor{Type: route.BGPPathType}, filter.NewAcceptAllFilter(), true),
    										},
    									},
    								},
    							},
    						},
    					},
    				},
    			},
    			addRoutes: []*route.Route{},
    			req: &api.DumpRIBRequest{
    				Peer: bnet.IPv4FromOctets(10, 0, 0, 0).ToProto(),
    				Afi:  packet.IPv4AFI,
    				Safi: packet.UnicastSAFI,
    			},
    			expected: []*routeapi.Route{},
    			wantFail: false,
    		},
    		{
    			name: "Test #2: One simple routes given",
    			apisrv: &BGPAPIServer{
    				srv: &bgpServer{
    					peers: &peerManager{
    						peers: map[bnet.IP]*peer{
    							bnet.IPv4FromOctets(10, 0, 0, 0): {
    								fsms: []*FSM{
    									0: {
    										ipv4Unicast: &fsmAddressFamily{
    											adjRIBIn:  adjRIBIn.New(filter.NewAcceptAllFilter(), nil, 0, 0, true),
    											adjRIBOut: adjRIBOut.New(&routingtable.Neighbor{Type: route.BGPPathType, RouteServerClient: true}, filter.NewAcceptAllFilter(), false),
    										},
    									},
    								},
    							},
    						},
    					},
    				},
    			},
    			addRoutes: []*route.Route{
    				route.NewRoute(bnet.NewPfx(bnet.IPv4FromOctets(20, 0, 0, 0), 16), &route.Path{
    					Type: route.BGPPathType,
    					BGPPath: &route.BGPPath{
    						OriginatorID: 1,
    						NextHop:      bnet.IPv4FromOctets(100, 100, 100, 100),
    						Source:       bnet.IPv4FromOctets(100, 100, 100, 100),
    					},
    				}),
    			},
    			req: &api.DumpRIBRequest{
    				Peer: bnet.IPv4FromOctets(10, 0, 0, 0).ToProto(),
    				Afi:  packet.IPv4AFI,
    				Safi: packet.UnicastSAFI,
    			},
    			expected: []*routeapi.Route{
    				{
    					Pfx: bnet.NewPfx(bnet.IPv4FromOctets(20, 0, 0, 0), 16).ToProto(),
    					Paths: []*routeapi.Path{
    						{
    							Type: routeapi.Path_BGP,
    
    takt's avatar
    takt committed
    							BgpPath: &routeapi.BGPPath{
    
    								OriginatorId:      1,
    								NextHop:           bnet.IPv4FromOctets(100, 100, 100, 100).ToProto(),
    								Source:            bnet.IPv4FromOctets(100, 100, 100, 100).ToProto(),
    
    takt's avatar
    takt committed
    								AsPath:            nil,
    
    								Communities:       nil,
    								LargeCommunities:  nil,
    								UnknownAttributes: nil,
    								ClusterList:       nil,
    							},
    						},
    					},
    				},
    			},
    			wantFail: false,
    		},
    		{
    			name: "Test #3: One complex routes given",
    			apisrv: &BGPAPIServer{
    				srv: &bgpServer{
    					peers: &peerManager{
    						peers: map[bnet.IP]*peer{
    							bnet.IPv4FromOctets(10, 0, 0, 0): {
    								fsms: []*FSM{
    									0: {
    										ipv4Unicast: &fsmAddressFamily{
    											adjRIBIn:  adjRIBIn.New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs(), 0, 0, true),
    											adjRIBOut: adjRIBOut.New(&routingtable.Neighbor{Type: route.BGPPathType, RouteServerClient: true}, filter.NewAcceptAllFilter(), false),
    										},
    									},
    								},
    							},
    						},
    					},
    				},
    			},
    			addRoutes: []*route.Route{
    				route.NewRoute(bnet.NewPfx(bnet.IPv4FromOctets(20, 0, 0, 0), 16), &route.Path{
    					Type: route.BGPPathType,
    					BGPPath: &route.BGPPath{
    						OriginatorID: 1,
    						NextHop:      bnet.IPv4FromOctets(100, 100, 100, 100),
    						Source:       bnet.IPv4FromOctets(100, 100, 100, 100),
    						ASPath: types.ASPath{
    							types.ASPathSegment{
    								Type: types.ASSequence,
    								ASNs: []uint32{15169, 3320},
    							},
    						},
    						Communities: []uint32{100, 200, 300},
    						LargeCommunities: []types.LargeCommunity{
    							{
    								GlobalAdministrator: 1,
    								DataPart1:           2,
    								DataPart2:           3,
    							},
    						},
    						LocalPref: 1000,
    						MED:       2000,
    						UnknownAttributes: []types.UnknownPathAttribute{
    							{
    								Optional:   true,
    								Transitive: true,
    								Partial:    true,
    								TypeCode:   222,
    								Value:      []byte{0xff, 0xff},
    							},
    						},
    						ClusterList: []uint32{},
    					},
    				}),
    			},
    			req: &api.DumpRIBRequest{
    				Peer: bnet.IPv4FromOctets(10, 0, 0, 0).ToProto(),
    				Afi:  packet.IPv4AFI,
    				Safi: packet.UnicastSAFI,
    			},
    			expected: []*routeapi.Route{
    				{
    					Pfx: bnet.NewPfx(bnet.IPv4FromOctets(20, 0, 0, 0), 16).ToProto(),
    					Paths: []*routeapi.Path{
    						{
    							Type: routeapi.Path_BGP,
    
    takt's avatar
    takt committed
    							BgpPath: &routeapi.BGPPath{
    
    								OriginatorId: 1,
    								LocalPref:    1000,
    
    takt's avatar
    takt committed
    								Med:          2000,
    
    								NextHop:      bnet.IPv4FromOctets(100, 100, 100, 100).ToProto(),
    								Source:       bnet.IPv4FromOctets(100, 100, 100, 100).ToProto(),
    
    takt's avatar
    takt committed
    								AsPath: []*routeapi.ASPathSegment{
    
    takt's avatar
    takt committed
    										AsSequence: true,
    										Asns:       []uint32{15169, 3320},
    
    									},
    								},
    								Communities: []uint32{100, 200, 300},
    								LargeCommunities: []*routeapi.LargeCommunity{
    									{
    										GlobalAdministrator: 1,
    										DataPart1:           2,
    										DataPart2:           3,
    									},
    								},
    								ClusterList: nil,
    								UnknownAttributes: []*routeapi.UnknownPathAttribute{
    									{
    										Optional:   true,
    										Transitive: true,
    										Partial:    true,
    										TypeCode:   222,
    										Value:      []byte{0xff, 0xff},
    									},
    								},
    							},
    						},
    					},
    				},
    			},
    			wantFail: false,
    		},
    	}
    
    	// Test RIBin
    	for _, test := range tests {
    		for _, r := range test.addRoutes {
    			for _, p := range r.Paths() {
    				test.apisrv.srv.(*bgpServer).peers.peers[bnet.IPv4FromOctets(10, 0, 0, 0)].fsms[0].ipv4Unicast.adjRIBIn.AddPath(r.Prefix(), p)
    			}
    		}
    
    		bufSize := 1024 * 1024
    		lis := bufconn.Listen(bufSize)
    		s := grpc.NewServer()
    		api.RegisterBgpServiceServer(s, test.apisrv)
    		go func() {
    			if err := s.Serve(lis); err != nil {
    				log.Fatalf("Server exited with error: %v", err)
    			}
    		}()
    
    		ctx := context.Background()
    		conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithDialer(func(string, time.Duration) (net.Conn, error) {
    			return lis.Dial()
    		}), grpc.WithInsecure())
    		if err != nil {
    			t.Fatalf("Failed to dial bufnet: %v", err)
    		}
    		defer conn.Close()
    
    		client := api.NewBgpServiceClient(conn)
    		streamClient, err := client.DumpRIBIn(ctx, test.req)
    		if err != nil {
    			t.Fatalf("AdjRIBInStream client call failed: %v", err)
    		}
    
    		res := make([]*routeapi.Route, 0)
    		for {
    			r, err := streamClient.Recv()
    			if err != nil {
    				break
    			}
    
    			res = append(res, r)
    		}
    
    		assert.Equal(t, test.expected, res, test.name)
    	}
    
    	// Test RIBout
    	for _, test := range tests {
    		for _, r := range test.addRoutes {
    			for _, p := range r.Paths() {
    				test.apisrv.srv.(*bgpServer).peers.peers[bnet.IPv4FromOctets(10, 0, 0, 0)].fsms[0].ipv4Unicast.adjRIBOut.AddPath(r.Prefix(), p)
    			}
    		}
    
    		bufSize := 1024 * 1024
    		lis := bufconn.Listen(bufSize)
    		s := grpc.NewServer()
    		api.RegisterBgpServiceServer(s, test.apisrv)
    		go func() {
    			if err := s.Serve(lis); err != nil {
    				log.Fatalf("Server exited with error: %v", err)
    			}
    		}()
    
    		ctx := context.Background()
    		conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithDialer(func(string, time.Duration) (net.Conn, error) {
    			return lis.Dial()
    		}), grpc.WithInsecure())
    		if err != nil {
    			t.Fatalf("Failed to dial bufnet: %v", err)
    		}
    		defer conn.Close()
    
    		client := api.NewBgpServiceClient(conn)
    		streamClient, err := client.DumpRIBOut(ctx, test.req)
    		if err != nil {
    			t.Fatalf("AdjRIBInStream client call failed: %v", err)
    		}
    
    		res := make([]*routeapi.Route, 0)
    		for {
    			r, err := streamClient.Recv()
    			if err != nil {
    				break
    			}
    
    			res = append(res, r)
    		}
    
    		assert.Equal(t, test.expected, res, test.name)
    	}
    }