diff options
author | Wataru Ishida <ishida.wataru@lab.ntt.co.jp> | 2016-08-20 12:02:36 +0000 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-08-25 15:53:14 +0900 |
commit | b3c874da2581eb71d8c137d956e792565193ec0e (patch) | |
tree | 563169c8233d48a10fd5d45ac805e1320a89c532 /table | |
parent | a17ee18e5b1fe90a7c80d6cb1f0778b97f00235a (diff) |
server/api: fix GetRib API to return sorted destination
the feature has been broken.
Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
Diffstat (limited to 'table')
-rw-r--r-- | table/adj.go | 20 | ||||
-rw-r--r-- | table/destination.go | 42 | ||||
-rw-r--r-- | table/table.go | 97 |
3 files changed, 159 insertions, 0 deletions
diff --git a/table/adj.go b/table/adj.go index 2fb46b4a..b38e02b8 100644 --- a/table/adj.go +++ b/table/adj.go @@ -168,3 +168,23 @@ func (adj *AdjRib) Exists(path *Path) bool { _, ok = table[path.getPrefix()] return ok } + +func (adj *AdjRib) Select(family bgp.RouteFamily, accepted bool, option ...TableSelectOption) (*Table, error) { + paths := adj.PathList([]bgp.RouteFamily{family}, accepted) + dsts := make(map[string]*Destination, len(paths)) + for _, path := range paths { + if d, y := dsts[path.GetNlri().String()]; y { + d.knownPathList = append(d.knownPathList, path) + } else { + dst := NewDestination(path.GetNlri()) + dsts[path.GetNlri().String()] = dst + dst.knownPathList = append(dst.knownPathList, path) + } + } + tbl := &Table{ + routeFamily: family, + destinations: dsts, + } + option = append(option, TableSelectOption{adj: true}) + return tbl.Select(option...) +} diff --git a/table/destination.go b/table/destination.go index f6b3f7f9..7e0deb2b 100644 --- a/table/destination.go +++ b/table/destination.go @@ -850,6 +850,48 @@ func (dest *Destination) String() string { return fmt.Sprintf("Destination NLRI: %s", dest.nlri.String()) } +type DestinationSelectOption struct { + ID string + VRF *Vrf + adj bool +} + +func (old *Destination) Select(option ...DestinationSelectOption) *Destination { + id := GLOBAL_RIB_NAME + var vrf *Vrf + adj := false + for _, o := range option { + if o.ID != "" { + id = o.ID + } + if o.VRF != nil { + vrf = o.VRF + } + adj = o.adj + } + var paths []*Path + if adj { + paths = old.knownPathList + } else { + paths = old.GetKnownPathList(id) + } + new := NewDestination(old.nlri) + list := make([]*Path, 0, len(old.knownPathList)) + for _, path := range paths { + if vrf != nil && !CanImportToVrf(vrf, path) { + continue + } + p := path.Clone(path.IsWithdraw) + p.Filter("", path.Filtered(id)) + list = append(list, p) + } + if len(list) == 0 { + return nil + } + new.knownPathList = list + return new +} + type destinations []*Destination func (d destinations) Len() int { 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 +} |