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

222 lines
5.8 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"
"log"
"sort"
2017-05-16 14:10:19 +02:00
)
type Birdwatcher struct {
2017-05-18 18:10:55 +02:00
config Config
2017-05-19 17:40:22 +02:00
client *Client
2017-05-16 14:10:19 +02:00
}
2017-05-18 18:10:55 +02:00
func NewBirdwatcher(config Config) *Birdwatcher {
2017-05-19 17:40:22 +02:00
client := NewClient(config.Api)
2017-05-16 14:10:19 +02:00
birdwatcher := &Birdwatcher{
config: config,
2017-05-19 17:40:22 +02:00
client: client,
2017-05-16 14:10:19 +02:00
}
return birdwatcher
}
2017-05-18 18:10:55 +02:00
func (self *Birdwatcher) Status() (api.StatusResponse, error) {
2017-05-19 17:40:22 +02:00
bird, err := self.client.GetJson("/status")
if err != nil {
2017-05-22 11:09:22 +02:00
return api.StatusResponse{}, err
}
apiStatus, err := parseApiStatus(bird, self.config)
if err != nil {
return api.StatusResponse{}, err
2017-05-19 17:40:22 +02:00
}
2017-05-23 15:40:06 +02:00
birdStatus, err := parseBirdwatcherStatus(bird, self.config)
if err != nil {
return api.StatusResponse{}, err
2017-05-19 17:40:22 +02:00
}
response := api.StatusResponse{
2017-05-19 17:56:01 +02:00
Api: apiStatus,
2017-05-23 15:40:06 +02:00
Status: birdStatus,
2017-05-19 17:40:22 +02:00
}
2017-05-18 18:10:55 +02:00
2017-05-19 17:40:22 +02:00
return response, nil
2017-05-16 14:10:19 +02:00
}
2017-05-22 12:47:55 +02:00
// Get bird BGP protocols
2017-05-18 18:10:55 +02:00
func (self *Birdwatcher) Neighbours() (api.NeighboursResponse, error) {
2017-05-22 11:09:22 +02:00
bird, err := self.client.GetJson("/protocols/bgp")
if err != nil {
return api.NeighboursResponse{}, err
}
apiStatus, err := parseApiStatus(bird, self.config)
if err != nil {
return api.NeighboursResponse{}, err
}
2017-05-22 11:47:10 +02:00
neighbours, err := parseNeighbours(bird, self.config)
2017-05-22 11:09:22 +02:00
if err != nil {
return api.NeighboursResponse{}, err
}
2017-05-18 18:10:55 +02:00
2017-05-22 11:09:22 +02:00
return api.NeighboursResponse{
Api: apiStatus,
Neighbours: neighbours,
}, nil
2017-05-16 14:10:19 +02:00
}
2017-05-22 12:47:55 +02:00
// Get filtered and exported routes
2017-05-18 18:10:55 +02:00
func (self *Birdwatcher) Routes(neighbourId string) (api.RoutesResponse, error) {
2017-05-22 12:47:55 +02:00
// Exported
bird, err := self.client.GetJson("/routes/protocol/" + neighbourId)
if err != nil {
return api.RoutesResponse{}, err
}
// Use api status from first request
apiStatus, err := parseApiStatus(bird, self.config)
if err != nil {
return api.RoutesResponse{}, err
}
2017-05-23 15:25:15 +02:00
imported, err := parseRoutes(bird, self.config)
2017-05-22 12:47:55 +02:00
if err != nil {
return api.RoutesResponse{}, err
}
gateway := ""
learnt_from := ""
if len(imported) > 0 { // infer next_hop ip address from imported[0]
gateway = imported[0].Gateway //TODO: change mechanism to infer gateway when state becomes available elsewhere.
learnt_from = mustString(imported[0].Details["learnt_from"], "") // also take learnt_from address into account if present.
// ^ learnt_from is regularly present on routes for remote-triggered blackholing.
}
// Optional: Filtered
bird, _ = self.client.GetJson("/routes/filtered/" + neighbourId)
2017-05-22 13:26:37 +02:00
filtered, err := parseRoutes(bird, self.config)
if err != nil {
log.Println("WARNING Could not retrieve filtered routes:", err)
log.Println("Is the 'routes_filtered' module active in birdwatcher?")
} else { // we got a filtered routes response => perform routes deduplication
result_filtered := make(api.Routes, 0, len(filtered))
result_imported := make(api.Routes, 0, len(imported))
importedMap := make(map[string]api.Route) // for O(1) access
for _, route := range imported {
importedMap[route.Id] = route
}
// choose routes with next_hop == gateway of this neighbour
for _, route := range filtered {
if (route.Gateway == gateway) || (route.Gateway == learnt_from) {
result_filtered = append(result_filtered, route)
delete(importedMap, route.Id) // remove routes that are filtered on pipe
} else if len(imported) == 0 { // in case there are just filtered routes
result_filtered = append(result_filtered, route)
}
}
sort.Sort(result_filtered)
filtered = result_filtered
// map to slice
for _, route := range importedMap {
result_imported = append(result_imported, route)
}
sort.Sort(result_imported)
imported = result_imported
2017-05-22 13:26:37 +02:00
}
2017-05-18 18:10:55 +02:00
2017-05-23 15:25:15 +02:00
// Optional: NoExport
bird, _ = self.client.GetJson("/routes/noexport/" + neighbourId)
noexport, err := parseRoutes(bird, self.config)
if err != nil {
log.Println("WARNING Could not retrieve routes not exported:", err)
log.Println("Is the 'routes_noexport' module active in birdwatcher?")
} else {
result_noexport := make([]api.Route, 0, len(noexport))
// choose routes with next_hop == gateway of this neighbour
for _, route := range noexport {
if (route.Gateway == gateway) || (route.Gateway == learnt_from) {
result_noexport = append(result_noexport, route)
} else if len(imported) == 0 { // in case there are just filtered routes
result_noexport = append(result_noexport, route)
}
}
}
2017-05-23 15:25:15 +02:00
2017-05-22 12:47:55 +02:00
return api.RoutesResponse{
2017-05-23 15:25:15 +02:00
Api: apiStatus,
Imported: imported,
Filtered: filtered,
NotExported: noexport,
2017-05-22 12:47:55 +02:00
}, nil
2017-05-16 14:10:19 +02:00
}
2017-05-23 13:58:58 +02:00
// Make routes lookup
func (self *Birdwatcher) 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 {
return api.RoutesLookupResponse{}, err
2017-06-19 15:27:11 +02:00
}
// Parse API status
apiStatus, err := parseApiStatus(bird, self.config)
if err != nil {
return api.RoutesLookupResponse{}, 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
results := []api.LookupRoute{}
for _, src := range routes {
// Okay. This is actually really hacky.
// A less bruteforce approach would be highly appreciated
route := api.LookupRoute{
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
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
}
2017-06-22 21:04:41 +02:00
func (self *Birdwatcher) AllRoutes() (api.RoutesResponse, error) {
bird, err := self.client.GetJson("/routes/dump")
if err != nil {
return api.RoutesResponse{}, err
}
2017-06-23 11:12:01 +02:00
result, err := parseRoutesDump(bird, self.config)
return result, err
2017-06-22 21:04:41 +02:00
}