summaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/grpc_server.go1
-rw-r--r--server/peer.go19
-rw-r--r--server/server.go108
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