summaryrefslogtreecommitdiffhomepage
path: root/server/server.go
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2016-01-23 20:54:23 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-02-10 23:35:41 -0800
commitb19bbd415e8d33f01bcd407baece94ea1b81c957 (patch)
treee2a2ebec25d13924dfc7411ad25759c951dd70f8 /server/server.go
parenta207c90fe4544caa95d30ffaec5defee78ef6fd3 (diff)
gobgpd: support graceful-restart restarting-speaker behavior
use `-r` option to start gobgpd in restarting-speaker mode Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'server/server.go')
-rw-r--r--server/server.go108
1 files changed, 99 insertions, 9 deletions
diff --git a/server/server.go b/server/server.go
index f98d4f4c..a833fa7f 100644
--- a/server/server.go
+++ b/server/server.go
@@ -874,7 +874,7 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) ([]
dsts := rib.ProcessPaths(append(pathList, moded...))
server.validatePaths(dsts, false)
for _, targetPeer := range server.neighborMap {
- if !targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED {
+ if !targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED || targetPeer.fsm.pConf.GracefulRestart.State.LocalRestarting {
continue
}
sendPathList := make([]*table.Path, 0, len(dsts))
@@ -913,7 +913,13 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) ([]
}
for _, targetPeer := range server.neighborMap {
- if targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED {
+ if targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED || targetPeer.fsm.pConf.GracefulRestart.State.LocalRestarting {
+ if targetPeer.fsm.pConf.GracefulRestart.State.LocalRestarting {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": targetPeer.conf.Config.NeighborAddress,
+ }).Debug("now syncing, suppress sending updates")
+ }
continue
}
pathList := make([]*table.Path, len(sendPathList))
@@ -963,10 +969,29 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
// update for export policy
laddr, _ := peer.fsm.LocalHostPort()
peer.conf.Transport.Config.LocalAddress = laddr
- pathList, _ := peer.getBestFromLocal(peer.configuredRFlist())
- if len(pathList) > 0 {
- peer.adjRibOut.Update(pathList)
- msgs = append(msgs, newSenderMsg(peer, table.CreateUpdateMsgFromPaths(pathList)))
+ if !peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
+ pathList, _ := peer.getBestFromLocal(peer.configuredRFlist())
+ if len(pathList) > 0 {
+ peer.adjRibOut.Update(pathList)
+ msgs = append(msgs, newSenderMsg(peer, table.CreateUpdateMsgFromPaths(pathList)))
+ }
+ } 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.conf.Config.NeighborAddress,
+ }).Debugf("now syncing, suppress sending updates. start deferral timer(%d)", deferral)
+ time.AfterFunc(time.Second*time.Duration(deferral), func() {
+ req := NewGrpcRequest(REQ_DEFERRAL_TIMER_EXPIRED, peer.conf.Config.NeighborAddress, bgp.RouteFamily(0), nil)
+ server.GrpcReqCh <- req
+ <-req.ResponseCh
+ })
}
} else {
if server.shutdown && nextState == bgp.BGP_FSM_IDLE {
@@ -996,7 +1021,7 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
case *bgp.MessageError:
msgs = append(msgs, newSenderMsg(peer, []*bgp.BGPMessage{bgp.NewBGPNotificationMessage(m.TypeCode, m.SubTypeCode, m.Data)}))
case *bgp.BGPMessage:
- pathList, msgList := peer.handleBGPmessage(e)
+ pathList, msgList, eor := peer.handleBGPmessage(e)
if m.Header.Type == bgp.BGP_MSG_UPDATE && server.watchers.watching(WATCHER_EVENT_UPDATE_MSG) {
_, y := peer.fsm.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER]
@@ -1045,6 +1070,58 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) []*SenderMsg {
}
}
}
+
+ if len(eor) > 0 {
+ // RFC 4724 4.1
+ // Once the session between the Restarting Speaker and the Receiving
+ // 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 ...snip...
+ if peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
+ var end bool
+ for _, f := range eor {
+ end = true
+ for i, a := range peer.fsm.pConf.AfiSafis {
+ if g, _ := bgp.GetRouteFamily(string(a.AfiSafiName)); f == g {
+ peer.fsm.pConf.AfiSafis[i].MpGracefulRestart.State.EndOfRibReceived = true
+ }
+ if s := a.MpGracefulRestart.State; s.Enabled && !s.EndOfRibReceived {
+ end = false
+ }
+ }
+ }
+ if end {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.conf.Config.NeighborAddress,
+ }).Debug("all family's EOR received")
+ peer.fsm.pConf.GracefulRestart.State.LocalRestarting = false
+ }
+ allEnd := true
+ for _, p := range server.neighborMap {
+ if p.fsm.pConf.GracefulRestart.State.LocalRestarting {
+ allEnd = false
+ }
+ }
+ if allEnd {
+ for _, p := range server.neighborMap {
+ if !p.isGracefulRestartEnabled() {
+ continue
+ }
+ pathList, _ := p.getBestFromLocal(p.configuredRFlist())
+ if len(pathList) > 0 {
+ p.adjRibOut.Update(pathList)
+ msgs = append(msgs, newSenderMsg(p, table.CreateUpdateMsgFromPaths(pathList)))
+ }
+ }
+ log.WithFields(log.Fields{
+ "Topic": "Server",
+ }).Info("sync finished")
+ }
+ }
+ }
default:
log.WithFields(log.Fields{
"Topic": "Peer",
@@ -1942,7 +2019,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
break
}
fallthrough
- case REQ_NEIGHBOR_SOFT_RESET_OUT:
+ case REQ_NEIGHBOR_SOFT_RESET_OUT, REQ_DEFERRAL_TIMER_EXPIRED:
peers, err := reqToPeers(grpcReq)
if err != nil {
break
@@ -1954,6 +2031,19 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
if peer.fsm.state != bgp.BGP_FSM_ESTABLISHED {
continue
}
+
+ if grpcReq.RequestType == REQ_DEFERRAL_TIMER_EXPIRED {
+ if peer.fsm.pConf.GracefulRestart.State.LocalRestarting {
+ peer.fsm.pConf.GracefulRestart.State.LocalRestarting = false
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": peer.conf.Config.NeighborAddress,
+ }).Debug("deferral timer expired")
+ } else {
+ continue
+ }
+ }
+
families := []bgp.RouteFamily{grpcReq.RouteFamily}
if families[0] == bgp.RouteFamily(0) {
families = peer.configuredRFlist()
@@ -1965,7 +2055,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
peer.adjRibOut.Update(pathList)
msgs = append(msgs, newSenderMsg(peer, table.CreateUpdateMsgFromPaths(pathList)))
}
- if len(filtered) > 0 {
+ if grpcReq.RequestType != REQ_DEFERRAL_TIMER_EXPIRED && len(filtered) > 0 {
withdrawnList := make([]*table.Path, 0, len(filtered))
for _, p := range filtered {
found := false