diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/grpc_server.go | 1 | ||||
-rw-r--r-- | server/peer.go | 19 | ||||
-rw-r--r-- | server/server.go | 108 |
3 files changed, 115 insertions, 13 deletions
diff --git a/server/grpc_server.go b/server/grpc_server.go index a15143ee..1cce90bb 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -71,6 +71,7 @@ const ( REQ_BMP_NEIGHBORS REQ_BMP_GLOBAL REQ_BMP_ADJ_IN + REQ_DEFERRAL_TIMER_EXPIRED ) type Server struct { diff --git a/server/peer.go b/server/peer.go index 5b4fd701..da76bf93 100644 --- a/server/peer.go +++ b/server/peer.go @@ -138,13 +138,14 @@ func (peer *Peer) getBestFromLocal(rfList []bgp.RouteFamily) ([]*table.Path, []* return pathList, filtered } -func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage) { +func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage, []bgp.RouteFamily) { m := e.MsgData.(*bgp.BGPMessage) log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.Config.NeighborAddress, "data": m, }).Debug("received") + eor := []bgp.RouteFamily{} switch m.Header.Type { case bgp.BGP_MSG_ROUTE_REFRESH: @@ -167,7 +168,7 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage) path.IsWithdraw = true accepted = append(accepted, path) } - return nil, table.CreateUpdateMsgFromPaths(accepted) + return nil, table.CreateUpdateMsgFromPaths(accepted), eor } else { log.WithFields(log.Fields{ "Topic": "Peer", @@ -181,14 +182,24 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage) peer.adjRibIn.Update(e.PathList) paths := make([]*table.Path, 0, len(e.PathList)) for _, path := range e.PathList { + if path.IsEOR() { + family := path.GetRouteFamily() + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": peer.conf.Config.NeighborAddress, + "AddressFamily": family, + }).Debug("EOR received") + eor = append(eor, family) + continue + } if path.Filtered(peer.ID()) != table.POLICY_DIRECTION_IN { paths = append(paths, path) } } - return paths, nil + return paths, nil, eor } } - return nil, nil + return nil, nil, eor } func (peer *Peer) startFSMHandler(incoming, stateCh chan *FsmMsg) { 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 |