github.com/osrg/gobgp/v3@v3.30.0/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  	"math/bits"
    21  	"net"
    22  	"strconv"
    23  	"strings"
    24  	"unsafe"
    25  
    26  	"github.com/k-sone/critbitgo"
    27  
    28  	"github.com/osrg/gobgp/v3/pkg/log"
    29  	"github.com/osrg/gobgp/v3/pkg/packet/bgp"
    30  )
    31  
    32  type LookupOption uint8
    33  
    34  const (
    35  	LOOKUP_EXACT LookupOption = iota
    36  	LOOKUP_LONGER
    37  	LOOKUP_SHORTER
    38  )
    39  
    40  type LookupPrefix struct {
    41  	Prefix string
    42  	RD     string
    43  	LookupOption
    44  }
    45  
    46  type TableSelectOption struct {
    47  	ID             string
    48  	AS             uint32
    49  	LookupPrefixes []*LookupPrefix
    50  	VRF            *Vrf
    51  	adj            bool
    52  	Best           bool
    53  	MultiPath      bool
    54  }
    55  
    56  type Table struct {
    57  	routeFamily  bgp.RouteFamily
    58  	destinations map[string]*Destination
    59  	logger       log.Logger
    60  	// index of evpn prefixes with paths to a specific MAC in a MAC-VRF
    61  	// this is a map[rt, MAC address]map[prefix]struct{}
    62  	// this holds a map for a set of prefixes.
    63  	macIndex map[string]map[string]struct{}
    64  }
    65  
    66  func NewTable(logger log.Logger, rf bgp.RouteFamily, dsts ...*Destination) *Table {
    67  	t := &Table{
    68  		routeFamily:  rf,
    69  		destinations: make(map[string]*Destination),
    70  		logger:       logger,
    71  		macIndex:     make(map[string]map[string]struct{}),
    72  	}
    73  	for _, dst := range dsts {
    74  		t.setDestination(dst)
    75  	}
    76  	return t
    77  }
    78  
    79  func (t *Table) GetRoutefamily() bgp.RouteFamily {
    80  	return t.routeFamily
    81  }
    82  
    83  func (t *Table) deletePathsByVrf(vrf *Vrf) []*Path {
    84  	pathList := make([]*Path, 0)
    85  	for _, dest := range t.destinations {
    86  		for _, p := range dest.knownPathList {
    87  			var rd bgp.RouteDistinguisherInterface
    88  			nlri := p.GetNlri()
    89  			switch v := nlri.(type) {
    90  			case *bgp.LabeledVPNIPAddrPrefix:
    91  				rd = v.RD
    92  			case *bgp.LabeledVPNIPv6AddrPrefix:
    93  				rd = v.RD
    94  			case *bgp.EVPNNLRI:
    95  				rd = v.RD()
    96  			case *bgp.MUPNLRI:
    97  				rd = v.RD()
    98  			default:
    99  				return pathList
   100  			}
   101  			if p.IsLocal() && vrf.Rd.String() == rd.String() {
   102  				pathList = append(pathList, p.Clone(true))
   103  				break
   104  			}
   105  		}
   106  	}
   107  	return pathList
   108  }
   109  
   110  func (t *Table) deleteRTCPathsByVrf(vrf *Vrf, vrfs map[string]*Vrf) []*Path {
   111  	pathList := make([]*Path, 0)
   112  	if t.routeFamily != bgp.RF_RTC_UC {
   113  		return pathList
   114  	}
   115  	for _, target := range vrf.ImportRt {
   116  		lhs := target.String()
   117  		for _, dest := range t.destinations {
   118  			nlri := dest.GetNlri().(*bgp.RouteTargetMembershipNLRI)
   119  			rhs := nlri.RouteTarget.String()
   120  			if lhs == rhs && isLastTargetUser(vrfs, target) {
   121  				for _, p := range dest.knownPathList {
   122  					if p.IsLocal() {
   123  						pathList = append(pathList, p.Clone(true))
   124  						break
   125  					}
   126  				}
   127  			}
   128  		}
   129  	}
   130  	return pathList
   131  }
   132  
   133  func (t *Table) deleteDest(dest *Destination) {
   134  	count := 0
   135  	for _, v := range dest.localIdMap.bitmap {
   136  		count += bits.OnesCount64(v)
   137  	}
   138  	if len(dest.localIdMap.bitmap) != 0 && count != 1 {
   139  		return
   140  	}
   141  	destinations := t.GetDestinations()
   142  	delete(destinations, t.tableKey(dest.GetNlri()))
   143  	if len(destinations) == 0 {
   144  		t.destinations = make(map[string]*Destination)
   145  	}
   146  
   147  	if nlri, ok := dest.nlri.(*bgp.EVPNNLRI); ok {
   148  		if macadv, ok := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute); ok {
   149  			for _, path := range dest.knownPathList {
   150  				for _, ec := range path.GetRouteTargets() {
   151  					macKey := t.macKey(ec, macadv.MacAddress)
   152  					if keys, ok := t.macIndex[macKey]; ok {
   153  						delete(keys, t.tableKey(nlri))
   154  						if len(keys) == 0 {
   155  							delete(t.macIndex, macKey)
   156  						}
   157  					}
   158  				}
   159  			}
   160  		}
   161  	}
   162  }
   163  
   164  func (t *Table) validatePath(path *Path) {
   165  	if path == nil {
   166  		t.logger.Error("path is nil",
   167  			log.Fields{
   168  				"Topic": "Table",
   169  				"Key":   t.routeFamily})
   170  	}
   171  	if path.GetRouteFamily() != t.routeFamily {
   172  		t.logger.Error("Invalid path. RouteFamily mismatch",
   173  			log.Fields{
   174  				"Topic":      "Table",
   175  				"Key":        t.routeFamily,
   176  				"Prefix":     path.GetPrefix(),
   177  				"ReceivedRf": path.GetRouteFamily().String()})
   178  	}
   179  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH); attr != nil {
   180  		pathParam := attr.(*bgp.PathAttributeAsPath).Value
   181  		for _, as := range pathParam {
   182  			_, y := as.(*bgp.As4PathParam)
   183  			if !y {
   184  				t.logger.Fatal("AsPathParam must be converted to As4PathParam",
   185  					log.Fields{
   186  						"Topic": "Table",
   187  						"Key":   t.routeFamily,
   188  						"As":    as})
   189  			}
   190  		}
   191  	}
   192  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS4_PATH); attr != nil {
   193  		t.logger.Fatal("AS4_PATH must be converted to AS_PATH",
   194  			log.Fields{
   195  				"Topic": "Table",
   196  				"Key":   t.routeFamily})
   197  	}
   198  	if path.GetNlri() == nil {
   199  		t.logger.Fatal("path's nlri is nil",
   200  			log.Fields{
   201  				"Topic": "Table",
   202  				"Key":   t.routeFamily})
   203  	}
   204  }
   205  
   206  func (t *Table) getOrCreateDest(nlri bgp.AddrPrefixInterface, size int) *Destination {
   207  	dest := t.GetDestination(nlri)
   208  	// If destination for given prefix does not exist we create it.
   209  	if dest == nil {
   210  		t.logger.Debug("create Destination",
   211  			log.Fields{
   212  				"Topic": "Table",
   213  				"Nlri":  nlri})
   214  		dest = NewDestination(nlri, size)
   215  		t.setDestination(dest)
   216  	}
   217  	return dest
   218  }
   219  
   220  func (t *Table) update(newPath *Path) *Update {
   221  	t.validatePath(newPath)
   222  	dst := t.getOrCreateDest(newPath.GetNlri(), 64)
   223  	u := dst.Calculate(t.logger, newPath)
   224  
   225  	if len(dst.knownPathList) == 0 {
   226  		t.deleteDest(dst)
   227  		return u
   228  	}
   229  
   230  	if nlri, ok := newPath.GetNlri().(*bgp.EVPNNLRI); ok {
   231  		if macadv, ok := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute); ok {
   232  			tableKey := t.tableKey(nlri)
   233  			for _, ec := range newPath.GetRouteTargets() {
   234  				macKey := t.macKey(ec, macadv.MacAddress)
   235  				if _, ok := t.macIndex[macKey]; !ok {
   236  					t.macIndex[macKey] = make(map[string]struct{})
   237  				}
   238  				t.macIndex[macKey][tableKey] = struct{}{}
   239  			}
   240  		}
   241  	}
   242  
   243  	return u
   244  }
   245  
   246  func (t *Table) GetDestinations() map[string]*Destination {
   247  	return t.destinations
   248  }
   249  func (t *Table) setDestinations(destinations map[string]*Destination) {
   250  	t.destinations = destinations
   251  }
   252  func (t *Table) GetDestination(nlri bgp.AddrPrefixInterface) *Destination {
   253  	dest, ok := t.destinations[t.tableKey(nlri)]
   254  	if ok {
   255  		return dest
   256  	} else {
   257  		return nil
   258  	}
   259  }
   260  
   261  func (t *Table) GetLongerPrefixDestinations(key string) ([]*Destination, error) {
   262  	results := make([]*Destination, 0, len(t.GetDestinations()))
   263  	switch t.routeFamily {
   264  	case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC, bgp.RF_IPv4_MPLS, bgp.RF_IPv6_MPLS:
   265  		_, prefix, err := net.ParseCIDR(key)
   266  		if err != nil {
   267  			return nil, fmt.Errorf("error parsing cidr %s: %v", key, err)
   268  		}
   269  		ones, bits := prefix.Mask.Size()
   270  
   271  		r := critbitgo.NewNet()
   272  		for _, dst := range t.GetDestinations() {
   273  			r.Add(nlriToIPNet(dst.nlri), dst)
   274  		}
   275  		p := &net.IPNet{
   276  			IP:   prefix.IP,
   277  			Mask: net.CIDRMask((ones>>3)<<3, bits),
   278  		}
   279  		mask := 0
   280  		div := 0
   281  		if ones%8 != 0 {
   282  			mask = 8 - ones&0x7
   283  			div = ones >> 3
   284  		}
   285  		r.WalkPrefix(p, func(n *net.IPNet, v interface{}) bool {
   286  			if mask != 0 && n.IP[div]>>mask != p.IP[div]>>mask {
   287  				return true
   288  			}
   289  			l, _ := n.Mask.Size()
   290  
   291  			if ones > l {
   292  				return true
   293  			}
   294  			results = append(results, v.(*Destination))
   295  			return true
   296  		})
   297  	case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN:
   298  		prefixRd, _, network, err := bgp.ParseVPNPrefix(key)
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  		ones, bits := network.Mask.Size()
   303  
   304  		r := critbitgo.NewNet()
   305  		for _, dst := range t.GetDestinations() {
   306  			var dstRD bgp.RouteDistinguisherInterface
   307  			switch t.routeFamily {
   308  			case bgp.RF_IPv4_VPN:
   309  				dstRD = dst.nlri.(*bgp.LabeledVPNIPAddrPrefix).RD
   310  			case bgp.RF_IPv6_VPN:
   311  				dstRD = dst.nlri.(*bgp.LabeledVPNIPv6AddrPrefix).RD
   312  			}
   313  
   314  			if prefixRd.String() != dstRD.String() {
   315  				continue
   316  			}
   317  
   318  			r.Add(nlriToIPNet(dst.nlri), dst)
   319  		}
   320  
   321  		p := &net.IPNet{
   322  			IP:   network.IP,
   323  			Mask: net.CIDRMask((ones>>3)<<3, bits),
   324  		}
   325  
   326  		mask := 0
   327  		div := 0
   328  		if ones%8 != 0 {
   329  			mask = 8 - ones&0x7
   330  			div = ones >> 3
   331  		}
   332  
   333  		r.WalkPrefix(p, func(n *net.IPNet, v interface{}) bool {
   334  			if mask != 0 && n.IP[div]>>mask != p.IP[div]>>mask {
   335  				return true
   336  			}
   337  			l, _ := n.Mask.Size()
   338  
   339  			if ones > l {
   340  				return true
   341  			}
   342  			results = append(results, v.(*Destination))
   343  			return true
   344  		})
   345  	default:
   346  		for _, dst := range t.GetDestinations() {
   347  			results = append(results, dst)
   348  		}
   349  	}
   350  	return results, nil
   351  }
   352  
   353  func (t *Table) GetEvpnDestinationsWithRouteType(typ string) ([]*Destination, error) {
   354  	var routeType uint8
   355  	switch strings.ToLower(typ) {
   356  	case "a-d":
   357  		routeType = bgp.EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY
   358  	case "macadv":
   359  		routeType = bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT
   360  	case "multicast":
   361  		routeType = bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG
   362  	case "esi":
   363  		routeType = bgp.EVPN_ETHERNET_SEGMENT_ROUTE
   364  	case "prefix":
   365  		routeType = bgp.EVPN_IP_PREFIX
   366  	default:
   367  		return nil, fmt.Errorf("unsupported evpn route type: %s", typ)
   368  	}
   369  	destinations := t.GetDestinations()
   370  	results := make([]*Destination, 0, len(destinations))
   371  	switch t.routeFamily {
   372  	case bgp.RF_EVPN:
   373  		for _, dst := range destinations {
   374  			if nlri, ok := dst.nlri.(*bgp.EVPNNLRI); !ok {
   375  				return nil, fmt.Errorf("invalid evpn nlri type detected: %T", dst.nlri)
   376  			} else if nlri.RouteType == routeType {
   377  				results = append(results, dst)
   378  			}
   379  		}
   380  	default:
   381  		for _, dst := range destinations {
   382  			results = append(results, dst)
   383  		}
   384  	}
   385  	return results, nil
   386  }
   387  
   388  func (t *Table) GetMUPDestinationsWithRouteType(p string) ([]*Destination, error) {
   389  	var routeType uint16
   390  	switch strings.ToLower(p) {
   391  	case "isd":
   392  		routeType = bgp.MUP_ROUTE_TYPE_INTERWORK_SEGMENT_DISCOVERY
   393  	case "dsd":
   394  		routeType = bgp.MUP_ROUTE_TYPE_DIRECT_SEGMENT_DISCOVERY
   395  	case "t1st":
   396  		routeType = bgp.MUP_ROUTE_TYPE_TYPE_1_SESSION_TRANSFORMED
   397  	case "t2st":
   398  		routeType = bgp.MUP_ROUTE_TYPE_TYPE_2_SESSION_TRANSFORMED
   399  	default:
   400  		// use prefix as route key
   401  	}
   402  	destinations := t.GetDestinations()
   403  	results := make([]*Destination, 0, len(destinations))
   404  	switch t.routeFamily {
   405  	case bgp.RF_MUP_IPv4, bgp.RF_MUP_IPv6:
   406  		for _, dst := range destinations {
   407  			if nlri, ok := dst.nlri.(*bgp.MUPNLRI); !ok {
   408  				return nil, fmt.Errorf("invalid mup nlri type detected: %T", dst.nlri)
   409  			} else if nlri.RouteType == routeType {
   410  				results = append(results, dst)
   411  			} else if nlri.String() == p {
   412  				results = append(results, dst)
   413  			}
   414  		}
   415  	default:
   416  		for _, dst := range destinations {
   417  			results = append(results, dst)
   418  		}
   419  	}
   420  	return results, nil
   421  }
   422  
   423  func (t *Table) setDestination(dst *Destination) {
   424  	tableKey := t.tableKey(dst.nlri)
   425  	t.destinations[tableKey] = dst
   426  
   427  	if nlri, ok := dst.nlri.(*bgp.EVPNNLRI); ok {
   428  		if macadv, ok := nlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute); ok {
   429  			for _, path := range dst.knownPathList {
   430  				for _, ec := range path.GetRouteTargets() {
   431  					macKey := t.macKey(ec, macadv.MacAddress)
   432  					if _, ok := t.macIndex[macKey]; !ok {
   433  						t.macIndex[macKey] = make(map[string]struct{})
   434  					}
   435  					t.macIndex[macKey][tableKey] = struct{}{}
   436  				}
   437  			}
   438  		}
   439  	}
   440  }
   441  
   442  func (t *Table) tableKey(nlri bgp.AddrPrefixInterface) string {
   443  	switch T := nlri.(type) {
   444  	case *bgp.IPAddrPrefix:
   445  		b := make([]byte, 5)
   446  		copy(b, T.Prefix.To4())
   447  		b[4] = T.Length
   448  		return *(*string)(unsafe.Pointer(&b))
   449  	case *bgp.IPv6AddrPrefix:
   450  		b := make([]byte, 17)
   451  		copy(b, T.Prefix.To16())
   452  		b[16] = T.Length
   453  		return *(*string)(unsafe.Pointer(&b))
   454  	case *bgp.LabeledVPNIPAddrPrefix:
   455  		b := make([]byte, 13)
   456  		serializedRD, _ := T.RD.Serialize()
   457  		copy(b, serializedRD)
   458  		copy(b[8:12], T.Prefix.To4())
   459  		b[12] = T.Length
   460  		return *(*string)(unsafe.Pointer(&b))
   461  	case *bgp.LabeledVPNIPv6AddrPrefix:
   462  		b := make([]byte, 25)
   463  		serializedRD, _ := T.RD.Serialize()
   464  		copy(b, serializedRD)
   465  		copy(b[8:24], T.Prefix.To16())
   466  		b[24] = T.Length
   467  		return *(*string)(unsafe.Pointer(&b))
   468  	}
   469  	return nlri.String()
   470  }
   471  
   472  func (t *Table) macKey(rt bgp.ExtendedCommunityInterface, mac net.HardwareAddr) string {
   473  	b, _ := rt.Serialize()
   474  	b = append(b, mac...)
   475  	return *(*string)(unsafe.Pointer(&b))
   476  }
   477  
   478  func (t *Table) Bests(id string, as uint32) []*Path {
   479  	paths := make([]*Path, 0, len(t.destinations))
   480  	for _, dst := range t.destinations {
   481  		path := dst.GetBestPath(id, as)
   482  		if path != nil {
   483  			paths = append(paths, path)
   484  		}
   485  	}
   486  	return paths
   487  }
   488  
   489  func (t *Table) MultiBests(id string) [][]*Path {
   490  	paths := make([][]*Path, 0, len(t.destinations))
   491  	for _, dst := range t.destinations {
   492  		path := dst.GetMultiBestPath(id)
   493  		if path != nil {
   494  			paths = append(paths, path)
   495  		}
   496  	}
   497  	return paths
   498  }
   499  
   500  func (t *Table) GetKnownPathList(id string, as uint32) []*Path {
   501  	paths := make([]*Path, 0, len(t.destinations))
   502  	for _, dst := range t.destinations {
   503  		paths = append(paths, dst.GetKnownPathList(id, as)...)
   504  	}
   505  	return paths
   506  }
   507  
   508  func (t *Table) GetKnownPathListWithMac(id string, as uint32, rt bgp.ExtendedCommunityInterface, mac net.HardwareAddr, onlyBest bool) []*Path {
   509  	var paths []*Path
   510  	if prefixes, ok := t.macIndex[t.macKey(rt, mac)]; ok {
   511  		for prefix := range prefixes {
   512  			if dst, ok := t.destinations[prefix]; ok {
   513  				if onlyBest {
   514  					paths = append(paths, dst.GetBestPath(id, as))
   515  				} else {
   516  					paths = append(paths, dst.GetKnownPathList(id, as)...)
   517  				}
   518  			}
   519  		}
   520  	}
   521  	return paths
   522  }
   523  
   524  func (t *Table) Select(option ...TableSelectOption) (*Table, error) {
   525  	id := GLOBAL_RIB_NAME
   526  	var vrf *Vrf
   527  	adj := false
   528  	prefixes := make([]*LookupPrefix, 0, len(option))
   529  	best := false
   530  	mp := false
   531  	as := uint32(0)
   532  	for _, o := range option {
   533  		if o.ID != "" {
   534  			id = o.ID
   535  		}
   536  		if o.VRF != nil {
   537  			vrf = o.VRF
   538  		}
   539  		adj = o.adj
   540  		prefixes = append(prefixes, o.LookupPrefixes...)
   541  		best = o.Best
   542  		mp = o.MultiPath
   543  		as = o.AS
   544  	}
   545  	dOption := DestinationSelectOption{ID: id, AS: as, VRF: vrf, adj: adj, Best: best, MultiPath: mp}
   546  	r := &Table{
   547  		routeFamily:  t.routeFamily,
   548  		destinations: make(map[string]*Destination),
   549  		macIndex:     make(map[string]map[string]struct{}),
   550  	}
   551  
   552  	if len(prefixes) != 0 {
   553  		switch t.routeFamily {
   554  		case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC:
   555  			f := func(prefixStr string) (bool, error) {
   556  				var nlri bgp.AddrPrefixInterface
   557  				var err error
   558  				if t.routeFamily == bgp.RF_IPv4_UC {
   559  					nlri, err = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP, bgp.SAFI_UNICAST, prefixStr)
   560  				} else {
   561  					nlri, err = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP6, bgp.SAFI_UNICAST, prefixStr)
   562  				}
   563  				if err != nil {
   564  					return false, err
   565  				}
   566  				if dst := t.GetDestination(nlri); dst != nil {
   567  					if d := dst.Select(dOption); d != nil {
   568  						r.setDestination(d)
   569  						return true, nil
   570  					}
   571  				}
   572  				return false, nil
   573  			}
   574  
   575  			for _, p := range prefixes {
   576  				key := p.Prefix
   577  				switch p.LookupOption {
   578  				case LOOKUP_LONGER:
   579  					ds, err := t.GetLongerPrefixDestinations(key)
   580  					if err != nil {
   581  						return nil, err
   582  					}
   583  					for _, dst := range ds {
   584  						if d := dst.Select(dOption); d != nil {
   585  							r.setDestination(d)
   586  						}
   587  					}
   588  				case LOOKUP_SHORTER:
   589  					addr, prefix, err := net.ParseCIDR(key)
   590  					if err != nil {
   591  						return nil, err
   592  					}
   593  					ones, _ := prefix.Mask.Size()
   594  					for i := ones; i >= 0; i-- {
   595  						_, prefix, _ := net.ParseCIDR(fmt.Sprintf("%s/%d", addr.String(), i))
   596  						f(prefix.String())
   597  					}
   598  				default:
   599  					if host := net.ParseIP(key); host != nil {
   600  						masklen := 32
   601  						if t.routeFamily == bgp.RF_IPv6_UC {
   602  							masklen = 128
   603  						}
   604  						for i := masklen; i >= 0; i-- {
   605  							_, prefix, err := net.ParseCIDR(fmt.Sprintf("%s/%d", key, i))
   606  							if err != nil {
   607  								return nil, err
   608  							}
   609  							ret, err := f(prefix.String())
   610  							if err != nil {
   611  								return nil, err
   612  							}
   613  							if ret {
   614  								break
   615  							}
   616  						}
   617  					} else {
   618  						f(key)
   619  					}
   620  				}
   621  			}
   622  		case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN:
   623  			f := func(prefixStr string) error {
   624  				var nlri bgp.AddrPrefixInterface
   625  				var err error
   626  
   627  				if t.routeFamily == bgp.RF_IPv4_VPN {
   628  					nlri, err = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP, bgp.SAFI_MPLS_VPN, prefixStr)
   629  				} else {
   630  					nlri, err = bgp.NewPrefixFromRouteFamily(bgp.AFI_IP6, bgp.SAFI_MPLS_VPN, prefixStr)
   631  				}
   632  				if err != nil {
   633  					return fmt.Errorf("failed to create prefix: %w", err)
   634  				}
   635  
   636  				if dst := t.GetDestination(nlri); dst != nil {
   637  					if d := dst.Select(dOption); d != nil {
   638  						r.setDestination(d)
   639  					}
   640  				}
   641  				return nil
   642  			}
   643  
   644  			for _, p := range prefixes {
   645  				switch p.LookupOption {
   646  				case LOOKUP_LONGER:
   647  					_, prefix, err := net.ParseCIDR(p.Prefix)
   648  					if err != nil {
   649  						return nil, err
   650  					}
   651  
   652  					if p.RD == "" {
   653  						for _, dst := range t.GetDestinations() {
   654  							tablePrefix := nlriToIPNet(dst.nlri)
   655  
   656  							if bgp.ContainsCIDR(prefix, tablePrefix) {
   657  								r.setDestination(dst)
   658  							}
   659  						}
   660  
   661  						return r, nil
   662  					}
   663  
   664  					ds, err := t.GetLongerPrefixDestinations(p.RD + ":" + p.Prefix)
   665  					if err != nil {
   666  						return nil, err
   667  					}
   668  
   669  					for _, dst := range ds {
   670  						if d := dst.Select(dOption); d != nil {
   671  							r.setDestination(d)
   672  						}
   673  					}
   674  				case LOOKUP_SHORTER:
   675  					addr, prefix, err := net.ParseCIDR(p.Prefix)
   676  					if err != nil {
   677  						return nil, err
   678  					}
   679  
   680  					if p.RD == "" {
   681  						for _, dst := range t.GetDestinations() {
   682  							tablePrefix := nlriToIPNet(dst.nlri)
   683  
   684  							if bgp.ContainsCIDR(tablePrefix, prefix) {
   685  								r.setDestination(dst)
   686  							}
   687  						}
   688  
   689  						return r, nil
   690  					}
   691  
   692  					rd, err := bgp.ParseRouteDistinguisher(p.RD)
   693  					if err != nil {
   694  						return nil, err
   695  					}
   696  
   697  					ones, _ := prefix.Mask.Size()
   698  					for i := ones; i >= 0; i-- {
   699  						_, prefix, _ := net.ParseCIDR(addr.String() + "/" + strconv.Itoa(i))
   700  
   701  						err := f(rd.String() + ":" + prefix.String())
   702  						if err != nil {
   703  							return nil, err
   704  						}
   705  					}
   706  				default:
   707  					if p.RD == "" {
   708  						for _, dst := range t.GetDestinations() {
   709  							net := nlriToIPNet(dst.nlri)
   710  							if net.String() == p.Prefix {
   711  								r.setDestination(dst)
   712  							}
   713  						}
   714  
   715  						return r, nil
   716  					}
   717  
   718  					err := f(p.RD + ":" + p.Prefix)
   719  					if err != nil {
   720  						return nil, err
   721  					}
   722  				}
   723  			}
   724  		case bgp.RF_EVPN:
   725  			for _, p := range prefixes {
   726  				// Uses LookupPrefix.Prefix as EVPN Route Type string
   727  				ds, err := t.GetEvpnDestinationsWithRouteType(p.Prefix)
   728  				if err != nil {
   729  					return nil, err
   730  				}
   731  				for _, dst := range ds {
   732  					if d := dst.Select(dOption); d != nil {
   733  						r.setDestination(d)
   734  					}
   735  				}
   736  			}
   737  		case bgp.RF_MUP_IPv4, bgp.RF_MUP_IPv6:
   738  			for _, p := range prefixes {
   739  				ds, err := t.GetMUPDestinationsWithRouteType(p.Prefix)
   740  				if err != nil {
   741  					return nil, err
   742  				}
   743  				for _, dst := range ds {
   744  					if d := dst.Select(dOption); d != nil {
   745  						r.setDestination(d)
   746  					}
   747  				}
   748  			}
   749  		default:
   750  			return nil, fmt.Errorf("route filtering is not supported for this family")
   751  		}
   752  	} else {
   753  		for _, dst := range t.GetDestinations() {
   754  			if d := dst.Select(dOption); d != nil {
   755  				r.setDestination(d)
   756  			}
   757  		}
   758  	}
   759  	return r, nil
   760  }
   761  
   762  type TableInfo struct {
   763  	NumDestination int
   764  	NumPath        int
   765  	NumAccepted    int
   766  }
   767  
   768  type TableInfoOptions struct {
   769  	ID  string
   770  	AS  uint32
   771  	VRF *Vrf
   772  }
   773  
   774  func (t *Table) Info(option ...TableInfoOptions) *TableInfo {
   775  	var numD, numP int
   776  
   777  	id := GLOBAL_RIB_NAME
   778  	var vrf *Vrf
   779  	as := uint32(0)
   780  
   781  	for _, o := range option {
   782  		if o.ID != "" {
   783  			id = o.ID
   784  		}
   785  		if o.VRF != nil {
   786  			vrf = o.VRF
   787  		}
   788  		as = o.AS
   789  	}
   790  
   791  	for _, d := range t.destinations {
   792  		paths := d.GetKnownPathList(id, as)
   793  		n := len(paths)
   794  
   795  		if vrf != nil {
   796  			ps := make([]*Path, 0, len(paths))
   797  			for _, p := range paths {
   798  				if CanImportToVrf(vrf, p) {
   799  					ps = append(ps, p.ToLocal())
   800  				}
   801  			}
   802  			n = len(ps)
   803  		}
   804  		if n != 0 {
   805  			numD++
   806  			numP += n
   807  		}
   808  	}
   809  	return &TableInfo{
   810  		NumDestination: numD,
   811  		NumPath:        numP,
   812  	}
   813  }