Skip to content
Snippets Groups Projects
bmp_router_test.go 14.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • package server
    
    import (
    
    	"bytes"
    	"net"
    
    	"testing"
    
    	bnet "github.com/bio-routing/bio-rd/net"
    	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
    	bmppkt "github.com/bio-routing/bio-rd/protocols/bmp/packet"
    	"github.com/bio-routing/bio-rd/routingtable"
    	"github.com/bio-routing/bio-rd/routingtable/adjRIBIn"
    	"github.com/bio-routing/bio-rd/routingtable/filter"
    	"github.com/bio-routing/bio-rd/routingtable/locRIB"
    
    	biotesting "github.com/bio-routing/bio-rd/testing"
    	log "github.com/sirupsen/logrus"
    
    	"github.com/stretchr/testify/assert"
    )
    
    func TestConfigureBySentOpen(t *testing.T) {
    	tests := []struct {
    		name     string
    		p        *peer
    		openMsg  *packet.BGPOpen
    		expected *peer
    	}{
    		{
    			name: "Test 32bit ASN",
    			p:    &peer{},
    			openMsg: &packet.BGPOpen{
    				OptParams: []packet.OptParam{
    					{
    						Type: 2,
    						Value: packet.Capabilities{
    							{
    								Code: packet.ASN4CapabilityCode,
    								Value: packet.ASN4Capability{
    									ASN4: 201701,
    								},
    							},
    						},
    					},
    				},
    			},
    			expected: &peer{
    				localASN: 201701,
    			},
    		},
    		{
    			name: "Test Add Path TX",
    			p: &peer{
    				ipv4: &peerAddressFamily{},
    			},
    			openMsg: &packet.BGPOpen{
    				OptParams: []packet.OptParam{
    					{
    						Type: 2,
    						Value: packet.Capabilities{
    							{
    								Code: packet.AddPathCapabilityCode,
    								Value: packet.AddPathCapability{
    									AFI:         1,
    									SAFI:        1,
    									SendReceive: 2,
    								},
    							},
    						},
    					},
    				},
    			},
    			expected: &peer{
    				ipv4: &peerAddressFamily{
    					addPathSend: routingtable.ClientOptions{
    						MaxPaths: 10,
    					},
    				},
    			},
    		},
    		{
    			name: "Test Add Path RX",
    			p: &peer{
    				ipv4: &peerAddressFamily{},
    			},
    			openMsg: &packet.BGPOpen{
    				OptParams: []packet.OptParam{
    					{
    						Type: 2,
    						Value: packet.Capabilities{
    							{
    								Code: packet.AddPathCapabilityCode,
    								Value: packet.AddPathCapability{
    									AFI:         1,
    									SAFI:        1,
    									SendReceive: 1,
    								},
    							},
    						},
    					},
    				},
    			},
    			expected: &peer{
    				ipv4: &peerAddressFamily{
    					addPathReceive: true,
    				},
    			},
    		},
    		{
    			name: "Test Add Path RX/TX",
    			p: &peer{
    				ipv4: &peerAddressFamily{},
    			},
    			openMsg: &packet.BGPOpen{
    				OptParams: []packet.OptParam{
    					{
    						Type: 2,
    						Value: packet.Capabilities{
    							{
    								Code: packet.AddPathCapabilityCode,
    								Value: packet.AddPathCapability{
    									AFI:         1,
    									SAFI:        1,
    									SendReceive: 3,
    								},
    							},
    						},
    					},
    				},
    			},
    			expected: &peer{
    				ipv4: &peerAddressFamily{
    					addPathSend: routingtable.ClientOptions{
    						MaxPaths: 10,
    					},
    					addPathReceive: true,
    				},
    			},
    		},
    	}
    
    	for _, test := range tests {
    		test.p.configureBySentOpen(test.openMsg)
    
    		assert.Equalf(t, test.expected, test.p, "Test %q", test.name)
    	}
    }
    
    func TestProcessPeerUpNotification(t *testing.T) {
    	tests := []struct {
    		name     string
    		router   *router
    		pkt      *bmppkt.PeerUpNotification
    		wantFail bool
    		expected *router
    	}{
    		{
    			name: "Invalid sent open message",
    			router: &router{
    				neighbors: make(map[[16]byte]*neighbor),
    			},
    			pkt: &bmppkt.PeerUpNotification{
    				PerPeerHeader: &bmppkt.PerPeerHeader{
    					PeerType:          0,
    					PeerFlags:         0,
    					PeerDistinguisher: 0,
    					PeerAddress:       [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 1},
    					PeerAS:            51324,
    					PeerBGPID:         100,
    				},
    				LocalAddress:    [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 0},
    				LocalPort:       179,
    				RemotePort:      34542,
    				SentOpenMsg:     []byte{},
    				ReceivedOpenMsg: []byte{},
    				Information:     []byte{},
    			},
    			wantFail: true,
    		},
    		{
    			name: "Invalid received open message",
    			router: &router{
    				neighbors: make(map[[16]byte]*neighbor),
    			},
    			pkt: &bmppkt.PeerUpNotification{
    				PerPeerHeader: &bmppkt.PerPeerHeader{
    					PeerType:          0,
    					PeerFlags:         0,
    					PeerDistinguisher: 0,
    					PeerAddress:       [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 1},
    					PeerAS:            51324,
    					PeerBGPID:         100,
    				},
    				LocalAddress: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 0},
    				LocalPort:    179,
    				RemotePort:   34542,
    				SentOpenMsg: []byte{
    					255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    					0, 29,
    					1,
    					4,
    					100, 200,
    					20, 0,
    					10, 20, 30, 40,
    					0,
    				},
    				ReceivedOpenMsg: []byte{},
    				Information:     []byte{},
    			},
    			wantFail: true,
    		},
    		{
    			name: "Regular BGP by RFC4271",
    			router: &router{
    				rib4:      locRIB.New(),
    				rib6:      locRIB.New(),
    				neighbors: make(map[[16]byte]*neighbor),
    			},
    			pkt: &bmppkt.PeerUpNotification{
    				PerPeerHeader: &bmppkt.PerPeerHeader{
    					PeerType:          0,
    					PeerFlags:         0,
    					PeerDistinguisher: 0,
    					PeerAddress:       [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 1},
    					PeerAS:            100,
    					PeerBGPID:         100,
    				},
    				LocalAddress: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 0},
    				LocalPort:    179,
    				RemotePort:   34542,
    				SentOpenMsg: []byte{
    					255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    					0, 29,
    					1,
    					4,
    					0, 200,
    					20, 0,
    					10, 20, 30, 40,
    					0,
    				},
    				ReceivedOpenMsg: []byte{
    					255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    					0, 29,
    					1,
    					4,
    					0, 100,
    					20, 0,
    					10, 20, 30, 50,
    					0,
    				},
    				Information: []byte{},
    			},
    			wantFail: false,
    			expected: &router{
    				rib4: locRIB.New(),
    				rib6: locRIB.New(),
    				neighbors: map[[16]byte]*neighbor{
    					[16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 1}: {
    						localAS:  200,
    						peerAS:   100,
    						address:  [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 255, 1},
    						routerID: 169090610,
    						opt: &packet.DecodeOptions{
    							AddPath:     false,
    							Use32BitASN: false,
    						},
    						fsm: &FSM{
    							isBMP:      true,
    							neighborID: 169090610,
    							state:      &establishedState{},
    							peer: &peer{
    								addr:      bnet.IPv4FromOctets(10, 0, 255, 1),
    								localAddr: bnet.IPv4FromOctets(10, 0, 255, 0),
    								peerASN:   100,
    								localASN:  200,
    								ipv4:      &peerAddressFamily{},
    								ipv6:      &peerAddressFamily{},
    							},
    							ipv4Unicast: &fsmAddressFamily{
    								afi:          1,
    								safi:         1,
    								adjRIBIn:     adjRIBIn.New(filter.NewAcceptAllFilter(), &routingtable.ContributingASNs{}, 0, 0, false),
    								importFilter: filter.NewAcceptAllFilter(),
    							},
    						},
    					},
    				},
    			},
    		},
    	}
    
    	for _, test := range tests {
    		err := test.router.processPeerUpNotification(test.pkt)
    		if err != nil {
    			if test.wantFail {
    				continue
    			}
    
    			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
    			continue
    		}
    
    		if test.wantFail {
    			t.Errorf("Unexpected success for test %q", test.name)
    			continue
    		}
    
    		test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.state = &establishedState{fsm: test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm}
    
    		if test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv4Unicast != nil {
    			test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv4Unicast.rib = test.router.rib4
    			test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv4Unicast.fsm = test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm
    			test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv4Unicast.adjRIBIn.Register(test.router.rib4)
    		}
    
    		if test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv6Unicast != nil {
    			test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv6Unicast.rib = test.router.rib6
    			test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv6Unicast.fsm = test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm
    			test.expected.neighbors[test.pkt.PerPeerHeader.PeerAddress].fsm.ipv6Unicast.adjRIBIn.Register(test.router.rib6)
    		}
    
    		assert.Equalf(t, test.expected, test.router, "Test %q", test.name)
    	}
    
    }
    
    
    func TestProcessRouteMonitoringMsg(t *testing.T) {
    	tests := []struct {
    		name           string
    		r              *router
    		msg            *bmppkt.RouteMonitoringMsg
    		expectedLogBuf string
    		logOnly        bool
    		expected       *router
    	}{
    		{
    			name: "Unknown peer address",
    			r: &router{
    				address: net.IP{10, 20, 30, 40},
    				logger:  log.New(),
    			},
    			msg: &bmppkt.RouteMonitoringMsg{
    				PerPeerHeader: &bmppkt.PerPeerHeader{
    					PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
    				},
    			},
    			expectedLogBuf: "level=error msg=\"Received route monitoring message for non-existent neighbor [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] on 10.20.30.40\"",
    			logOnly:        true,
    			expected:       &router{},
    		},
    	}
    
    	for _, test := range tests {
    		logBuf := bytes.NewBuffer(nil)
    		test.r.logger.Out = logBuf
    		test.r.logger.Formatter = biotesting.NewLogFormatter()
    
    		test.expected.logger = test.r.logger
    
    		test.r.processRouteMonitoringMsg(test.msg)
    
    		assert.Equalf(t, test.expectedLogBuf, string(logBuf.Bytes()), "Test %q", test.name)
    		if test.logOnly {
    			continue
    		}
    
    		assert.Equalf(t, test.expected, test.r, "Test %q", test.name)
    	}
    }
    
    func TestProcessInitiationMsg(t *testing.T) {
    	tests := []struct {
    		name        string
    		r           *router
    		msg         *bmppkt.InitiationMessage
    		expectedLog string
    	}{
    		{
    			name: "Test #1",
    			r: &router{
    				address: net.IP{10, 20, 30, 40},
    				logger:  log.New(),
    			},
    			msg: &bmppkt.InitiationMessage{
    				TLVs: []*bmppkt.InformationTLV{
    					{
    						InformationType: 0,
    						Information:     []byte("Foo Bar"),
    					},
    					{
    						InformationType: 1,
    						Information:     []byte("SYS DESCR"),
    					},
    					{
    						InformationType: 2,
    						Information:     []byte("core01.fra01"),
    					},
    				},
    			},
    			expectedLog: "level=info msg=\"Received initiation message from 10.20.30.40: Message: \\\"Foo Bar\\\" sysDescr.: SYS DESCR sysName.: core01.fra01\"",
    		},
    	}
    
    	for _, test := range tests {
    		logBuf := bytes.NewBuffer(nil)
    		test.r.logger.Out = logBuf
    		test.r.logger.Formatter = biotesting.NewLogFormatter()
    
    		test.r.processInitiationMsg(test.msg)
    
    		assert.Equalf(t, test.expectedLog, string(logBuf.Bytes()), "Test %q", test.name)
    	}
    }
    
    func TestProcessTerminationMsg(t *testing.T) {
    	tests := []struct {
    		name        string
    		r           *router
    		msg         *bmppkt.TerminationMessage
    		expectedLog string
    		expected    *router
    	}{
    		{
    			name: "Test shutdown",
    			r: &router{
    				con:     &biotesting.MockConn{},
    				address: net.IP{10, 20, 30, 40},
    				logger:  log.New(),
    				neighbors: map[[16]byte]*neighbor{
    					[16]byte{1, 2, 3}: &neighbor{},
    				},
    			},
    			msg: &bmppkt.TerminationMessage{
    				TLVs: []*bmppkt.InformationTLV{
    					{
    						InformationType: 0, // string type
    						Information:     []byte("Foo Bar"),
    					},
    				},
    			},
    			expectedLog: "level=warning msg=\"Received termination message from 10.20.30.40: Message: \\\"Foo Bar\\\"\"",
    			expected: &router{
    				con: &biotesting.MockConn{
    					Closed: true,
    				},
    				address:   net.IP{10, 20, 30, 40},
    				neighbors: map[[16]byte]*neighbor{},
    			},
    		},
    		{
    			name: "Test logs",
    			r: &router{
    				con:     &biotesting.MockConn{},
    				address: net.IP{10, 20, 30, 40},
    				logger:  log.New(),
    				neighbors: map[[16]byte]*neighbor{
    					[16]byte{1, 2, 3}: &neighbor{},
    				},
    			},
    			msg: &bmppkt.TerminationMessage{
    				TLVs: []*bmppkt.InformationTLV{
    					{
    						InformationType: 1, // reason type
    						Information:     []byte{0, 0},
    					},
    					{
    						InformationType: 1, // reason type
    						Information:     []byte{0, 1},
    					},
    					{
    						InformationType: 1, // reason type
    						Information:     []byte{0, 2},
    					},
    					{
    						InformationType: 1, // reason type
    						Information:     []byte{0, 3},
    					},
    					{
    						InformationType: 1, // reason type
    						Information:     []byte{0, 4},
    					},
    				},
    			},
    			expectedLog: "level=warning msg=\"Received termination message from 10.20.30.40: Session administratively downUnespcified reasonOut of resourcesRedundant connectionSession permanently administratively closed\"",
    			expected: &router{
    				con: &biotesting.MockConn{
    					Closed: true,
    				},
    				address:   net.IP{10, 20, 30, 40},
    				neighbors: map[[16]byte]*neighbor{},
    			},
    		},
    	}
    
    	for _, test := range tests {
    		logBuf := bytes.NewBuffer(nil)
    		test.r.logger.Out = logBuf
    		test.r.logger.Formatter = biotesting.NewLogFormatter()
    
    		test.expected.logger = test.r.logger
    
    		test.r.processTerminationMsg(test.msg)
    
    		assert.Equalf(t, test.expectedLog, string(logBuf.Bytes()), "Test %q", test.name)
    		assert.Equalf(t, test.expected, test.r, "Test %q", test.name)
    	}
    }
    
    func TestProcessPeerDownNotification(t *testing.T) {
    	tests := []struct {
    		name        string
    		r           *router
    		msg         *bmppkt.PeerDownNotification
    		expectedLog string
    		expected    *router
    	}{
    		{
    			name: "Peer down notification for existing peer",
    			r: &router{
    				address: net.IP{10, 20, 30, 40},
    				logger:  log.New(),
    				neighbors: map[[16]byte]*neighbor{
    					[16]byte{1, 2, 3}: &neighbor{},
    				},
    			},
    			msg: &bmppkt.PeerDownNotification{
    				PerPeerHeader: &bmppkt.PerPeerHeader{
    					PeerAddress: [16]byte{1, 2, 3},
    				},
    			},
    			expectedLog: "",
    			expected: &router{
    				address:   net.IP{10, 20, 30, 40},
    				neighbors: map[[16]byte]*neighbor{},
    			},
    		},
    		{
    			name: "Peer down notification for non-existing peer",
    			r: &router{
    				address: net.IP{10, 20, 30, 40},
    				logger:  log.New(),
    				neighbors: map[[16]byte]*neighbor{
    					[16]byte{1, 2, 3}: &neighbor{},
    				},
    			},
    			msg: &bmppkt.PeerDownNotification{
    				PerPeerHeader: &bmppkt.PerPeerHeader{
    					PeerAddress: [16]byte{10, 20, 30},
    				},
    			},
    			expectedLog: "level=warning msg=\"Received peer down notification for [10 20 30 0 0 0 0 0 0 0 0 0 0 0 0 0]: Peer doesn't exist.\"",
    			expected: &router{
    				address: net.IP{10, 20, 30, 40},
    				neighbors: map[[16]byte]*neighbor{
    					[16]byte{1, 2, 3}: &neighbor{},
    				},
    			},
    		},
    	}
    
    	for _, test := range tests {
    		logBuf := bytes.NewBuffer(nil)
    		test.r.logger.Out = logBuf
    		test.r.logger.Formatter = biotesting.NewLogFormatter()
    
    		test.expected.logger = test.r.logger
    
    		test.r.processPeerDownNotification(test.msg)
    
    		assert.Equalf(t, test.expectedLog, string(logBuf.Bytes()), "Test %q", test.name)
    		assert.Equalf(t, test.expected, test.r, "Test %q", test.name)
    	}
    }