diff --git a/pkg/server/peer.go b/pkg/server/peer.go index 7f6a161a5..8ccdc4d33 100644 --- a/pkg/server/peer.go +++ b/pkg/server/peer.go @@ -104,6 +104,7 @@ type peer struct { policy *table.RoutingPolicy localRib *table.TableManager prefixLimitWarned map[bgp.RouteFamily]bool + dstRoutesCount map[bgp.RouteFamily]map[string]uint8 llgrEndChs []chan struct{} } @@ -113,6 +114,7 @@ func newPeer(g *oc.Global, conf *oc.Neighbor, loc *table.TableManager, policy *t policy: policy, fsm: newFSM(g, conf, logger), prefixLimitWarned: make(map[bgp.RouteFamily]bool), + dstRoutesCount: make(map[bgp.RouteFamily]map[string]uint8), } if peer.isRouteServerClient() { peer.tableId = conf.State.NeighborAddress @@ -121,6 +123,11 @@ func newPeer(g *oc.Global, conf *oc.Neighbor, loc *table.TableManager, policy *t } rfs, _ := oc.AfiSafis(conf.AfiSafis).ToRfList() peer.adjRibIn = table.NewAdjRib(peer.fsm.logger, rfs) + for _, f := range rfs { + if peer.isAddPathSendEnabled(f) { + peer.dstRoutesCount[f] = make(map[string]uint8) + } + } return peer } @@ -200,6 +207,20 @@ func (peer *peer) isAddPathSendEnabled(family bgp.RouteFamily) bool { return (peer.getAddPathMode(family) & bgp.BGP_ADD_PATH_SEND) > 0 } +func (peer *peer) getAddPathSendMax(family bgp.RouteFamily) uint8 { + peer.fsm.lock.RLock() + defer peer.fsm.lock.RUnlock() + if !peer.isAddPathSendEnabled(family) { + return 0 + } + for _, a := range peer.fsm.pConf.AfiSafis { + if a.State.Family == family { + return a.AddPaths.Config.SendMax + } + } + return 0 +} + func (peer *peer) isDynamicNeighbor() bool { peer.fsm.lock.RLock() defer peer.fsm.lock.RUnlock() diff --git a/pkg/server/server.go b/pkg/server/server.go index a962a1e20..7cdb3b3bd 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -717,6 +717,39 @@ func (s *BgpServer) prePolicyFilterpath(peer *peer, path, old *table.Path) (*tab } } + if path != nil { + family := path.GetRouteFamily() + f := func() bgp.RouteFamily { + if peerVrf != "" { + switch family { + case bgp.RF_IPv4_VPN: + return bgp.RF_IPv4_UC + case bgp.RF_IPv6_VPN: + return bgp.RF_IPv6_UC + case bgp.RF_FS_IPv4_VPN: + return bgp.RF_FS_IPv4_UC + case bgp.RF_FS_IPv6_VPN: + return bgp.RF_FS_IPv6_UC + } + } + return family + }() + + sendMax := peer.getAddPathSendMax(f) + if sendMax > 0 { + dstPrefix := path.GetNlri().String() + dstRouteCount := peer.dstRoutesCount[f][dstPrefix] + if dstRouteCount > 0 && path.IsWithdraw { + dstRouteCount-- + } else if dstRouteCount < sendMax && !path.IsWithdraw { + dstRouteCount++ + } else if dstRouteCount >= sendMax { + return nil, nil, true + } + peer.dstRoutesCount[f][dstPrefix] = dstRouteCount + } + } + // replace-peer-as handling peer.fsm.lock.RLock() if path != nil && !path.IsWithdraw && peer.fsm.pConf.AsPathOptions.State.ReplacePeerAs { @@ -760,6 +793,7 @@ func (s *BgpServer) postFilterpath(peer *peer, path *table.Path) *table.Path { if path != nil && !peer.isIBGPPeer() && !peer.isRouteServerClient() { path.RemoveLocalPref() } + return path } @@ -1132,7 +1166,6 @@ func (s *BgpServer) processOutgoingPaths(peer *peer, paths, olds []*table.Path) } outgoing := make([]*table.Path, 0, len(paths)) - for idx, path := range paths { var old *table.Path if olds != nil {