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 }