diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index 2d1d3ce03c5ae7d3ff77198799440c6bf58e5ff1..115a1eafada9bd3ed486f68fc899315dc7cdc50e 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -46,8 +46,8 @@ type FSM struct { connectRetryTimer *time.Timer connectRetryCounter int - holdTime time.Duration - holdTimer *time.Timer + holdTime time.Duration + lastUpdateOrKeepalive time.Time keepaliveTime time.Duration keepaliveTimer *time.Timer @@ -113,6 +113,10 @@ func newFSM(peer *peer) *FSM { return f } +func (fsm *FSM) updateLastUpdateOrKeepalive() { + fsm.lastUpdateOrKeepalive = time.Now() +} + func (fsm *FSM) addressFamily(afi uint16, safi uint8) *fsmAddressFamily { if safi != packet.UnicastSAFI { return nil diff --git a/protocols/bgp/server/fsm_active.go b/protocols/bgp/server/fsm_active.go index a84f910d945b473f655465239ae1b08c61d94ebc..b05d66ebad52f3f7ceb57fd295414d0c23b5fe82 100644 --- a/protocols/bgp/server/fsm_active.go +++ b/protocols/bgp/server/fsm_active.go @@ -3,7 +3,6 @@ package server import ( "fmt" "net" - "time" ) type activeState struct { @@ -63,6 +62,5 @@ func (s *activeState) connectionSuccess(con net.Conn) (state, string) { s.fsm.connectRetryCounter++ return newIdleState(s.fsm), fmt.Sprintf("Sending OPEN message failed: %v", err) } - s.fsm.holdTimer = time.NewTimer(time.Minute * 4) return newOpenSentState(s.fsm), "Sent OPEN message" } diff --git a/protocols/bgp/server/fsm_connect.go b/protocols/bgp/server/fsm_connect.go index 70142ea9702d2673f6c9a2450fc1ec2fb7f50c76..d8afdc7c57d0863d6dd7dcf479e6375011f3d8e0 100644 --- a/protocols/bgp/server/fsm_connect.go +++ b/protocols/bgp/server/fsm_connect.go @@ -3,7 +3,6 @@ package server import ( "fmt" "net" - "time" ) type connectState struct { @@ -44,7 +43,6 @@ func (s *connectState) connectionSuccess(c net.Conn) (state, string) { if err != nil { return newIdleState(s.fsm), fmt.Sprintf("Unable to send open: %v", err) } - s.fsm.holdTimer = time.NewTimer(time.Minute * 4) return newOpenSentState(s.fsm), "TCP connection succeeded" } diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go index ae4265e73cc3befe6110d2ca588f8de5001199a7..3152605151a56680fdb5e401cd5c198c26a0a0e3 100644 --- a/protocols/bgp/server/fsm_established.go +++ b/protocols/bgp/server/fsm_established.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "net" + "time" bnet "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/protocols/bgp/packet" @@ -45,16 +46,24 @@ func (s establishedState) run() (state, string) { default: continue } - case <-s.fsm.holdTimer.C: - return s.holdTimerExpired() case <-s.fsm.keepaliveTimer.C: return s.keepaliveTimerExpired() + case <-time.After(time.Second): + return s.checkHoldtimer() case recvMsg := <-s.fsm.msgRecvCh: return s.msgReceived(recvMsg, opt) } } } +func (s *establishedState) checkHoldtimer() (state, string) { + if time.Since(s.fsm.lastUpdateOrKeepalive) > s.fsm.holdTime { + return s.holdTimerExpired() + } + + return newEstablishedState(s.fsm), s.fsm.reason +} + func (s *establishedState) init() error { host, _, err := net.SplitHostPort(s.fsm.con.LocalAddr().String()) if err != nil { @@ -184,7 +193,7 @@ func (s *establishedState) notification() (state, string) { func (s *establishedState) update(u *packet.BGPUpdate) (state, string) { if s.fsm.holdTime != 0 { - s.fsm.holdTimer.Reset(s.fsm.holdTime) + s.fsm.updateLastUpdateOrKeepalive() } if s.fsm.ipv4Unicast != nil { @@ -240,7 +249,7 @@ func (s *establishedState) updateAddressFamily(u *packet.BGPUpdate) (afi uint16, func (s *establishedState) keepaliveReceived() (state, string) { if s.fsm.holdTime != 0 { - s.fsm.holdTimer.Reset(s.fsm.holdTime) + s.fsm.updateLastUpdateOrKeepalive() } return newEstablishedState(s.fsm), s.fsm.reason } diff --git a/protocols/bgp/server/fsm_open_confirm.go b/protocols/bgp/server/fsm_open_confirm.go index 17df63c1a3481b09f6b1671ce412d761e27cf240..26c32ace0700b1daf4b1c6b0f71ddb5169cb4592 100644 --- a/protocols/bgp/server/fsm_open_confirm.go +++ b/protocols/bgp/server/fsm_open_confirm.go @@ -3,6 +3,7 @@ package server import ( "bytes" "fmt" + "time" "github.com/bio-routing/bio-rd/protocols/bgp/packet" ) @@ -31,8 +32,8 @@ func (s openConfirmState) run() (state, string) { default: continue } - case <-s.fsm.holdTimer.C: - return s.holdTimerExpired() + case <-time.After(time.Second): + return s.checkHoldtimer() case <-s.fsm.keepaliveTimer.C: return s.keepaliveTimerExpired() case recvMsg := <-s.fsm.msgRecvCh: @@ -41,6 +42,14 @@ func (s openConfirmState) run() (state, string) { } } +func (s *openConfirmState) checkHoldtimer() (state, string) { + if time.Since(s.fsm.lastUpdateOrKeepalive) > s.fsm.holdTime { + return s.holdTimerExpired() + } + + return newOpenConfirmState(s.fsm), s.fsm.reason +} + func (s *openConfirmState) manualStop() (state, string) { s.fsm.sendNotification(packet.Cease, 0) stopTimer(s.fsm.connectRetryTimer) @@ -117,7 +126,7 @@ func (s *openConfirmState) notification(msg *packet.BGPMessage) (state, string) } func (s *openConfirmState) keepaliveReceived() (state, string) { - s.fsm.holdTimer.Reset(s.fsm.holdTime) + s.fsm.updateLastUpdateOrKeepalive() return newEstablishedState(s.fsm), "Received KEEPALIVE" } diff --git a/protocols/bgp/server/fsm_open_sent.go b/protocols/bgp/server/fsm_open_sent.go index 8b306a2a3145bd5d7ac640f8e6fe31b50bcf7176..e7beb88363c4984fb7c9374da7e2efafeade01a4 100644 --- a/protocols/bgp/server/fsm_open_sent.go +++ b/protocols/bgp/server/fsm_open_sent.go @@ -38,14 +38,22 @@ func (s openSentState) run() (state, string) { default: continue } - case <-s.fsm.holdTimer.C: - return s.holdTimerExpired() + case <-time.After(time.Second): + return s.checkHoldtimer() case recvMsg := <-s.fsm.msgRecvCh: return s.msgReceived(recvMsg, opt) } } } +func (s *openSentState) checkHoldtimer() (state, string) { + if time.Since(s.fsm.lastUpdateOrKeepalive) > s.fsm.holdTime { + return s.holdTimerExpired() + } + + return newOpenSentState(s.fsm), s.fsm.reason +} + func (s *openSentState) manualStop() (state, string) { s.fsm.sendNotification(packet.Cease, 0) s.fsm.resetConnectRetryTimer() @@ -130,9 +138,7 @@ func (s *openSentState) openMsgReceived(openMsg *packet.BGPOpen) (state, string) func (s *openSentState) handleOpenMessage(openMsg *packet.BGPOpen) (state, string) { s.fsm.holdTime = time.Duration(math.Min(float64(s.fsm.peer.holdTime), float64(time.Duration(openMsg.HoldTime)*time.Second))) if s.fsm.holdTime != 0 { - if !s.fsm.holdTimer.Reset(s.fsm.holdTime) { - <-s.fsm.holdTimer.C - } + s.fsm.updateLastUpdateOrKeepalive() s.fsm.keepaliveTime = s.fsm.holdTime / 3 s.fsm.keepaliveTimer = time.NewTimer(s.fsm.keepaliveTime) } diff --git a/protocols/bgp/server/fsm_test.go b/protocols/bgp/server/fsm_test.go index 86a8fd78c305781d190ba9cc33811c709e146e34..62a1c1428ceda110e34c34e0241d659c463499f8 100644 --- a/protocols/bgp/server/fsm_test.go +++ b/protocols/bgp/server/fsm_test.go @@ -24,7 +24,7 @@ func TestFSM255UpdatesIPv4(t *testing.T) { }, }) - fsmA.holdTimer = time.NewTimer(time.Second * 90) + fsmA.holdTime = time.Second * 180 fsmA.keepaliveTimer = time.NewTimer(time.Second * 30) fsmA.connectRetryTimer = time.NewTimer(time.Second * 120) fsmA.state = newEstablishedState(fsmA) @@ -112,11 +112,11 @@ func TestFSM255UpdatesIPv4(t *testing.T) { b + 25, 169, a, i, 0, 0, 0, } + fsmA.msgRecvCh <- update ribRouteCount = fsmA.ipv4Unicast.rib.RouteCount() } time.Sleep(time.Second * 1) - ribRouteCount = fsmA.ipv4Unicast.rib.RouteCount() if ribRouteCount != 0 { t.Errorf("Unexpected route count in LocRIB: %d", ribRouteCount) @@ -139,7 +139,7 @@ func TestFSM255UpdatesIPv6(t *testing.T) { }) fsmA.ipv6Unicast.multiProtocol = true - fsmA.holdTimer = time.NewTimer(time.Second * 90) + fsmA.holdTime = time.Second * 180 fsmA.keepaliveTimer = time.NewTimer(time.Second * 30) fsmA.connectRetryTimer = time.NewTimer(time.Second * 120) fsmA.state = newEstablishedState(fsmA) diff --git a/protocols/bgp/server/update_sender_test.go b/protocols/bgp/server/update_sender_test.go index 4e75183a294384446b57684566a35273611966ed..1d4d97fd4f2735283327341ade693344ecd484b4 100644 --- a/protocols/bgp/server/update_sender_test.go +++ b/protocols/bgp/server/update_sender_test.go @@ -897,7 +897,6 @@ func TestSender(t *testing.T) { fsmA.ipv4Unicast.addPathTX = test.addPath } - fsmA.holdTimer = time.NewTimer(time.Second * 90) fsmA.keepaliveTimer = time.NewTimer(time.Second * 30) fsmA.connectRetryTimer = time.NewTimer(time.Second * 120) fsmA.state = newEstablishedState(fsmA)