diff options
-rw-r--r-- | server/peer.go | 2 | ||||
-rw-r--r-- | server/server.go | 102 | ||||
-rw-r--r-- | table/table_manager.go | 61 |
3 files changed, 162 insertions, 3 deletions
diff --git a/server/peer.go b/server/peer.go index 39859c3c..4bda6c9d 100644 --- a/server/peer.go +++ b/server/peer.go @@ -195,7 +195,7 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) ([]*table.Path, bool, []*b func (peer *Peer) getBests(loc *LocalRib) []*table.Path { pathList := []*table.Path{} for _, rf := range peer.configuredRFlist() { - for _, paths := range loc.rib.GetPathList(rf) { + for _, paths := range loc.rib.GetBestPathList(rf) { pathList = append(pathList, paths) } } diff --git a/server/server.go b/server/server.go index 984762e6..78a15da9 100644 --- a/server/server.go +++ b/server/server.go @@ -16,6 +16,7 @@ package server import ( + "bytes" "fmt" log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/api" @@ -584,6 +585,9 @@ func (server *BgpServer) propagateUpdate(neighborAddress string, RouteServerClie continue } f := filterpath(targetPeer, sendPathList) + if len(f) == 0 { + continue + } for _, path := range f { path.UpdatePathAttrs(&server.bgpConfig.Global, &targetPeer.conf) } @@ -735,12 +739,84 @@ func (server *BgpServer) checkNeighborRequest(grpcReq *GrpcRequest) (*Peer, erro return peer, nil } -func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path { +// EVPN MAC MOBILITY HANDLING +// +// We don't have multihoming function now, so ignore +// ESI comparison. +// +// RFC7432 15. MAC Mobility +// +// A PE detecting a locally attached MAC address for which it had +// previously received a MAC/IP Advertisement route with the same zero +// Ethernet segment identifier (single-homed scenarios) advertises it +// with a MAC Mobility extended community attribute with the sequence +// number set properly. In the case of single-homed scenarios, there +// is no need for ESI comparison. + +func getMacMobilityExtendedCommunity(etag uint32, mac net.HardwareAddr, evpnPaths []*table.Path) *bgp.MacMobilityExtended { + seqs := make([]struct { + seq int + isLocal bool + }, 0) + + for _, path := range evpnPaths { + nlri := path.GetNlri().(*bgp.EVPNNLRI) + target, ok := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute) + if !ok { + continue + } + if target.ETag == etag && bytes.Equal(target.MacAddress, mac) { + found := false + for _, ec := range path.GetExtCommunities() { + if t, st := ec.GetTypes(); t == bgp.EC_TYPE_EVPN && st == bgp.EC_SUBTYPE_MAC_MOBILITY { + seqs = append(seqs, struct { + seq int + isLocal bool + }{int(ec.(*bgp.MacMobilityExtended).Sequence), path.IsLocal()}) + found = true + break + } + } + + if !found { + seqs = append(seqs, struct { + seq int + isLocal bool + }{-1, path.IsLocal()}) + } + } + } + + if len(seqs) > 0 { + newSeq := -2 + var isLocal bool + for _, seq := range seqs { + if seq.seq > newSeq { + newSeq = seq.seq + isLocal = seq.isLocal + } + } + + if !isLocal { + newSeq += 1 + } + + if newSeq != -1 { + return &bgp.MacMobilityExtended{ + Sequence: uint32(newSeq), + } + } + } + return nil +} + +func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path { var isWithdraw bool var nlri bgp.AddrPrefixInterface result := &GrpcResponse{} pattr := make([]bgp.PathAttributeInterface, 0) + extcomms := make([]bgp.ExtendedCommunityInterface, 0) args, ok := grpcReq.Data.(*api.ModPathArguments) if !ok { @@ -774,6 +850,11 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t } switch p.GetType() { + case bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: + value := p.(*bgp.PathAttributeExtendedCommunities).Value + if len(value) > 0 { + extcomms = append(extcomms, value...) + } case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI: value := p.(*bgp.PathAttributeMpReachNLRI).Value if len(value) != 1 { @@ -792,6 +873,23 @@ func handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*t goto ERR } + if bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()) == bgp.RF_EVPN { + evpnNlri := nlri.(*bgp.EVPNNLRI) + if evpnNlri.RouteType == bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { + macIpAdv := evpnNlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute) + etag := macIpAdv.ETag + mac := macIpAdv.MacAddress + paths := server.localRibMap[GLOBAL_RIB_NAME].rib.GetBestPathList(bgp.RF_EVPN) + if m := getMacMobilityExtendedCommunity(etag, mac, paths); m != nil { + extcomms = append(extcomms, m) + } + } + } + + if len(extcomms) > 0 { + pattr = append(pattr, bgp.NewPathAttributeExtendedCommunities(extcomms)) + } + return []*table.Path{table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), args.NoImplicitWithdraw)} ERR: grpcReq.ResponseCh <- result @@ -819,7 +917,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { AS: server.bgpConfig.Global.GlobalConfig.As, LocalID: server.bgpConfig.Global.GlobalConfig.RouterId, } - pathList := handleGlobalRibRequest(grpcReq, pi) + pathList := server.handleGlobalRibRequest(grpcReq, pi) if len(pathList) > 0 { msgs = append(msgs, server.propagateUpdate("", false, pathList)...) grpcReq.ResponseCh <- &GrpcResponse{} diff --git a/table/table_manager.go b/table/table_manager.go index 4b164228..2b34f2c6 100644 --- a/table/table_manager.go +++ b/table/table_manager.go @@ -16,8 +16,10 @@ package table import ( + "bytes" log "github.com/Sirupsen/logrus" "github.com/osrg/gobgp/packet" + "net" "reflect" "time" ) @@ -236,11 +238,58 @@ func (manager *TableManager) ProcessPaths(pathList []*Path) ([]*Path, error) { rf := path.GetRouteFamily() if t, ok := manager.Tables[rf]; ok { destinationList = append(destinationList, t.insert(path)) + if rf == bgp.RF_EVPN { + dsts := manager.handleMacMobility(path) + if len(dsts) > 0 { + destinationList = append(destinationList, dsts...) + } + } } } return manager.calculate(destinationList) } +// EVPN MAC MOBILITY HANDLING +// +// RFC7432 15. MAC Mobility +// +// A PE receiving a MAC/IP Advertisement route for a MAC address with a +// different Ethernet segment identifier and a higher sequence number +// than that which it had previously advertised withdraws its MAC/IP +// Advertisement route. +func (manager *TableManager) handleMacMobility(path *Path) []*Destination { + dsts := make([]*Destination, 0) + nlri := path.GetNlri().(*bgp.EVPNNLRI) + if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { + return nil + } + for _, path2 := range manager.GetPathList(bgp.RF_EVPN) { + if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT { + continue + } + f := func(p *Path) (uint32, net.HardwareAddr, int) { + nlri := p.GetNlri().(*bgp.EVPNNLRI) + d := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute) + ecs := p.GetExtCommunities() + seq := -1 + for _, ec := range ecs { + if t, st := ec.GetTypes(); t == bgp.EC_TYPE_EVPN && st == bgp.EC_SUBTYPE_MAC_MOBILITY { + seq = int(ec.(*bgp.MacMobilityExtended).Sequence) + break + } + } + return d.ETag, d.MacAddress, seq + } + e1, m1, s1 := f(path) + e2, m2, s2 := f(path2) + if e1 == e2 && bytes.Equal(m1, m2) && s1 > s2 { + path2.IsWithdraw = true + dsts = append(dsts, manager.Tables[bgp.RF_EVPN].insert(path2)) + } + } + return dsts +} + func (manager *TableManager) GetPathList(rf bgp.RouteFamily) []*Path { if _, ok := manager.Tables[rf]; !ok { return []*Path{} @@ -248,6 +297,18 @@ func (manager *TableManager) GetPathList(rf bgp.RouteFamily) []*Path { destinations := manager.Tables[rf].GetDestinations() paths := make([]*Path, 0, len(destinations)) for _, dest := range destinations { + paths = append(paths, dest.knownPathList...) + } + return paths +} + +func (manager *TableManager) GetBestPathList(rf bgp.RouteFamily) []*Path { + if _, ok := manager.Tables[rf]; !ok { + return []*Path{} + } + destinations := manager.Tables[rf].GetDestinations() + paths := make([]*Path, 0, len(destinations)) + for _, dest := range destinations { paths = append(paths, dest.GetBestPath()) } return paths |