mirror of
https://github.com/osrg/gobgp.git
synced 2024-05-11 05:55:10 +00:00
evpn: fix quadratic evpn mac-mobility handling
This patch adds a special case in the destination hashmap for EVPN Type-2 routes, to index them by MAC address. This allows for direct access to the destination struct, instead of iterating over all destination and all paths. In effect, this replaces an iteration over all known paths by a quick lookup to the MAC, leaving only an iteration to multiple paths to the same MAC (e.g. multihoming or through multiple VNIs). The practical effect is a reasonable convergence time for large EVPN instances. - before: 6m 7s - after: 11s The comparison was performed on a Xeon Silver 4209T, and an EVPN instance comprising of 13k EVPN type-2 routes. The time is measured by comparing the timestamp of the first and the last routes logged by the cli's monitor mode. Given the extreme difference, no further work was done for a more accurate measurment.
This commit is contained in:
@ -57,6 +57,10 @@ type Table struct {
|
||||
routeFamily bgp.RouteFamily
|
||||
destinations map[string]*Destination
|
||||
logger log.Logger
|
||||
// index of route distinguishers with paths to a specific MAC
|
||||
// this is a map[MAC address]map[RD]struct{}
|
||||
// this holds a map for a set of RD.
|
||||
macIndex map[string]map[string]struct{}
|
||||
}
|
||||
|
||||
func NewTable(logger log.Logger, rf bgp.RouteFamily, dsts ...*Destination) *Table {
|
||||
@ -64,6 +68,7 @@ func NewTable(logger log.Logger, rf bgp.RouteFamily, dsts ...*Destination) *Tabl
|
||||
routeFamily: rf,
|
||||
destinations: make(map[string]*Destination),
|
||||
logger: logger,
|
||||
macIndex: make(map[string]map[string]struct{}),
|
||||
}
|
||||
for _, dst := range dsts {
|
||||
t.setDestination(dst)
|
||||
@ -138,6 +143,20 @@ func (t *Table) deleteDest(dest *Destination) {
|
||||
if len(destinations) == 0 {
|
||||
t.destinations = make(map[string]*Destination)
|
||||
}
|
||||
|
||||
if nlri, ok := dest.nlri.(*bgp.EVPNNLRI); ok {
|
||||
if macadv, ok := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute); ok {
|
||||
mac := *(*string)(unsafe.Pointer(&macadv.MacAddress))
|
||||
serializedRD, _ := macadv.RD.Serialize()
|
||||
rd := *(*string)(unsafe.Pointer(&serializedRD))
|
||||
if rds, ok := t.macIndex[mac]; ok {
|
||||
delete(rds, rd)
|
||||
if len(rds) == 0 {
|
||||
delete(t.macIndex, mac)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) validatePath(path *Path) {
|
||||
@ -375,6 +394,19 @@ func (t *Table) GetMUPDestinationsWithRouteType(p string) ([]*Destination, error
|
||||
|
||||
func (t *Table) setDestination(dst *Destination) {
|
||||
t.destinations[t.tableKey(dst.nlri)] = dst
|
||||
|
||||
if nlri, ok := dst.nlri.(*bgp.EVPNNLRI); ok {
|
||||
if macadv, ok := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute); ok {
|
||||
mac := *(*string)(unsafe.Pointer(&macadv.MacAddress))
|
||||
serializedRD, _ := macadv.RD.Serialize()
|
||||
rd := *(*string)(unsafe.Pointer(&serializedRD))
|
||||
if rds, ok := t.macIndex[mac]; ok {
|
||||
rds[rd] = struct{}{}
|
||||
} else {
|
||||
t.macIndex[mac] = map[string]struct{}{rd: {}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) tableKey(nlri bgp.AddrPrefixInterface) string {
|
||||
@ -403,6 +435,17 @@ func (t *Table) tableKey(nlri bgp.AddrPrefixInterface) string {
|
||||
copy(b[8:24], T.Prefix.To16())
|
||||
b[24] = T.Length
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
// we need fast lookup to routes for a specific mac address for evpn mac mobility
|
||||
case *bgp.EVPNNLRI:
|
||||
switch U := T.RouteTypeData.(type) {
|
||||
case *bgp.EVPNMacIPAdvertisementRoute:
|
||||
b := make([]byte, 15)
|
||||
serializedRD, _ := U.RD.Serialize()
|
||||
copy(b, serializedRD)
|
||||
b[8] = bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT
|
||||
copy(b[9:15], U.MacAddress)
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
}
|
||||
return nlri.String()
|
||||
}
|
||||
@ -437,6 +480,23 @@ func (t *Table) GetKnownPathList(id string, as uint32) []*Path {
|
||||
return paths
|
||||
}
|
||||
|
||||
func (t *Table) GetKnownPathListWithMac(id string, as uint32, mac net.HardwareAddr) []*Path {
|
||||
var paths []*Path
|
||||
if rds, ok := t.macIndex[*(*string)(unsafe.Pointer(&mac))]; ok {
|
||||
for rd := range rds {
|
||||
b := make([]byte, 15)
|
||||
copy(b, rd)
|
||||
b[8] = bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT
|
||||
copy(b[9:15], mac)
|
||||
key := *(*string)(unsafe.Pointer(&b))
|
||||
if dst, ok := t.destinations[key]; ok {
|
||||
paths = append(paths, dst.GetKnownPathList(id, as)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func (t *Table) Select(option ...TableSelectOption) (*Table, error) {
|
||||
id := GLOBAL_RIB_NAME
|
||||
var vrf *Vrf
|
||||
@ -462,6 +522,7 @@ func (t *Table) Select(option ...TableSelectOption) (*Table, error) {
|
||||
r := &Table{
|
||||
routeFamily: t.routeFamily,
|
||||
destinations: make(map[string]*Destination),
|
||||
macIndex: make(map[string]map[string]struct{}),
|
||||
}
|
||||
|
||||
if len(prefixes) != 0 {
|
||||
|
@ -239,10 +239,7 @@ func (manager *TableManager) handleMacMobility(path *Path) []*Path {
|
||||
if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
|
||||
return nil
|
||||
}
|
||||
for _, path2 := range manager.GetPathList(GLOBAL_RIB_NAME, 0, []bgp.RouteFamily{bgp.RF_EVPN}) {
|
||||
if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
|
||||
continue
|
||||
}
|
||||
|
||||
f := func(p *Path) (bgp.EthernetSegmentIdentifier, uint32, net.HardwareAddr, int, net.IP) {
|
||||
nlri := p.GetNlri().(*bgp.EVPNNLRI)
|
||||
d := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute)
|
||||
@ -257,6 +254,11 @@ func (manager *TableManager) handleMacMobility(path *Path) []*Path {
|
||||
return d.ESI, d.ETag, d.MacAddress, seq, p.GetSource().Address
|
||||
}
|
||||
e1, et1, m1, s1, i1 := f(path)
|
||||
|
||||
for _, path2 := range manager.GetPathListWithMac(GLOBAL_RIB_NAME, 0, []bgp.RouteFamily{bgp.RF_EVPN}, m1) {
|
||||
if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
|
||||
continue
|
||||
}
|
||||
e2, et2, m2, s2, i2 := f(path2)
|
||||
if et1 == et2 && bytes.Equal(m1, m2) && !bytes.Equal(e1.Value, e2.Value) {
|
||||
if s1 > s2 || s1 == s2 && bytes.Compare(i1, i2) < 0 {
|
||||
@ -324,6 +326,14 @@ func (manager *TableManager) GetPathList(id string, as uint32, rfList []bgp.Rout
|
||||
return paths
|
||||
}
|
||||
|
||||
func (manager *TableManager) GetPathListWithMac(id string, as uint32, rfList []bgp.RouteFamily, mac net.HardwareAddr) []*Path {
|
||||
var paths []*Path
|
||||
for _, t := range manager.tables(rfList...) {
|
||||
paths = append(paths, t.GetKnownPathListWithMac(id, as, mac)...)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func (manager *TableManager) GetPathListWithNexthop(id string, rfList []bgp.RouteFamily, nexthop net.IP) []*Path {
|
||||
paths := make([]*Path, 0, manager.getDestinationCount(rfList))
|
||||
for _, rf := range rfList {
|
||||
|
Reference in New Issue
Block a user