github.com/osrg/gobgp/v3@v3.30.0/internal/pkg/table/table_manager.go (about)

     1  // Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package table
    17  
    18  import (
    19  	"bytes"
    20  	"fmt"
    21  	"net"
    22  	"time"
    23  
    24  	farm "github.com/dgryski/go-farm"
    25  
    26  	"github.com/osrg/gobgp/v3/pkg/log"
    27  	"github.com/osrg/gobgp/v3/pkg/packet/bgp"
    28  )
    29  
    30  const (
    31  	GLOBAL_RIB_NAME = "global"
    32  )
    33  
    34  func ProcessMessage(m *bgp.BGPMessage, peerInfo *PeerInfo, timestamp time.Time) []*Path {
    35  	update := m.Body.(*bgp.BGPUpdate)
    36  
    37  	if y, f := update.IsEndOfRib(); y {
    38  		// this message has no normal updates or withdrawals.
    39  		return []*Path{NewEOR(f)}
    40  	}
    41  
    42  	adds := make([]bgp.AddrPrefixInterface, 0, len(update.NLRI))
    43  	for _, nlri := range update.NLRI {
    44  		adds = append(adds, nlri)
    45  	}
    46  
    47  	dels := make([]bgp.AddrPrefixInterface, 0, len(update.WithdrawnRoutes))
    48  	for _, nlri := range update.WithdrawnRoutes {
    49  		dels = append(dels, nlri)
    50  	}
    51  
    52  	attrs := make([]bgp.PathAttributeInterface, 0, len(update.PathAttributes))
    53  	var reach *bgp.PathAttributeMpReachNLRI
    54  	for _, attr := range update.PathAttributes {
    55  		switch a := attr.(type) {
    56  		case *bgp.PathAttributeMpReachNLRI:
    57  			reach = a
    58  		case *bgp.PathAttributeMpUnreachNLRI:
    59  			l := make([]bgp.AddrPrefixInterface, 0, len(a.Value))
    60  			l = append(l, a.Value...)
    61  			dels = append(dels, l...)
    62  		default:
    63  			// update msg may not contain next_hop (type:3) in attr
    64  			// due to it uses MpReachNLRI and it also has empty update.NLRI
    65  			attrs = append(attrs, attr)
    66  		}
    67  	}
    68  
    69  	listLen := len(adds) + len(dels)
    70  	if reach != nil {
    71  		listLen += len(reach.Value)
    72  	}
    73  
    74  	var hash uint32
    75  	if len(adds) > 0 || reach != nil {
    76  		total := bytes.NewBuffer(make([]byte, 0))
    77  		for _, a := range attrs {
    78  			b, _ := a.Serialize()
    79  			total.Write(b)
    80  		}
    81  		hash = farm.Hash32(total.Bytes())
    82  	}
    83  
    84  	pathList := make([]*Path, 0, listLen)
    85  	for _, nlri := range adds {
    86  		p := NewPath(peerInfo, nlri, false, attrs, timestamp, false)
    87  		p.SetHash(hash)
    88  		pathList = append(pathList, p)
    89  	}
    90  	if reach != nil {
    91  		reachAttrs := make([]bgp.PathAttributeInterface, len(attrs)+1)
    92  		copy(reachAttrs, attrs)
    93  		// we sort attributes when creating a bgp message from paths
    94  		reachAttrs[len(reachAttrs)-1] = reach
    95  
    96  		for _, nlri := range reach.Value {
    97  			// when build path from reach
    98  			// reachAttrs might not contain next_hop if `attrs` does not have one
    99  			// this happens when a MP peer send update to gobgp
   100  			// However nlri is always populated because how we build the path
   101  			// path.info{nlri: nlri}
   102  			p := NewPath(peerInfo, nlri, false, reachAttrs, timestamp, false)
   103  			p.SetHash(hash)
   104  			pathList = append(pathList, p)
   105  		}
   106  	}
   107  	for _, nlri := range dels {
   108  		p := NewPath(peerInfo, nlri, true, []bgp.PathAttributeInterface{}, timestamp, false)
   109  		pathList = append(pathList, p)
   110  	}
   111  	return pathList
   112  }
   113  
   114  type TableManager struct {
   115  	Tables map[bgp.RouteFamily]*Table
   116  	Vrfs   map[string]*Vrf
   117  	rfList []bgp.RouteFamily
   118  	logger log.Logger
   119  }
   120  
   121  func NewTableManager(logger log.Logger, rfList []bgp.RouteFamily) *TableManager {
   122  	t := &TableManager{
   123  		Tables: make(map[bgp.RouteFamily]*Table),
   124  		Vrfs:   make(map[string]*Vrf),
   125  		rfList: rfList,
   126  		logger: logger,
   127  	}
   128  	for _, rf := range rfList {
   129  		t.Tables[rf] = NewTable(logger, rf)
   130  	}
   131  	return t
   132  }
   133  
   134  func (manager *TableManager) GetRFlist() []bgp.RouteFamily {
   135  	return manager.rfList
   136  }
   137  
   138  func (manager *TableManager) AddVrf(name string, id uint32, rd bgp.RouteDistinguisherInterface, importRt, exportRt []bgp.ExtendedCommunityInterface, info *PeerInfo) ([]*Path, error) {
   139  	if _, ok := manager.Vrfs[name]; ok {
   140  		return nil, fmt.Errorf("vrf %s already exists", name)
   141  	}
   142  	manager.logger.Debug("add vrf",
   143  		log.Fields{
   144  			"Topic":    "Vrf",
   145  			"Key":      name,
   146  			"Rd":       rd,
   147  			"ImportRt": importRt,
   148  			"ExportRt": exportRt})
   149  	manager.Vrfs[name] = &Vrf{
   150  		Name:     name,
   151  		Id:       id,
   152  		Rd:       rd,
   153  		ImportRt: importRt,
   154  		ExportRt: exportRt,
   155  	}
   156  	msgs := make([]*Path, 0, len(importRt))
   157  	nexthop := "0.0.0.0"
   158  	for _, target := range importRt {
   159  		nlri := bgp.NewRouteTargetMembershipNLRI(info.AS, target)
   160  		pattr := make([]bgp.PathAttributeInterface, 0, 2)
   161  		pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP))
   162  		pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}))
   163  		msgs = append(msgs, NewPath(info, nlri, false, pattr, time.Now(), false))
   164  	}
   165  	return msgs, nil
   166  }
   167  
   168  func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) {
   169  	if _, ok := manager.Vrfs[name]; !ok {
   170  		return nil, fmt.Errorf("vrf %s not found", name)
   171  	}
   172  	msgs := make([]*Path, 0)
   173  	vrf := manager.Vrfs[name]
   174  	for _, t := range manager.Tables {
   175  		msgs = append(msgs, t.deletePathsByVrf(vrf)...)
   176  	}
   177  	manager.logger.Debug("delete vrf",
   178  		log.Fields{
   179  			"Topic":     "Vrf",
   180  			"Key":       vrf.Name,
   181  			"Rd":        vrf.Rd,
   182  			"ImportRt":  vrf.ImportRt,
   183  			"ExportRt":  vrf.ExportRt,
   184  			"MplsLabel": vrf.MplsLabel})
   185  	delete(manager.Vrfs, name)
   186  	rtcTable := manager.Tables[bgp.RF_RTC_UC]
   187  	msgs = append(msgs, rtcTable.deleteRTCPathsByVrf(vrf, manager.Vrfs)...)
   188  	return msgs, nil
   189  }
   190  
   191  func (manager *TableManager) Update(newPath *Path) []*Update {
   192  	if newPath == nil || newPath.IsEOR() {
   193  		return nil
   194  	}
   195  
   196  	// Except for a special case with EVPN, we'll have one destination.
   197  	updates := make([]*Update, 0, 1)
   198  	family := newPath.GetRouteFamily()
   199  	if table, ok := manager.Tables[family]; ok {
   200  		updates = append(updates, table.update(newPath))
   201  
   202  		if family == bgp.RF_EVPN {
   203  			for _, p := range manager.handleMacMobility(newPath) {
   204  				updates = append(updates, table.update(p))
   205  			}
   206  		}
   207  	}
   208  	return updates
   209  }
   210  
   211  // EVPN MAC MOBILITY HANDLING
   212  //
   213  // RFC7432 15. MAC Mobility
   214  //
   215  // A PE receiving a MAC/IP Advertisement route for a MAC address with a
   216  // different Ethernet segment identifier and a higher sequence number
   217  // than that which it had previously advertised withdraws its MAC/IP
   218  // Advertisement route.
   219  // ......
   220  // If the PE is the originator of the MAC route and it receives the same
   221  // MAC address with the same sequence number that it generated, it will
   222  // compare its own IP address with the IP address of the remote PE and
   223  // will select the lowest IP.  If its own route is not the best one, it
   224  // will withdraw the route.
   225  func (manager *TableManager) handleMacMobility(path *Path) []*Path {
   226  	pathList := make([]*Path, 0)
   227  	nlri := path.GetNlri().(*bgp.EVPNNLRI)
   228  	if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
   229  		return nil
   230  	}
   231  
   232  	f := func(p *Path) (bgp.EthernetSegmentIdentifier, uint32, net.HardwareAddr, int, net.IP) {
   233  		nlri := p.GetNlri().(*bgp.EVPNNLRI)
   234  		d := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute)
   235  		ecs := p.GetExtCommunities()
   236  		seq := -1
   237  		for _, ec := range ecs {
   238  			if t, st := ec.GetTypes(); t == bgp.EC_TYPE_EVPN && st == bgp.EC_SUBTYPE_MAC_MOBILITY {
   239  				seq = int(ec.(*bgp.MacMobilityExtended).Sequence)
   240  				break
   241  			}
   242  		}
   243  		return d.ESI, d.ETag, d.MacAddress, seq, p.GetSource().Address
   244  	}
   245  	e1, et1, m1, s1, i1 := f(path)
   246  
   247  	// Extract the route targets to scope the lookup to the MAC-VRF with the MAC address.
   248  	// This will help large EVPN instances where a single MAC is present in a lot of MAC-VRFs (e.g.
   249  	// an anycast router).
   250  	// A route may have multiple route targets, to target multiple MAC-VRFs (e.g. in both an L2VNI
   251  	// and L3VNI in the VXLAN case).
   252  	var paths []*Path
   253  	for _, ec := range path.GetRouteTargets() {
   254  		paths = append(paths, manager.GetPathListWithMac(GLOBAL_RIB_NAME, 0, []bgp.RouteFamily{bgp.RF_EVPN}, ec, m1)...)
   255  	}
   256  
   257  	for _, path2 := range paths {
   258  		if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
   259  			continue
   260  		}
   261  		e2, et2, m2, s2, i2 := f(path2)
   262  		if et1 == et2 && bytes.Equal(m1, m2) && !bytes.Equal(e1.Value, e2.Value) {
   263  			if s1 > s2 || s1 == s2 && bytes.Compare(i1, i2) < 0 {
   264  				pathList = append(pathList, path2.Clone(true))
   265  			}
   266  		}
   267  	}
   268  	return pathList
   269  }
   270  
   271  func (manager *TableManager) tables(list ...bgp.RouteFamily) []*Table {
   272  	l := make([]*Table, 0, len(manager.Tables))
   273  	if len(list) == 0 {
   274  		for _, v := range manager.Tables {
   275  			l = append(l, v)
   276  		}
   277  		return l
   278  	}
   279  	for _, f := range list {
   280  		if t, ok := manager.Tables[f]; ok {
   281  			l = append(l, t)
   282  		}
   283  	}
   284  	return l
   285  }
   286  
   287  func (manager *TableManager) getDestinationCount(rfList []bgp.RouteFamily) int {
   288  	count := 0
   289  	for _, t := range manager.tables(rfList...) {
   290  		count += len(t.GetDestinations())
   291  	}
   292  	return count
   293  }
   294  
   295  func (manager *TableManager) GetBestPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path {
   296  	if SelectionOptions.DisableBestPathSelection {
   297  		// Note: If best path selection disabled, there is no best path.
   298  		return nil
   299  	}
   300  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   301  	for _, t := range manager.tables(rfList...) {
   302  		paths = append(paths, t.Bests(id, as)...)
   303  	}
   304  	return paths
   305  }
   306  
   307  func (manager *TableManager) GetBestMultiPathList(id string, rfList []bgp.RouteFamily) [][]*Path {
   308  	if !UseMultiplePaths.Enabled || SelectionOptions.DisableBestPathSelection {
   309  		// Note: If multi path not enabled or best path selection disabled,
   310  		// there is no best multi path.
   311  		return nil
   312  	}
   313  	paths := make([][]*Path, 0, manager.getDestinationCount(rfList))
   314  	for _, t := range manager.tables(rfList...) {
   315  		paths = append(paths, t.MultiBests(id)...)
   316  	}
   317  	return paths
   318  }
   319  
   320  func (manager *TableManager) GetPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path {
   321  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   322  	for _, t := range manager.tables(rfList...) {
   323  		paths = append(paths, t.GetKnownPathList(id, as)...)
   324  	}
   325  	return paths
   326  }
   327  
   328  func (manager *TableManager) GetPathListWithMac(id string, as uint32, rfList []bgp.RouteFamily, rt bgp.ExtendedCommunityInterface, mac net.HardwareAddr) []*Path {
   329  	var paths []*Path
   330  	for _, t := range manager.tables(rfList...) {
   331  		paths = append(paths, t.GetKnownPathListWithMac(id, as, rt, mac, false)...)
   332  	}
   333  	return paths
   334  }
   335  
   336  func (manager *TableManager) GetPathListWithNexthop(id string, rfList []bgp.RouteFamily, nexthop net.IP) []*Path {
   337  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   338  	for _, rf := range rfList {
   339  		if t, ok := manager.Tables[rf]; ok {
   340  			for _, path := range t.GetKnownPathList(id, 0) {
   341  				if path.GetNexthop().Equal(nexthop) {
   342  					paths = append(paths, path)
   343  				}
   344  			}
   345  		}
   346  	}
   347  	return paths
   348  }
   349  
   350  func (manager *TableManager) GetPathListWithSource(id string, rfList []bgp.RouteFamily, source *PeerInfo) []*Path {
   351  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   352  	for _, rf := range rfList {
   353  		if t, ok := manager.Tables[rf]; ok {
   354  			for _, path := range t.GetKnownPathList(id, 0) {
   355  				if path.GetSource().Equal(source) {
   356  					paths = append(paths, path)
   357  				}
   358  			}
   359  		}
   360  	}
   361  	return paths
   362  }
   363  
   364  func (manager *TableManager) GetDestination(path *Path) *Destination {
   365  	if path == nil {
   366  		return nil
   367  	}
   368  	family := path.GetRouteFamily()
   369  	t, ok := manager.Tables[family]
   370  	if !ok {
   371  		return nil
   372  	}
   373  	return t.GetDestination(path.GetNlri())
   374  }