From 4770c95ed6b7f0d675473586b6712ca03f20aca7 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Sun, 24 May 2020 18:53:00 +0200 Subject: [PATCH] Add method to get BMP Neighbors as API Session objects This method can be used to expose a BGPServer-like API with a BMP server as backend. --- protocols/bgp/server/bmp_router.go | 43 ++++++++++++++++++++++++++++++ protocols/bgp/server/fsm.go | 22 +++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/protocols/bgp/server/bmp_router.go b/protocols/bgp/server/bmp_router.go index 490c8b01..330b6b87 100644 --- a/protocols/bgp/server/bmp_router.go +++ b/protocols/bgp/server/bmp_router.go @@ -12,6 +12,7 @@ import ( log "github.com/sirupsen/logrus" bnet "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/protocols/bgp/api" "github.com/bio-routing/bio-rd/protocols/bgp/packet" bmppkt "github.com/bio-routing/bio-rd/protocols/bmp/packet" "github.com/bio-routing/bio-rd/routingtable" @@ -128,6 +129,48 @@ func (r *Router) serve(con net.Conn) { } } +// GetNeighborSessions returns all neighbors as API session objects +func (r *Router) GetNeighborSessions() []*api.Session { + sessions := make([]*api.Session, 0) + + for _, neigh := range r.neighborManager.list() { + estSince := neigh.fsm.establishedTime.Unix() + if estSince < 0 { + estSince = 0 + } + + // for now get this from adjRibIn/adjRibOut, can be replaced when we + // bmp gets its own bgpSrv or Router gets the bmpMetricsService + var routesReceived, routesSent uint64 + for _, afi := range []uint16{packet.IPv4AFI, packet.IPv6AFI} { + ribIn, err1 := r.GetNeighborRIBIn(neigh.fsm.peer.addr, afi, packet.UnicastSAFI) + if err1 == nil { + routesReceived += uint64(ribIn.RouteCount()) + } + + // adjRIBOut might not work properly with BMP, keeping it here for when it will + ribOut, err2 := r.GetNeighborRIBOut(neigh.fsm.peer.addr, afi, packet.UnicastSAFI) + if err2 == nil { + routesSent += uint64(ribOut.RouteCount()) + } + } + session := &api.Session{ + LocalAddress: neigh.fsm.peer.localAddr.ToProto(), + NeighborAddress: neigh.fsm.peer.addr.ToProto(), + LocalAsn: neigh.localAS, + PeerAsn: neigh.peerAS, + Status: stateToProto(neigh.fsm.state), + Stats: &api.SessionStats{ + RoutesReceived: routesReceived, + RoutesExported: routesSent, + }, + EstablishedSince: uint64(estSince), + } + sessions = append(sessions, session) + } + return sessions +} + func (r *Router) processMsg(msg []byte) { bmpMsg, err := bmppkt.Decode(msg) if err != nil { diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index 18017bbb..26f5daff 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -9,6 +9,7 @@ import ( "time" "github.com/bio-routing/bio-rd/net/tcp" + "github.com/bio-routing/bio-rd/protocols/bgp/api" "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/routingtable/filter" "github.com/pkg/errors" @@ -239,6 +240,27 @@ func stateName(s state) string { } } +func stateToProto(s state) api.Session_State { + switch s.(type) { + case *idleState: + return api.Session_Idle + case *connectState: + return api.Session_Connect + case *activeState: + return api.Session_Active + case *openSentState: + return api.Session_OpenSent + case *openConfirmState: + return api.Session_OpenConfirmed + case *establishedState: + return api.Session_Established + case *ceaseState: + return api.Session_Active // substitution + default: + panic(fmt.Sprintf("Unknown state: %v", s)) + } +} + func (fsm *FSM) cease() { fsm.eventCh <- Cease }