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 }