github.com/osrg/gobgp@v2.0.0+incompatible/internal/pkg/table/table.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  	"fmt"
    20  	"net"
    21  	"strings"
    22  	"unsafe"
    23  
    24  	"github.com/armon/go-radix"
    25  	"github.com/osrg/gobgp/pkg/packet/bgp"
    26  	log "github.com/sirupsen/logrus"
    27  )
    28  
    29  type LookupOption uint8
    30  
    31  const (
    32  	LOOKUP_EXACT LookupOption = iota
    33  	LOOKUP_LONGER
    34  	LOOKUP_SHORTER
    35  )
    36  
    37  type LookupPrefix struct {
    38  	Prefix string
    39  	LookupOption
    40  }
    41  
    42  type TableSelectOption struct {
    43  	ID             string
    44  	AS             uint32
    45  	LookupPrefixes []*LookupPrefix
    46  	VRF            *Vrf
    47  	adj            bool
    48  	Best           bool
    49  	MultiPath      bool
    50  }
    51  
    52  type Table struct {
    53  	routeFamily  bgp.RouteFamily
    54  	destinations map[string]*Destination
    55  }
    56  
    57  func NewTable(rf bgp.RouteFamily, dsts ...*Destination) *Table {
    58  	t := &Table{
    59  		routeFamily:  rf,
    60  		destinations: make(map[string]*Destination),
    61  	}
    62  	for _, dst := range dsts {
    63  		t.setDestination(dst)
    64  	}
    65  	return t
    66  }
    67  
    68  func (t *Table) GetRoutefamily() bgp.RouteFamily {
    69  	return t.routeFamily
    70  }
    71  
    72  func (t *Table) deletePathsByVrf(vrf *Vrf) []*Path {
    73  	pathList := make([]*Path, 0)
    74  	for _, dest := range t.destinations {
    75  		for _, p := range dest.knownPathList {
    76  			var rd bgp.RouteDistinguisherInterface
    77  			nlri := p.GetNlri()
    78  			switch nlri.(type) {
    79  			case *bgp.LabeledVPNIPAddrPrefix:
    80  				rd = nlri.(*bgp.LabeledVPNIPAddrPrefix).RD
    81  			case *bgp.LabeledVPNIPv6AddrPrefix:
    82  				rd = nlri.(*bgp.LabeledVPNIPv6AddrPrefix).RD
    83  			case *bgp.EVPNNLRI:
    84  				rd = nlri.(*bgp.EVPNNLRI).RD()
    85  			default:
    86  				return pathList
    87  			}
    88  			if p.IsLocal() && vrf.Rd.String() == rd.String() {
    89  				pathList = append(pathList, p.Clone(true))
    90  				break
    91  			}
    92  		}
    93  	}
    94  	return pathList
    95  }
    96  
    97  func (t *Table) deleteRTCPathsByVrf(vrf *Vrf, vrfs map[string]*Vrf) []*Path {
    98  	pathList := make([]*Path, 0)
    99  	if t.routeFamily != bgp.RF_RTC_UC {
   100  		return pathList
   101  	}
   102  	for _, target := range vrf.ImportRt {
   103  		lhs := target.String()
   104  		for _, dest := range t.destinations {
   105  			nlri := dest.GetNlri().(*bgp.RouteTargetMembershipNLRI)
   106  			rhs := nlri.RouteTarget.String()
   107  			if lhs == rhs && isLastTargetUser(vrfs, target) {
   108  				for _, p := range dest.knownPathList {
   109  					if p.IsLocal() {
   110  						pathList = append(pathList, p.Clone(true))
   111  						break
   112  					}
   113  				}
   114  			}
   115  		}
   116  	}
   117  	return pathList
   118  }
   119  
   120  func (t *Table) deleteDestByNlri(nlri bgp.AddrPrefixInterface) *Destination {
   121  	if dst := t.GetDestination(nlri); dst != nil {
   122  		t.deleteDest(dst)
   123  		return dst
   124  	}
   125  	return nil
   126  }
   127  
   128  func (t *Table) deleteDest(dest *Destination) {
   129  	destinations := t.GetDestinations()
   130  	delete(destinations, t.tableKey(dest.GetNlri()))
   131  	if len(destinations) == 0 {
   132  		t.destinations = make(map[string]*Destination)
   133  	}
   134  }
   135  
   136  func (t *Table) validatePath(path *Path) {
   137  	if path == nil {
   138  		log.WithFields(log.Fields{
   139  			"Topic": "Table",
   140  			"Key":   t.routeFamily,
   141  		}).Error("path is nil")
   142  	}
   143  	if path.GetRouteFamily() != t.routeFamily {
   144  		log.WithFields(log.Fields{
   145  			"Topic":      "Table",
   146  			"Key":        t.routeFamily,
   147  			"Prefix":     path.GetNlri().String(),
   148  			"ReceivedRf": path.GetRouteFamily().String(),
   149  		}).Error("Invalid path. RouteFamily mismatch")
   150  	}
   151  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH); attr != nil {
   152  		pathParam := attr.(*bgp.PathAttributeAsPath).Value
   153  		for _, as := range pathParam {
   154  			_, y := as.(*bgp.As4PathParam)
   155  			if !y {
   156  				log.WithFields(log.Fields{
   157  					"Topic": "Table",
   158  					"Key":   t.routeFamily,
   159  					"As":    as,
   160  				}).Fatal("AsPathParam must be converted to As4PathParam")
   161  			}
   162  		}
   163  	}
   164  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS4_PATH); attr != nil {
   165  		log.WithFields(log.Fields{
   166  			"Topic": "Table",
   167  			"Key":   t.routeFamily,
   168  		}).Fatal("AS4_PATH must be converted to AS_PATH")
   169  	}
   170  	if path.GetNlri() == nil {
   171  		log.WithFields(log.Fields{
   172  			"Topic": "Table",
   173  			"Key":   t.routeFamily,
   174  		}).Fatal("path's nlri is nil")
   175  	}
   176  }
   177  
   178  func (t *Table) getOrCreateDest(nlri bgp.AddrPrefixInterface) *Destination {
   179  	dest := t.GetDestination(nlri)
   180  	// If destination for given prefix does not exist we create it.
   181  	if dest == nil {
   182  		log.WithFields(log.Fields{
   183  			"Topic": "Table",
   184  			"Nlri":  nlri,
   185  		}).Debugf("create Destination")
   186  		dest = NewDestination(nlri, 64)
   187  		t.setDestination(dest)
   188  	}
   189  	return dest
   190  }
   191  
   192  func (t *Table) GetDestinations() map[string]*Destination {
   193  	return t.destinations
   194  }
   195  func (t *Table) setDestinations(destinations map[string]*Destination) {
   196  	t.destinations = destinations
   197  }
   198  func (t *Table) GetDestination(nlri bgp.AddrPrefixInterface) *Destination {
   199  	dest, ok := t.destinations[t.tableKey(nlri)]
   200  	if ok {
   201  		return dest
   202  	} else {
   203  		return nil
   204  	}
   205  }
   206  
   207  func (t *Table) GetLongerPrefixDestinations(key string) ([]*Destination, error) {
   208  	results := make([]*Destination, 0, len(t.GetDestinations()))
   209  	switch t.routeFamily {
   210  	case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC, bgp.RF_IPv4_MPLS, bgp.RF_IPv6_MPLS:
   211  		_, prefix, err := net.ParseCIDR(key)
   212  		if err != nil {
   213  			return nil, err
   214  		}
   215  		k := CidrToRadixkey(prefix.String())
   216  		r := radix.New()
   217  		for _, dst := range t.GetDestinations() {
   218  			r.Insert(AddrToRadixkey(dst.nlri), dst)
   219  		}
   220  		r.WalkPrefix(k, func(s string, v interface{}) bool {
   221  			results = append(results, v.(*Destination))
   222  			return false
   223  		})
   224  	default:
   225  		for _, dst := range t.GetDestinations() {
   226  			results = append(results, dst)
   227  		}
   228  	}
   229  	return results, nil
   230  }
   231  
   232  func (t *Table) GetEvpnDestinationsWithRouteType(typ string) ([]*Destination, error) {
   233  	var routeType uint8
   234  	switch strings.ToLower(typ) {
   235  	case "a-d":
   236  		routeType = bgp.EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY
   237  	case "macadv":
   238  		routeType = bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT
   239  	case "multicast":
   240  		routeType = bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG
   241  	case "esi":
   242  		routeType = bgp.EVPN_ETHERNET_SEGMENT_ROUTE
   243  	case "prefix":
   244  		routeType = bgp.EVPN_IP_PREFIX
   245  	default:
   246  		return nil, fmt.Errorf("unsupported evpn route type: %s", typ)
   247  	}
   248  	destinations := t.GetDestinations()
   249  	results := make([]*Destination, 0, len(destinations))
   250  	switch t.routeFamily {
   251  	case bgp.RF_EVPN:
   252  		for _, dst := range destinations {
   253  			if nlri, ok := dst.nlri.(*bgp.EVPNNLRI); !ok {
   254  				return nil, fmt.Errorf("invalid evpn nlri type detected: %T", dst.nlri)
   255  			} else if nlri.RouteType == routeType {
   256  				results = append(results, dst)
   257  			}
   258  		}
   259  	default:
   260  		for _, dst := range destinations {
   261  			results = append(results, dst)
   262  		}
   263  	}
   264  	return results, nil
   265  }
   266  
   267  func (t *Table) setDestination(dst *Destination) {
   268  	t.destinations[t.tableKey(dst.nlri)] = dst
   269  }
   270  
   271  func (t *Table) tableKey(nlri bgp.AddrPrefixInterface) string {
   272  	switch T := nlri.(type) {
   273  	case *bgp.IPAddrPrefix:
   274  		b := make([]byte, 5)
   275  		copy(b, T.Prefix.To4())
   276  		b[4] = T.Length
   277  		return *(*string)(unsafe.Pointer(&b))
   278  	case *bgp.IPv6AddrPrefix:
   279  		b := make([]byte, 17)
   280  		copy(b, T.Prefix.To16())
   281  		b[16] = T.Length
   282  		return *(*string)(unsafe.Pointer(&b))
   283  	}
   284  	return nlri.String()
   285  }
   286  
   287  func (t *Table) Bests(id string, as uint32) []*Path {
   288  	paths := make([]*Path, 0, len(t.destinations))
   289  	for _, dst := range t.destinations {
   290  		path := dst.GetBestPath(id, as)
   291  		if path != nil {
   292  			paths = append(paths, path)
   293  		}
   294  	}
   295  	return paths
   296  }
   297  
   298  func (t *Table) MultiBests(id string) [][]*Path {
   299  	paths := make([][]*Path, 0, len(t.destinations))
   300  	for _, dst := range t.destinations {
   301  		path := dst.GetMultiBestPath(id)
   302  		if path != nil {
   303  			paths = append(paths, path)
   304  		}
   305  	}
   306  	return paths
   307  }
   308  
   309  func (t *Table) GetKnownPathList(id string, as uint32) []*Path {
   310  	paths := make([]*Path, 0, len(t.destinations))
   311  	for _, dst := range t.destinations {
   312  		paths = append(paths, dst.GetKnownPathList(id, as)...)
   313  	}
   314  	return paths
   315  }
   316  
   317  func (t *Table) Select(option ...TableSelectOption) (*Table, error) {
   318  	id := GLOBAL_RIB_NAME
   319  	var vrf *Vrf
   320  	adj := false
   321  	prefixes := make([]*LookupPrefix, 0, len(option))
   322  	best := false
   323  	mp := false
   324  	as := uint32(0)
   325  	for _, o := range option {
   326  		if o.ID != "" {
   327  			id = o.ID
   328  		}
   329  		if o.VRF != nil {
   330  			vrf = o.VRF
   331  		}
   332  		adj = o.adj
   333  		prefixes = append(prefixes, o.LookupPrefixes...)
   334  		best = o.Best
   335  		mp = o.MultiPath
   336  		as = o.AS
   337  	}
   338  	dOption := DestinationSelectOption{ID: id, AS: as, VRF: vrf, adj: adj, Best: best, MultiPath: mp}
   339  	r := &Table{
   340  		routeFamily:  t.routeFamily,
   341  		destinations: make(map[string]*Destination),
   342  	}
   343  
   344  	if len(prefixes) != 0 {
   345  		switch t.routeFamily {
   346  		case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC:
   347  			f := func(prefixStr string) bool {
   348  				var nlri bgp.AddrPrefixInterface
   349  				if t.routeFamily == bgp.RF_IPv4_UC {
   350  					nlri, _ = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP, bgp.SAFI_UNICAST, prefixStr)
   351  				} else {
   352  					nlri, _ = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP6, bgp.SAFI_UNICAST, prefixStr)
   353  				}
   354  				if dst := t.GetDestination(nlri); dst != nil {
   355  					if d := dst.Select(dOption); d != nil {
   356  						r.setDestination(d)
   357  						return true
   358  					}
   359  				}
   360  				return false
   361  			}
   362  
   363  			for _, p := range prefixes {
   364  				key := p.Prefix
   365  				switch p.LookupOption {
   366  				case LOOKUP_LONGER:
   367  					ds, err := t.GetLongerPrefixDestinations(key)
   368  					if err != nil {
   369  						return nil, err
   370  					}
   371  					for _, dst := range ds {
   372  						if d := dst.Select(dOption); d != nil {
   373  							r.setDestination(d)
   374  						}
   375  					}
   376  				case LOOKUP_SHORTER:
   377  					addr, prefix, err := net.ParseCIDR(key)
   378  					if err != nil {
   379  						return nil, err
   380  					}
   381  					ones, _ := prefix.Mask.Size()
   382  					for i := ones; i >= 0; i-- {
   383  						_, prefix, _ := net.ParseCIDR(fmt.Sprintf("%s/%d", addr.String(), i))
   384  						f(prefix.String())
   385  					}
   386  				default:
   387  					if host := net.ParseIP(key); host != nil {
   388  						masklen := 32
   389  						if t.routeFamily == bgp.RF_IPv6_UC {
   390  							masklen = 128
   391  						}
   392  						for i := masklen; i >= 0; i-- {
   393  							_, prefix, err := net.ParseCIDR(fmt.Sprintf("%s/%d", key, i))
   394  							if err != nil {
   395  								return nil, err
   396  							}
   397  							if f(prefix.String()) {
   398  								break
   399  							}
   400  						}
   401  					} else {
   402  						f(key)
   403  					}
   404  				}
   405  			}
   406  		case bgp.RF_EVPN:
   407  			for _, p := range prefixes {
   408  				// Uses LookupPrefix.Prefix as EVPN Route Type string
   409  				ds, err := t.GetEvpnDestinationsWithRouteType(p.Prefix)
   410  				if err != nil {
   411  					return nil, err
   412  				}
   413  				for _, dst := range ds {
   414  					if d := dst.Select(dOption); d != nil {
   415  						r.setDestination(d)
   416  					}
   417  				}
   418  			}
   419  		default:
   420  			return nil, fmt.Errorf("route filtering is not supported for this family")
   421  		}
   422  	} else {
   423  		for _, dst := range t.GetDestinations() {
   424  			if d := dst.Select(dOption); d != nil {
   425  				r.setDestination(d)
   426  			}
   427  		}
   428  	}
   429  	return r, nil
   430  }
   431  
   432  type TableInfo struct {
   433  	NumDestination int
   434  	NumPath        int
   435  	NumAccepted    int
   436  }
   437  
   438  func (t *Table) Info(id string, as uint32) *TableInfo {
   439  	var numD, numP int
   440  	for _, d := range t.destinations {
   441  		ps := d.GetKnownPathList(id, as)
   442  		if len(ps) > 0 {
   443  			numD += 1
   444  			numP += len(ps)
   445  		}
   446  	}
   447  	return &TableInfo{
   448  		NumDestination: numD,
   449  		NumPath:        numP,
   450  	}
   451  }