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

336 lines
6.6 KiB
Go
Raw Normal View History

2017-06-23 11:12:24 +02:00
package main
import (
"log"
2017-06-23 16:11:47 +02:00
"strings"
2017-07-14 14:18:47 +02:00
"sync"
2017-06-23 11:12:24 +02:00
"time"
2017-07-14 14:18:47 +02:00
"github.com/ecix/alice-lg/backend/api"
2017-06-23 11:12:24 +02:00
)
type RoutesStore struct {
2017-06-23 18:01:49 +02:00
routesMap map[int]api.RoutesResponse
statusMap map[int]StoreStatus
configMap map[int]SourceConfig
2017-07-14 14:18:47 +02:00
rwlock *sync.RWMutex
2017-06-23 11:12:24 +02:00
}
func NewRoutesStore(config *Config) *RoutesStore {
// Build mapping based on source instances
2017-06-23 18:01:49 +02:00
routesMap := make(map[int]api.RoutesResponse)
statusMap := make(map[int]StoreStatus)
configMap := make(map[int]SourceConfig)
2017-06-23 14:25:40 +02:00
2017-06-23 11:12:24 +02:00
for _, source := range config.Sources {
2017-06-23 18:01:49 +02:00
id := source.Id
configMap[id] = source
routesMap[id] = api.RoutesResponse{}
statusMap[id] = StoreStatus{
2017-06-23 12:36:32 +02:00
State: STATE_INIT,
}
2017-06-23 11:12:24 +02:00
}
store := &RoutesStore{
routesMap: routesMap,
2017-06-23 12:36:32 +02:00
statusMap: statusMap,
2017-06-23 14:25:40 +02:00
configMap: configMap,
2017-07-14 14:18:47 +02:00
rwlock: &sync.RWMutex{},
2017-06-23 11:12:24 +02:00
}
return store
}
func (self *RoutesStore) Start() {
log.Println("Starting local routes store")
2017-06-23 14:25:40 +02:00
go self.init()
}
2017-06-23 11:12:24 +02:00
2017-06-23 14:25:40 +02:00
// Service initialization
func (self *RoutesStore) init() {
2017-06-23 12:36:32 +02:00
// Initial refresh
2017-06-23 14:25:40 +02:00
self.update()
// Initial stats
self.Stats().Log()
2017-06-23 16:25:21 +02:00
// Periodically update store
for {
// TODO: Add config option
time.Sleep(5 * time.Minute)
self.update()
}
2017-06-23 11:12:24 +02:00
}
// Update all routes
func (self *RoutesStore) update() {
2017-06-23 18:01:49 +02:00
for sourceId, _ := range self.routesMap {
source := self.configMap[sourceId].getInstance()
2017-06-23 12:36:32 +02:00
// Get current update state
2017-06-23 18:01:49 +02:00
if self.statusMap[sourceId].State == STATE_UPDATING {
2017-06-23 12:36:32 +02:00
continue // nothing to do here
}
// Set update state
2017-07-14 14:18:47 +02:00
self.rwlock.Lock()
2017-06-23 18:01:49 +02:00
self.statusMap[sourceId] = StoreStatus{
2017-06-23 12:36:32 +02:00
State: STATE_UPDATING,
}
2017-07-14 14:18:47 +02:00
self.rwlock.Unlock()
2017-06-23 12:36:32 +02:00
2017-06-23 11:12:24 +02:00
routes, err := source.AllRoutes()
if err != nil {
2017-07-14 14:18:47 +02:00
self.rwlock.Lock()
2017-06-23 18:01:49 +02:00
self.statusMap[sourceId] = StoreStatus{
2017-06-23 12:36:32 +02:00
State: STATE_ERROR,
LastError: err,
LastRefresh: time.Now(),
}
2017-07-14 14:18:47 +02:00
self.rwlock.Unlock()
2017-06-23 12:36:32 +02:00
2017-06-23 11:12:24 +02:00
continue
}
2017-06-23 12:36:32 +02:00
2017-07-14 14:18:47 +02:00
self.rwlock.Lock()
2017-06-23 12:36:32 +02:00
// Update data
2017-06-23 18:01:49 +02:00
self.routesMap[sourceId] = routes
2017-06-23 12:36:32 +02:00
// Update state
2017-06-23 18:01:49 +02:00
self.statusMap[sourceId] = StoreStatus{
2017-06-23 12:36:32 +02:00
LastRefresh: time.Now(),
State: STATE_READY,
}
2017-07-14 14:18:47 +02:00
self.rwlock.Unlock()
2017-06-23 11:12:24 +02:00
}
}
2017-06-23 12:55:08 +02:00
// Calculate store insights
2017-06-23 16:25:21 +02:00
func (self *RoutesStore) Stats() RoutesStoreStats {
2017-06-23 12:55:08 +02:00
totalImported := 0
totalFiltered := 0
2017-06-23 17:40:19 +02:00
rsStats := []RouteServerRoutesStats{}
2017-06-23 12:55:08 +02:00
2017-07-14 14:18:47 +02:00
self.rwlock.RLock()
2017-06-23 18:01:49 +02:00
for sourceId, routes := range self.routesMap {
status := self.statusMap[sourceId]
2017-06-23 12:55:08 +02:00
totalImported += len(routes.Imported)
totalFiltered += len(routes.Filtered)
2017-06-23 17:40:19 +02:00
serverStats := RouteServerRoutesStats{
2017-06-23 18:01:49 +02:00
Name: self.configMap[sourceId].Name,
2017-06-23 14:25:40 +02:00
2017-06-23 12:55:08 +02:00
Routes: RoutesStats{
Filtered: len(routes.Filtered),
Imported: len(routes.Imported),
},
State: stateToString(status.State),
UpdatedAt: status.LastRefresh,
}
rsStats = append(rsStats, serverStats)
}
2017-07-14 14:18:47 +02:00
self.rwlock.RUnlock()
2017-06-23 12:55:08 +02:00
// Make stats
2017-06-23 16:25:21 +02:00
storeStats := RoutesStoreStats{
2017-06-23 12:55:08 +02:00
TotalRoutes: RoutesStats{
Imported: totalImported,
Filtered: totalFiltered,
},
RouteServers: rsStats,
}
return storeStats
}
2017-06-30 14:15:43 +02:00
// Lookup routes transform
func routeToLookupRoute(source SourceConfig, state string, route api.Route) api.LookupRoute {
// Get neighbour
neighbour := AliceNeighboursStore.GetNeighbourAt(source.Id, route.NeighbourId)
// Make route
lookup := api.LookupRoute{
Id: route.Id,
NeighbourId: route.NeighbourId,
Neighbour: neighbour,
Routeserver: api.Routeserver{
Id: source.Id,
Name: source.Name,
},
State: state,
Network: route.Network,
Interface: route.Interface,
Gateway: route.Gateway,
Metric: route.Metric,
Bgp: route.Bgp,
Age: route.Age,
Type: route.Type,
}
return lookup
}
2017-06-23 16:11:47 +02:00
// Routes filter
2017-06-30 14:15:43 +02:00
func filterRoutesByPrefix(
source SourceConfig,
2017-06-23 16:11:47 +02:00
routes []api.Route,
prefix string,
state string,
) []api.LookupRoute {
results := []api.LookupRoute{}
for _, route := range routes {
// Naiive filtering:
if strings.HasPrefix(route.Network, prefix) {
2017-06-30 14:15:43 +02:00
lookup := routeToLookupRoute(source, state, route)
2017-06-23 16:11:47 +02:00
results = append(results, lookup)
}
}
return results
}
2017-06-30 14:15:43 +02:00
func filterRoutesByNeighbourIds(
source SourceConfig,
routes []api.Route,
neighbourIds []string,
state string,
) []api.LookupRoute {
results := []api.LookupRoute{}
for _, route := range routes {
// Filtering:
if MemberOf(neighbourIds, route.NeighbourId) == true {
lookup := routeToLookupRoute(source, state, route)
results = append(results, lookup)
}
}
return results
2017-06-23 17:40:19 +02:00
}
2017-06-30 11:12:15 +02:00
// Single RS lookup by neighbour id
2017-06-30 14:15:43 +02:00
func (self *RoutesStore) LookupNeighboursPrefixesAt(
2017-06-30 11:12:15 +02:00
sourceId int,
2017-06-30 14:15:43 +02:00
neighbourIds []string,
) chan []api.LookupRoute {
response := make(chan []api.LookupRoute)
2017-06-30 11:12:15 +02:00
2017-06-30 14:15:43 +02:00
go func() {
2017-07-14 14:18:47 +02:00
self.rwlock.RLock()
2017-06-30 14:15:43 +02:00
source := self.configMap[sourceId]
routes := self.routesMap[sourceId]
2017-07-14 14:18:47 +02:00
self.rwlock.RUnlock()
2017-06-30 14:15:43 +02:00
filtered := filterRoutesByNeighbourIds(
source,
routes.Filtered,
neighbourIds,
"filtered")
imported := filterRoutesByNeighbourIds(
source,
routes.Imported,
neighbourIds,
"imported")
var result []api.LookupRoute
result = append(filtered, imported...)
response <- result
}()
return response
2017-06-30 11:12:15 +02:00
}
2017-06-23 16:11:47 +02:00
// Single RS lookup
2017-06-30 11:12:15 +02:00
func (self *RoutesStore) LookupPrefixAt(
2017-06-23 18:01:49 +02:00
sourceId int,
2017-06-23 16:11:47 +02:00
prefix string,
) chan []api.LookupRoute {
response := make(chan []api.LookupRoute)
go func() {
2017-07-14 14:18:47 +02:00
self.rwlock.RLock()
2017-06-30 14:15:43 +02:00
config := self.configMap[sourceId]
routes := self.routesMap[sourceId]
2017-07-14 14:18:47 +02:00
self.rwlock.RUnlock()
2017-06-23 17:40:19 +02:00
2017-06-30 14:15:43 +02:00
filtered := filterRoutesByPrefix(
2017-06-23 16:11:47 +02:00
config,
routes.Filtered,
prefix,
"filtered")
2017-06-30 14:15:43 +02:00
imported := filterRoutesByPrefix(
2017-06-23 16:11:47 +02:00
config,
routes.Imported,
prefix,
"imported")
2017-06-30 14:15:43 +02:00
var result []api.LookupRoute
result = append(filtered, imported...)
2017-06-23 16:11:47 +02:00
response <- result
}()
return response
}
2017-06-30 11:12:15 +02:00
func (self *RoutesStore) LookupPrefix(prefix string) []api.LookupRoute {
2017-06-23 11:12:24 +02:00
result := []api.LookupRoute{}
2017-06-23 16:11:47 +02:00
responses := []chan []api.LookupRoute{}
// Dispatch
2017-07-14 14:18:47 +02:00
self.rwlock.RLock()
2017-06-23 18:01:49 +02:00
for sourceId, _ := range self.routesMap {
2017-06-30 11:12:15 +02:00
res := self.LookupPrefixAt(sourceId, prefix)
2017-06-23 16:11:47 +02:00
responses = append(responses, res)
}
2017-07-14 14:18:47 +02:00
self.rwlock.RUnlock()
2017-06-23 16:11:47 +02:00
// Collect
for _, response := range responses {
routes := <-response
result = append(result, routes...)
2017-06-30 14:15:43 +02:00
close(response)
}
return result
}
func (self *RoutesStore) LookupPrefixForNeighbours(
neighbours api.NeighboursLookupResults,
) []api.LookupRoute {
result := []api.LookupRoute{}
responses := []chan []api.LookupRoute{}
// Dispatch
for sourceId, locals := range neighbours {
lookupNeighbourIds := []string{}
for _, n := range locals {
lookupNeighbourIds = append(lookupNeighbourIds, n.Id)
}
res := self.LookupNeighboursPrefixesAt(sourceId, lookupNeighbourIds)
responses = append(responses, res)
}
// Collect
for _, response := range responses {
routes := <-response
result = append(result, routes...)
close(response)
2017-06-23 16:11:47 +02:00
}
2017-06-23 11:12:24 +02:00
return result
}