summaryrefslogtreecommitdiffhomepage
path: root/table
diff options
context:
space:
mode:
authorWataru Ishida <ishida.wataru@lab.ntt.co.jp>2016-08-20 12:02:36 +0000
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-08-25 15:53:14 +0900
commitb3c874da2581eb71d8c137d956e792565193ec0e (patch)
tree563169c8233d48a10fd5d45ac805e1320a89c532 /table
parenta17ee18e5b1fe90a7c80d6cb1f0778b97f00235a (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.go20
-rw-r--r--table/destination.go42
-rw-r--r--table/table.go97
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
+}