mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
fix graceful-restart when not all peers are restarting
This fixes an issue where GoBGP would incorrectly defer sending routes to a peer on a graceful restart.
RFC4724 states:
> Once the session between the Restarting Speaker and the Receiving
> Speaker is re-established, the Restarting Speaker will receive and
> process BGP messages from its peers. However, it MUST defer route
> selection for an address family until it either (a) receives the
> End-of-RIB marker from all its peers (excluding the ones with the
> "Restart State" bit set in the received capability and excluding the
> ones that do not advertise the graceful restart capability) or (b)
> the Selection_Deferral_Timer referred to below has expired.
The scenario that this fixes is where you have 3 (or more) peers, and 2 of the peers ("A" and "B") perform a graceful restart at the same time, but the 3rd ("C") does not. If after restart peer C sends EOR to peer A before peer B reaches BGP_FSM_ESTABLISHED with peer A, it defers the route selection. However once peer B does reach BGP_FSM_ESTABLISHED, peer A still wouldn't send any updates to peer C until the deferral expired.
This commit changes the behavior so that upon restart, once the peer receives EOR from all non-restarting peers and reaches BGP_FSM_ESTABLISHED for all restarting peers, the routes are sent to all peers.
This commit is contained in:
committed by
FUJITA Tomonori
parent
8c453bc936
commit
9c8b20a2ef
+4
-2
@@ -1163,8 +1163,10 @@ func (h *FSMHandler) opensent() (bgp.FSMState, FsmStateReason) {
|
||||
"Topic": "Peer",
|
||||
"Key": fsm.pConf.State.NeighborAddress,
|
||||
"State": fsm.state.String(),
|
||||
}).Debug("peer is restarting, skipping sync process")
|
||||
fsm.pConf.GracefulRestart.State.LocalRestarting = false
|
||||
}).Debug("peer has restarted, skipping wait for EOR")
|
||||
for i := range fsm.pConf.AfiSafis {
|
||||
fsm.pConf.AfiSafis[i].MpGracefulRestart.State.EndOfRibReceived = true
|
||||
}
|
||||
}
|
||||
if fsm.pConf.GracefulRestart.Config.NotificationEnabled && cap.Flags&0x04 > 0 {
|
||||
fsm.pConf.GracefulRestart.State.NotificationEnabled = true
|
||||
|
||||
+36
-10
@@ -1156,16 +1156,42 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) {
|
||||
} else {
|
||||
// RFC 4724 4.1
|
||||
// Once the session between the Restarting Speaker and the Receiving
|
||||
// Speaker is re-established, the Restarting Speaker will receive and
|
||||
// process BGP messages from its peers. However, it MUST defer route
|
||||
// selection for an address family until it either (a) ...snip...
|
||||
// or (b) the Selection_Deferral_Timer referred to below has expired.
|
||||
deferral := peer.fsm.pConf.GracefulRestart.Config.DeferralTime
|
||||
log.WithFields(log.Fields{
|
||||
"Topic": "Peer",
|
||||
"Key": peer.ID(),
|
||||
}).Debugf("Now syncing, suppress sending updates. start deferral timer(%d)", deferral)
|
||||
time.AfterFunc(time.Second*time.Duration(deferral), deferralExpiredFunc(bgp.RouteFamily(0)))
|
||||
// Speaker is re-established, ...snip... it MUST defer route
|
||||
// selection for an address family until it either (a) receives the
|
||||
// End-of-RIB marker from all its peers (excluding the ones with the
|
||||
// "Restart State" bit set in the received capability and excluding the
|
||||
// ones that do not advertise the graceful restart capability) or (b)
|
||||
// the Selection_Deferral_Timer referred to below has expired.
|
||||
allEnd := func() bool {
|
||||
for _, p := range server.neighborMap {
|
||||
if !p.recvedAllEOR() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}()
|
||||
if allEnd {
|
||||
for _, p := range server.neighborMap {
|
||||
p.fsm.pConf.GracefulRestart.State.LocalRestarting = false
|
||||
if !p.isGracefulRestartEnabled() {
|
||||
continue
|
||||
}
|
||||
paths, _ := server.getBestFromLocal(p, p.configuredRFlist())
|
||||
if len(paths) > 0 {
|
||||
sendFsmOutgoingMsg(p, paths, nil, false)
|
||||
}
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"Topic": "Server",
|
||||
}).Info("sync finished")
|
||||
} else {
|
||||
deferral := peer.fsm.pConf.GracefulRestart.Config.DeferralTime
|
||||
log.WithFields(log.Fields{
|
||||
"Topic": "Peer",
|
||||
"Key": peer.ID(),
|
||||
}).Debugf("Now syncing, suppress sending updates. start deferral timer(%d)", deferral)
|
||||
time.AfterFunc(time.Second*time.Duration(deferral), deferralExpiredFunc(bgp.RouteFamily(0)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if server.shutdown && nextState == bgp.BGP_FSM_IDLE {
|
||||
|
||||
Reference in New Issue
Block a user