github.com/osrg/gobgp@v2.0.0+incompatible/pkg/server/fsm_test.go (about)

     1  // Copyright (C) 2014 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/internal/pkg/config"
    29  	"github.com/osrg/gobgp/internal/pkg/table"
    30  	"github.com/osrg/gobgp/pkg/packet/bgp"
    31  
    32  	log "github.com/sirupsen/logrus"
    33  	"github.com/stretchr/testify/assert"
    34  )
    35  
    36  type MockConnection struct {
    37  	*testing.T
    38  	net.Conn
    39  	recvCh    chan chan byte
    40  	sendBuf   [][]byte
    41  	currentCh chan byte
    42  	isClosed  bool
    43  	wait      int
    44  	mtx       sync.Mutex
    45  }
    46  
    47  func NewMockConnection(t *testing.T) *MockConnection {
    48  	m := &MockConnection{
    49  		T:        t,
    50  		recvCh:   make(chan chan byte, 128),
    51  		sendBuf:  make([][]byte, 0),
    52  		isClosed: false,
    53  	}
    54  	return m
    55  }
    56  
    57  func (m *MockConnection) SetWriteDeadline(t time.Time) error {
    58  	return nil
    59  }
    60  
    61  func (m *MockConnection) setData(data []byte) int {
    62  	dataChan := make(chan byte, 4096)
    63  	for _, b := range data {
    64  		dataChan <- b
    65  	}
    66  	m.recvCh <- dataChan
    67  	return len(dataChan)
    68  }
    69  
    70  func (m *MockConnection) Read(buf []byte) (int, error) {
    71  	m.mtx.Lock()
    72  	closed := m.isClosed
    73  	m.mtx.Unlock()
    74  	if closed {
    75  		return 0, errors.New("already closed")
    76  	}
    77  
    78  	if m.currentCh == nil {
    79  		m.currentCh = <-m.recvCh
    80  	}
    81  
    82  	length := 0
    83  	rest := len(buf)
    84  	for i := 0; i < rest; i++ {
    85  		if len(m.currentCh) > 0 {
    86  			val := <-m.currentCh
    87  			buf[i] = val
    88  			length++
    89  		} else {
    90  			m.currentCh = nil
    91  			break
    92  		}
    93  	}
    94  
    95  	m.Logf("%d bytes read from peer", length)
    96  	return length, nil
    97  }
    98  
    99  func (m *MockConnection) Write(buf []byte) (int, error) {
   100  	time.Sleep(time.Duration(m.wait) * time.Millisecond)
   101  	m.sendBuf = append(m.sendBuf, buf)
   102  	msg, _ := bgp.ParseBGPMessage(buf)
   103  	m.Logf("%d bytes written by gobgp  message type : %s",
   104  		len(buf), showMessageType(msg.Header.Type))
   105  	return len(buf), nil
   106  }
   107  
   108  func showMessageType(t uint8) string {
   109  	switch t {
   110  	case bgp.BGP_MSG_KEEPALIVE:
   111  		return "BGP_MSG_KEEPALIVE"
   112  	case bgp.BGP_MSG_NOTIFICATION:
   113  		return "BGP_MSG_NOTIFICATION"
   114  	case bgp.BGP_MSG_OPEN:
   115  		return "BGP_MSG_OPEN"
   116  	case bgp.BGP_MSG_UPDATE:
   117  		return "BGP_MSG_UPDATE"
   118  	case bgp.BGP_MSG_ROUTE_REFRESH:
   119  		return "BGP_MSG_ROUTE_REFRESH"
   120  	}
   121  	return strconv.Itoa(int(t))
   122  }
   123  
   124  func (m *MockConnection) Close() error {
   125  	m.mtx.Lock()
   126  	defer m.mtx.Unlock()
   127  	if !m.isClosed {
   128  		close(m.recvCh)
   129  		m.isClosed = true
   130  	}
   131  	return nil
   132  }
   133  
   134  func (m *MockConnection) LocalAddr() net.Addr {
   135  	return &net.TCPAddr{
   136  		IP:   net.ParseIP("10.10.10.10"),
   137  		Port: bgp.BGP_PORT}
   138  }
   139  
   140  func TestReadAll(t *testing.T) {
   141  	assert := assert.New(t)
   142  	m := NewMockConnection(t)
   143  	msg := open()
   144  	expected1, _ := msg.Header.Serialize()
   145  	expected2, _ := msg.Body.Serialize()
   146  
   147  	pushBytes := func() {
   148  		m.Log("push 5 bytes")
   149  		m.setData(expected1[0:5])
   150  		m.Log("push rest")
   151  		m.setData(expected1[5:])
   152  		m.Log("push bytes at once")
   153  		m.setData(expected2)
   154  	}
   155  
   156  	go pushBytes()
   157  
   158  	var actual1 []byte
   159  	actual1, _ = readAll(m, bgp.BGP_HEADER_LENGTH)
   160  	m.Log(actual1)
   161  	assert.Equal(expected1, actual1)
   162  
   163  	var actual2 []byte
   164  	actual2, _ = readAll(m, len(expected2))
   165  	m.Log(actual2)
   166  	assert.Equal(expected2, actual2)
   167  }
   168  
   169  func TestFSMHandlerOpensent_HoldTimerExpired(t *testing.T) {
   170  	assert := assert.New(t)
   171  	m := NewMockConnection(t)
   172  
   173  	p, h := makePeerAndHandler()
   174  
   175  	// push mock connection
   176  	p.fsm.conn = m
   177  	p.fsm.h = h
   178  
   179  	// set keepalive ticker
   180  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
   181  
   182  	// set holdtime
   183  	p.fsm.opensentHoldTime = 2
   184  
   185  	state, _ := h.opensent(context.Background())
   186  
   187  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   188  	lastMsg := m.sendBuf[len(m.sendBuf)-1]
   189  	sent, _ := bgp.ParseBGPMessage(lastMsg)
   190  	assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
   191  	assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
   192  
   193  }
   194  
   195  func TestFSMHandlerOpenconfirm_HoldTimerExpired(t *testing.T) {
   196  	assert := assert.New(t)
   197  	m := NewMockConnection(t)
   198  
   199  	p, h := makePeerAndHandler()
   200  
   201  	// push mock connection
   202  	p.fsm.conn = m
   203  	p.fsm.h = h
   204  
   205  	// set up keepalive ticker
   206  	p.fsm.pConf.Timers.Config.KeepaliveInterval = 1
   207  
   208  	// set holdtime
   209  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
   210  	state, _ := h.openconfirm(context.Background())
   211  
   212  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   213  	lastMsg := m.sendBuf[len(m.sendBuf)-1]
   214  	sent, _ := bgp.ParseBGPMessage(lastMsg)
   215  	assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
   216  	assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
   217  
   218  }
   219  
   220  func TestFSMHandlerEstablish_HoldTimerExpired(t *testing.T) {
   221  	assert := assert.New(t)
   222  	m := NewMockConnection(t)
   223  
   224  	p, h := makePeerAndHandler()
   225  
   226  	// push mock connection
   227  	p.fsm.conn = m
   228  	p.fsm.h = h
   229  
   230  	// set keepalive ticker
   231  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
   232  
   233  	msg := keepalive()
   234  	header, _ := msg.Header.Serialize()
   235  	body, _ := msg.Body.Serialize()
   236  
   237  	pushPackets := func() {
   238  		// first keepalive from peer
   239  		m.setData(header)
   240  		m.setData(body)
   241  	}
   242  
   243  	// set holdtime
   244  	p.fsm.pConf.Timers.Config.HoldTime = 2
   245  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
   246  
   247  	go pushPackets()
   248  	state, _ := h.established(context.Background())
   249  	time.Sleep(time.Second * 1)
   250  	assert.Equal(bgp.BGP_FSM_IDLE, state)
   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 TestFSMHandlerOpenconfirm_HoldtimeZero(t *testing.T) {
   260  	log.SetLevel(log.DebugLevel)
   261  	assert := assert.New(t)
   262  	m := NewMockConnection(t)
   263  
   264  	p, h := makePeerAndHandler()
   265  
   266  	// push mock connection
   267  	p.fsm.conn = m
   268  	p.fsm.h = h
   269  
   270  	// set up keepalive ticker
   271  	p.fsm.pConf.Timers.Config.KeepaliveInterval = 1
   272  	// set holdtime
   273  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 0
   274  	go h.openconfirm(context.Background())
   275  
   276  	time.Sleep(100 * time.Millisecond)
   277  
   278  	assert.Equal(0, len(m.sendBuf))
   279  
   280  }
   281  
   282  func TestFSMHandlerEstablished_HoldtimeZero(t *testing.T) {
   283  	log.SetLevel(log.DebugLevel)
   284  	assert := assert.New(t)
   285  	m := NewMockConnection(t)
   286  
   287  	p, h := makePeerAndHandler()
   288  
   289  	// push mock connection
   290  	p.fsm.conn = m
   291  	p.fsm.h = h
   292  
   293  	// set holdtime
   294  	p.fsm.pConf.Timers.State.NegotiatedHoldTime = 0
   295  
   296  	go h.established(context.Background())
   297  
   298  	time.Sleep(100 * time.Millisecond)
   299  
   300  	assert.Equal(0, len(m.sendBuf))
   301  }
   302  
   303  func TestCheckOwnASLoop(t *testing.T) {
   304  	assert := assert.New(t)
   305  	aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65100})}
   306  	aspath := bgp.NewPathAttributeAsPath(aspathParam)
   307  	assert.False(hasOwnASLoop(65100, 10, aspath))
   308  	assert.True(hasOwnASLoop(65100, 0, aspath))
   309  	assert.False(hasOwnASLoop(65200, 0, aspath))
   310  }
   311  
   312  func makePeerAndHandler() (*peer, *fsmHandler) {
   313  	p := &peer{
   314  		fsm:      newFSM(&config.Global{}, &config.Neighbor{}, table.NewRoutingPolicy()),
   315  		outgoing: channels.NewInfiniteChannel(),
   316  	}
   317  
   318  	h := &fsmHandler{
   319  		fsm:           p.fsm,
   320  		stateReasonCh: make(chan fsmStateReason, 2),
   321  		incoming:      channels.NewInfiniteChannel(),
   322  		outgoing:      p.outgoing,
   323  	}
   324  
   325  	return p, h
   326  
   327  }
   328  
   329  func open() *bgp.BGPMessage {
   330  	p1 := bgp.NewOptionParameterCapability(
   331  		[]bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
   332  	p2 := bgp.NewOptionParameterCapability(
   333  		[]bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(bgp.RF_IPv4_UC)})
   334  	g := &bgp.CapGracefulRestartTuple{AFI: 4, SAFI: 2, Flags: 3}
   335  	p3 := bgp.NewOptionParameterCapability(
   336  		[]bgp.ParameterCapabilityInterface{bgp.NewCapGracefulRestart(true, true, 100,
   337  			[]*bgp.CapGracefulRestartTuple{g})})
   338  	p4 := bgp.NewOptionParameterCapability(
   339  		[]bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(100000)})
   340  	return bgp.NewBGPOpenMessage(11033, 303, "100.4.10.3",
   341  		[]bgp.OptionParameterInterface{p1, p2, p3, p4})
   342  }
   343  
   344  func keepalive() *bgp.BGPMessage {
   345  	return bgp.NewBGPKeepAliveMessage()
   346  }