Skip to content
Snippets Groups Projects
Unverified Commit 71458b44 authored by Serge Bazanski's avatar Serge Bazanski Committed by GitHub
Browse files

Merge pull request #59 from bio-routing/unfuck/as_loop_detection

Unfuck iBGP loop detection et all
parents 423bba84 57871c3f
Branches
Tags
No related merge requests found
Showing
with 224 additions and 41 deletions
...@@ -22,6 +22,7 @@ script: ...@@ -22,6 +22,7 @@ script:
- mkdir -p $HOME/gopath/src/github.com/bio-routing/ - mkdir -p $HOME/gopath/src/github.com/bio-routing/
- ln -s $TRAVIS_BUILD_DIR $HOME/gopath/src/github.com/bio-routing/bio-rd || true - ln -s $TRAVIS_BUILD_DIR $HOME/gopath/src/github.com/bio-routing/bio-rd || true
- cp .bazelrc.travis .bazelrc - cp .bazelrc.travis .bazelrc
- bazel test //...
- bazel coverage //... - bazel coverage //...
- bazel build //vendor/github.com/q3k/goveralls - bazel build //vendor/github.com/q3k/goveralls
- bazel-bin/vendor/github.com/q3k/goveralls/linux_amd64_stripped/goveralls -coverprofile=$(find bazel-testlogs/ -iname coverage.dat -or -iname baseline_coverage.dat | paste -sd ',') -merge=false - bazel-bin/vendor/github.com/q3k/goveralls/linux_amd64_stripped/goveralls -coverprofile=$(find bazel-testlogs/ -iname coverage.dat -or -iname baseline_coverage.dat | paste -sd ',') -merge=false
......
...@@ -33,6 +33,7 @@ go_library( ...@@ -33,6 +33,7 @@ go_library(
"//routingtable/adjRIBIn:go_default_library", "//routingtable/adjRIBIn:go_default_library",
"//routingtable/adjRIBOut:go_default_library", "//routingtable/adjRIBOut:go_default_library",
"//routingtable/filter:go_default_library", "//routingtable/filter:go_default_library",
"//routingtable/locRIB:go_default_library",
"//vendor/github.com/sirupsen/logrus:go_default_library", "//vendor/github.com/sirupsen/logrus:go_default_library",
], ],
) )
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/protocols/bgp/packet"
"github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable"
"github.com/bio-routing/bio-rd/routingtable/locRIB"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
...@@ -63,7 +64,7 @@ type FSM struct { ...@@ -63,7 +64,7 @@ type FSM struct {
ribsInitialized bool ribsInitialized bool
adjRIBIn routingtable.RouteTableClient adjRIBIn routingtable.RouteTableClient
adjRIBOut routingtable.RouteTableClient adjRIBOut routingtable.RouteTableClient
rib routingtable.RouteTableClient rib *locRIB.LocRIB
updateSender routingtable.RouteTableClient updateSender routingtable.RouteTableClient
neighborID uint32 neighborID uint32
......
...@@ -55,7 +55,10 @@ func (s establishedState) run() (state, string) { ...@@ -55,7 +55,10 @@ func (s establishedState) run() (state, string) {
} }
func (s *establishedState) init() error { func (s *establishedState) init() error {
s.fsm.adjRIBIn = adjRIBIn.New(s.fsm.peer.importFilter) contributingASNs := s.fsm.rib.GetContributingASNs()
s.fsm.adjRIBIn = adjRIBIn.New(s.fsm.peer.importFilter, contributingASNs)
contributingASNs.Add(s.fsm.peer.localASN)
s.fsm.adjRIBIn.Register(s.fsm.rib) s.fsm.adjRIBIn.Register(s.fsm.rib)
host, _, err := net.SplitHostPort(s.fsm.con.LocalAddr().String()) host, _, err := net.SplitHostPort(s.fsm.con.LocalAddr().String())
...@@ -96,6 +99,7 @@ func (s *establishedState) init() error { ...@@ -96,6 +99,7 @@ func (s *establishedState) init() error {
} }
func (s *establishedState) uninit() { func (s *establishedState) uninit() {
s.fsm.rib.GetContributingASNs().Remove(s.fsm.peer.localASN)
s.fsm.adjRIBIn.Unregister(s.fsm.rib) s.fsm.adjRIBIn.Unregister(s.fsm.rib)
s.fsm.rib.Unregister(s.fsm.adjRIBOut) s.fsm.rib.Unregister(s.fsm.adjRIBOut)
s.fsm.adjRIBOut.Unregister(s.fsm.updateSender) s.fsm.adjRIBOut.Unregister(s.fsm.updateSender)
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/protocols/bgp/packet"
"github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable"
"github.com/bio-routing/bio-rd/routingtable/filter" "github.com/bio-routing/bio-rd/routingtable/filter"
"github.com/bio-routing/bio-rd/routingtable/locRIB"
) )
type PeerInfo struct { type PeerInfo struct {
...@@ -27,7 +28,7 @@ type peer struct { ...@@ -27,7 +28,7 @@ type peer struct {
fsms []*FSM fsms []*FSM
fsmsMu sync.Mutex fsmsMu sync.Mutex
rib routingtable.RouteTableClient rib *locRIB.LocRIB
routerID uint32 routerID uint32
addPathSend routingtable.ClientOptions addPathSend routingtable.ClientOptions
addPathRecv bool addPathRecv bool
...@@ -100,7 +101,7 @@ func isEstablishedState(s state) bool { ...@@ -100,7 +101,7 @@ func isEstablishedState(s state) bool {
// NewPeer creates a new peer with the given config. If an connection is established, the adjRIBIN of the peer is connected // NewPeer creates a new peer with the given config. If an connection is established, the adjRIBIN of the peer is connected
// to the given rib. To actually connect the peer, call Start() on the returned peer. // to the given rib. To actually connect the peer, call Start() on the returned peer.
func newPeer(c config.Peer, rib routingtable.RouteTableClient, server *bgpServer) (*peer, error) { func newPeer(c config.Peer, rib *locRIB.LocRIB, server *bgpServer) (*peer, error) {
if c.LocalAS == 0 { if c.LocalAS == 0 {
c.LocalAS = server.localASN c.LocalAS = server.localASN
} }
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/config"
"github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/protocols/bgp/packet"
"github.com/bio-routing/bio-rd/routingtable" "github.com/bio-routing/bio-rd/routingtable/locRIB"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
...@@ -28,7 +28,7 @@ type bgpServer struct { ...@@ -28,7 +28,7 @@ type bgpServer struct {
type BGPServer interface { type BGPServer interface {
RouterID() uint32 RouterID() uint32
Start(*config.Global) error Start(*config.Global) error
AddPeer(config.Peer, routingtable.RouteTableClient) error AddPeer(config.Peer, *locRIB.LocRIB) error
GetPeerInfoAll() map[string]PeerInfo GetPeerInfoAll() map[string]PeerInfo
} }
...@@ -112,7 +112,7 @@ func (b *bgpServer) incomingConnectionWorker() { ...@@ -112,7 +112,7 @@ func (b *bgpServer) incomingConnectionWorker() {
} }
} }
func (b *bgpServer) AddPeer(c config.Peer, rib routingtable.RouteTableClient) error { func (b *bgpServer) AddPeer(c config.Peer, rib *locRIB.LocRIB) error {
peer, err := newPeer(c, rib, b) peer, err := newPeer(c, rib, b)
if err != nil { if err != nil {
return err return err
......
...@@ -11,23 +11,6 @@ import ( ...@@ -11,23 +11,6 @@ import (
"github.com/bio-routing/bio-rd/routingtable/locRIB" "github.com/bio-routing/bio-rd/routingtable/locRIB"
) )
func TestBgpServerConfigCheck(t *testing.T) {
s := NewBgpServer()
err := s.Start(&config.Global{})
if err == nil {
t.Fatalf("server with empty config should not start")
}
err = s.Start(&config.Global{
LocalASN: 204880,
RouterID: 2137,
})
if err != nil {
t.Fatalf("server should have started, got err: %v", err)
}
}
func TestBgpServerPeerSnapshot(t *testing.T) { func TestBgpServerPeerSnapshot(t *testing.T) {
s := NewBgpServer() s := NewBgpServer()
err := s.Start(&config.Global{ err := s.Start(&config.Global{
......
...@@ -5,6 +5,7 @@ go_library( ...@@ -5,6 +5,7 @@ go_library(
srcs = [ srcs = [
"client_interface.go", "client_interface.go",
"client_manager.go", "client_manager.go",
"contributing_asn_list.go",
"neighbor.go", "neighbor.go",
"rib_interface.go", "rib_interface.go",
"table.go", "table.go",
...@@ -25,6 +26,7 @@ go_test( ...@@ -25,6 +26,7 @@ go_test(
name = "go_default_test", name = "go_default_test",
srcs = [ srcs = [
"client_manager_test.go", "client_manager_test.go",
"contributing_asn_list_test.go",
"table_test.go", "table_test.go",
"trie_test.go", "trie_test.go",
"update_helper_test.go", "update_helper_test.go",
......
...@@ -7,6 +7,7 @@ go_library( ...@@ -7,6 +7,7 @@ go_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//net:go_default_library", "//net:go_default_library",
"//protocols/bgp/packet:go_default_library",
"//route:go_default_library", "//route:go_default_library",
"//routingtable:go_default_library", "//routingtable:go_default_library",
"//routingtable/filter:go_default_library", "//routingtable/filter:go_default_library",
......
...@@ -3,6 +3,7 @@ package adjRIBIn ...@@ -3,6 +3,7 @@ package adjRIBIn
import ( import (
"sync" "sync"
"github.com/bio-routing/bio-rd/protocols/bgp/packet"
"github.com/bio-routing/bio-rd/routingtable/filter" "github.com/bio-routing/bio-rd/routingtable/filter"
"github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/net"
...@@ -14,16 +15,18 @@ import ( ...@@ -14,16 +15,18 @@ import (
// AdjRIBIn represents an Adjacency RIB In as described in RFC4271 // AdjRIBIn represents an Adjacency RIB In as described in RFC4271
type AdjRIBIn struct { type AdjRIBIn struct {
routingtable.ClientManager routingtable.ClientManager
rt *routingtable.RoutingTable rt *routingtable.RoutingTable
mu sync.RWMutex mu sync.RWMutex
exportFilter *filter.Filter exportFilter *filter.Filter
contributingASNs *routingtable.ContributingASNs
} }
// New creates a new Adjacency RIB In // New creates a new Adjacency RIB In
func New(exportFilter *filter.Filter) *AdjRIBIn { func New(exportFilter *filter.Filter, contributingASNs *routingtable.ContributingASNs) *AdjRIBIn {
a := &AdjRIBIn{ a := &AdjRIBIn{
rt: routingtable.NewRoutingTable(), rt: routingtable.NewRoutingTable(),
exportFilter: exportFilter, exportFilter: exportFilter,
contributingASNs: contributingASNs,
} }
a.ClientManager = routingtable.NewClientManager(a) a.ClientManager = routingtable.NewClientManager(a)
return a return a
...@@ -65,12 +68,32 @@ func (a *AdjRIBIn) AddPath(pfx net.Prefix, p *route.Path) error { ...@@ -65,12 +68,32 @@ func (a *AdjRIBIn) AddPath(pfx net.Prefix, p *route.Path) error {
return nil return nil
} }
// Bail out - for all clients for now - if any of our ASNs is within the path
if a.ourASNsInPath(p) {
return nil
}
for _, client := range a.ClientManager.Clients() { for _, client := range a.ClientManager.Clients() {
client.AddPath(pfx, p) client.AddPath(pfx, p)
} }
return nil return nil
} }
func (a *AdjRIBIn) ourASNsInPath(p *route.Path) bool {
// Don't accept path via iBGP which contain our ASN
ASPathAttr, _ := packet.ParseASPathStr(p.BGPPath.ASPath)
for _, pathSegment := range ASPathAttr.Value.(packet.ASPath) {
for _, asn := range pathSegment.ASNs {
if a.contributingASNs.IsContributingASN(asn) {
return true
}
}
}
return false
}
// RemovePath removes the path for prefix `pfx` // RemovePath removes the path for prefix `pfx`
func (a *AdjRIBIn) RemovePath(pfx net.Prefix, p *route.Path) bool { func (a *AdjRIBIn) RemovePath(pfx net.Prefix, p *route.Path) bool {
a.mu.Lock() a.mu.Lock()
......
...@@ -115,7 +115,7 @@ func TestAddPath(t *testing.T) { ...@@ -115,7 +115,7 @@ func TestAddPath(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
adjRIBIn := New(filter.NewAcceptAllFilter()) adjRIBIn := New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs())
mc := NewRTMockClient() mc := NewRTMockClient()
adjRIBIn.ClientManager.Register(mc) adjRIBIn.ClientManager.Register(mc)
...@@ -206,7 +206,7 @@ func TestRemovePath(t *testing.T) { ...@@ -206,7 +206,7 @@ func TestRemovePath(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
adjRIBIn := New(filter.NewAcceptAllFilter()) adjRIBIn := New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs())
for _, route := range test.routes { for _, route := range test.routes {
adjRIBIn.AddPath(route.Prefix(), route.Paths()[0]) adjRIBIn.AddPath(route.Prefix(), route.Paths()[0])
} }
......
package routingtable
import (
"fmt"
"math"
"sync"
)
type contributingASN struct {
asn uint32
count uint32
}
// ContributingASNs contains a list of contributing ASN to a LocRIB to check ASPaths for possible routing loops.
type ContributingASNs struct {
contributingASNs []*contributingASN
contributingASNsLock sync.RWMutex
}
// NewContributingASNs creates a list of contributing ASNs to a LocRIB for routing loop prevention.
func NewContributingASNs() *ContributingASNs {
c := &ContributingASNs{
contributingASNs: []*contributingASN{},
}
return c
}
// Add a new ASN to the list of contributing ASNs or add the ref count of an existing one.
func (c *ContributingASNs) Add(asn uint32) {
c.contributingASNsLock.Lock()
defer c.contributingASNsLock.Unlock()
for _, cASN := range c.contributingASNs {
if cASN.asn == asn {
cASN.count++
if cASN.count == math.MaxUint32 {
panic(fmt.Sprintf("Contributing ASNs counter overflow triggered for AS %d. Dyning of shame.", asn))
}
return
}
}
c.contributingASNs = append(c.contributingASNs, &contributingASN{
asn: asn,
count: 1,
})
}
// Remove a ASN to the list of contributing ASNs or decrement the ref count of an existing one.
func (c *ContributingASNs) Remove(asn uint32) {
c.contributingASNsLock.Lock()
defer c.contributingASNsLock.Unlock()
asnList := c.contributingASNs
for i, cASN := range asnList {
if cASN.asn != asn {
continue
}
cASN.count--
if cASN.count == 0 {
copy(asnList[i:], asnList[i+1:])
asnList = asnList[:len(asnList)]
c.contributingASNs = asnList[:len(asnList)-1]
}
return
}
}
// IsContributingASN checks if a given ASN is part of the contributing ASNs
func (c *ContributingASNs) IsContributingASN(asn uint32) bool {
c.contributingASNsLock.RLock()
defer c.contributingASNsLock.RUnlock()
for _, cASN := range c.contributingASNs {
if asn == cASN.asn {
return true
}
}
return false
}
package routingtable
import (
"fmt"
"testing"
)
func TestFancy(t *testing.T) {
c := NewContributingASNs()
tests := []struct {
runCmd func()
expect func() bool
msg string
}{
// Empty list
{
runCmd: func() {},
expect: func() bool { return !c.IsContributingASN(41981) },
msg: "AS41981 shouldn't be contributing yet.",
},
// Add and remove one ASN
{
runCmd: func() { c.Add(41981) },
expect: func() bool { return c.IsContributingASN(41981) },
msg: "AS41981 should be contributing",
},
{
runCmd: func() { c.Remove(41981) },
expect: func() bool { return !c.IsContributingASN(41981) },
msg: "AS41981 shouldn't be contributing no more.",
},
// Two ASNs present
{
runCmd: func() { c.Add(41981) },
expect: func() bool { return c.IsContributingASN(41981) },
msg: "AS41981 should be contributing",
},
{
runCmd: func() { c.Add(201701) },
expect: func() bool { return c.IsContributingASN(41981) },
msg: "AS201701 should be contributing",
},
// Add AS41981 2nd time
{
runCmd: func() { c.Add(41981) },
expect: func() bool { return c.IsContributingASN(41981) },
msg: "AS41981 should be still contributing",
},
{
runCmd: func() {},
expect: func() bool { return c.contributingASNs[0].asn == 41981 },
msg: "AS41981 is first ASN in list",
},
{
runCmd: func() { fmt.Printf("%+v", c.contributingASNs) },
expect: func() bool { return c.contributingASNs[0].count == 2 },
msg: "AS41981 should be present twice.",
},
}
for i, test := range tests {
test.runCmd()
if !test.expect() {
t.Errorf("Test %d failed: %v", i, test.msg)
}
}
}
...@@ -14,19 +14,26 @@ import ( ...@@ -14,19 +14,26 @@ import (
// LocRIB represents a routing information base // LocRIB represents a routing information base
type LocRIB struct { type LocRIB struct {
routingtable.ClientManager routingtable.ClientManager
rt *routingtable.RoutingTable rt *routingtable.RoutingTable
mu sync.RWMutex mu sync.RWMutex
contributingASNs *routingtable.ContributingASNs
} }
// New creates a new routing information base // New creates a new routing information base
func New() *LocRIB { func New() *LocRIB {
a := &LocRIB{ a := &LocRIB{
rt: routingtable.NewRoutingTable(), rt: routingtable.NewRoutingTable(),
contributingASNs: routingtable.NewContributingASNs(),
} }
a.ClientManager = routingtable.NewClientManager(a) a.ClientManager = routingtable.NewClientManager(a)
return a return a
} }
// GetContributingASNs returns a pointer to the list of contributing ASNs
func (a *LocRIB) GetContributingASNs() *routingtable.ContributingASNs {
return a.contributingASNs
}
//Count routes from the LocRIP //Count routes from the LocRIP
func (a *LocRIB) Count() uint64 { func (a *LocRIB) Count() uint64 {
a.mu.RLock() a.mu.RLock()
......
...@@ -13,7 +13,7 @@ go_library( ...@@ -13,7 +13,7 @@ go_library(
"union.go", "union.go",
"version.go", "version.go",
], ],
importmap = "vendor/github.com/Masterminds/semver", importmap = "github.com/bio-routing/bio-rd/vendor/github.com/Masterminds/semver",
importpath = "github.com/Masterminds/semver", importpath = "github.com/Masterminds/semver",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
...@@ -12,7 +12,7 @@ go_library( ...@@ -12,7 +12,7 @@ go_library(
"vcs_local_lookup.go", "vcs_local_lookup.go",
"vcs_remote_lookup.go", "vcs_remote_lookup.go",
], ],
importmap = "vendor/github.com/Masterminds/vcs", importmap = "github.com/bio-routing/bio-rd/vendor/github.com/Masterminds/vcs",
importpath = "github.com/Masterminds/vcs", importpath = "github.com/Masterminds/vcs",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
...@@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["radix.go"], srcs = ["radix.go"],
importmap = "vendor/github.com/armon/go-radix", importmap = "github.com/bio-routing/bio-rd/vendor/github.com/armon/go-radix",
importpath = "github.com/armon/go-radix", importpath = "github.com/armon/go-radix",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
...@@ -26,7 +26,7 @@ go_library( ...@@ -26,7 +26,7 @@ go_library(
"page.go", "page.go",
"tx.go", "tx.go",
], ],
importmap = "vendor/github.com/boltdb/bolt", importmap = "github.com/bio-routing/bio-rd/vendor/github.com/boltdb/bolt",
importpath = "github.com/boltdb/bolt", importpath = "github.com/boltdb/bolt",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = select({ deps = select({
......
...@@ -11,7 +11,7 @@ go_library( ...@@ -11,7 +11,7 @@ go_library(
"format.go", "format.go",
"spew.go", "spew.go",
], ],
importmap = "vendor/github.com/davecgh/go-spew/spew", importmap = "github.com/bio-routing/bio-rd/vendor/github.com/davecgh/go-spew/spew",
importpath = "github.com/davecgh/go-spew/spew", importpath = "github.com/davecgh/go-spew/spew",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
...@@ -17,7 +17,7 @@ go_library( ...@@ -17,7 +17,7 @@ go_library(
"yamlh.go", "yamlh.go",
"yamlprivateh.go", "yamlprivateh.go",
], ],
importmap = "vendor/github.com/go-yaml/yaml", importmap = "github.com/bio-routing/bio-rd/vendor/github.com/go-yaml/yaml",
importpath = "github.com/go-yaml/yaml", importpath = "github.com/go-yaml/yaml",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment