github.com/osrg/gobgp/v3@v3.30.0/pkg/server/fsm_test.go (about)

     1  // Copyright (C) 2014-2021 Nippon Telegraph and Telephone Corporation.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package server
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"net"
    22  	"strconv"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/eapache/channels"
    28  	"github.com/osrg/gobgp/v3/pkg/config/oc"
    29  	"github.com/osrg/gobgp/v3/pkg/log"
    30  	"github.com/osrg/gobgp/v3/pkg/packet/bgp"
    31  
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  type MockConnection struct {
    36  	*testing.T
    37  	net.Conn
    38  	recvCh    chan chan byte
    39  	sendBuf   [][]byte
    40  	currentCh chan byte
    41  	isClosed  bool
    42  	wait      int
    43  	mtx       sync.Mutex
    44  }
    45  
    46  func NewMockConnection(t *testing.T) *MockConnection {
    47  	m := &MockConnection{
    48  		T:        t,
    49  		recvCh:   make(chan chan byte, 128),
    50  		sendBuf:  make([][]byte, 0),
    51  		isClosed: false,
    52  	}
    53  	return m
    54  }
    55  
    56  func (m *MockConnection) SetWriteDeadline(t time.Time) error {
    57  	return nil
    58  }
    59  
    60  func (m *MockConnection) setData(data []byte) int {
    61  	dataChan := make(chan byte, 4096)
    62  	for _, b := range data {
    63  		dataChan <- b
    64  	}
    65  	m.recvCh <- dataChan
    66  	return len(dataChan)
    67  }
    68  
    69  func (m *MockConnection) Read(buf []byte) (int, error) {
    70  	m.mtx.Lock()
    71  	closed := m.isClosed
    72  	m.mtx.Unlock()
    73  	if closed {
    74  		return 0, errors.New("already closed")
    75  	}
    76  
    77  	if m.currentCh == nil {
    78  		m.currentCh = <-m.recvCh
    79  	}
    80  
    81  	length := 0
    82  	rest := len(buf)
    83  	for i := 0; i < rest; i++ {
    84  		if len(m.currentCh) > 0 {
    85  			val := <-m.currentCh
    86  			buf[i] = val
    87  			length++
    88  		} else {
    89  			m.currentCh = nil
    90  			break
    91  		}
    92  	}
    93  
    94  	m.Logf("%d bytes read from peer", length)
    95  	return length, nil
    96  }
    97  
    98  func (m *MockConnection) Write(buf []byte) (int, error) {
    99  	time.Sleep(time.Duration(m.wait) * time.Millisecond)
   100  	m.sendBuf = append(m.sendBuf, buf)
   101  	msg, _ := bgp.ParseBGPMessage(buf)
   102  	m.Logf("%d bytes written by gobgp  message type : %s",
   103  		len(buf), showMessageType(msg.Header.Type))
   104  	return len(buf), nil
   105  }
   106  
   107  func showMessageType(t uint8) string {
   108  	switch t {
   109  	case bgp.BGP_MSG_KEEPALIVE:
   110  		return "BGP_MSG_KEEPALIVE"
   111  	case bgp.BGP_MSG_NOTIFICATION:
   112  		return "BGP_MSG_NOTIFICATION"
   113  	case bgp.BGP_MSG_OPEN:
   114  		return "BGP_MSG_OPEN"
   115  	case bgp.BGP_MSG_UPDATE:
   116  		return "BGP_MSG_UPDATE"
   117  	case bgp.BGP_MSG_ROUTE_REFRESH:
   118  		return "BGP_MSG_ROUTE_REFRESH"
   119  	}
   120  	return strconv.Itoa(int(t))
   121  }
   122  
   123  func (m *MockConnection) Close() error {
   124  	m.mtx.Lock()
   125  	defer m.mtx.Unlock()
   126  	if !m.isClosed {
   127  		close(m.recvCh)
   128  		m.isClosed = true
   129  	}
   130  	return nil
   131  }
   132  
   133  func (m *MockConnection) LocalAddr() net.Addr {
   134  	return &net.TCPAddr{
   135  		IP:   net.ParseIP("10.10.10.10"),
   136  		Port: bgp.BGP_PORT}
   137  }
   138  
   139  func TestReadAll(t *testing.T) {
   140  	assert := assert.New(t)
   141  	m := NewMockConnection(t)
   142  	msg := open()
   143  	expected1, _ := msg.Header.Serialize()
   144  	expected2, _ := msg.Body.Serialize()
   145  
   146  	pushBytes := func() {
   147  		m.Log("push 5 bytes")
   148  		m.setData(expected1[0:5])
   149  		m.Log("push rest")
   150  		m.setData(expected1[5:])
   151  		m.Log("push bytes at once")
   152  		m.setData(expected2)
   153  	}
   154  
   155  	go pushBytes()
   156  
   157  	var actual1 []byte
   158  	actual1, _ = readAll(m, bgp.BGP_HEADER_LENGTH)
   159  	m.Log(actual1)
   160  	assert.Equal(expected1, actual1)
   161  
   162  	var actual2 []byte
   163  	actual2, _ = readAll(m, len(expected2))
   164  	m.Log(actual2)
   165  	assert.Equal(expected2, actual2)
   166  }
   167  
   168  func TestFSMHandlerOpensent_HoldTimerExpired(t *testing.T) {
   169  	assert := assert.New(t)
   170  	m := NewMockConnection(t)
   171  
   172  	p, h := makePeerAndHandler()
   173  
   174  	// push mock connection
   175  	p.fsm.conn = m
   176  	p.fsm.h = h
   177  
   178  	// set keepalive ticker
   179  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
   180  
   181  	// set holdtime
   182  	p.fsm.opensentHoldTime = 2
   183  
   184  	state, _ := h.opensent(context.Background())
   185  
   186  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   187  	lastMsg := m.sendBuf[len(m.sendBuf)-1]
   188  	sent, _ := bgp.ParseBGPMessage(lastMsg)
   189  	assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
   190  	assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
   191  
   192  }
   193  
   194  func TestFSMHandlerOpenconfirm_HoldTimerExpired(t *testing.T) {
   195  	assert := assert.New(t)
   196  	m := NewMockConnection(t)
   197  
   198  	p, h := makePeerAndHandler()
   199  
   200  	// push mock connection
   201  	p.fsm.conn = m
   202  	p.fsm.h = h
   203  
   204  	// set up keepalive ticker
   205  	p.fsm.pConf.Timers.Config.KeepaliveInterval = 1
   206  
   207  	// set holdtime
   208  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
   209  	state, _ := h.openconfirm(context.Background())
   210  
   211  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   212  	lastMsg := m.sendBuf[len(m.sendBuf)-1]
   213  	sent, _ := bgp.ParseBGPMessage(lastMsg)
   214  	assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
   215  	assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
   216  
   217  }
   218  
   219  func TestFSMHandlerEstablish_HoldTimerExpired(t *testing.T) {
   220  	assert := assert.New(t)
   221  	m := NewMockConnection(t)
   222  
   223  	p, h := makePeerAndHandler()
   224  
   225  	// push mock connection
   226  	p.fsm.conn = m
   227  	p.fsm.h = h
   228  
   229  	// set keepalive ticker
   230  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
   231  
   232  	msg := keepalive()
   233  	header, _ := msg.Header.Serialize()
   234  	body, _ := msg.Body.Serialize()
   235  
   236  	pushPackets := func() {
   237  		// first keepalive from peer
   238  		m.setData(header)
   239  		m.setData(body)
   240  	}
   241  
   242  	// set holdtime
   243  	p.fsm.pConf.Timers.Config.HoldTime = 2
   244  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
   245  
   246  	go pushPackets()
   247  	state, fsmStateReason := h.established(context.Background())
   248  	time.Sleep(time.Second * 1)
   249  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   250  	assert.Equal(fsmHoldTimerExpired, fsmStateReason.Type)
   251  	m.mtx.Lock()
   252  	lastMsg := m.sendBuf[len(m.sendBuf)-1]
   253  	m.mtx.Unlock()
   254  	sent, _ := bgp.ParseBGPMessage(lastMsg)
   255  	assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
   256  	assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
   257  }
   258  
   259  func TestFSMHandlerEstablish_HoldTimerExpired_GR_Enabled(t *testing.T) {
   260  	assert := assert.New(t)
   261  	m := NewMockConnection(t)
   262  
   263  	p, h := makePeerAndHandler()
   264  
   265  	// push mock connection
   266  	p.fsm.conn = m
   267  	p.fsm.h = h
   268  
   269  	// set keepalive ticker
   270  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
   271  
   272  	msg := keepalive()
   273  	header, _ := msg.Header.Serialize()
   274  	body, _ := msg.Body.Serialize()
   275  
   276  	pushPackets := func() {
   277  		// first keepalive from peer
   278  		m.setData(header)
   279  		m.setData(body)
   280  	}
   281  
   282  	// set holdtime
   283  	p.fsm.pConf.Timers.Config.HoldTime = 2
   284  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
   285  
   286  	// Enable graceful restart
   287  	p.fsm.pConf.GracefulRestart.State.Enabled = true
   288  
   289  	go pushPackets()
   290  	state, fsmStateReason := h.established(context.Background())
   291  	time.Sleep(time.Second * 1)
   292  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   293  	assert.Equal(fsmGracefulRestart, fsmStateReason.Type)
   294  	m.mtx.Lock()
   295  	lastMsg := m.sendBuf[len(m.sendBuf)-1]
   296  	m.mtx.Unlock()
   297  	sent, _ := bgp.ParseBGPMessage(lastMsg)
   298  	assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
   299  	assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
   300  }
   301  
   302  func TestFSMHandlerOpenconfirm_HoldtimeZero(t *testing.T) {
   303  	assert := assert.New(t)
   304  	m := NewMockConnection(t)
   305  
   306  	p, h := makePeerAndHandler()
   307  
   308  	// push mock connection
   309  	p.fsm.conn = m
   310  	p.fsm.h = h
   311  
   312  	// set up keepalive ticker
   313  	p.fsm.pConf.Timers.Config.KeepaliveInterval = 1
   314  	// set holdtime
   315  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 0
   316  	go h.openconfirm(context.Background())
   317  
   318  	time.Sleep(100 * time.Millisecond)
   319  
   320  	assert.Equal(0, len(m.sendBuf))
   321  
   322  }
   323  
   324  func TestFSMHandlerEstablished_HoldtimeZero(t *testing.T) {
   325  	assert := assert.New(t)
   326  	m := NewMockConnection(t)
   327  
   328  	p, h := makePeerAndHandler()
   329  
   330  	// push mock connection
   331  	p.fsm.conn = m
   332  	p.fsm.h = h
   333  
   334  	// set holdtime
   335  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 0
   336  
   337  	go h.established(context.Background())
   338  
   339  	time.Sleep(100 * time.Millisecond)
   340  
   341  	assert.Equal(0, len(m.sendBuf))
   342  }
   343  
   344  func TestCheckOwnASLoop(t *testing.T) {
   345  	assert := assert.New(t)
   346  	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65100})}
   347  	aspath := bgp.NewPathAttributeAsPath(aspathParam)
   348  	assert.False(hasOwnASLoop(65100, 10, aspath))
   349  	assert.True(hasOwnASLoop(65100, 0, aspath))
   350  	assert.False(hasOwnASLoop(65200, 0, aspath))
   351  }
   352  
   353  func TestBadBGPIdentifier(t *testing.T) {
   354  	assert := assert.New(t)
   355  	msg1 := openWithBadBGPIdentifier_Zero()
   356  	msg2 := openWithBadBGPIdentifier_Same()
   357  	body1 := msg1.Body.(*bgp.BGPOpen)
   358  	body2 := msg2.Body.(*bgp.BGPOpen)
   359  
   360  	// Test if Bad BGP Identifier notification is sent if remote router-id is 0.0.0.0.
   361  	peerAs, err := bgp.ValidateOpenMsg(body1, 65000, 65001, net.ParseIP("192.168.1.1"))
   362  	assert.Equal(int(peerAs), 0)
   363  	assert.Equal(uint8(bgp.BGP_ERROR_SUB_BAD_BGP_IDENTIFIER), err.(*bgp.MessageError).SubTypeCode)
   364  
   365  	// Test if Bad BGP Identifier notification is sent if remote router-id is the same for iBGP.
   366  	peerAs, err = bgp.ValidateOpenMsg(body2, 65000, 65000, net.ParseIP("192.168.1.1"))
   367  	assert.Equal(int(peerAs), 0)
   368  	assert.Equal(uint8(bgp.BGP_ERROR_SUB_BAD_BGP_IDENTIFIER), err.(*bgp.MessageError).SubTypeCode)
   369  }
   370  
   371  func makePeerAndHandler() (*peer, *fsmHandler) {
   372  	p := &peer{
   373  		fsm: newFSM(&oc.Global{}, &oc.Neighbor{}, log.NewDefaultLogger()),
   374  	}
   375  
   376  	h := &fsmHandler{
   377  		fsm:           p.fsm,
   378  		stateReasonCh: make(chan fsmStateReason, 2),
   379  		incoming:      channels.NewInfiniteChannel(),
   380  		outgoing:      channels.NewInfiniteChannel(),
   381  	}
   382  
   383  	return p, h
   384  
   385  }
   386  
   387  func open() *bgp.BGPMessage {
   388  	p1 := bgp.NewOptionParameterCapability(
   389  		[]bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
   390  	p2 := bgp.NewOptionParameterCapability(
   391  		[]bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(bgp.RF_IPv4_UC)})
   392  	g := &bgp.CapGracefulRestartTuple{AFI: 4, SAFI: 2, Flags: 3}
   393  	p3 := bgp.NewOptionParameterCapability(
   394  		[]bgp.ParameterCapabilityInterface{bgp.NewCapGracefulRestart(true, true, 100,
   395  			[]*bgp.CapGracefulRestartTuple{g})})
   396  	p4 := bgp.NewOptionParameterCapability(
   397  		[]bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(100000)})
   398  	return bgp.NewBGPOpenMessage(11033, 303, "100.4.10.3",
   399  		[]bgp.OptionParameterInterface{p1, p2, p3, p4})
   400  }
   401  
   402  func openWithBadBGPIdentifier_Zero() *bgp.BGPMessage {
   403  	return bgp.NewBGPOpenMessage(65000, 303, "0.0.0.0",
   404  		[]bgp.OptionParameterInterface{})
   405  }
   406  
   407  func openWithBadBGPIdentifier_Same() *bgp.BGPMessage {
   408  	return bgp.NewBGPOpenMessage(65000, 303, "192.168.1.1",
   409  		[]bgp.OptionParameterInterface{})
   410  }
   411  
   412  func keepalive() *bgp.BGPMessage {
   413  	return bgp.NewBGPKeepAliveMessage()
   414  }