diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index 33e000d1c6010a2e3b976b13bec591a7e0e67545..0c5221391c80e1dbd7bf1262d2506192eba80924 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -8,6 +8,7 @@ import ( "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" ) @@ -61,7 +62,7 @@ type FSM struct { ribsInitialized bool adjRIBIn routingtable.RouteTableClient adjRIBOut routingtable.RouteTableClient - rib routingtable.RouteTableClient + rib *locRIB.LocRIB updateSender routingtable.RouteTableClient neighborID uint32 diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go index 80ff7fa7990493186924f8c35f1a90deb0c93e5b..58facab0cd4ad487245cfe431a73478d3ca455a8 100644 --- a/protocols/bgp/server/fsm_established.go +++ b/protocols/bgp/server/fsm_established.go @@ -55,7 +55,10 @@ func (s establishedState) run() (state, string) { } 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) host, _, err := net.SplitHostPort(s.fsm.con.LocalAddr().String()) @@ -96,6 +99,7 @@ func (s *establishedState) init() error { } func (s *establishedState) uninit() { + s.fsm.rib.GetContributingASNs().Remove(s.fsm.peer.localASN) s.fsm.adjRIBIn.Unregister(s.fsm.rib) s.fsm.rib.Unregister(s.fsm.adjRIBOut) s.fsm.adjRIBOut.Unregister(s.fsm.updateSender) diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go index bad268285a156e5d32576af75521f42a7436a603..3e5e6aeea408d1be12c4fd1ca38b6e62ba2af3b4 100644 --- a/protocols/bgp/server/peer.go +++ b/protocols/bgp/server/peer.go @@ -5,6 +5,8 @@ import ( "sync" "time" + "github.com/bio-routing/bio-rd/routingtable/locRIB" + "github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/routingtable" @@ -27,7 +29,7 @@ type peer struct { fsms []*FSM fsmsMu sync.Mutex - rib routingtable.RouteTableClient + rib *locRIB.LocRIB routerID uint32 addPathSend routingtable.ClientOptions addPathRecv bool @@ -100,7 +102,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 // 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 { c.LocalAS = server.localASN } diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go index 61c79de10315e5efa65c27e7da820b3a39aee4df..f0354f7ed1587ffd2ec84132ec50e117edfb72bb 100644 --- a/protocols/bgp/server/server.go +++ b/protocols/bgp/server/server.go @@ -7,9 +7,10 @@ import ( "strings" "sync" + "github.com/bio-routing/bio-rd/routingtable/locRIB" + "github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/protocols/bgp/packet" - "github.com/bio-routing/bio-rd/routingtable" log "github.com/sirupsen/logrus" ) @@ -29,7 +30,7 @@ type bgpServer struct { type BGPServer interface { RouterID() uint32 Start(*config.Global) error - AddPeer(config.Peer, routingtable.RouteTableClient) error + AddPeer(config.Peer, *locRIB.LocRIB) error GetPeerInfoAll() map[string]PeerInfo } @@ -113,7 +114,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 { if c.LocalAS > uint16max || c.PeerAS > uint16max { return fmt.Errorf("32bit ASNs are not supported yet") } diff --git a/routingtable/adjRIBIn/adj_rib_in.go b/routingtable/adjRIBIn/adj_rib_in.go index ca9d0bb07570811beec3ffa3eb99ec12423f6041..81416d9a488ac25711946d8b64f8bfe316a31a5a 100644 --- a/routingtable/adjRIBIn/adj_rib_in.go +++ b/routingtable/adjRIBIn/adj_rib_in.go @@ -20,7 +20,7 @@ type AdjRIBIn struct { } // New creates a new Adjacency RIB In -func New(exportFilter *filter.Filter) *AdjRIBIn { +func New(exportFilter *filter.Filter, contributingASNs *routingtable.ContributingASNs) *AdjRIBIn { a := &AdjRIBIn{ rt: routingtable.NewRoutingTable(), exportFilter: exportFilter, diff --git a/routingtable/contributing_asn_list.go b/routingtable/contributing_asn_list.go new file mode 100644 index 0000000000000000000000000000000000000000..0b0efca268d477d59728bbf44151f75d733845f3 --- /dev/null +++ b/routingtable/contributing_asn_list.go @@ -0,0 +1,64 @@ +package routingtable + +import ( + "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 + mu 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.mu.RLock() + defer c.mu.RUnlock() + + for _, cASN := range c.contributingASNs { + if cASN.asn == asn { + cASN.count++ + 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.mu.RLock() + defer c.mu.RUnlock() + + asnList := c.contributingASNs + + for i, cASN := range asnList { + if cASN.asn == asn { + cASN.count-- + + if cASN.count == 0 { + copy(asnList[i:], asnList[i+1:]) + asnList = asnList[:len(asnList)] + c.contributingASNs = asnList[:len(asnList)-1] + } + return + } + } +} diff --git a/routingtable/locRIB/loc_rib.go b/routingtable/locRIB/loc_rib.go index ff5750c34d226080bea079968becdec410d2704e..a8ddf1e6a15ff40a6b6f1d6d9f0a643e4e81a20c 100644 --- a/routingtable/locRIB/loc_rib.go +++ b/routingtable/locRIB/loc_rib.go @@ -14,19 +14,26 @@ import ( // LocRIB represents a routing information base type LocRIB struct { routingtable.ClientManager - rt *routingtable.RoutingTable - mu sync.RWMutex + rt *routingtable.RoutingTable + mu sync.RWMutex + contributingASNs *routingtable.ContributingASNs } // New creates a new routing information base func New() *LocRIB { a := &LocRIB{ - rt: routingtable.NewRoutingTable(), + rt: routingtable.NewRoutingTable(), + contributingASNs: routingtable.NewContributingASNs(), } a.ClientManager = routingtable.NewClientManager(a) return a } +// GetContributingASNs returns a pointer to the list of contributing ASNs +func (a *LocRIB) GetContributingASNs() *routingtable.ContributingASNs { + return a.contributingASNs +} + // UpdateNewClient sends current state to a new client func (a *LocRIB) UpdateNewClient(client routingtable.RouteTableClient) error { a.mu.RLock()