diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2015-11-29 04:08:36 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-12-08 14:45:37 +0900 |
commit | a719a3de6e8b2bb7803e02e7e05ea8e854d6f396 (patch) | |
tree | fbe41ae4055542414a7a02d81c87a0fc57b65f5c /server | |
parent | 3213eed6a5aca1625ffa03ab410ffc587121b9da (diff) |
server/table: use only one rib for multiple route server clients
speed up and reduce memory footprint
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'server')
-rw-r--r-- | server/fsm.go | 13 | ||||
-rw-r--r-- | server/fsm_test.go | 3 | ||||
-rw-r--r-- | server/peer.go | 176 | ||||
-rw-r--r-- | server/server.go | 447 |
4 files changed, 286 insertions, 353 deletions
diff --git a/server/fsm.go b/server/fsm.go index 15d935bb..2d952065 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -86,7 +86,7 @@ type FSM struct { rfMap map[bgp.RouteFamily]bool confedCheck bool peerInfo *table.PeerInfo - peer *Peer + policy *table.RoutingPolicy } func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) { @@ -138,7 +138,7 @@ func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) { } } -func NewFSM(gConf *config.Global, pConf *config.Neighbor, peer *Peer) *FSM { +func NewFSM(gConf *config.Global, pConf *config.Neighbor, policy *table.RoutingPolicy) *FSM { adminState := ADMIN_STATE_UP if pConf.NeighborState.AdminDown == true { adminState = ADMIN_STATE_DOWN @@ -155,7 +155,7 @@ func NewFSM(gConf *config.Global, pConf *config.Neighbor, peer *Peer) *FSM { rfMap: make(map[bgp.RouteFamily]bool), confedCheck: !config.IsConfederationMember(gConf, pConf) && config.IsEBGPPeer(gConf, pConf), peerInfo: table.NewPeerInfo(gConf, pConf), - peer: peer, + policy: policy, } fsm.t.Go(fsm.connectLoop) return fsm @@ -512,8 +512,13 @@ func (h *FSMHandler) recvMessageWithError() error { // FIXME: we should use the original message for bmp/mrt table.UpdatePathAttrs4ByteAs(body) fmsg.PathList = table.ProcessMessage(m, h.fsm.peerInfo, fmsg.timestamp) + id := h.fsm.pConf.NeighborConfig.NeighborAddress.String() policyMutex.RLock() - h.fsm.peer.ApplyPolicy(table.POLICY_DIRECTION_IN, fmsg.PathList) + for _, path := range fmsg.PathList { + if h.fsm.policy.ApplyPolicy(id, table.POLICY_DIRECTION_IN, path) == nil { + path.Filter(id, table.POLICY_DIRECTION_IN) + } + } policyMutex.RUnlock() } fmsg.payload = make([]byte, len(headerBuf)+len(bodyBuf)) diff --git a/server/fsm_test.go b/server/fsm_test.go index aad9ff07..3b1bedd2 100644 --- a/server/fsm_test.go +++ b/server/fsm_test.go @@ -20,6 +20,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet" + "github.com/osrg/gobgp/table" "github.com/stretchr/testify/assert" "net" "strconv" @@ -293,7 +294,7 @@ func makePeerAndHandler() (*Peer, *FSMHandler) { capMap: make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface), } - p.fsm = NewFSM(&gConf, &pConf, &Peer{}) + p.fsm = NewFSM(&gConf, &pConf, table.NewRoutingPolicy()) incoming := make(chan *FsmMsg, 4096) p.outgoing = make(chan *bgp.BGPMessage, 4096) diff --git a/server/peer.go b/server/peer.go index 8f43299e..1844236e 100644 --- a/server/peer.go +++ b/server/peer.go @@ -32,35 +32,41 @@ const ( ) type Peer struct { - gConf config.Global - conf config.Neighbor - fsm *FSM - rfMap map[bgp.RouteFamily]bool - capMap map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface - adjRibIn *table.AdjRib - adjRibOut *table.AdjRib - outgoing chan *bgp.BGPMessage - inPolicies []*table.Policy - defaultInPolicy table.RouteType - recvOpen *bgp.BGPMessage - localRib *table.TableManager + tableId string + gConf config.Global + conf config.Neighbor + fsm *FSM + rfMap map[bgp.RouteFamily]bool + capMap map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface + adjRibIn *table.AdjRib + adjRibOut *table.AdjRib + outgoing chan *bgp.BGPMessage + recvOpen *bgp.BGPMessage + policy *table.RoutingPolicy + localRib *table.TableManager } -func NewPeer(g config.Global, conf config.Neighbor, loc *table.TableManager) *Peer { - rfs, _ := conf.AfiSafis.ToRfList() +func NewPeer(g config.Global, conf config.Neighbor, loc *table.TableManager, policy *table.RoutingPolicy) *Peer { peer := &Peer{ - gConf: g, - conf: conf, - rfMap: make(map[bgp.RouteFamily]bool), - capMap: make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface), - outgoing: make(chan *bgp.BGPMessage, 128), - adjRibIn: table.NewAdjRib(rfs), - adjRibOut: table.NewAdjRib(rfs), - localRib: loc, + gConf: g, + conf: conf, + rfMap: make(map[bgp.RouteFamily]bool), + capMap: make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface), + outgoing: make(chan *bgp.BGPMessage, 128), + localRib: loc, + policy: policy, + } + tableId := table.GLOBAL_RIB_NAME + if peer.isRouteServerClient() { + tableId = conf.NeighborConfig.NeighborAddress.String() } + peer.tableId = tableId conf.NeighborState.SessionState = uint32(bgp.BGP_FSM_IDLE) conf.Timers.TimersState.Downtime = time.Now().Unix() - peer.fsm = NewFSM(&g, &conf, peer) + rfs, _ := conf.AfiSafis.ToRfList() + peer.adjRibIn = table.NewAdjRib(peer.ID(), rfs) + peer.adjRibOut = table.NewAdjRib(peer.ID(), rfs) + peer.fsm = NewFSM(&g, &conf, policy) return peer } @@ -72,6 +78,14 @@ func (peer *Peer) Outgoing() chan *bgp.BGPMessage { return peer.outgoing } +func (peer *Peer) ID() string { + return peer.conf.NeighborConfig.NeighborAddress.String() +} + +func (peer *Peer) TableID() string { + return peer.tableId +} + func (peer *Peer) isIBGPPeer() bool { return peer.conf.NeighborConfig.PeerAs == peer.gConf.GlobalConfig.As } @@ -94,11 +108,18 @@ func (peer *Peer) getAccepted(rfList []bgp.RouteFamily) []*table.Path { } func (peer *Peer) getBestFromLocal(rfList []bgp.RouteFamily) ([]*table.Path, []*table.Path) { - pathList, filtered := peer.ApplyPolicy(table.POLICY_DIRECTION_EXPORT, filterpath(peer, peer.localRib.GetBestPathList(rfList))) - if peer.isRouteServerClient() == false { - for _, path := range pathList { - path.UpdatePathAttrs(&peer.gConf, &peer.conf) + pathList := []*table.Path{} + filtered := []*table.Path{} + for _, path := range peer.localRib.GetBestPathList(peer.TableID(), rfList) { + p := peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, filterpath(peer, path)) + if p == nil { + filtered = append(filtered, path) + continue + } + if !peer.isRouteServerClient() { + p.UpdatePathAttrs(&peer.gConf, &peer.conf) } + pathList = append(pathList, p) } return pathList, filtered } @@ -132,16 +153,13 @@ func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode] return capMap, rfMap } -func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, bool, []*bgp.BGPMessage) { +func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, []*bgp.BGPMessage) { m := e.MsgData.(*bgp.BGPMessage) - bgpMsgList := []*bgp.BGPMessage{} - pathList := []*table.Path{} log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, "data": m, }).Debug("received") - update := false switch m.Header.Type { case bgp.BGP_MSG_OPEN: @@ -178,11 +196,11 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, bool, []*bgp.BGPMe peer.adjRibOut.Drop(rfList) accepted, filtered := peer.getBestFromLocal(rfList) peer.adjRibOut.Update(accepted) - pathList = append(pathList, accepted...) for _, path := range filtered { path.IsWithdraw = true - pathList = append(pathList, path) + accepted = append(accepted, path) } + return nil, table.CreateUpdateMsgFromPaths(accepted) } else { log.WithFields(log.Fields{ "Topic": "Peer", @@ -191,11 +209,16 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, bool, []*bgp.BGPMe } case bgp.BGP_MSG_UPDATE: - update = true peer.conf.Timers.TimersState.UpdateRecvTime = time.Now().Unix() if len(e.PathList) > 0 { peer.adjRibIn.Update(e.PathList) - pathList = e.PathList + paths := make([]*table.Path, 0, len(e.PathList)) + for _, path := range e.PathList { + if path.Filtered(peer.TableID()) != table.POLICY_DIRECTION_IN { + paths = append(paths, path) + } + } + return paths, nil } case bgp.BGP_MSG_NOTIFICATION: body := m.Body.(*bgp.BGPNotification) @@ -207,7 +230,7 @@ func (peer *Peer) handleBGPmessage(e *FsmMsg) ([]*table.Path, bool, []*bgp.BGPMe "Data": body.Data, }).Warn("received notification") } - return pathList, update, bgpMsgList + return nil, nil } func (peer *Peer) startFSMHandler(incoming chan *FsmMsg) { @@ -351,87 +374,6 @@ func (peer *Peer) ToApiStruct() *api.Peer { } } -func (peer *Peer) GetPolicy(d table.PolicyDirection) []*table.Policy { - switch d { - case table.POLICY_DIRECTION_IN: - return peer.inPolicies - default: - return peer.localRib.GetPolicy(d) - } - return nil -} - -func (peer *Peer) SetPolicy(d table.PolicyDirection, policies []*table.Policy) error { - switch d { - case table.POLICY_DIRECTION_IN: - peer.inPolicies = policies - default: - return peer.localRib.SetPolicy(d, policies) - } - return nil -} - -func (peer *Peer) GetDefaultPolicy(d table.PolicyDirection) table.RouteType { - switch d { - case table.POLICY_DIRECTION_IN: - return peer.defaultInPolicy - default: - return peer.localRib.GetDefaultPolicy(d) - } - return table.ROUTE_TYPE_NONE -} - -func (peer *Peer) SetDefaultPolicy(d table.PolicyDirection, typ table.RouteType) error { - switch d { - case table.POLICY_DIRECTION_IN: - peer.defaultInPolicy = typ - default: - if peer.isRouteServerClient() { - return peer.localRib.SetDefaultPolicy(d, typ) - } - } - return nil -} - -func (peer *Peer) ApplyPolicy(d table.PolicyDirection, paths []*table.Path) ([]*table.Path, []*table.Path) { - newpaths := make([]*table.Path, 0, len(paths)) - filteredPaths := make([]*table.Path, 0) - for _, path := range paths { - result := table.ROUTE_TYPE_NONE - newpath := path - for _, p := range peer.GetPolicy(d) { - result, newpath = p.Apply(path) - if result != table.ROUTE_TYPE_NONE { - break - } - } - - if result == table.ROUTE_TYPE_NONE { - result = peer.GetDefaultPolicy(d) - } - - switch result { - case table.ROUTE_TYPE_ACCEPT: - if d == table.POLICY_DIRECTION_IN { - path.Filtered = false - } - newpaths = append(newpaths, newpath) - case table.ROUTE_TYPE_REJECT: - if d == table.POLICY_DIRECTION_IN { - path.Filtered = true - } - filteredPaths = append(filteredPaths, path) - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": peer.conf.NeighborConfig.NeighborAddress, - "Path": path, - "Direction": d, - }).Debug("reject") - } - } - return newpaths, filteredPaths -} - func (peer *Peer) DropAll(rfList []bgp.RouteFamily) { peer.adjRibIn.Drop(rfList) peer.adjRibOut.Drop(rfList) diff --git a/server/server.go b/server/server.go index 2bb89d8e..7b1617ee 100644 --- a/server/server.go +++ b/server/server.go @@ -34,10 +34,6 @@ import ( "time" ) -const ( - GLOBAL_RIB_NAME = "global" -) - var policyMutex sync.RWMutex type SenderMsg struct { @@ -120,6 +116,7 @@ func NewBgpServer(port int) *BgpServer { b.listenPort = port b.watchers = make(map[watcherType]watcher) b.roaClient, _ = newROAClient(0, config.RpkiServers{}) + b.policy = table.NewRoutingPolicy() return &b } @@ -218,15 +215,8 @@ func (server *BgpServer) Serve() { } }(broadcastCh) - toRFlist := func(l []config.AfiSafi) []bgp.RouteFamily { - rfList := []bgp.RouteFamily{} - for _, rf := range l { - k, _ := bgp.GetRouteFamily(rf.AfiSafiName) - rfList = append(rfList, k) - } - return rfList - } - server.globalRib = table.NewTableManager(GLOBAL_RIB_NAME, toRFlist(g.AfiSafis.AfiSafiList), g.MplsLabelRange.MinLabel, g.MplsLabelRange.MaxLabel) + rfs, _ := g.AfiSafis.ToRfList() + server.globalRib = table.NewTableManager(table.GLOBAL_RIB_NAME, rfs, g.MplsLabelRange.MinLabel, g.MplsLabelRange.MaxLabel) server.listenerMap = make(map[string]*net.TCPListener) acceptCh := make(chan *net.TCPConn) l4, err1 := listenAndAccept("tcp4", server.listenPort, acceptCh) @@ -362,26 +352,23 @@ func (server *BgpServer) Serve() { } SetTcpMD5SigSockopts(listener(config.NeighborConfig.NeighborAddress), addr, config.NeighborConfig.AuthPassword) - var loc *table.TableManager - if config.RouteServer.RouteServerConfig.RouteServerClient { - loc = table.NewTableManager(config.NeighborConfig.NeighborAddress.String(), toRFlist(config.AfiSafis.AfiSafiList), g.MplsLabelRange.MinLabel, g.MplsLabelRange.MaxLabel) - } else { - loc = server.globalRib - } - peer := NewPeer(g, config, loc) - - server.setPolicyByConfig(peer, config.ApplyPolicy) + peer := NewPeer(g, config, server.globalRib, server.policy) + server.setPolicyByConfig(peer.ID(), config.ApplyPolicy) if peer.isRouteServerClient() { pathList := make([]*table.Path, 0) rfList := peer.configuredRFlist() for _, p := range server.neighborMap { - if p.isRouteServerClient() == true { - pathList = append(pathList, p.getAccepted(rfList)...) + if p.isRouteServerClient() { + for _, path := range p.getAccepted(rfList) { + path = server.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_IMPORT, path) + if path != nil { + pathList = append(pathList, path) + } + } } } - pathList, _ = peer.ApplyPolicy(table.POLICY_DIRECTION_IMPORT, pathList) if len(pathList) > 0 { - peer.localRib.ProcessPaths(pathList) + server.globalRib.ProcessPaths(pathList) } } server.neighborMap[addr] = peer @@ -416,7 +403,7 @@ func (server *BgpServer) Serve() { addr := config.NeighborConfig.NeighborAddress.String() peer := server.neighborMap[addr] peer.conf = config - server.setPolicyByConfig(peer, config.ApplyPolicy) + server.setPolicyByConfig(peer.ID(), config.ApplyPolicy) case e := <-server.fsmincomingCh: peer, found := server.neighborMap[e.MsgSrc] if !found { @@ -452,121 +439,121 @@ func newSenderMsg(peer *Peer, messages []*bgp.BGPMessage) *SenderMsg { } } -func filterpath(peer *Peer, pathList []*table.Path) []*table.Path { - filtered := make([]*table.Path, 0) - - for _, path := range pathList { - if _, ok := peer.rfMap[path.GetRouteFamily()]; !ok { - continue - } +func filterpath(peer *Peer, path *table.Path) *table.Path { + if path == nil { + return nil + } + if _, ok := peer.rfMap[path.GetRouteFamily()]; !ok { + return nil + } - remoteAddr := peer.conf.NeighborConfig.NeighborAddress + remoteAddr := peer.conf.NeighborConfig.NeighborAddress - //iBGP handling - if !path.IsLocal() && peer.isIBGPPeer() { - ignore := true - info := path.GetSource() + //iBGP handling + if !path.IsLocal() && peer.isIBGPPeer() { + ignore := true + info := path.GetSource() - //if the path comes from eBGP peer - if info.AS != peer.conf.NeighborConfig.PeerAs { - ignore = false - } + //if the path comes from eBGP peer + if info.AS != peer.conf.NeighborConfig.PeerAs { + ignore = false + } + // RFC4456 8. Avoiding Routing Information Loops + // A router that recognizes the ORIGINATOR_ID attribute SHOULD + // ignore a route received with its BGP Identifier as the ORIGINATOR_ID. + if id := path.GetOriginatorID(); peer.gConf.GlobalConfig.RouterId.Equal(id) { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": remoteAddr, + "OriginatorID": id, + "Data": path, + }).Debug("Originator ID is mine, ignore") + return nil + } + if info.RouteReflectorClient { + ignore = false + } + if peer.isRouteReflectorClient() { // RFC4456 8. Avoiding Routing Information Loops - // A router that recognizes the ORIGINATOR_ID attribute SHOULD - // ignore a route received with its BGP Identifier as the ORIGINATOR_ID. - if id := path.GetOriginatorID(); peer.gConf.GlobalConfig.RouterId.Equal(id) { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": remoteAddr, - "OriginatorID": id, - "Data": path, - }).Debug("Originator ID is mine, ignore") - continue - } - if info.RouteReflectorClient { - ignore = false - } - if peer.isRouteReflectorClient() { - // RFC4456 8. Avoiding Routing Information Loops - // If the local CLUSTER_ID is found in the CLUSTER_LIST, - // the advertisement received SHOULD be ignored. - for _, clusterId := range path.GetClusterList() { - if clusterId.Equal(peer.fsm.peerInfo.RouteReflectorClusterID) { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": remoteAddr, - "ClusterID": clusterId, - "Data": path, - }).Debug("cluster list path attribute has local cluster id, ignore") - continue - } + // If the local CLUSTER_ID is found in the CLUSTER_LIST, + // the advertisement received SHOULD be ignored. + for _, clusterId := range path.GetClusterList() { + if clusterId.Equal(peer.fsm.peerInfo.RouteReflectorClusterID) { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": remoteAddr, + "ClusterID": clusterId, + "Data": path, + }).Debug("cluster list path attribute has local cluster id, ignore") + return nil } - ignore = false - } - - if ignore { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": remoteAddr, - "Data": path, - }).Debug("From same AS, ignore.") - continue } + ignore = false } - if remoteAddr.Equal(path.GetSource().Address) { + if ignore { log.WithFields(log.Fields{ "Topic": "Peer", "Key": remoteAddr, "Data": path, - }).Debug("From me, ignore.") - continue + }).Debug("From same AS, ignore.") + return nil } + } - send := true - for _, as := range path.GetAsList() { - if as == peer.conf.NeighborConfig.PeerAs { - send = false - break - } - } + if remoteAddr.Equal(path.GetSource().Address) { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": remoteAddr, + "Data": path, + }).Debug("From me, ignore.") + return nil + } - if !send { + for _, as := range path.GetAsList() { + if as == peer.conf.NeighborConfig.PeerAs { log.WithFields(log.Fields{ "Topic": "Peer", "Key": remoteAddr, "Data": path, }).Debug("AS PATH loop, ignore.") - continue + return nil } - filtered = append(filtered, path.Clone(remoteAddr, path.IsWithdraw)) } - return filtered + return path.Clone(remoteAddr, path.IsWithdraw) } func (server *BgpServer) dropPeerAllRoutes(peer *Peer) []*SenderMsg { msgs := make([]*SenderMsg, 0) for _, rf := range peer.configuredRFlist() { + dsts := server.globalRib.DeletePathsByPeer(peer.fsm.peerInfo, rf) if peer.isRouteServerClient() { + pathList := make([]*table.Path, len(dsts)) for _, targetPeer := range server.neighborMap { - rib := targetPeer.localRib - if !targetPeer.isRouteServerClient() || rib.OwnerName() == peer.conf.NeighborConfig.NeighborAddress.String() { + if !targetPeer.isRouteServerClient() || targetPeer == peer || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED { continue } - pathList, _ := rib.DeletePathsforPeer(peer.fsm.peerInfo, rf) - if targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED || len(pathList) == 0 { - continue + i := 0 + for _, dst := range dsts { + feed := dst.NewFeed(targetPeer.TableID()) + pathList[i] = feed + i++ } msgList := table.CreateUpdateMsgFromPaths(pathList) msgs = append(msgs, newSenderMsg(targetPeer, msgList)) targetPeer.adjRibOut.Update(pathList) } } else { - rib := server.globalRib - pathList, _ := rib.DeletePathsforPeer(peer.fsm.peerInfo, rf) + pathList := make([]*table.Path, 0, len(dsts)) + for _, dst := range dsts { + path := dst.NewFeed(table.GLOBAL_RIB_NAME) + if path != nil { + pathList = append(pathList, path) + } + } if len(pathList) == 0 { - continue + return msgs } server.broadcastBests(pathList) @@ -606,7 +593,7 @@ func (server *BgpServer) broadcastBests(bests []*table.Path) { result := &GrpcResponse{ Data: &api.Destination{ Prefix: path.GetNlri().String(), - Paths: []*api.Path{path.ToApiStruct()}, + Paths: []*api.Path{path.ToApiStruct(table.GLOBAL_RIB_NAME)}, }, } remainReqs := make([]*GrpcRequest, 0, len(server.broadcastReqs)) @@ -662,29 +649,61 @@ func (server *BgpServer) broadcastPeerState(peer *Peer) { func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) []*SenderMsg { msgs := make([]*SenderMsg, 0) + rib := server.globalRib if peer != nil && peer.isRouteServerClient() { + for _, path := range pathList { + path.Filter(peer.TableID(), table.POLICY_DIRECTION_IMPORT) + path.Filter(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT) + } + moded := []*table.Path{} for _, targetPeer := range server.neighborMap { - rib := targetPeer.localRib - if !targetPeer.isRouteServerClient() || rib.OwnerName() == peer.conf.NeighborConfig.NeighborAddress.String() { + if !targetPeer.isRouteServerClient() || peer == targetPeer { continue } - sendPathList, _ := targetPeer.ApplyPolicy(table.POLICY_DIRECTION_IMPORT, pathList) - sendPathList, _ = rib.ProcessPaths(sendPathList) - if targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED || len(sendPathList) == 0 { - continue + for _, before := range pathList { + after := server.policy.ApplyPolicy(targetPeer.TableID(), table.POLICY_DIRECTION_IMPORT, before) + if after == nil { + before.Filter(targetPeer.TableID(), table.POLICY_DIRECTION_IMPORT) + } else if after != before { + before.Filter(targetPeer.TableID(), table.POLICY_DIRECTION_IMPORT) + for _, n := range server.neighborMap { + if n == targetPeer { + continue + } + after.Filter(n.TableID(), table.POLICY_DIRECTION_IMPORT) + } + moded = append(moded, after) + } } - sendPathList, _ = targetPeer.ApplyPolicy(table.POLICY_DIRECTION_EXPORT, filterpath(targetPeer, sendPathList)) - if len(sendPathList) == 0 { + } + dsts := rib.ProcessPaths(append(pathList, moded...)) + for _, targetPeer := range server.neighborMap { + if !targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED { continue } + sendPathList := make([]*table.Path, 0, len(dsts)) + for _, dst := range dsts { + path := server.policy.ApplyPolicy(targetPeer.TableID(), table.POLICY_DIRECTION_EXPORT, filterpath(targetPeer, dst.NewFeed(targetPeer.TableID()))) + if path != nil { + sendPathList = append(sendPathList, path) + } + } msgList := table.CreateUpdateMsgFromPaths(sendPathList) targetPeer.adjRibOut.Update(sendPathList) msgs = append(msgs, newSenderMsg(targetPeer, msgList)) } } else { - rib := server.globalRib - pathList = rib.ApplyPolicy(table.POLICY_DIRECTION_IMPORT, pathList) - sendPathList, _ := rib.ProcessPaths(pathList) + for idx, path := range pathList { + pathList[idx] = server.policy.ApplyPolicy(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT, path) + } + dsts := rib.ProcessPaths(pathList) + sendPathList := make([]*table.Path, 0, len(dsts)) + for _, dst := range dsts { + path := dst.NewFeed(table.GLOBAL_RIB_NAME) + if path != nil { + sendPathList = append(sendPathList, path) + } + } if len(sendPathList) == 0 { return msgs } @@ -695,15 +714,18 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) []* if targetPeer.isRouteServerClient() || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED { continue } - f := rib.ApplyPolicy(table.POLICY_DIRECTION_EXPORT, filterpath(targetPeer, sendPathList)) - if len(f) == 0 { - continue - } - for _, path := range f { - path.UpdatePathAttrs(&server.bgpConfig.Global, &targetPeer.conf) + pathList := make([]*table.Path, len(sendPathList)) + copy(pathList, sendPathList) + for idx, path := range pathList { + path = server.policy.ApplyPolicy(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_EXPORT, filterpath(targetPeer, path)) + if path != nil { + path.UpdatePathAttrs(&server.bgpConfig.Global, &targetPeer.conf) + } + pathList[idx] = path } - targetPeer.adjRibOut.Update(f) - msgList := table.CreateUpdateMsgFromPaths(f) + targetPeer.adjRibOut.Update(pathList) + msgList := table.CreateUpdateMsgFromPaths(pathList) + msgs = append(msgs, newSenderMsg(targetPeer, msgList)) } } @@ -823,32 +845,12 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg, incoming chan * } } - pathList, update, msgList := peer.handleBGPmessage(e) + pathList, msgList := peer.handleBGPmessage(e) if len(msgList) > 0 { msgs = append(msgs, newSenderMsg(peer, msgList)) - break } - if update == false { - if len(pathList) > 0 { - msgList := table.CreateUpdateMsgFromPaths(pathList) - msgs = append(msgs, newSenderMsg(peer, msgList)) - } - break - } else { - if len(pathList) > 0 { - server.roaClient.validate(pathList) - } - } - // FIXME: refactor peer.handleBGPmessage and this func - if peer.isRouteServerClient() { - var accepted []*table.Path - for _, p := range pathList { - if p.Filtered == false { - accepted = append(accepted, p) - } - } - msgs = append(msgs, server.propagateUpdate(peer, accepted)...) - } else { + if len(pathList) > 0 { + server.roaClient.validate(pathList) msgs = append(msgs, server.propagateUpdate(peer, pathList)...) } default: @@ -899,7 +901,7 @@ func (server *BgpServer) UpdatePolicy(policy config.RoutingPolicy) { server.policyUpdateCh <- policy } -func (server *BgpServer) setPolicyByConfig(p policyPoint, c config.ApplyPolicy) { +func (server *BgpServer) setPolicyByConfig(id string, c config.ApplyPolicy) { for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_IN, table.POLICY_DIRECTION_IMPORT, table.POLICY_DIRECTION_EXPORT} { ps, def, err := server.policy.GetAssignmentFromConfig(dir, c) if err != nil { @@ -909,26 +911,24 @@ func (server *BgpServer) setPolicyByConfig(p policyPoint, c config.ApplyPolicy) }).Errorf("failed to get policy info: %s", err) continue } - p.SetDefaultPolicy(dir, def) - p.SetPolicy(dir, ps) + server.policy.SetDefaultPolicy(id, dir, def) + server.policy.SetPolicy(id, dir, ps) } } -func (server *BgpServer) SetPolicy(pl config.RoutingPolicy) error { - p, err := table.NewRoutingPolicy(pl) - if err != nil { +func (server *BgpServer) SetRoutingPolicy(pl config.RoutingPolicy) error { + if err := server.policy.Reload(pl); err != nil { log.WithFields(log.Fields{ "Topic": "Policy", }).Errorf("failed to create routing policy: %s", err) return err } - server.policy = p - server.setPolicyByConfig(server.globalRib, server.bgpConfig.Global.ApplyPolicy) + server.setPolicyByConfig(table.GLOBAL_RIB_NAME, server.bgpConfig.Global.ApplyPolicy) return nil } func (server *BgpServer) handlePolicy(pl config.RoutingPolicy) error { - if err := server.SetPolicy(pl); err != nil { + if err := server.SetRoutingPolicy(pl); err != nil { log.WithFields(log.Fields{ "Topic": "Policy", }).Errorf("failed to set new policy: %s", err) @@ -939,7 +939,7 @@ func (server *BgpServer) handlePolicy(pl config.RoutingPolicy) error { "Topic": "Peer", "Key": peer.conf.NeighborConfig.NeighborAddress, }).Info("call set policy") - server.setPolicyByConfig(peer, peer.conf.ApplyPolicy) + server.setPolicyByConfig(peer.ID(), peer.conf.ApplyPolicy) } return nil } @@ -1162,7 +1162,7 @@ func (server *BgpServer) handleModPathRequest(grpcReq *GrpcRequest) []*table.Pat macIpAdv := evpnNlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute) etag := macIpAdv.ETag mac := macIpAdv.MacAddress - paths := server.globalRib.GetBestPathList([]bgp.RouteFamily{bgp.RF_EVPN}) + paths := server.globalRib.GetBestPathList(table.GLOBAL_RIB_NAME, []bgp.RouteFamily{bgp.RF_EVPN}) if m := getMacMobilityExtendedCommunity(etag, mac, paths); m != nil { extcomms = append(extcomms, m) } @@ -1256,7 +1256,7 @@ func (server *BgpServer) handleVrfRequest(req *GrpcRequest) []*table.Path { result.ResponseErr = fmt.Errorf("unsupported route family: %s", bgp.RouteFamily(arg.Family)) break } - paths := rib.GetPathList(rf) + paths := rib.GetPathList(table.GLOBAL_RIB_NAME, rf) dsts := make([]*api.Destination, 0, len(paths)) for _, path := range paths { ok := table.CanImportToVrf(vrfs[name], path) @@ -1265,7 +1265,7 @@ func (server *BgpServer) handleVrfRequest(req *GrpcRequest) []*table.Path { } dsts = append(dsts, &api.Destination{ Prefix: path.GetNlri().String(), - Paths: []*api.Path{path.ToApiStruct()}, + Paths: []*api.Path{path.ToApiStruct(table.GLOBAL_RIB_NAME)}, }) } req.ResponseCh <- &GrpcResponse{ @@ -1357,12 +1357,14 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { return []*Peer{peer}, err } - sortedDsts := func(t *table.Table) []*api.Destination { + sortedDsts := func(id string, t *table.Table) []*api.Destination { results := make([]*api.Destination, 0, len(t.GetDestinations())) r := radix.New() for _, dst := range t.GetDestinations() { - r.Insert(dst.RadixKey, dst.ToApiStruct()) + if d := dst.ToApiStruct(id); d != nil { + r.Insert(dst.RadixKey, d) + } } r.Walk(func(s string, v interface{}) bool { results = append(results, v.(*api.Destination)) @@ -1405,6 +1407,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { Family: arg.Family, } rib := server.globalRib + id := table.GLOBAL_RIB_NAME if grpcReq.RequestType == REQ_LOCAL_RIB { peer, ok := server.neighborMap[arg.Name] if !ok { @@ -1415,7 +1418,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { err = fmt.Errorf("Neighbor %v doesn't have local rib", arg.Name) goto ERROR } - rib = peer.localRib + id = peer.ID() } af := bgp.RouteFamily(arg.Family) if _, ok := rib.Tables[af]; !ok { @@ -1427,13 +1430,15 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC: if len(arg.Destinations) > 0 { dsts := []*api.Destination{} - f := func(cidr string) (bool, error) { + f := func(id, cidr string) (bool, error) { _, prefix, err := net.ParseCIDR(cidr) if err != nil { return false, err } if dst := rib.Tables[af].GetDestination(prefix.String()); dst != nil { - dsts = append(dsts, dst.ToApiStruct()) + if d := dst.ToApiStruct(id); d != nil { + dsts = append(dsts, d) + } return true, nil } else { return false, nil @@ -1441,14 +1446,14 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } for _, dst := range arg.Destinations { key := dst.Prefix - if _, err := f(key); err != nil { + if _, err := f(id, key); err != nil { if host := net.ParseIP(key); host != nil { masklen := 32 if af == bgp.RF_IPv6_UC { masklen = 128 } for i := masklen; i > 0; i-- { - if y, _ := f(fmt.Sprintf("%s/%d", key, i)); y { + if y, _ := f(id, fmt.Sprintf("%s/%d", key, i)); y { break } } @@ -1458,18 +1463,20 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { ones, bits := prefix.Mask.Size() for i := ones + 1; i <= bits; i++ { prefix.Mask = net.CIDRMask(i, bits) - f(prefix.String()) + f(id, prefix.String()) } } } d.Destinations = dsts } else { - d.Destinations = sortedDsts(rib.Tables[af]) + d.Destinations = sortedDsts(id, rib.Tables[af]) } default: d.Destinations = make([]*api.Destination, 0, len(rib.Tables[af].GetDestinations())) for _, dst := range rib.Tables[af].GetDestinations() { - d.Destinations = append(d.Destinations, dst.ToApiStruct()) + if s := dst.ToApiStruct(id); s != nil { + d.Destinations = append(d.Destinations, s) + } } } grpcReq.ResponseCh <- &GrpcResponse{ @@ -1548,7 +1555,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { if found { r.Insert(table.CidrToRadixkey(key), &api.Destination{ Prefix: key, - Paths: []*api.Path{p.ToApiStruct()}, + Paths: []*api.Path{p.ToApiStruct(peer.TableID())}, }) } } @@ -1560,7 +1567,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { for _, p := range paths { results = append(results, &api.Destination{ Prefix: p.GetNlri().String(), - Paths: []*api.Path{p.ToApiStruct()}, + Paths: []*api.Path{p.ToApiStruct(peer.TableID())}, }) } } @@ -1608,9 +1615,11 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { } for _, peer := range peers { - pathList := peer.adjRibIn.PathList([]bgp.RouteFamily{grpcReq.RouteFamily}, false) - if peer.isRouteServerClient() { - pathList, _ = peer.ApplyPolicy(table.POLICY_DIRECTION_IN, pathList) + pathList := []*table.Path{} + for _, path := range peer.adjRibIn.PathList([]bgp.RouteFamily{grpcReq.RouteFamily}, false) { + if path = server.policy.ApplyPolicy(peer.ID(), table.POLICY_DIRECTION_IN, path); path != nil { + pathList = append(pathList, path.Clone(peer.conf.NeighborConfig.NeighborAddress, false)) + } } msgs = append(msgs, server.propagateUpdate(peer, pathList)...) } @@ -1826,24 +1835,6 @@ func (server *BgpServer) handleGrpcModNeighbor(grpcReq *GrpcRequest) (sMsgs []*S log.Infof("Peer %s is added", addr) } SetTcpMD5SigSockopts(listener(net.ParseIP(addr)), addr, arg.Peer.Conf.AuthPassword) - var loc *table.TableManager - if arg.Peer.RouteServer != nil { - if arg.Peer.RouteServer.RouteServerClient { - apitoRFlist := func(l []*api.AfiSafi) []bgp.RouteFamily { - rfList := []bgp.RouteFamily{} - for _, rf := range l { - k, _ := bgp.GetRouteFamily(rf.Name) - rfList = append(rfList, k) - } - return rfList - } - loc = table.NewTableManager(addr, apitoRFlist(arg.Peer.Afisafis.Afisafi), server.bgpConfig.Global.MplsLabelRange.MinLabel, server.bgpConfig.Global.MplsLabelRange.MaxLabel) - } else { - loc = server.globalRib - } - } else { - loc = server.globalRib - } apitoConfig := func(a *api.Peer) config.Neighbor { var pconf config.Neighbor if a.Conf != nil { @@ -1906,19 +1897,20 @@ func (server *BgpServer) handleGrpcModNeighbor(grpcReq *GrpcRequest) (sMsgs []*S return pconf } configneigh := apitoConfig(arg.Peer) - peer := NewPeer(server.bgpConfig.Global, configneigh, loc) - server.setPolicyByConfig(peer, configneigh.ApplyPolicy) + peer := NewPeer(server.bgpConfig.Global, configneigh, server.globalRib, server.policy) + server.setPolicyByConfig(peer.ID(), configneigh.ApplyPolicy) if peer.isRouteServerClient() { pathList := make([]*table.Path, 0) rfList := peer.configuredRFlist() for _, p := range server.neighborMap { - if p.isRouteServerClient() == true { - pathList = append(pathList, p.getAccepted(rfList)...) + if p.isRouteServerClient() { + for _, path := range p.getAccepted(rfList) { + pathList = append(pathList, server.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_IMPORT, path)) + } } } - pathList, _ = peer.ApplyPolicy(table.POLICY_DIRECTION_IMPORT, pathList) if len(pathList) > 0 { - peer.localRib.ProcessPaths(pathList) + server.globalRib.ProcessPaths(pathList) } } server.neighborMap[addr] = peer @@ -2064,7 +2056,7 @@ func (server *BgpServer) handleGrpcGetPolicy(grpcReq *GrpcRequest) error { func (server *BgpServer) policyInUse(x *table.Policy) bool { for _, peer := range server.neighborMap { for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_IN, table.POLICY_DIRECTION_EXPORT, table.POLICY_DIRECTION_EXPORT} { - for _, y := range peer.GetPolicy(dir) { + for _, y := range server.policy.GetPolicy(peer.ID(), dir) { if x.Name() == y.Name() { return true } @@ -2072,7 +2064,7 @@ func (server *BgpServer) policyInUse(x *table.Policy) bool { } } for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_EXPORT, table.POLICY_DIRECTION_EXPORT} { - for _, y := range server.globalRib.GetPolicy(dir) { + for _, y := range server.policy.GetPolicy(table.GLOBAL_RIB_NAME, dir) { if x.Name() == y.Name() { return true } @@ -2144,53 +2136,46 @@ func (server *BgpServer) handleGrpcModPolicy(grpcReq *GrpcRequest) error { return err } -type policyPoint interface { - GetDefaultPolicy(table.PolicyDirection) table.RouteType - GetPolicy(table.PolicyDirection) []*table.Policy - SetDefaultPolicy(table.PolicyDirection, table.RouteType) error - SetPolicy(table.PolicyDirection, []*table.Policy) error -} - -func (server *BgpServer) getPolicyInfo(a *api.PolicyAssignment) (policyPoint, table.PolicyDirection, error) { +func (server *BgpServer) getPolicyInfo(a *api.PolicyAssignment) (string, table.PolicyDirection, error) { switch a.Resource { case api.Resource_GLOBAL: switch a.Type { case api.PolicyType_IMPORT: - return server.globalRib, table.POLICY_DIRECTION_IMPORT, nil + return table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT, nil case api.PolicyType_EXPORT: - return server.globalRib, table.POLICY_DIRECTION_EXPORT, nil + return table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_EXPORT, nil default: - return nil, table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") } case api.Resource_LOCAL: peer, ok := server.neighborMap[a.Name] if !ok { - return nil, table.POLICY_DIRECTION_NONE, fmt.Errorf("not found peer %s", a.Name) + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("not found peer %s", a.Name) } switch a.Type { case api.PolicyType_IN: - return peer, table.POLICY_DIRECTION_IN, nil + return peer.ID(), table.POLICY_DIRECTION_IN, nil case api.PolicyType_IMPORT: - return peer, table.POLICY_DIRECTION_IMPORT, nil + return peer.ID(), table.POLICY_DIRECTION_IMPORT, nil case api.PolicyType_EXPORT: - return peer, table.POLICY_DIRECTION_EXPORT, nil + return peer.ID(), table.POLICY_DIRECTION_EXPORT, nil default: - return nil, table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid policy type") } default: - return nil, table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid resource type") + return "", table.POLICY_DIRECTION_NONE, fmt.Errorf("invalid resource type") } } func (server *BgpServer) handleGrpcGetPolicyAssignment(grpcReq *GrpcRequest) error { arg := grpcReq.Data.(*api.PolicyAssignment) - i, dir, err := server.getPolicyInfo(arg) + id, dir, err := server.getPolicyInfo(arg) if err != nil { return err } - arg.Default = i.GetDefaultPolicy(dir).ToApiStruct() - ps := i.GetPolicy(dir) + arg.Default = server.policy.GetDefaultPolicy(id, dir).ToApiStruct() + ps := server.policy.GetPolicy(id, dir) arg.Policies = make([]*api.Policy, 0, len(ps)) for _, x := range ps { arg.Policies = append(arg.Policies, x.ToApiStruct()) @@ -2204,12 +2189,12 @@ func (server *BgpServer) handleGrpcGetPolicyAssignment(grpcReq *GrpcRequest) err func (server *BgpServer) handleGrpcModPolicyAssignment(grpcReq *GrpcRequest) error { var err error var dir table.PolicyDirection - var i policyPoint + var id string policyMutex.Lock() defer policyMutex.Unlock() arg := grpcReq.Data.(*api.ModPolicyAssignmentArguments) assignment := arg.Assignment - i, dir, err = server.getPolicyInfo(assignment) + id, dir, err = server.getPolicyInfo(assignment) if err != nil { return err } @@ -2221,22 +2206,22 @@ func (server *BgpServer) handleGrpcModPolicyAssignment(grpcReq *GrpcRequest) err } ps = append(ps, p) } - cur := i.GetPolicy(dir) + cur := server.policy.GetPolicy(id, dir) switch arg.Operation { case api.Operation_ADD, api.Operation_REPLACE: if arg.Operation == api.Operation_REPLACE || cur == nil { - err = i.SetPolicy(dir, ps) + err = server.policy.SetPolicy(id, dir, ps) } else { - err = i.SetPolicy(dir, append(cur, ps...)) + err = server.policy.SetPolicy(id, dir, append(cur, ps...)) } if err != nil { return err } switch assignment.Default { case api.RouteAction_ACCEPT: - err = i.SetDefaultPolicy(dir, table.ROUTE_TYPE_ACCEPT) + err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_ACCEPT) case api.RouteAction_REJECT: - err = i.SetDefaultPolicy(dir, table.ROUTE_TYPE_REJECT) + err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_REJECT) } case api.Operation_DEL: n := make([]*table.Policy, 0, len(cur)-len(ps)) @@ -2252,13 +2237,13 @@ func (server *BgpServer) handleGrpcModPolicyAssignment(grpcReq *GrpcRequest) err n = append(n, x) } } - err = i.SetPolicy(dir, n) + err = server.policy.SetPolicy(id, dir, n) case api.Operation_DEL_ALL: - err = i.SetPolicy(dir, nil) + err = server.policy.SetPolicy(id, dir, nil) if err != nil { return err } - err = i.SetDefaultPolicy(dir, table.ROUTE_TYPE_NONE) + err = server.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_NONE) } return err } @@ -2473,7 +2458,7 @@ func (server *BgpServer) mkMrtRibMsgs(tbl *table.Table, t uint32) ([]*bgp.MRTMes var seq uint32 msgs := make([]*bgp.MRTMessage, 0, len(tbl.GetDestinations())) for _, dst := range tbl.GetDestinations() { - l := dst.GetKnownPathList() + l := dst.GetKnownPathList(table.GLOBAL_RIB_NAME) entries := make([]*bgp.RibEntry, 0, len(l)) for _, p := range l { // mrt doesn't assume to dump locally generated routes |