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

230 lines
5.7 KiB
Go
Raw Normal View History

2017-05-16 14:10:19 +02:00
package birdwatcher
import (
2018-06-19 10:02:16 +02:00
"github.com/alice-lg/alice-lg/backend/api"
2018-07-11 14:56:38 +02:00
"github.com/alice-lg/alice-lg/backend/caches"
"github.com/alice-lg/alice-lg/backend/sources"
"sort"
2017-05-16 14:10:19 +02:00
)
type Birdwatcher interface {
sources.Source
}
type GenericBirdwatcher struct {
2018-07-13 16:40:28 +02:00
config Config
client *Client
// Caches: Neighbors
2018-07-11 14:56:38 +02:00
neighborsCache *caches.NeighborsCache
2018-07-13 16:40:28 +02:00
// Caches: Routes
2018-07-13 17:47:41 +02:00
routesRequiredCache *caches.RoutesCache
2018-07-13 16:40:28 +02:00
routesNotExportedCache *caches.RoutesCache
// Mutices:
2018-11-09 12:13:47 +01:00
routesFetchMutex *LockMap
2017-05-16 14:10:19 +02:00
}
func NewBirdwatcher(config Config) Birdwatcher {
2017-05-19 17:40:22 +02:00
client := NewClient(config.Api)
2018-07-13 16:40:28 +02:00
// Cache settings:
// TODO: Maybe read from config file
neighborsCacheDisable := false
routesCacheDisabled := false
routesCacheMaxSize := 128
// Initialize caches
neighborsCache := caches.NewNeighborsCache(neighborsCacheDisable)
2018-07-13 17:47:41 +02:00
routesRequiredCache := caches.NewRoutesCache(
2018-07-13 16:40:28 +02:00
routesCacheDisabled, routesCacheMaxSize)
routesNotExportedCache := caches.NewRoutesCache(
routesCacheDisabled, routesCacheMaxSize)
var birdwatcher Birdwatcher
if config.Type == "single_table" {
singleTableBirdwatcher := new(SingleTableBirdwatcher)
2018-07-13 16:40:28 +02:00
singleTableBirdwatcher.config = config
singleTableBirdwatcher.client = client
2018-07-13 16:40:28 +02:00
singleTableBirdwatcher.neighborsCache = neighborsCache
2017-05-16 14:10:19 +02:00
singleTableBirdwatcher.routesRequiredCache = routesRequiredCache
singleTableBirdwatcher.routesNotExportedCache = routesNotExportedCache
2017-05-22 11:09:22 +02:00
singleTableBirdwatcher.routesFetchMutex = NewLockMap()
2017-05-19 17:40:22 +02:00
birdwatcher = singleTableBirdwatcher
} else if config.Type == "multi_table" {
multiTableBirdwatcher := new(MultiTableBirdwatcher)
2017-05-19 17:40:22 +02:00
multiTableBirdwatcher.config = config
multiTableBirdwatcher.client = client
2017-05-18 18:10:55 +02:00
multiTableBirdwatcher.neighborsCache = neighborsCache
2017-05-16 14:10:19 +02:00
multiTableBirdwatcher.routesRequiredCache = routesRequiredCache
multiTableBirdwatcher.routesNotExportedCache = routesNotExportedCache
multiTableBirdwatcher.routesFetchMutex = NewLockMap()
birdwatcher = multiTableBirdwatcher
}
return birdwatcher
}
func (self *GenericBirdwatcher) filterProtocols(protocols map[string]interface{}, protocol string) map[string]interface{} {
response := make(map[string]interface{})
response["protocols"] = make(map[string]interface{})
for protocolId, protocolData := range protocols {
if protocolData.(map[string]interface{})["bird_protocol"] == protocol {
response["protocols"].(map[string]interface{})[protocolId] = protocolData
}
}
return response
}
func (self *GenericBirdwatcher) filterProtocolsBgp(bird ClientResponse) map[string]interface{} {
return self.filterProtocols(bird["protocols"].(map[string]interface{}), "BGP")
2017-05-16 14:10:19 +02:00
}
func (self *GenericBirdwatcher) filterProtocolsPipe(bird ClientResponse) map[string]interface{} {
return self.filterProtocols(bird["protocols"].(map[string]interface{}), "Pipe")
2018-07-13 16:40:28 +02:00
}
func (self *GenericBirdwatcher) filterRoutesByPeerOrLearntFrom(routes api.Routes, peer string, learntFrom string) api.Routes {
result_routes := make(api.Routes, 0, len(routes))
2018-07-13 17:47:41 +02:00
// Choose routes with next_hop == gateway of this neighbour
for _, route := range routes {
if (route.Gateway == peer) ||
(route.Gateway == learntFrom) ||
(route.Details["learnt_from"] == peer) {
result_routes = append(result_routes, route)
2018-07-13 17:47:41 +02:00
}
}
// Sort routes for deterministic ordering
sort.Sort(result_routes)
routes = result_routes
2018-07-13 16:40:28 +02:00
return routes
2018-07-13 16:40:28 +02:00
}
func (self *GenericBirdwatcher) filterRoutesByDuplicates(routes api.Routes, filterRoutes api.Routes) api.Routes {
result_routes := make(api.Routes, 0, len(routes))
2018-07-13 16:40:28 +02:00
routesMap := make(map[string]*api.Route) // for O(1) access
for _, route := range routes {
routesMap[route.Id] = route
2018-07-13 17:47:41 +02:00
}
// Remove routes from "routes" that are contained within filterRoutes
for _, filterRoute := range filterRoutes {
if _, ok := routesMap[filterRoute.Id]; ok {
delete(routesMap, filterRoute.Id)
}
2018-07-13 16:40:28 +02:00
}
for _, route := range routesMap {
result_routes = append(result_routes, route)
2018-07-13 16:40:28 +02:00
}
// Sort routes for deterministic ordering
sort.Sort(result_routes)
routes = result_routes
2018-07-13 16:40:28 +02:00
return routes
2018-07-13 16:40:28 +02:00
}
func (self *GenericBirdwatcher) Status() (*api.StatusResponse, error) {
// Query birdwatcher
bird, err := self.client.GetJson("/status")
2018-07-13 16:40:28 +02:00
if err != nil {
return nil, err
}
// Use api status from first request
apiStatus, err := parseApiStatus(bird, self.config)
if err != nil {
return nil, err
}
// Parse the status
birdStatus, err := parseBirdwatcherStatus(bird, self.config)
2018-07-13 16:40:28 +02:00
if err != nil {
return nil, err
}
response := &api.StatusResponse{
Api: apiStatus,
Status: birdStatus,
2018-07-13 16:40:28 +02:00
}
2018-07-11 18:25:42 +02:00
return response, nil
2017-05-16 14:10:19 +02:00
}
2017-05-23 13:58:58 +02:00
// Make routes lookup
func (self *GenericBirdwatcher) LookupPrefix(prefix string) (*api.RoutesLookupResponse, error) {
2017-06-19 15:27:11 +02:00
// Get RS info
rs := api.Routeserver{
Id: self.config.Id,
Name: self.config.Name,
}
// Query prefix on RS
bird, err := self.client.GetJson("/routes/prefix?prefix=" + prefix)
if err != nil {
2018-07-11 18:25:42 +02:00
return nil, err
2017-06-19 15:27:11 +02:00
}
// Parse API status
apiStatus, err := parseApiStatus(bird, self.config)
if err != nil {
2018-07-11 18:25:42 +02:00
return nil, err
2017-06-19 15:27:11 +02:00
}
// Parse routes
routes, err := parseRoutes(bird, self.config)
// Add corresponding neighbour and source rs to result
2018-07-07 11:45:34 +02:00
results := api.LookupRoutes{}
2017-06-19 15:27:11 +02:00
for _, src := range routes {
// Okay. This is actually really hacky.
// A less bruteforce approach would be highly appreciated
2018-07-06 17:04:09 +02:00
route := &api.LookupRoute{
2017-06-19 15:27:11 +02:00
Id: src.Id,
Routeserver: rs,
NeighbourId: src.NeighbourId,
Network: src.Network,
Interface: src.Interface,
Gateway: src.Gateway,
Metric: src.Metric,
Bgp: src.Bgp,
Age: src.Age,
Type: src.Type,
Details: src.Details,
}
results = append(results, route)
}
// Make result
2018-07-11 18:25:42 +02:00
response := &api.RoutesLookupResponse{
2017-06-19 15:27:11 +02:00
Api: apiStatus,
Routes: results,
}
return response, nil
2017-05-23 13:58:58 +02:00
}