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 }