summaryrefslogtreecommitdiffhomepage
path: root/table/table.go
diff options
context:
space:
mode:
Diffstat (limited to 'table/table.go')
-rw-r--r--table/table.go97
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
+}