diff --git a/main.go b/main.go index 7e19a5aa8d1e0d982435fe12dd8229eecfbb1a35..3e0598bce10567ead6b30ea7f9e1caeebeafdcf3 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( ) func main() { - fmt.Printf("This is a BGP speaker\n") + logrus.Printf("This is a BGP speaker\n") rib := locRIB.New() b := server.NewBgpServer() diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index fc342e821871667f3d4fe7aab18e5d50e225674a..2a9f89dc96eba5d33ae21896452c1abca73249da 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -16,7 +16,6 @@ import ( "github.com/bio-routing/bio-rd/routingtable/adjRIBIn" "github.com/bio-routing/bio-rd/routingtable/adjRIBOut" "github.com/bio-routing/bio-rd/routingtable/adjRIBOutAddPath" - "github.com/bio-routing/bio-rd/routingtable/locRIB" log "github.com/sirupsen/logrus" tomb "gopkg.in/tomb.v2" ) @@ -92,7 +91,7 @@ type FSM struct { adjRIBIn *adjRIBIn.AdjRIBIn adjRIBOut routingtable.RouteTableClient - rib *locRIB.LocRIB + rib routingtable.RouteTableClient updateSender routingtable.RouteTableClient capAddPathSend bool @@ -109,7 +108,7 @@ type msgRecvErr struct { con *net.TCPConn } -func NewFSM(peer *Peer, c config.Peer, rib *locRIB.LocRIB) *FSM { +func NewFSM(peer *Peer, c config.Peer, rib routingtable.RouteTableClient) *FSM { fsm := &FSM{ peer: peer, state: Idle, @@ -647,7 +646,7 @@ func (fsm *FSM) openConfirm() int { case recvMsg := <-fsm.msgRecvCh: msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg)) if err != nil { - fmt.Printf("Failed to decode message: %v\n", recvMsg.msg) + log.WithError(err).Errorf("Failed to decode BGP message %v\n", recvMsg.msg) switch bgperr := err.(type) { case packet.BGPError: sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode) @@ -790,7 +789,8 @@ func (fsm *FSM) established() int { case recvMsg := <-fsm.msgRecvCh: msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg)) if err != nil { - fmt.Printf("Failed to decode BGP message: %v\n", recvMsg.msg) + log.WithError(err).Errorf("Failed to decode BGP message %v\n", recvMsg.msg) + switch bgperr := err.(type) { case packet.BGPError: sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode) @@ -815,14 +815,13 @@ func (fsm *FSM) established() int { for r := u.WithdrawnRoutes; r != nil; r = r.Next { pfx := tnet.NewPfx(r.IP, r.Pfxlen) - fmt.Printf("LPM: Removing prefix %s\n", pfx.String()) + log.WithField("Prefix", pfx.String()).Debug("LPM: Removing prefix") fsm.adjRIBIn.RemovePath(pfx, nil) } for r := u.NLRI; r != nil; r = r.Next { pfx := tnet.NewPfx(r.IP, r.Pfxlen) - fmt.Printf("LPM: Adding prefix %s\n", pfx.String()) - + log.WithField("Prefix", pfx.String()).Debug("LPM: Adding prefix") path := &route.Path{ Type: route.BGPPathType, BGPPath: &route.BGPPath{ @@ -831,7 +830,6 @@ func (fsm *FSM) established() int { } for pa := u.PathAttributes; pa != nil; pa = pa.Next { - fmt.Printf("TypeCode: %d\n", pa.TypeCode) switch pa.TypeCode { case packet.OriginAttr: path.BGPPath.Origin = pa.Value.(uint8) @@ -840,7 +838,7 @@ func (fsm *FSM) established() int { case packet.MEDAttr: path.BGPPath.MED = pa.Value.(uint32) case packet.NextHopAttr: - fmt.Printf("RECEIVED NEXT_HOP: %d\n", pa.Value.(uint32)) + log.WithField("NextHop", pa.Value.(uint32)).Debug("RECEIVED NEXT_HOP") path.BGPPath.NextHop = pa.Value.(uint32) case packet.ASPathAttr: path.BGPPath.ASPath = pa.ASPathString() diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go index c891b9ddcea9042980c2d71e6b1475f16018b7b0..ab1dd7467c13597bbece848f6c169b17b6cccd34 100644 --- a/protocols/bgp/server/peer.go +++ b/protocols/bgp/server/peer.go @@ -3,9 +3,9 @@ package server import ( "net" + "github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/routingtable" - "github.com/bio-routing/bio-rd/routingtable/locRIB" "time" @@ -16,7 +16,7 @@ type Peer struct { addr net.IP asn uint32 fsm *FSM - rib *locRIB.LocRIB + rib routingtable.RouteTableClient routerID uint32 addPathSend routingtable.ClientOptions addPathRecv bool @@ -26,7 +26,7 @@ type Peer struct { // 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 *locRIB.LocRIB) (*Peer, error) { +func NewPeer(c config.Peer, rib routingtable.RouteTableClient) (*Peer, error) { p := &Peer{ addr: c.PeerAddress, asn: c.PeerAS, diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go index 8a11cd3a0641c6ff926ddc4459da157d7273db44..a6025140fd62f81d8fa503aeb0c31114a7589f2b 100644 --- a/protocols/bgp/server/server.go +++ b/protocols/bgp/server/server.go @@ -8,7 +8,7 @@ import ( "github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/protocols/bgp/packet" - "github.com/bio-routing/bio-rd/routingtable/locRIB" + "github.com/bio-routing/bio-rd/routingtable" log "github.com/sirupsen/logrus" ) @@ -39,7 +39,7 @@ func (b *BGPServer) Start(c *config.Global) error { return fmt.Errorf("Failed to load defaults: %v", err) } - fmt.Printf("ROUTER ID: %d\n", c.RouterID) + log.Infof("ROUTER ID: %d\n", c.RouterID) b.routerID = c.RouterID if c.Listen { @@ -62,8 +62,6 @@ func (b *BGPServer) Start(c *config.Global) error { func (b *BGPServer) incomingConnectionWorker() { for { c := <-b.acceptCh - fmt.Printf("Incoming connection!\n") - fmt.Printf("Connection from: %v\n", c.RemoteAddr()) peerAddr := strings.Split(c.RemoteAddr().String(), ":")[0] if _, ok := b.peers[peerAddr]; !ok { @@ -78,13 +76,13 @@ func (b *BGPServer) incomingConnectionWorker() { "source": c.RemoteAddr(), }).Info("Incoming TCP connection") - fmt.Printf("DEBUG: Sending incoming TCP connection to fsm for peer %s\n", peerAddr) + log.WithField("Peer", peerAddr).Debug("Sending incoming TCP connection to fsm for peer") b.peers[peerAddr].fsm.conCh <- c - fmt.Printf("DEBUG: Sending done\n") + log.Debug("Sending done") } } -func (b *BGPServer) AddPeer(c config.Peer, rib *locRIB.LocRIB) error { +func (b *BGPServer) AddPeer(c config.Peer, rib routingtable.RouteTableClient) error { if c.LocalAS > uint16max || c.PeerAS > uint16max { return fmt.Errorf("32bit ASNs are not supported yet") } diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go index a5d05887f026cf336e3792e405fa7c456eae6e74..c33f2ce01882e0ba1326962fce7396c9005d9aae 100644 --- a/protocols/bgp/server/update_sender.go +++ b/protocols/bgp/server/update_sender.go @@ -15,18 +15,20 @@ import ( // UpdateSender converts table changes into BGP update messages type UpdateSender struct { routingtable.ClientManager - fsm *FSM + fsm *FSM + iBGP bool } func newUpdateSender(fsm *FSM) *UpdateSender { return &UpdateSender{ - fsm: fsm, + fsm: fsm, + iBGP: fsm.localASN == fsm.remoteASN, } } // AddPath serializes a new path and sends out a BGP update message func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error { - asPathPA, err := packet.ParseASPathStr(strings.TrimRight(fmt.Sprintf("%d %s", u.fsm.localASN, p.BGPPath.ASPath), " ")) + asPathPA, err := packet.ParseASPathStr(asPathString(u.iBGP, u.fsm.localASN, p.BGPPath.ASPath)) if err != nil { return fmt.Errorf("Unable to parse AS path: %v", err) } @@ -41,6 +43,10 @@ func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error { Next: &packet.PathAttribute{ TypeCode: packet.NextHopAttr, Value: p.BGPPath.NextHop, + Next: &packet.PathAttribute{ + TypeCode: packet.LocalPrefAttr, + Value: p.BGPPath.LocalPref, + }, }, }, }, @@ -74,3 +80,12 @@ func (u *UpdateSender) UpdateNewClient(client routingtable.RouteTableClient) err log.Warningf("BGP Update Sender: UpdateNewClient() not supported") return nil } + +func asPathString(iBGP bool, localASN uint16, asPath string) string { + ret := "" + if iBGP { + ret = ret + fmt.Sprintf("%d ", localASN) + } + ret = ret + asPath + return strings.TrimRight(ret, " ") +} diff --git a/protocols/bgp/server/update_sender_add_path.go b/protocols/bgp/server/update_sender_add_path.go index e7b46577c594c5b5f84e115981ac560777899d11..a0fe2b3046174cfd5abd929366f631fb07c4d4fc 100644 --- a/protocols/bgp/server/update_sender_add_path.go +++ b/protocols/bgp/server/update_sender_add_path.go @@ -2,7 +2,6 @@ package server import ( "fmt" - "strings" log "github.com/sirupsen/logrus" @@ -15,18 +14,20 @@ import ( // UpdateSenderAddPath converts table changes into BGP update messages with add path type UpdateSenderAddPath struct { routingtable.ClientManager - fsm *FSM + fsm *FSM + iBGP bool } func newUpdateSenderAddPath(fsm *FSM) *UpdateSenderAddPath { return &UpdateSenderAddPath{ - fsm: fsm, + fsm: fsm, + iBGP: fsm.localASN == fsm.remoteASN, } } // AddPath serializes a new path and sends out a BGP update message func (u *UpdateSenderAddPath) AddPath(pfx net.Prefix, p *route.Path) error { - asPathPA, err := packet.ParseASPathStr(strings.TrimRight(fmt.Sprintf("%d %s", u.fsm.localASN, p.BGPPath.ASPath), " ")) + asPathPA, err := packet.ParseASPathStr(asPathString(u.iBGP, u.fsm.localASN, p.BGPPath.ASPath)) if err != nil { return fmt.Errorf("Unable to parse AS path: %v", err) } @@ -41,6 +42,10 @@ func (u *UpdateSenderAddPath) AddPath(pfx net.Prefix, p *route.Path) error { Next: &packet.PathAttribute{ TypeCode: packet.NextHopAttr, Value: p.BGPPath.NextHop, + Next: &packet.PathAttribute{ + TypeCode: packet.LocalPrefAttr, + Value: p.BGPPath.LocalPref, + }, }, }, }, diff --git a/routingtable/adjRIBIn/adj_rib_in.go b/routingtable/adjRIBIn/adj_rib_in.go index 1427278bbd5aa6c465c16bf2ac4e1462fd5a34d8..cd4dde58f17e42d9bf75433850dfa39bf2498fbf 100644 --- a/routingtable/adjRIBIn/adj_rib_in.go +++ b/routingtable/adjRIBIn/adj_rib_in.go @@ -6,6 +6,7 @@ import ( "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable" + log "github.com/sirupsen/logrus" ) // AdjRIBIn represents an Adjacency RIB In as described in RFC4271 @@ -33,7 +34,11 @@ func (a *AdjRIBIn) UpdateNewClient(client routingtable.RouteTableClient) error { for _, route := range routes { paths := route.Paths() for _, path := range paths { - client.AddPath(route.Prefix(), path) + + err := client.AddPath(route.Prefix(), path) + if err != nil { + log.WithField("Sender", "AdjRIBOutAddPath").WithError(err).Error("Could not send update to client") + } } } return nil diff --git a/routingtable/adjRIBIn/adj_rib_in_test.go b/routingtable/adjRIBIn/adj_rib_in_test.go index 5659ab805f73b3bf888a08fa8ff6a7dbe8185bdf..a994e0f5e82be4ccef141ce63463b762d055d111 100644 --- a/routingtable/adjRIBIn/adj_rib_in_test.go +++ b/routingtable/adjRIBIn/adj_rib_in_test.go @@ -34,6 +34,10 @@ func (m *RTMockClient) Register(routingtable.RouteTableClient) { return } +func (m *RTMockClient) RegisterWithOptions(routingtable.RouteTableClient, routingtable.ClientOptions) { + return +} + func (m *RTMockClient) Unregister(routingtable.RouteTableClient) { return } diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go index 1ddd93c6e05b835c9952b6e86ba5fe57545ed5e4..51347119a6b360fd2f81283edc18d9225548fdf2 100644 --- a/routingtable/adjRIBOut/adj_rib_out.go +++ b/routingtable/adjRIBOut/adj_rib_out.go @@ -7,6 +7,7 @@ import ( "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable" + log "github.com/sirupsen/logrus" ) // AdjRIBOut represents an Adjacency RIB In as described in RFC4271 @@ -45,7 +46,10 @@ func (a *AdjRIBOut) AddPath(pfx net.Prefix, p *route.Path) error { a.removePathsFromClients(pfx, oldPaths) for _, client := range a.ClientManager.Clients() { - client.AddPath(pfx, p) + err := client.AddPath(pfx, p) + if err != nil { + log.WithField("Sender", "AdjRIBOut").WithError(err).Error("Could not send update to client") + } } return nil } diff --git a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go index 2b4dff95575b2df72036642f40bd69cfedb4e5ab..90f76fcc873643a6d94086b0b84f5bf940b6fa9f 100644 --- a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go +++ b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go @@ -7,6 +7,7 @@ import ( "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable" + log "github.com/sirupsen/logrus" ) // AdjRIBOutAddPath represents an Adjacency RIB Out with BGP add path @@ -52,7 +53,10 @@ func (a *AdjRIBOutAddPath) AddPath(pfx net.Prefix, p *route.Path) error { a.rt.AddPath(pfx, p) for _, client := range a.ClientManager.Clients() { - client.AddPath(pfx, p) + err := client.AddPath(pfx, p) + if err != nil { + log.WithField("Sender", "AdjRIBOutAddPath").WithError(err).Error("Could not send update to client") + } } return nil } diff --git a/routingtable/client_interface.go b/routingtable/client_interface.go index 0800ceec8db1cb3b758b74b3a1d3c8b7aef62acb..e7190c5b6c0bb1829f59cf5faadd0623ef3b395c 100644 --- a/routingtable/client_interface.go +++ b/routingtable/client_interface.go @@ -11,5 +11,6 @@ type RouteTableClient interface { RemovePath(net.Prefix, *route.Path) bool UpdateNewClient(RouteTableClient) error Register(RouteTableClient) + RegisterWithOptions(RouteTableClient, ClientOptions) Unregister(RouteTableClient) } diff --git a/routingtable/client_manager.go b/routingtable/client_manager.go index 20d848b2c090a4c311cb4a81fc8c1c4697cf5891..f29ae2dce47dc7e4a3d3ba725ff5d57fd27f74f6 100644 --- a/routingtable/client_manager.go +++ b/routingtable/client_manager.go @@ -55,9 +55,8 @@ func (c *ClientManager) Register(client RouteTableClient) { // RegisterWithOptions registers a client with options for updates func (c *ClientManager) RegisterWithOptions(client RouteTableClient, opt ClientOptions) { c.mu.Lock() - defer c.mu.Unlock() - c.clients[client] = opt + c.mu.Unlock() c.master.UpdateNewClient(client) } diff --git a/routingtable/client_manager_test.go b/routingtable/client_manager_test.go index af2507855bfac8a5d09551b105d7bfc4ae93dd79..78e2e58c4030a2e25a1b9ae228ef712fc1c67550 100644 --- a/routingtable/client_manager_test.go +++ b/routingtable/client_manager_test.go @@ -25,6 +25,11 @@ func (m MockClient) UpdateNewClient(RouteTableClient) error { func (m MockClient) Register(RouteTableClient) { return } + +func (m MockClient) RegisterWithOptions(RouteTableClient, ClientOptions) { + return +} + func (m MockClient) Unregister(RouteTableClient) { return } diff --git a/routingtable/filter/term_condition.go b/routingtable/filter/term_condition.go index 92c3616a8cc55f21c73696b2f87a1b2a9cfbcbd4..8bc87485d58bd9215d122e4af9792c7c0c1c2b82 100644 --- a/routingtable/filter/term_condition.go +++ b/routingtable/filter/term_condition.go @@ -10,6 +10,13 @@ type TermCondition struct { routeFilters []*RouteFilter } +func NewTermCondition(prefixLists []*PrefixList, routeFilters []*RouteFilter) *TermCondition { + return &TermCondition{ + prefixLists: prefixLists, + routeFilters: routeFilters, + } +} + func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool { return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p) } diff --git a/routingtable/filter/term_condition_test.go b/routingtable/filter/term_condition_test.go index 876746a240d195ee2a6612636a888a2cf41a9d25..fba97b673bea6901983e6bba509358fe8bf504f3 100644 --- a/routingtable/filter/term_condition_test.go +++ b/routingtable/filter/term_condition_test.go @@ -109,10 +109,10 @@ func TestMatches(t *testing.T) { for _, test := range tests { t.Run(test.name, func(te *testing.T) { - f := &TermCondition{ - prefixLists: test.prefixLists, - routeFilters: test.routeFilters, - } + f := NewTermCondition( + test.prefixLists, + test.routeFilters, + ) assert.Equal(te, test.expected, f.Matches(test.prefix, &route.Path{})) }) diff --git a/routingtable/locRIB/loc_rib.go b/routingtable/locRIB/loc_rib.go index a1701743b1b5d946f958f47e1b163285427a57b0..ff5750c34d226080bea079968becdec410d2704e 100644 --- a/routingtable/locRIB/loc_rib.go +++ b/routingtable/locRIB/loc_rib.go @@ -8,6 +8,7 @@ import ( "github.com/bio-routing/bio-rd/net" "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable" + "github.com/sirupsen/logrus" ) // LocRIB represents a routing information base @@ -44,6 +45,10 @@ func (a *LocRIB) AddPath(pfx net.Prefix, p *route.Path) error { a.mu.Lock() defer a.mu.Unlock() + logrus.WithFields(map[string]interface{}{ + "Prefix": pfx, + "Route": p, + }).Debug("AddPath to locRIB") routeExisted := false oldRoute := &route.Route{} r := a.rt.Get(pfx) @@ -70,6 +75,10 @@ func (a *LocRIB) RemovePath(pfx net.Prefix, p *route.Path) bool { a.mu.Lock() defer a.mu.Unlock() + logrus.WithFields(map[string]interface{}{ + "Prefix": pfx, + "Route": p, + }).Debug("Remove from locRIB") var oldRoute *route.Route r := a.rt.Get(pfx) if r != nil {