2019-01-08 10:15:53 +01:00
|
|
|
package gobgp
|
|
|
|
|
|
|
|
import (
|
|
|
|
aliceapi "github.com/alice-lg/alice-lg/backend/api"
|
|
|
|
"github.com/alice-lg/alice-lg/backend/caches"
|
|
|
|
api "github.com/osrg/gobgp/api"
|
2019-01-10 11:37:17 +01:00
|
|
|
|
2019-01-08 10:15:53 +01:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
|
|
|
"log"
|
2019-01-08 10:36:36 +01:00
|
|
|
"fmt"
|
2019-01-08 11:25:13 +01:00
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
"io"
|
2019-01-08 10:15:53 +01:00
|
|
|
_ "sort"
|
|
|
|
)
|
|
|
|
|
|
|
|
type GoBGP struct {
|
|
|
|
config Config
|
|
|
|
client api.GobgpApiClient
|
|
|
|
|
|
|
|
// Caches: Neighbors
|
|
|
|
neighborsCache *caches.NeighborsCache
|
|
|
|
|
|
|
|
// Caches: Routes
|
|
|
|
routesRequiredCache *caches.RoutesCache
|
|
|
|
routesReceivedCache *caches.RoutesCache
|
|
|
|
routesFilteredCache *caches.RoutesCache
|
|
|
|
routesNotExportedCache *caches.RoutesCache
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGoBGP(config Config) *GoBGP {
|
|
|
|
|
2019-01-08 10:36:36 +01:00
|
|
|
dialOpts := make([]grpc.DialOption,0)
|
|
|
|
|
|
|
|
if config.Insecure {
|
|
|
|
dialOpts = append(dialOpts,grpc.WithInsecure())
|
|
|
|
} else {
|
|
|
|
//TODO: We need credentials...
|
|
|
|
}
|
|
|
|
|
|
|
|
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 := api.NewGobgpApiClient(conn)
|
|
|
|
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gobgp *GoBGP) Status() (*aliceapi.StatusResponse, error) {
|
2019-01-08 11:25:13 +01:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := gobgp.client.GetBgp(ctx, &api.GetBgpRequest{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
response := aliceapi.StatusResponse{}
|
|
|
|
response.Status.RouterId = resp.Global.RouterId
|
|
|
|
response.Status.Backend = "gobgp"
|
|
|
|
return &response,nil
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get bird BGP protocols
|
|
|
|
func (gobgp *GoBGP) Neighbours() (*aliceapi.NeighboursResponse, error) {
|
2019-01-08 11:25:13 +01:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
response := aliceapi.NeighboursResponse{}
|
|
|
|
response.Neighbours = make(aliceapi.Neighbours,0)
|
|
|
|
|
2019-01-10 11:37:17 +01:00
|
|
|
resp, err := gobgp.client.ListPeer(ctx, &api.ListPeerRequest{EnableAdvertised: true})
|
2019-01-08 11:25:13 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
_resp, err := resp.Recv()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
neigh := aliceapi.Neighbour{}
|
2019-01-10 11:37:17 +01:00
|
|
|
|
2019-01-08 11:25:13 +01:00
|
|
|
neigh.Address = _resp.Peer.State.NeighborAddress
|
|
|
|
neigh.Asn = int(_resp.Peer.State.PeerAs)
|
2019-01-10 11:37:17 +01:00
|
|
|
switch _resp.Peer.State.SessionState {
|
|
|
|
case api.PeerState_ESTABLISHED:
|
|
|
|
neigh.State = "up"
|
|
|
|
default:
|
|
|
|
neigh.State = "down"
|
|
|
|
}
|
|
|
|
neigh.Description = _resp.Peer.Conf.Description
|
|
|
|
|
2019-02-26 16:59:40 +01:00
|
|
|
neigh.Id = PeerHash(_resp.Peer)
|
2019-01-08 11:25:13 +01:00
|
|
|
|
|
|
|
|
2019-01-10 11:37:17 +01:00
|
|
|
response.Neighbours = append(response.Neighbours, &neigh)
|
|
|
|
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)
|
|
|
|
}
|
2019-01-08 11:25:13 +01:00
|
|
|
|
|
|
|
|
2019-01-10 11:37:17 +01:00
|
|
|
if _resp.Peer.Timers.State.Uptime != nil {
|
|
|
|
neigh.Uptime = time.Now().Sub(time.Unix(_resp.Peer.Timers.State.Uptime.Seconds,int64(_resp.Peer.Timers.State.Uptime.Nanos)))
|
|
|
|
}
|
2019-01-08 11:25:13 +01:00
|
|
|
|
2019-01-10 11:37:17 +01:00
|
|
|
}
|
2019-01-08 11:25:13 +01:00
|
|
|
|
|
|
|
return &response, nil
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get neighbors from neighbors summary
|
|
|
|
func (gobgp *GoBGP) summaryNeighbors() (*aliceapi.NeighboursResponse, error) {
|
2019-02-26 16:59:40 +01:00
|
|
|
|
2019-01-10 11:37:17 +01:00
|
|
|
return nil,fmt.Errorf("Not implemented summaryNeighbors")
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get neighbors from protocols
|
|
|
|
func (gobgp *GoBGP) bgpProtocolsNeighbors() (*aliceapi.NeighboursResponse, error) {
|
2019-01-10 11:37:17 +01:00
|
|
|
return nil,fmt.Errorf("Not implemented protocols")
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get filtered and exported routes
|
|
|
|
func (gobgp *GoBGP) Routes(neighbourId string) (*aliceapi.RoutesResponse, error) {
|
2019-02-22 09:34:21 +01:00
|
|
|
neigh, err := gobgp.lookupNeighbour(neighbourId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
routes := NewRoutesResponse();
|
|
|
|
err = gobgp.GetRoutes(neigh,api.TableType_ADJ_IN,&routes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &routes,nil
|
2019-01-08 10:15:53 +01: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.
|
|
|
|
*/
|
|
|
|
|
2019-02-26 16:59:40 +01:00
|
|
|
func (gobgp *GoBGP) getRoutes(neighbourId string,) (*aliceapi.RoutesResponse, error) {
|
2019-02-22 09:34:21 +01:00
|
|
|
neigh, err := gobgp.lookupNeighbour(neighbourId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
routes := NewRoutesResponse();
|
|
|
|
err = gobgp.GetRoutes(neigh,api.TableType_ADJ_IN,&routes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &routes,nil
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
2019-02-26 16:59:40 +01:00
|
|
|
func (gobgp *GoBGP) RoutesRequired(neighbourId string,) (*aliceapi.RoutesResponse, error) {
|
|
|
|
return gobgp.getRoutes(neighbourId)
|
|
|
|
}
|
|
|
|
|
2019-01-08 10:15:53 +01:00
|
|
|
|
2019-02-26 16:59:40 +01:00
|
|
|
// Get all received routes
|
|
|
|
func (gobgp *GoBGP) RoutesReceived(neighbourId string,) (*aliceapi.RoutesResponse, error) {
|
2019-02-22 09:34:21 +01:00
|
|
|
neigh, err := gobgp.lookupNeighbour(neighbourId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-02-26 16:59:40 +01:00
|
|
|
|
2019-02-22 09:34:21 +01:00
|
|
|
routes := NewRoutesResponse();
|
|
|
|
err = gobgp.GetRoutes(neigh,api.TableType_ADJ_IN,&routes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-02-26 16:59:40 +01:00
|
|
|
routes.Filtered = nil
|
2019-02-22 09:34:21 +01:00
|
|
|
return &routes,nil
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
2019-02-26 16:59:40 +01:00
|
|
|
|
|
|
|
// Get all filtered routes
|
|
|
|
func (gobgp *GoBGP) RoutesFiltered(neighbourId string,) (*aliceapi.RoutesResponse, error) {
|
|
|
|
routes, err := gobgp.getRoutes(neighbourId)
|
|
|
|
routes.Imported = nil
|
|
|
|
return routes, err
|
|
|
|
}
|
|
|
|
|
2019-01-08 10:15:53 +01:00
|
|
|
// Get all not exported routes
|
2019-01-10 13:05:51 +01:00
|
|
|
func (gobgp *GoBGP) RoutesNotExported(neighbourId string,) (*aliceapi.RoutesResponse, error) {
|
2019-02-22 09:34:21 +01:00
|
|
|
neigh, err := gobgp.lookupNeighbour(neighbourId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
routes := NewRoutesResponse();
|
2019-02-26 16:59:40 +01:00
|
|
|
err = gobgp.GetRoutes(neigh,api.TableType_LOCAL,&routes)
|
2019-02-22 09:34:21 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-02-26 16:59:40 +01:00
|
|
|
routes.Imported = nil
|
2019-02-22 09:34:21 +01:00
|
|
|
return &routes,nil
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make routes lookup
|
|
|
|
func (gobgp *GoBGP) LookupPrefix(prefix string) (*aliceapi.RoutesLookupResponse, error) {
|
2019-01-10 11:37:17 +01:00
|
|
|
return nil,fmt.Errorf("Not implemented LookupPrefix")
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|
2019-02-26 16:59:40 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
AllRoutes:
|
|
|
|
Here a routes dump (filtered, received) is returned, which is used to learn all prefixes to build up a local store for searching.
|
|
|
|
*/
|
2019-01-08 10:15:53 +01:00
|
|
|
func (gobgp *GoBGP) AllRoutes() (*aliceapi.RoutesResponse, error) {
|
2019-02-22 09:34:21 +01:00
|
|
|
routes := NewRoutesResponse();
|
|
|
|
peers, err := gobgp.GetNeighbours()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, peer := range peers {
|
|
|
|
err = gobgp.GetRoutes(peer,api.TableType_ADJ_IN,&routes)
|
|
|
|
if err != nil {
|
|
|
|
log.Print(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &routes, nil
|
2019-01-08 10:15:53 +01:00
|
|
|
}
|
|
|
|
|