From b19bbd415e8d33f01bcd407baece94ea1b81c957 Mon Sep 17 00:00:00 2001 From: ISHIDA Wataru Date: Sat, 23 Jan 2016 20:54:23 +0900 Subject: gobgpd: support graceful-restart restarting-speaker behavior use `-r` option to start gobgpd in restarting-speaker mode Signed-off-by: ISHIDA Wataru --- server/server.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 9 deletions(-) (limited to 'server/server.go') 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 -- cgit v1.2.3