github.com/osrg/gobgp@v2.0.0+incompatible/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  	log "github.com/sirupsen/logrus"
    26  
    27  	"github.com/osrg/gobgp/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  			attrs = append(attrs, attr)
    64  		}
    65  	}
    66  
    67  	listLen := len(adds) + len(dels)
    68  	if reach != nil {
    69  		listLen += len(reach.Value)
    70  	}
    71  
    72  	var hash uint32
    73  	if len(adds) > 0 || reach != nil {
    74  		total := bytes.NewBuffer(make([]byte, 0))
    75  		for _, a := range attrs {
    76  			b, _ := a.Serialize()
    77  			total.Write(b)
    78  		}
    79  		hash = farm.Hash32(total.Bytes())
    80  	}
    81  
    82  	pathList := make([]*Path, 0, listLen)
    83  	for _, nlri := range adds {
    84  		p := NewPath(peerInfo, nlri, false, attrs, timestamp, false)
    85  		p.SetHash(hash)
    86  		pathList = append(pathList, p)
    87  	}
    88  	if reach != nil {
    89  		reachAttrs := make([]bgp.PathAttributeInterface, len(attrs)+1)
    90  		copy(reachAttrs, attrs)
    91  		// we sort attributes when creating a bgp message from paths
    92  		reachAttrs[len(reachAttrs)-1] = reach
    93  
    94  		for _, nlri := range reach.Value {
    95  			p := NewPath(peerInfo, nlri, false, reachAttrs, timestamp, false)
    96  			p.SetHash(hash)
    97  			pathList = append(pathList, p)
    98  		}
    99  	}
   100  	for _, nlri := range dels {
   101  		p := NewPath(peerInfo, nlri, true, []bgp.PathAttributeInterface{}, timestamp, false)
   102  		pathList = append(pathList, p)
   103  	}
   104  	return pathList
   105  }
   106  
   107  type TableManager struct {
   108  	Tables map[bgp.RouteFamily]*Table
   109  	Vrfs   map[string]*Vrf
   110  	rfList []bgp.RouteFamily
   111  }
   112  
   113  func NewTableManager(rfList []bgp.RouteFamily) *TableManager {
   114  	t := &TableManager{
   115  		Tables: make(map[bgp.RouteFamily]*Table),
   116  		Vrfs:   make(map[string]*Vrf),
   117  		rfList: rfList,
   118  	}
   119  	for _, rf := range rfList {
   120  		t.Tables[rf] = NewTable(rf)
   121  	}
   122  	return t
   123  }
   124  
   125  func (manager *TableManager) GetRFlist() []bgp.RouteFamily {
   126  	return manager.rfList
   127  }
   128  
   129  func (manager *TableManager) AddVrf(name string, id uint32, rd bgp.RouteDistinguisherInterface, importRt, exportRt []bgp.ExtendedCommunityInterface, info *PeerInfo) ([]*Path, error) {
   130  	if _, ok := manager.Vrfs[name]; ok {
   131  		return nil, fmt.Errorf("vrf %s already exists", name)
   132  	}
   133  	log.WithFields(log.Fields{
   134  		"Topic":    "Vrf",
   135  		"Key":      name,
   136  		"Rd":       rd,
   137  		"ImportRt": importRt,
   138  		"ExportRt": exportRt,
   139  	}).Debugf("add vrf")
   140  	manager.Vrfs[name] = &Vrf{
   141  		Name:     name,
   142  		Id:       id,
   143  		Rd:       rd,
   144  		ImportRt: importRt,
   145  		ExportRt: exportRt,
   146  	}
   147  	msgs := make([]*Path, 0, len(importRt))
   148  	nexthop := "0.0.0.0"
   149  	for _, target := range importRt {
   150  		nlri := bgp.NewRouteTargetMembershipNLRI(info.AS, target)
   151  		pattr := make([]bgp.PathAttributeInterface, 0, 2)
   152  		pattr = append(pattr, bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP))
   153  		pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}))
   154  		msgs = append(msgs, NewPath(info, nlri, false, pattr, time.Now(), false))
   155  	}
   156  	return msgs, nil
   157  }
   158  
   159  func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) {
   160  	if _, ok := manager.Vrfs[name]; !ok {
   161  		return nil, fmt.Errorf("vrf %s not found", name)
   162  	}
   163  	msgs := make([]*Path, 0)
   164  	vrf := manager.Vrfs[name]
   165  	for _, t := range manager.Tables {
   166  		msgs = append(msgs, t.deletePathsByVrf(vrf)...)
   167  	}
   168  	log.WithFields(log.Fields{
   169  		"Topic":    "Vrf",
   170  		"Key":      vrf.Name,
   171  		"Rd":       vrf.Rd,
   172  		"ImportRt": vrf.ImportRt,
   173  		"ExportRt": vrf.ExportRt,
   174  	}).Debugf("delete vrf")
   175  	delete(manager.Vrfs, name)
   176  	rtcTable := manager.Tables[bgp.RF_RTC_UC]
   177  	msgs = append(msgs, rtcTable.deleteRTCPathsByVrf(vrf, manager.Vrfs)...)
   178  	return msgs, nil
   179  }
   180  
   181  func (tm *TableManager) update(newPath *Path) *Update {
   182  	t := tm.Tables[newPath.GetRouteFamily()]
   183  	t.validatePath(newPath)
   184  	dst := t.getOrCreateDest(newPath.GetNlri())
   185  	u := dst.Calculate(newPath)
   186  	if len(dst.knownPathList) == 0 {
   187  		t.deleteDest(dst)
   188  	}
   189  	return u
   190  }
   191  
   192  func (manager *TableManager) GetPathListByPeer(info *PeerInfo, rf bgp.RouteFamily) []*Path {
   193  	if t, ok := manager.Tables[rf]; ok {
   194  		pathList := make([]*Path, 0, len(t.destinations))
   195  		for _, dst := range t.destinations {
   196  			for _, p := range dst.knownPathList {
   197  				if p.GetSource().Equal(info) {
   198  					pathList = append(pathList, p)
   199  				}
   200  			}
   201  		}
   202  		return pathList
   203  	}
   204  	return nil
   205  }
   206  
   207  func (manager *TableManager) Update(newPath *Path) []*Update {
   208  	if newPath == nil || newPath.IsEOR() {
   209  		return nil
   210  	}
   211  
   212  	// Except for a special case with EVPN, we'll have one destination.
   213  	updates := make([]*Update, 0, 1)
   214  	family := newPath.GetRouteFamily()
   215  	if _, ok := manager.Tables[family]; ok {
   216  		updates = append(updates, manager.update(newPath))
   217  
   218  		if family == bgp.RF_EVPN {
   219  			for _, p := range manager.handleMacMobility(newPath) {
   220  				updates = append(updates, manager.update(p))
   221  			}
   222  		}
   223  	}
   224  	return updates
   225  }
   226  
   227  // EVPN MAC MOBILITY HANDLING
   228  //
   229  // RFC7432 15. MAC Mobility
   230  //
   231  // A PE receiving a MAC/IP Advertisement route for a MAC address with a
   232  // different Ethernet segment identifier and a higher sequence number
   233  // than that which it had previously advertised withdraws its MAC/IP
   234  // Advertisement route.
   235  // ......
   236  // If the PE is the originator of the MAC route and it receives the same
   237  // MAC address with the same sequence number that it generated, it will
   238  // compare its own IP address with the IP address of the remote PE and
   239  // will select the lowest IP.  If its own route is not the best one, it
   240  // will withdraw the route.
   241  func (manager *TableManager) handleMacMobility(path *Path) []*Path {
   242  	pathList := make([]*Path, 0)
   243  	nlri := path.GetNlri().(*bgp.EVPNNLRI)
   244  	if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
   245  		return nil
   246  	}
   247  	for _, path2 := range manager.GetPathList(GLOBAL_RIB_NAME, 0, []bgp.RouteFamily{bgp.RF_EVPN}) {
   248  		if !path2.IsLocal() || path2.GetNlri().(*bgp.EVPNNLRI).RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
   249  			continue
   250  		}
   251  		f := func(p *Path) (bgp.EthernetSegmentIdentifier, uint32, net.HardwareAddr, int, net.IP) {
   252  			nlri := p.GetNlri().(*bgp.EVPNNLRI)
   253  			d := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute)
   254  			ecs := p.GetExtCommunities()
   255  			seq := -1
   256  			for _, ec := range ecs {
   257  				if t, st := ec.GetTypes(); t == bgp.EC_TYPE_EVPN && st == bgp.EC_SUBTYPE_MAC_MOBILITY {
   258  					seq = int(ec.(*bgp.MacMobilityExtended).Sequence)
   259  					break
   260  				}
   261  			}
   262  			return d.ESI, d.ETag, d.MacAddress, seq, p.info.source.Address
   263  		}
   264  		e1, et1, m1, s1, i1 := f(path)
   265  		e2, et2, m2, s2, i2 := f(path2)
   266  		if et1 == et2 && bytes.Equal(m1, m2) && !bytes.Equal(e1.Value, e2.Value) {
   267  			if s1 > s2 || s1 == s2 && bytes.Compare(i1, i2) < 0 {
   268  				pathList = append(pathList, path2.Clone(true))
   269  			}
   270  		}
   271  	}
   272  	return pathList
   273  }
   274  
   275  func (manager *TableManager) tables(list ...bgp.RouteFamily) []*Table {
   276  	l := make([]*Table, 0, len(manager.Tables))
   277  	if len(list) == 0 {
   278  		for _, v := range manager.Tables {
   279  			l = append(l, v)
   280  		}
   281  		return l
   282  	}
   283  	for _, f := range list {
   284  		if t, ok := manager.Tables[f]; ok {
   285  			l = append(l, t)
   286  		}
   287  	}
   288  	return l
   289  }
   290  
   291  func (manager *TableManager) getDestinationCount(rfList []bgp.RouteFamily) int {
   292  	count := 0
   293  	for _, t := range manager.tables(rfList...) {
   294  		count += len(t.GetDestinations())
   295  	}
   296  	return count
   297  }
   298  
   299  func (manager *TableManager) GetBestPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path {
   300  	if SelectionOptions.DisableBestPathSelection {
   301  		// Note: If best path selection disabled, there is no best path.
   302  		return nil
   303  	}
   304  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   305  	for _, t := range manager.tables(rfList...) {
   306  		paths = append(paths, t.Bests(id, as)...)
   307  	}
   308  	return paths
   309  }
   310  
   311  func (manager *TableManager) GetBestMultiPathList(id string, rfList []bgp.RouteFamily) [][]*Path {
   312  	if !UseMultiplePaths.Enabled || SelectionOptions.DisableBestPathSelection {
   313  		// Note: If multi path not enabled or best path selection disabled,
   314  		// there is no best multi path.
   315  		return nil
   316  	}
   317  	paths := make([][]*Path, 0, manager.getDestinationCount(rfList))
   318  	for _, t := range manager.tables(rfList...) {
   319  		paths = append(paths, t.MultiBests(id)...)
   320  	}
   321  	return paths
   322  }
   323  
   324  func (manager *TableManager) GetPathList(id string, as uint32, rfList []bgp.RouteFamily) []*Path {
   325  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   326  	for _, t := range manager.tables(rfList...) {
   327  		paths = append(paths, t.GetKnownPathList(id, as)...)
   328  	}
   329  	return paths
   330  }
   331  
   332  func (manager *TableManager) GetPathListWithNexthop(id string, rfList []bgp.RouteFamily, nexthop net.IP) []*Path {
   333  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   334  	for _, rf := range rfList {
   335  		if t, ok := manager.Tables[rf]; ok {
   336  			for _, path := range t.GetKnownPathList(id, 0) {
   337  				if path.GetNexthop().Equal(nexthop) {
   338  					paths = append(paths, path)
   339  				}
   340  			}
   341  		}
   342  	}
   343  	return paths
   344  }
   345  
   346  func (manager *TableManager) GetPathListWithSource(id string, rfList []bgp.RouteFamily, source *PeerInfo) []*Path {
   347  	paths := make([]*Path, 0, manager.getDestinationCount(rfList))
   348  	for _, rf := range rfList {
   349  		if t, ok := manager.Tables[rf]; ok {
   350  			for _, path := range t.GetKnownPathList(id, 0) {
   351  				if path.GetSource().Equal(source) {
   352  					paths = append(paths, path)
   353  				}
   354  			}
   355  		}
   356  	}
   357  	return paths
   358  }
   359  
   360  func (manager *TableManager) GetDestination(path *Path) *Destination {
   361  	if path == nil {
   362  		return nil
   363  	}
   364  	family := path.GetRouteFamily()
   365  	t, ok := manager.Tables[family]
   366  	if !ok {
   367  		return nil
   368  	}
   369  	return t.GetDestination(path.GetNlri())
   370  }
   371  
   372  func (manager *TableManager) TableInfo(id string, as uint32, family bgp.RouteFamily) (*TableInfo, error) {
   373  	t, ok := manager.Tables[family]
   374  	if !ok {
   375  		return nil, fmt.Errorf("address family %s is not configured", family)
   376  	}
   377  	return t.Info(id, as), nil
   378  }