diff options
author | FUJITA Tomonori <fujita.tomonori@gmail.com> | 2019-09-08 18:45:27 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@gmail.com> | 2019-10-22 21:17:05 +0900 |
commit | a1a523a1b3323685e97cb88691fcd76c39156195 (patch) | |
tree | f62fb6e8e50b985f16597d8e4e2f7e0ebabe40f7 | |
parent | f1f0f77f5989f113336246a96737b7f246485ee1 (diff) |
move roa table code to table/ from server/
As the name implies, table/ is more appropriate for roa table code.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
-rw-r--r-- | internal/pkg/table/roa.go | 273 | ||||
-rw-r--r-- | internal/pkg/table/roa_test.go (renamed from pkg/server/rpki_test.go) | 103 | ||||
-rw-r--r-- | pkg/server/rpki.go | 306 | ||||
-rw-r--r-- | pkg/server/server.go | 23 |
4 files changed, 341 insertions, 364 deletions
diff --git a/internal/pkg/table/roa.go b/internal/pkg/table/roa.go index fe08fe54..88f81705 100644 --- a/internal/pkg/table/roa.go +++ b/internal/pkg/table/roa.go @@ -18,6 +18,12 @@ package table import ( "fmt" "net" + "sort" + + radix "github.com/armon/go-radix" + "github.com/osrg/gobgp/internal/pkg/config" + "github.com/osrg/gobgp/pkg/packet/bgp" + log "github.com/sirupsen/logrus" ) type IPPrefix struct { @@ -58,3 +64,270 @@ func (r *ROA) Equal(roa *ROA) bool { } return false } + +type roaBucket struct { + Prefix *IPPrefix + entries []*ROA +} + +func (r *roaBucket) GetEntries() []*ROA { + return r.entries +} + +type ROATable struct { + Roas map[bgp.RouteFamily]*radix.Tree +} + +func NewROATable() *ROATable { + m := make(map[bgp.RouteFamily]*radix.Tree) + m[bgp.RF_IPv4_UC] = radix.New() + m[bgp.RF_IPv6_UC] = radix.New() + return &ROATable{ + Roas: m, + } +} + +func (rt *ROATable) roa2tree(roa *ROA) (*radix.Tree, string) { + tree := rt.Roas[bgp.RF_IPv4_UC] + if roa.Family == bgp.AFI_IP6 { + tree = rt.Roas[bgp.RF_IPv6_UC] + } + return tree, IpToRadixkey(roa.Prefix.Prefix, roa.Prefix.Length) +} + +func (rt *ROATable) Add(roa *ROA) { + tree, key := rt.roa2tree(roa) + b, _ := tree.Get(key) + var bucket *roaBucket + if b == nil { + bucket = &roaBucket{ + Prefix: roa.Prefix, + entries: make([]*ROA, 0), + } + tree.Insert(key, bucket) + } else { + bucket = b.(*roaBucket) + for _, r := range bucket.entries { + if r.Equal(roa) { + // we already have the same one + return + } + } + } + bucket.entries = append(bucket.entries, roa) +} + +func (rt *ROATable) Delete(roa *ROA) { + tree, key := rt.roa2tree(roa) + b, _ := tree.Get(key) + if b != nil { + bucket := b.(*roaBucket) + newEntries := make([]*ROA, 0, len(bucket.entries)) + for _, r := range bucket.entries { + if !r.Equal(roa) { + newEntries = append(newEntries, r) + } + } + if len(newEntries) != len(bucket.entries) { + bucket.entries = newEntries + if len(newEntries) == 0 { + tree.Delete(key) + } + return + } + } + log.WithFields(log.Fields{ + "Topic": "rpki", + "Prefix": roa.Prefix.Prefix.String(), + "Prefix Length": roa.Prefix.Length, + "AS": roa.AS, + "Max Length": roa.MaxLen, + }).Info("Can't withdraw a ROA") +} + +func (rt *ROATable) DeleteAll(network string) { + for _, tree := range rt.Roas { + deleteKeys := make([]string, 0, tree.Len()) + tree.Walk(func(s string, v interface{}) bool { + b, _ := v.(*roaBucket) + newEntries := make([]*ROA, 0, len(b.entries)) + for _, r := range b.entries { + if r.Src != network { + newEntries = append(newEntries, r) + } + } + if len(newEntries) > 0 { + b.entries = newEntries + } else { + deleteKeys = append(deleteKeys, s) + } + return false + }) + for _, key := range deleteKeys { + tree.Delete(key) + } + } +} + +func validatePath(ownAs uint32, tree *radix.Tree, cidr string, asPath *bgp.PathAttributeAsPath) *Validation { + var as uint32 + + validation := &Validation{ + Status: config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, + Reason: RPKI_VALIDATION_REASON_TYPE_NONE, + Matched: make([]*ROA, 0), + UnmatchedLength: make([]*ROA, 0), + UnmatchedAs: make([]*ROA, 0), + } + + if asPath == nil || len(asPath.Value) == 0 { + as = ownAs + } else { + param := asPath.Value[len(asPath.Value)-1] + switch param.GetType() { + case bgp.BGP_ASPATH_ATTR_TYPE_SEQ: + asList := param.GetAS() + if len(asList) == 0 { + as = ownAs + } else { + as = asList[len(asList)-1] + } + case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: + as = ownAs + default: + return validation + } + } + _, n, _ := net.ParseCIDR(cidr) + ones, _ := n.Mask.Size() + prefixLen := uint8(ones) + key := IpToRadixkey(n.IP, prefixLen) + _, b, _ := tree.LongestPrefix(key) + if b == nil { + return validation + } + + var bucket *roaBucket + fn := radix.WalkFn(func(k string, v interface{}) bool { + bucket, _ = v.(*roaBucket) + for _, r := range bucket.entries { + if prefixLen <= r.MaxLen { + if r.AS != 0 && r.AS == as { + validation.Matched = append(validation.Matched, r) + } else { + validation.UnmatchedAs = append(validation.UnmatchedAs, r) + } + } else { + validation.UnmatchedLength = append(validation.UnmatchedLength, r) + } + } + return false + }) + tree.WalkPath(key, fn) + + if len(validation.Matched) != 0 { + validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_VALID + validation.Reason = RPKI_VALIDATION_REASON_TYPE_NONE + } else if len(validation.UnmatchedAs) != 0 { + validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID + validation.Reason = RPKI_VALIDATION_REASON_TYPE_AS + } else if len(validation.UnmatchedLength) != 0 { + validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID + validation.Reason = RPKI_VALIDATION_REASON_TYPE_LENGTH + } else { + validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND + validation.Reason = RPKI_VALIDATION_REASON_TYPE_NONE + } + + return validation +} + +func (rt *ROATable) Validate(path *Path) *Validation { + if path.IsWithdraw || path.IsEOR() { + // RPKI isn't enabled or invalid path + return nil + } + if tree, ok := rt.Roas[path.GetRouteFamily()]; ok { + return validatePath(path.OriginInfo().source.LocalAS, tree, path.GetNlri().String(), path.GetAsPath()) + } + return nil +} + +func (rt *ROATable) Info(family bgp.RouteFamily) (map[string]uint32, map[string]uint32) { + records := make(map[string]uint32) + prefixes := make(map[string]uint32) + + tree := rt.Roas[family] + tree.Walk(func(s string, v interface{}) bool { + b, _ := v.(*roaBucket) + tmpRecords := make(map[string]uint32) + for _, roa := range b.entries { + tmpRecords[roa.Src]++ + } + + for src, r := range tmpRecords { + if r > 0 { + records[src] += r + prefixes[src]++ + } + } + return false + }) + return records, prefixes +} + +func (rt *ROATable) List(family bgp.RouteFamily) ([]*ROA, error) { + var rfList []bgp.RouteFamily + switch family { + case bgp.RF_IPv4_UC: + rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC} + case bgp.RF_IPv6_UC: + rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC} + default: + rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} + } + l := make([]*ROA, 0) + for _, rf := range rfList { + if tree, ok := rt.Roas[rf]; ok { + tree.Walk(func(s string, v interface{}) bool { + b, _ := v.(*roaBucket) + var roaList roas + for _, r := range b.entries { + roaList = append(roaList, r) + } + sort.Sort(roaList) + for _, roa := range roaList { + l = append(l, roa) + } + return false + }) + } + } + return l, nil +} + +type roas []*ROA + +func (r roas) Len() int { + return len(r) +} + +func (r roas) Swap(i, j int) { + r[i], r[j] = r[j], r[i] +} + +func (r roas) Less(i, j int) bool { + r1 := r[i] + r2 := r[j] + + if r1.MaxLen < r2.MaxLen { + return true + } else if r1.MaxLen > r2.MaxLen { + return false + } + + if r1.AS < r2.AS { + return true + } + return false +} diff --git a/pkg/server/rpki_test.go b/internal/pkg/table/roa_test.go index 9f903a77..6b98269e 100644 --- a/pkg/server/rpki_test.go +++ b/internal/pkg/table/roa_test.go @@ -1,19 +1,4 @@ -// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package server +package table import ( "net" @@ -21,11 +6,9 @@ import ( "strings" "testing" + radix "github.com/armon/go-radix" "github.com/osrg/gobgp/internal/pkg/config" - "github.com/osrg/gobgp/internal/pkg/table" "github.com/osrg/gobgp/pkg/packet/bgp" - - radix "github.com/armon/go-radix" "github.com/stretchr/testify/assert" ) @@ -63,13 +46,13 @@ func validateOne(tree *radix.Tree, cidr, aspathStr string) config.RpkiValidation func TestValidate0(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("192.168.0.0").To4(), 24, 32, 100, "")) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("192.168.0.0").To4(), 24, 24, 200, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("192.168.0.0").To4(), 24, 32, 100, "")) + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("192.168.0.0").To4(), 24, 24, 200, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "192.168.0.0/24", "100") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID) @@ -92,12 +75,12 @@ func TestValidate0(t *testing.T) { func TestValidate1(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/16", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID) @@ -108,11 +91,11 @@ func TestValidate1(t *testing.T) { func TestValidate2(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) + table := NewROATable() var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/16", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND) @@ -123,22 +106,22 @@ func TestValidate2(t *testing.T) { func TestValidate3(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/8", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND) r = validateOne(tree, "10.0.0.0/17", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_INVALID) - manager, _ = newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, "")) + table = NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, "")) - tree = manager.Roas[bgp.RF_IPv4_UC] + tree = table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/17", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID) } @@ -146,12 +129,12 @@ func TestValidate3(t *testing.T) { func TestValidate4(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, "")) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65001, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65000, "")) + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 16, 65001, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/16", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID) @@ -162,12 +145,12 @@ func TestValidate4(t *testing.T) { func TestValidate5(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 17, 17, 65000, "")) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.128.0").To4(), 17, 17, 65000, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 17, 17, 65000, "")) + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.128.0").To4(), 17, 17, 65000, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/16", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND) } @@ -175,11 +158,11 @@ func TestValidate5(t *testing.T) { func TestValidate6(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 8, 32, 0, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 8, 32, 0, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/7", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND) @@ -193,11 +176,11 @@ func TestValidate6(t *testing.T) { func TestValidate7(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/24", "{65000}") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND) @@ -211,12 +194,12 @@ func TestValidate7(t *testing.T) { func TestValidate8(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 0, "")) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 0, "")) + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65000, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/24", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID) @@ -227,12 +210,12 @@ func TestValidate8(t *testing.T) { func TestValidate9(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 24, 24, 65000, "")) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65001, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 24, 24, 65000, "")) + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65001, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/24", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_VALID) @@ -243,12 +226,12 @@ func TestValidate9(t *testing.T) { func TestValidate10(t *testing.T) { assert := assert.New(t) - manager, _ := newROAManager(0) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 24, 24, 0, "")) - manager.addROA(table.NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65001, "")) + table := NewROATable() + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 24, 24, 0, "")) + table.Add(NewROA(bgp.AFI_IP, net.ParseIP("10.0.0.0").To4(), 16, 24, 65001, "")) var r config.RpkiValidationResultType - tree := manager.Roas[bgp.RF_IPv4_UC] + tree := table.Roas[bgp.RF_IPv4_UC] r = validateOne(tree, "10.0.0.0/24", "65000") assert.Equal(r, config.RPKI_VALIDATION_RESULT_TYPE_INVALID) diff --git a/pkg/server/rpki.go b/pkg/server/rpki.go index c46f8ffd..9eb3d2b7 100644 --- a/pkg/server/rpki.go +++ b/pkg/server/rpki.go @@ -20,7 +20,6 @@ import ( "fmt" "io" "net" - "sort" "strconv" "time" @@ -29,7 +28,6 @@ import ( "github.com/osrg/gobgp/pkg/packet/bgp" "github.com/osrg/gobgp/pkg/packet/rtr" - "github.com/armon/go-radix" log "github.com/sirupsen/logrus" "golang.org/x/net/context" ) @@ -42,41 +40,6 @@ func before(a, b uint32) bool { return int32(a-b) < 0 } -type roaBucket struct { - Prefix *table.IPPrefix - entries []*table.ROA -} - -func (r *roaBucket) GetEntries() []*table.ROA { - return r.entries -} - -type roas []*table.ROA - -func (r roas) Len() int { - return len(r) -} - -func (r roas) Swap(i, j int) { - r[i], r[j] = r[j], r[i] -} - -func (r roas) Less(i, j int) bool { - r1 := r[i] - r2 := r[j] - - if r1.MaxLen < r2.MaxLen { - return true - } else if r1.MaxLen > r2.MaxLen { - return false - } - - if r1.AS < r2.AS { - return true - } - return false -} - type roaEventType uint8 const ( @@ -94,36 +57,24 @@ type roaEvent struct { } type roaManager struct { - AS uint32 - Roas map[bgp.RouteFamily]*radix.Tree eventCh chan *roaEvent clientMap map[string]*roaClient + table *table.ROATable } -func newROAManager(as uint32) (*roaManager, error) { +func newROAManager(table *table.ROATable) *roaManager { m := &roaManager{ - AS: as, - Roas: make(map[bgp.RouteFamily]*radix.Tree), + table: table, } - m.Roas[bgp.RF_IPv4_UC] = radix.New() - m.Roas[bgp.RF_IPv6_UC] = radix.New() m.eventCh = make(chan *roaEvent) m.clientMap = make(map[string]*roaClient) - return m, nil + return m } func (m *roaManager) enabled() bool { return len(m.clientMap) != 0 } -func (m *roaManager) SetAS(as uint32) error { - if m.AS != 0 { - return fmt.Errorf("AS was already configured") - } - m.AS = as - return nil -} - func (m *roaManager) AddServer(host string, lifetime int64) error { address, port, err := net.SplitHostPort(host) if err != nil { @@ -145,35 +96,11 @@ func (m *roaManager) DeleteServer(host string) error { return fmt.Errorf("ROA server doesn't exists %s", host) } client.stop() - m.deleteAllROA(host) + m.table.DeleteAll(host) delete(m.clientMap, host) return nil } -func (m *roaManager) deleteAllROA(network string) { - for _, tree := range m.Roas { - deleteKeys := make([]string, 0, tree.Len()) - tree.Walk(func(s string, v interface{}) bool { - b, _ := v.(*roaBucket) - newEntries := make([]*table.ROA, 0, len(b.entries)) - for _, r := range b.entries { - if r.Src != network { - newEntries = append(newEntries, r) - } - } - if len(newEntries) > 0 { - b.entries = newEntries - } else { - deleteKeys = append(deleteKeys, s) - } - return false - }) - for _, key := range deleteKeys { - tree.Delete(key) - } - } -} - func (m *roaManager) Enable(address string) error { for network, client := range m.clientMap { add, _, _ := net.SplitHostPort(network) @@ -190,7 +117,7 @@ func (m *roaManager) Disable(address string) error { add, _, _ := net.SplitHostPort(network) if add == address { client.reset() - m.deleteAllROA(add) + m.table.DeleteAll(add) return nil } } @@ -206,7 +133,7 @@ func (m *roaManager) SoftReset(address string) error { add, _, _ := net.SplitHostPort(network) if add == address { client.softReset() - m.deleteAllROA(network) + m.table.DeleteAll(network) return nil } } @@ -264,77 +191,11 @@ func (m *roaManager) HandleROAEvent(ev *roaEvent) { log.WithFields(log.Fields{"Topic": "rpki"}).Infof("Reconnected to %s. Ignore timeout", client.host) } else { log.WithFields(log.Fields{"Topic": "rpki"}).Infof("Deleting all ROAs due to timeout with:%s", client.host) - m.deleteAllROA(client.host) + m.table.DeleteAll(client.host) } } } -func (m *roaManager) roa2tree(roa *table.ROA) (*radix.Tree, string) { - tree := m.Roas[bgp.RF_IPv4_UC] - if roa.Family == bgp.AFI_IP6 { - tree = m.Roas[bgp.RF_IPv6_UC] - } - return tree, table.IpToRadixkey(roa.Prefix.Prefix, roa.Prefix.Length) -} - -func (m *roaManager) deleteROA(roa *table.ROA) { - tree, key := m.roa2tree(roa) - b, _ := tree.Get(key) - if b != nil { - bucket := b.(*roaBucket) - newEntries := make([]*table.ROA, 0, len(bucket.entries)) - for _, r := range bucket.entries { - if !r.Equal(roa) { - newEntries = append(newEntries, r) - } - } - if len(newEntries) != len(bucket.entries) { - bucket.entries = newEntries - if len(newEntries) == 0 { - tree.Delete(key) - } - return - } - } - log.WithFields(log.Fields{ - "Topic": "rpki", - "Prefix": roa.Prefix.Prefix.String(), - "Prefix Length": roa.Prefix.Length, - "AS": roa.AS, - "Max Length": roa.MaxLen, - }).Info("Can't withdraw a ROA") -} - -func (m *roaManager) DeleteROA(roa *table.ROA) { - m.deleteROA(roa) -} - -func (m *roaManager) addROA(roa *table.ROA) { - tree, key := m.roa2tree(roa) - b, _ := tree.Get(key) - var bucket *roaBucket - if b == nil { - bucket = &roaBucket{ - Prefix: roa.Prefix, - entries: make([]*table.ROA, 0), - } - tree.Insert(key, bucket) - } else { - bucket = b.(*roaBucket) - for _, r := range bucket.entries { - if r.Equal(roa) { - // we already have the same one - return - } - } - } - bucket.entries = append(bucket.entries, roa) -} - -func (m *roaManager) AddROA(roa *table.ROA) { - m.addROA(roa) -} - func (m *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerState, buf []byte) { received := &state.RpkiMessages.RpkiReceived @@ -367,19 +228,19 @@ func (m *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerSta roa := table.NewROA(family, msg.Prefix, msg.PrefixLen, msg.MaxLen, msg.AS, client.host) if (msg.Flags & 1) == 1 { if client.endOfData { - m.addROA(roa) + m.table.Add(roa) } else { client.pendingROAs = append(client.pendingROAs, roa) } } else { - m.deleteROA(roa) + m.table.Delete(roa) } case *rtr.RTREndOfData: received.EndOfData++ if client.sessionID != msg.RTRCommon.SessionID { // remove all ROAs related with the // previous session - m.deleteAllROA(client.host) + m.table.DeleteAll(client.host) } client.sessionID = msg.RTRCommon.SessionID client.serialNumber = msg.RTRCommon.SerialNumber @@ -389,7 +250,7 @@ func (m *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerSta client.timer = nil } for _, roa := range client.pendingROAs { - m.addROA(roa) + m.table.Add(roa) } client.pendingROAs = make([]*table.ROA, 0) case *rtr.RTRCacheReset: @@ -408,30 +269,8 @@ func (m *roaManager) handleRTRMsg(client *roaClient, state *config.RpkiServerSta } func (m *roaManager) GetServers() []*config.RpkiServer { - f := func(tree *radix.Tree) (map[string]uint32, map[string]uint32) { - records := make(map[string]uint32) - prefixes := make(map[string]uint32) - - tree.Walk(func(s string, v interface{}) bool { - b, _ := v.(*roaBucket) - tmpRecords := make(map[string]uint32) - for _, roa := range b.entries { - tmpRecords[roa.Src]++ - } - - for src, r := range tmpRecords { - if r > 0 { - records[src] += r - prefixes[src]++ - } - } - return false - }) - return records, prefixes - } - - recordsV4, prefixesV4 := f(m.Roas[bgp.RF_IPv4_UC]) - recordsV6, prefixesV6 := f(m.Roas[bgp.RF_IPv6_UC]) + recordsV4, prefixesV4 := m.table.Info(bgp.RF_IPv4_UC) + recordsV6, prefixesV6 := m.table.Info(bgp.RF_IPv6_UC) l := make([]*config.RpkiServer, 0, len(m.clientMap)) for _, client := range m.clientMap { @@ -468,123 +307,6 @@ func (m *roaManager) GetServers() []*config.RpkiServer { return l } -func (m *roaManager) GetRoa(family bgp.RouteFamily) ([]*table.ROA, error) { - if len(m.clientMap) == 0 { - return []*table.ROA{}, fmt.Errorf("RPKI server isn't configured") - } - var rfList []bgp.RouteFamily - switch family { - case bgp.RF_IPv4_UC: - rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC} - case bgp.RF_IPv6_UC: - rfList = []bgp.RouteFamily{bgp.RF_IPv6_UC} - default: - rfList = []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} - } - l := make([]*table.ROA, 0) - for _, rf := range rfList { - if tree, ok := m.Roas[rf]; ok { - tree.Walk(func(s string, v interface{}) bool { - b, _ := v.(*roaBucket) - var roaList roas - for _, r := range b.entries { - roaList = append(roaList, r) - } - sort.Sort(roaList) - for _, roa := range roaList { - l = append(l, roa) - } - return false - }) - } - } - return l, nil -} - -func validatePath(ownAs uint32, tree *radix.Tree, cidr string, asPath *bgp.PathAttributeAsPath) *table.Validation { - var as uint32 - - validation := &table.Validation{ - Status: config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND, - Reason: table.RPKI_VALIDATION_REASON_TYPE_NONE, - Matched: make([]*table.ROA, 0), - UnmatchedLength: make([]*table.ROA, 0), - UnmatchedAs: make([]*table.ROA, 0), - } - - if asPath == nil || len(asPath.Value) == 0 { - as = ownAs - } else { - param := asPath.Value[len(asPath.Value)-1] - switch param.GetType() { - case bgp.BGP_ASPATH_ATTR_TYPE_SEQ: - asList := param.GetAS() - if len(asList) == 0 { - as = ownAs - } else { - as = asList[len(asList)-1] - } - case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - as = ownAs - default: - return validation - } - } - _, n, _ := net.ParseCIDR(cidr) - ones, _ := n.Mask.Size() - prefixLen := uint8(ones) - key := table.IpToRadixkey(n.IP, prefixLen) - _, b, _ := tree.LongestPrefix(key) - if b == nil { - return validation - } - - var bucket *roaBucket - fn := radix.WalkFn(func(k string, v interface{}) bool { - bucket, _ = v.(*roaBucket) - for _, r := range bucket.entries { - if prefixLen <= r.MaxLen { - if r.AS != 0 && r.AS == as { - validation.Matched = append(validation.Matched, r) - } else { - validation.UnmatchedAs = append(validation.UnmatchedAs, r) - } - } else { - validation.UnmatchedLength = append(validation.UnmatchedLength, r) - } - } - return false - }) - tree.WalkPath(key, fn) - - if len(validation.Matched) != 0 { - validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_VALID - validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_NONE - } else if len(validation.UnmatchedAs) != 0 { - validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID - validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_AS - } else if len(validation.UnmatchedLength) != 0 { - validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_INVALID - validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_LENGTH - } else { - validation.Status = config.RPKI_VALIDATION_RESULT_TYPE_NOT_FOUND - validation.Reason = table.RPKI_VALIDATION_REASON_TYPE_NONE - } - - return validation -} - -func (m *roaManager) validate(path *table.Path) *table.Validation { - if len(m.clientMap) == 0 || path.IsWithdraw || path.IsEOR() { - // RPKI isn't enabled or invalid path - return nil - } - if tree, ok := m.Roas[path.GetRouteFamily()]; ok { - return validatePath(m.AS, tree, path.GetNlri().String(), path.GetAsPath()) - } - return nil -} - type roaClient struct { host string conn *net.TCPConn diff --git a/pkg/server/server.go b/pkg/server/server.go index 966f48b7..4ee64cf6 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -134,6 +134,7 @@ type BgpServer struct { zclient *zebraClient bmpManager *bmpClientManager mrtManager *mrtManager + roaTable *table.ROATable uuidMap map[string]uuid.UUID } @@ -142,16 +143,16 @@ func NewBgpServer(opt ...ServerOption) *BgpServer { for _, o := range opt { o(&opts) } - - roaManager, _ := newROAManager(0) + roaTable := table.NewROATable() s := &BgpServer{ neighborMap: make(map[string]*peer), peerGroupMap: make(map[string]*peerGroup), policy: table.NewRoutingPolicy(), - roaManager: roaManager, mgmtCh: make(chan *mgmtOp, 1), watcherMap: make(map[watchEventType][]*watcher), uuidMap: make(map[string]uuid.UUID), + roaManager: newROAManager(roaTable), + roaTable: roaTable, } s.bmpManager = newBmpClientManager(s) s.mrtManager = newMrtManager(s) @@ -674,7 +675,7 @@ func (s *BgpServer) filterpath(peer *peer, path, old *table.Path) *table.Path { if stop { return path } - options.Validate = s.roaManager.validate + options.Validate = s.roaTable.Validate path = peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, path, options) // When 'path' is filtered (path == nil), check 'old' has been sent to this peer. // If it has, send withdrawal to the peer. @@ -994,7 +995,7 @@ func (s *BgpServer) sendSecondaryRoutes(peer *peer, newPath *table.Path, dsts [] if stop { return nil } - options.Validate = s.roaManager.validate + options.Validate = s.roaTable.Validate path = peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, path, options) if path != nil { return s.postFilterpath(peer, path) @@ -1109,7 +1110,7 @@ func (s *BgpServer) propagateUpdate(peer *peer, pathList []*table.Path) { } policyOptions := &table.PolicyOptions{ - Validate: s.roaManager.validate, + Validate: s.roaTable.Validate, } if !rs && peer != nil { @@ -2117,8 +2118,6 @@ func (s *BgpServer) StartBgp(ctx context.Context, r *api.StartBgpRequest) error // update route selection options table.SelectionOptions = c.RouteSelectionOptions.Config table.UseMultiplePaths = c.UseMultiplePaths.Config - - s.roaManager.SetAS(s.bgpConfig.Global.Config.As) return nil }, false) } @@ -2383,7 +2382,7 @@ func (s *BgpServer) validateTable(r *table.Table) (v []*table.Validation) { v = make([]*table.Validation, 0, len(r.GetDestinations())) for _, d := range r.GetDestinations() { for _, p := range d.GetAllKnownPathList() { - v = append(v, s.roaManager.validate(p)) + v = append(v, s.roaTable.Validate(p)) } } } @@ -2465,7 +2464,7 @@ func (s *BgpServer) getAdjRib(addr string, family bgp.RouteFamily, in bool, enab if enableFiltered { for _, path := range peer.adjRibIn.PathList([]bgp.RouteFamily{family}, true) { options := &table.PolicyOptions{ - Validate: s.roaManager.validate, + Validate: s.roaTable.Validate, } if s.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_IMPORT, path, options) == nil { filtered[path.GetNlri().String()] = path @@ -2480,7 +2479,7 @@ func (s *BgpServer) getAdjRib(addr string, family bgp.RouteFamily, in bool, enab if stop { continue } - options.Validate = s.roaManager.validate + options.Validate = s.roaTable.Validate p := peer.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_EXPORT, path, options) if p == nil { filtered[path.GetNlri().String()] = path @@ -3615,7 +3614,7 @@ func (s *BgpServer) ListRpkiTable(ctx context.Context, r *api.ListRpkiTableReque if r.Family != nil { family = bgp.AfiSafiToRouteFamily(uint16(r.Family.Afi), uint8(r.Family.Safi)) } - roas, err := s.roaManager.GetRoa(family) + roas, err := s.roaTable.List(family) if err == nil { l = append(l, newRoaListFromTableStructList(roas)...) } |