diff options
Diffstat (limited to 'table/table.go')
-rw-r--r-- | table/table.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/table/table.go b/table/table.go index b1ec94a1..bad0e824 100644 --- a/table/table.go +++ b/table/table.go @@ -16,6 +16,7 @@ package table import ( + "fmt" "net" "sort" @@ -24,6 +25,26 @@ import ( "github.com/osrg/gobgp/packet/bgp" ) +type LookupOption uint8 + +const ( + LOOKUP_EXACT LookupOption = iota + LOOKUP_LONGER + LOOKUP_SHORTER +) + +type LookupPrefix struct { + Prefix string + LookupOption +} + +type TableSelectOption struct { + ID string + LookupPrefixes []*LookupPrefix + VRF *Vrf + adj bool +} + type Table struct { routeFamily bgp.RouteFamily destinations map[string]*Destination @@ -287,3 +308,79 @@ func (t *Table) GetKnownPathList(id string) []*Path { } return paths } + +func (t *Table) Select(option ...TableSelectOption) (*Table, error) { + id := GLOBAL_RIB_NAME + var vrf *Vrf + adj := false + prefixes := make([]*LookupPrefix, 0, len(option)) + for _, o := range option { + if o.ID != "" { + id = o.ID + } + if o.VRF != nil { + vrf = o.VRF + } + adj = o.adj + prefixes = append(prefixes, o.LookupPrefixes...) + } + dsts := make(map[string]*Destination) + if (t.routeFamily == bgp.RF_IPv4_UC || t.routeFamily == bgp.RF_IPv6_UC) && len(prefixes) > 0 { + f := func(id, key string) (bool, error) { + if dst := t.GetDestination(key); dst != nil { + if d := dst.Select(DestinationSelectOption{ID: id, adj: adj}); d != nil { + dsts[key] = d + return true, nil + } + } + return false, nil + } + for _, p := range prefixes { + key := p.Prefix + switch p.LookupOption { + case LOOKUP_LONGER: + ds, err := t.GetLongerPrefixDestinations(key) + if err != nil { + return nil, err + } + for _, dst := range ds { + dsts[dst.GetNlri().String()] = dst.Select(DestinationSelectOption{ID: id, adj: adj}) + } + case LOOKUP_SHORTER: + _, prefix, err := net.ParseCIDR(key) + if err != nil { + return nil, err + } + ones, bits := prefix.Mask.Size() + for i := ones; i > 0; i-- { + prefix.Mask = net.CIDRMask(i, bits) + f(id, prefix.String()) + } + default: + if _, err := f(id, key); err != nil { + if host := net.ParseIP(key); host != nil { + masklen := 32 + if t.routeFamily == bgp.RF_IPv6_UC { + masklen = 128 + } + for i := masklen; i > 0; i-- { + if y, _ := f(id, fmt.Sprintf("%s/%d", key, i)); y { + break + } + } + } + } + } + } + } else { + for k, dst := range t.GetDestinations() { + if d := dst.Select(DestinationSelectOption{ID: id, VRF: vrf, adj: adj}); d != nil { + dsts[k] = d + } + } + } + return &Table{ + routeFamily: t.routeFamily, + destinations: dsts, + }, nil +} |