1
0
mirror of https://github.com/alice-lg/alice-lg.git synced 2024-05-11 05:55:03 +00:00

316 lines
8.0 KiB
Go
Raw Normal View History

2019-01-08 10:15:53 +01:00
package gobgp
import (
2019-05-10 11:17:55 +02:00
gobgpapi "github.com/osrg/gobgp/api"
2021-03-22 17:35:20 +01:00
"google.golang.org/grpc"
2019-05-09 11:17:43 +02:00
"google.golang.org/grpc/credentials"
2021-03-22 17:35:20 +01:00
api "github.com/alice-lg/alice-lg/pkg/api"
"github.com/alice-lg/alice-lg/pkg/caches"
2019-01-08 10:15:53 +01:00
"context"
2019-05-10 11:17:55 +02:00
"fmt"
"io"
2019-05-10 11:17:55 +02:00
"log"
"time"
2019-01-08 10:15:53 +01:00
)
2021-10-15 18:10:37 +02:00
// GoBGP is a source for Alice.
2019-01-08 10:15:53 +01:00
type GoBGP struct {
config Config
client gobgpapi.GobgpApiClient
2019-01-08 10:15:53 +01:00
// Caches: Neighbors
neighborsCache *caches.NeighborsCache
// Caches: Routes
routesRequiredCache *caches.RoutesCache
routesReceivedCache *caches.RoutesCache
routesFilteredCache *caches.RoutesCache
routesNotExportedCache *caches.RoutesCache
}
2021-10-15 18:10:37 +02:00
// NewGoBGP creates a new GoBGP source instance
2019-01-08 10:15:53 +01:00
func NewGoBGP(config Config) *GoBGP {
2019-05-10 11:17:55 +02:00
dialOpts := make([]grpc.DialOption, 0)
if config.Insecure {
2019-05-10 11:17:55 +02:00
dialOpts = append(dialOpts, grpc.WithInsecure())
} else {
2021-10-15 18:10:37 +02:00
creds, err := credentials.NewClientTLSFromFile(
config.TLSCert,
config.TLSCommonName)
2019-05-10 11:17:55 +02:00
if err != nil {
log.Fatalf("could not load tls cert: %s", err)
}
2019-05-09 11:17:43 +02:00
dialOpts = append(dialOpts, grpc.WithTransportCredentials(creds))
}
conn, err := grpc.Dial(config.Host, dialOpts...)
2019-01-08 10:15:53 +01:00
if err != nil {
log.Fatalf("did not connect: %v", err)
}
client := gobgpapi.NewGobgpApiClient(conn)
2019-01-08 10:15:53 +01:00
// Cache settings:
// TODO: Maybe read from config file
neighborsCacheDisable := false
routesCacheDisabled := false
routesCacheMaxSize := 128
// Initialize caches
neighborsCache := caches.NewNeighborsCache(neighborsCacheDisable)
routesRequiredCache := caches.NewRoutesCache(
routesCacheDisabled, routesCacheMaxSize)
routesReceivedCache := caches.NewRoutesCache(
routesCacheDisabled, routesCacheMaxSize)
routesFilteredCache := caches.NewRoutesCache(
routesCacheDisabled, routesCacheMaxSize)
routesNotExportedCache := caches.NewRoutesCache(
routesCacheDisabled, routesCacheMaxSize)
return &GoBGP{
config: config,
client: client,
neighborsCache: neighborsCache,
routesRequiredCache: routesRequiredCache,
routesReceivedCache: routesReceivedCache,
routesFilteredCache: routesFilteredCache,
routesNotExportedCache: routesNotExportedCache,
}
}
2021-10-15 18:10:37 +02:00
// ExpireCaches clears all local caches
func (gobgp *GoBGP) ExpireCaches() int {
count := gobgp.routesRequiredCache.Expire()
count += gobgp.routesNotExportedCache.Expire()
return count
}
2021-10-15 18:10:37 +02:00
// NeighborsStatus retrievs all status information
// for all peers on the RS.
func (gobgp *GoBGP) NeighborsStatus() (*api.NeighborsStatusResponse, error) {
ctx, cancel := context.WithTimeout(
context.Background(),
time.Second*time.Duration(gobgp.config.ProcessingTimeout))
defer cancel()
2021-10-15 18:10:37 +02:00
response := api.NeighborsStatusResponse{}
response.Neighbors = make(api.NeighborsStatus, 0)
resp, err := gobgp.client.ListPeer(ctx, &gobgpapi.ListPeerRequest{})
if err != nil {
return nil, err
}
for {
2019-05-10 11:17:55 +02:00
_resp, err := resp.Recv()
if err == io.EOF {
break
}
2021-10-15 18:10:37 +02:00
ns := api.NeighborStatus{}
ns.ID = PeerHash(_resp.Peer)
2019-05-10 11:17:55 +02:00
switch _resp.Peer.State.SessionState {
case gobgpapi.PeerState_ESTABLISHED:
ns.State = "up"
default:
ns.State = "down"
}
if _resp.Peer.Timers.State.Uptime != nil {
2021-10-15 18:10:37 +02:00
ns.Since = time.Since(time.Unix(
_resp.Peer.Timers.State.Uptime.Seconds,
int64(_resp.Peer.Timers.State.Uptime.Nanos)))
}
}
2019-05-10 11:17:55 +02:00
return &response, nil
}
2021-10-15 18:10:37 +02:00
// Status retrievs the routers status
func (gobgp *GoBGP) Status() (*api.StatusResponse, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(gobgp.config.ProcessingTimeout))
defer cancel()
resp, err := gobgp.client.GetBgp(ctx, &gobgpapi.GetBgpRequest{})
if err != nil {
return nil, err
}
response := api.StatusResponse{}
2021-10-15 18:10:37 +02:00
response.Status.RouterID = resp.Global.RouterId
response.Status.Backend = "gobgp"
2019-05-10 11:17:55 +02:00
return &response, nil
2019-01-08 10:15:53 +01:00
}
2021-10-15 18:10:37 +02:00
// Neighbors retrievs a list of neighbors
func (gobgp *GoBGP) Neighbors() (*api.NeighborsResponse, error) {
ctx, cancel := context.WithTimeout(
context.Background(),
time.Second*time.Duration(gobgp.config.ProcessingTimeout))
defer cancel()
2021-10-15 18:10:37 +02:00
response := api.NeighborsResponse{}
response.Neighbors = make(api.Neighbors, 0)
resp, err := gobgp.client.ListPeer(ctx, &gobgpapi.ListPeerRequest{EnableAdvertised: true})
if err != nil {
return nil, err
}
for {
2019-05-10 11:17:55 +02:00
_resp, err := resp.Recv()
if err == io.EOF {
break
}
2021-10-15 18:10:37 +02:00
neigh := api.Neighbor{}
2019-05-10 11:17:55 +02:00
neigh.Address = _resp.Peer.State.NeighborAddress
2021-10-15 18:10:37 +02:00
neigh.ASN = int(_resp.Peer.State.PeerAs)
2019-05-10 11:17:55 +02:00
switch _resp.Peer.State.SessionState {
case gobgpapi.PeerState_ESTABLISHED:
neigh.State = "up"
default:
neigh.State = "down"
}
neigh.Description = _resp.Peer.Conf.Description
2021-10-15 18:10:37 +02:00
neigh.ID = PeerHash(_resp.Peer)
neigh.RouteServerID = gobgp.config.ID
2021-10-15 18:10:37 +02:00
response.Neighbors = append(response.Neighbors, &neigh)
2019-05-10 11:17:55 +02:00
for _, afiSafi := range _resp.Peer.AfiSafis {
neigh.RoutesReceived += int(afiSafi.State.Received)
neigh.RoutesExported += int(afiSafi.State.Advertised)
neigh.RoutesAccepted += int(afiSafi.State.Accepted)
neigh.RoutesFiltered += (neigh.RoutesReceived - neigh.RoutesAccepted)
}
if _resp.Peer.Timers.State.Uptime != nil {
2021-10-15 18:10:37 +02:00
neigh.Uptime = time.Since(time.Unix(
_resp.Peer.Timers.State.Uptime.Seconds,
int64(_resp.Peer.Timers.State.Uptime.Nanos)))
}
}
return &response, nil
2019-01-08 10:15:53 +01:00
}
// NeighborsSummary is an alias of Neighbors for now
func (gobgp *GoBGP) NeighborsSummary() (*api.NeighborsResponse, error) {
return gobgp.Neighbors()
}
2021-10-15 18:10:37 +02:00
// Routes retrieves filtered and exported routes
func (gobgp *GoBGP) Routes(neighborID string) (*api.RoutesResponse, error) {
neigh, err := gobgp.lookupNeighbor(neighborID)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-05-10 11:17:55 +02:00
routes := NewRoutesResponse()
err = gobgp.GetRoutes(neigh, gobgpapi.TableType_ADJ_IN, &routes)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-05-10 11:17:55 +02:00
return &routes, nil
2019-01-08 10:15:53 +01:00
}
2021-10-15 18:10:37 +02:00
func (gobgp *GoBGP) getRoutes(neighborID string) (*api.RoutesResponse, error) {
neigh, err := gobgp.lookupNeighbor(neighborID)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-05-10 11:17:55 +02:00
routes := NewRoutesResponse()
err = gobgp.GetRoutes(neigh, gobgpapi.TableType_ADJ_IN, &routes)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-05-10 11:17:55 +02:00
return &routes, nil
2019-01-08 10:15:53 +01:00
}
2021-10-15 18:10:37 +02:00
// RoutesRequired is a specialized request to fetch:
//
// - RoutesExported and
// - RoutesFiltered
//
// from Birdwatcher. As the not exported routes can be very many
// these are optional and can be loaded on demand using the
// RoutesNotExported() API.
//
// A route deduplication is applied.
func (gobgp *GoBGP) RoutesRequired(neighborID string) (*api.RoutesResponse, error) {
return gobgp.getRoutes(neighborID)
}
2021-10-15 18:10:37 +02:00
// RoutesReceived gets all received routes
func (gobgp *GoBGP) RoutesReceived(neighborID string) (*api.RoutesResponse, error) {
neigh, err := gobgp.lookupNeighbor(neighborID)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-05-10 11:17:55 +02:00
routes := NewRoutesResponse()
err = gobgp.GetRoutes(neigh, gobgpapi.TableType_ADJ_IN, &routes)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
routes.Filtered = nil
2019-05-10 11:17:55 +02:00
return &routes, nil
2019-01-08 10:15:53 +01:00
}
2021-10-15 18:10:37 +02:00
// RoutesFiltered gets all filtered routes
func (gobgp *GoBGP) RoutesFiltered(neighborID string) (*api.RoutesResponse, error) {
routes, err := gobgp.getRoutes(neighborID)
2019-02-28 22:08:27 +01:00
if err != nil {
log.Print(err)
}
routes.Imported = nil
return routes, err
}
2021-10-15 18:10:37 +02:00
// RoutesNotExported gets all not exported routes
func (gobgp *GoBGP) RoutesNotExported(neighborID string) (*api.RoutesResponse, error) {
neigh, err := gobgp.lookupNeighbor(neighborID)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-05-10 11:17:55 +02:00
routes := NewRoutesResponse()
err = gobgp.GetRoutes(neigh, gobgpapi.TableType_ADJ_OUT, &routes)
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
2019-02-27 09:52:04 +01:00
routes.NotExported = routes.Filtered
2019-05-10 11:17:55 +02:00
return &routes, nil
2019-01-08 10:15:53 +01:00
}
2021-10-15 18:10:37 +02:00
// LookupPrefix searches for a prefix
func (gobgp *GoBGP) LookupPrefix(prefix string) (*api.RoutesLookupResponse, error) {
2021-10-15 18:10:37 +02:00
return nil, fmt.Errorf("not implemented: LookupPrefix")
2019-01-08 10:15:53 +01:00
}
2021-10-15 18:10:37 +02:00
// AllRoutes returns a routes dump (filtered, received),
// which is used to learn all prefixes to build
// up a local store for searching.
func (gobgp *GoBGP) AllRoutes() (*api.RoutesResponse, error) {
2019-05-10 11:17:55 +02:00
routes := NewRoutesResponse()
2021-10-15 18:10:37 +02:00
peers, err := gobgp.GetNeighbors()
2019-02-22 09:34:21 +01:00
if err != nil {
return nil, err
}
for _, peer := range peers {
2019-05-10 11:17:55 +02:00
err = gobgp.GetRoutes(peer, gobgpapi.TableType_ADJ_IN, &routes)
2019-02-22 09:34:21 +01:00
if err != nil {
log.Print(err)
}
}
return &routes, nil
2019-01-08 10:15:53 +01:00
}