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/pkg/backend/neighbours_store.go

335 lines
7.6 KiB
Go
Raw Normal View History

2021-03-22 16:25:47 +01:00
package backend
2017-06-23 16:27:09 +02:00
import (
"log"
"regexp"
"strconv"
2017-07-14 14:18:47 +02:00
"sync"
2017-06-23 16:27:09 +02:00
"time"
2017-07-14 14:18:47 +02:00
2021-03-22 17:35:20 +01:00
"github.com/alice-lg/alice-lg/pkg/api"
2017-06-23 16:27:09 +02:00
)
2017-06-23 17:40:19 +02:00
2018-12-16 16:29:02 +01:00
var REGEX_MATCH_ASLOOKUP = regexp.MustCompile(`(?i)^AS(\d+)`)
2018-07-06 17:04:09 +02:00
type NeighboursIndex map[string]*api.Neighbour
2017-06-23 16:27:09 +02:00
type NeighboursStore struct {
neighboursMap map[string]NeighboursIndex
configMap map[string]*SourceConfig
statusMap map[string]StoreStatus
refreshInterval time.Duration
refreshNeighborStatus bool
2019-10-07 18:29:25 +02:00
lastRefresh time.Time
2017-07-14 14:18:47 +02:00
2018-06-26 10:51:11 +02:00
sync.RWMutex
2017-06-23 17:40:19 +02:00
}
func NewNeighboursStore(config *Config) *NeighboursStore {
// Build source mapping
2018-12-09 17:31:02 +01:00
neighboursMap := make(map[string]NeighboursIndex)
configMap := make(map[string]*SourceConfig)
statusMap := make(map[string]StoreStatus)
2017-06-23 17:40:19 +02:00
for _, source := range config.Sources {
2017-06-23 18:01:49 +02:00
sourceId := source.Id
configMap[sourceId] = source
statusMap[sourceId] = StoreStatus{
2017-06-23 17:40:19 +02:00
State: STATE_INIT,
}
2017-06-23 18:01:49 +02:00
neighboursMap[sourceId] = make(NeighboursIndex)
2017-06-23 17:40:19 +02:00
}
2018-07-07 11:39:46 +02:00
// Set refresh interval, default to 5 minutes when
// interval is set to 0
refreshInterval := time.Duration(
config.Server.NeighboursStoreRefreshInterval) * time.Minute
if refreshInterval == 0 {
refreshInterval = time.Duration(5) * time.Minute
}
refreshNeighborStatus := config.Server.EnableNeighborsStatusRefresh
2017-06-23 17:40:19 +02:00
store := &NeighboursStore{
2019-10-07 18:13:08 +02:00
neighboursMap: neighboursMap,
statusMap: statusMap,
configMap: configMap,
refreshInterval: refreshInterval,
refreshNeighborStatus: refreshNeighborStatus,
2017-06-23 17:40:19 +02:00
}
return store
}
func (self *NeighboursStore) Start() {
log.Println("Starting local neighbours store")
2018-07-07 11:48:06 +02:00
log.Println("Neighbours Store refresh interval set to:", self.refreshInterval)
2017-06-23 17:40:19 +02:00
go self.init()
}
func (self *NeighboursStore) init() {
// Perform initial update
self.update()
// Initial logging
self.Stats().Log()
// Periodically update store
for {
2018-07-07 11:39:46 +02:00
time.Sleep(self.refreshInterval)
2017-06-23 17:40:19 +02:00
self.update()
}
}
2018-12-09 17:31:02 +01:00
func (self *NeighboursStore) SourceStatus(sourceId string) StoreStatus {
self.RLock()
status := self.statusMap[sourceId]
self.RUnlock()
return status
}
// Get state by source Id
2018-12-09 17:31:02 +01:00
func (self *NeighboursStore) SourceState(sourceId string) int {
status := self.SourceStatus(sourceId)
return status.State
}
2018-10-01 12:02:14 +02:00
// Update all neighbors
2017-06-23 17:40:19 +02:00
func (self *NeighboursStore) update() {
2018-10-01 12:13:40 +02:00
successCount := 0
errorCount := 0
2018-10-01 12:02:14 +02:00
t0 := time.Now()
2017-06-23 18:01:49 +02:00
for sourceId, _ := range self.neighboursMap {
2017-06-23 17:40:19 +02:00
// Get current state
2017-06-23 18:01:49 +02:00
if self.statusMap[sourceId].State == STATE_UPDATING {
2017-06-23 17:40:19 +02:00
continue // nothing to do here. really.
}
// Start updating
2018-06-26 10:51:11 +02:00
self.Lock()
2017-06-23 18:01:49 +02:00
self.statusMap[sourceId] = StoreStatus{
2017-06-23 17:40:19 +02:00
State: STATE_UPDATING,
}
2018-06-26 10:51:11 +02:00
self.Unlock()
2017-06-23 17:40:19 +02:00
2018-10-01 12:02:14 +02:00
sourceConfig := self.configMap[sourceId]
source := sourceConfig.getInstance()
2017-06-23 18:01:49 +02:00
2017-06-23 17:40:19 +02:00
neighboursRes, err := source.Neighbours()
if err != nil {
2018-10-01 12:02:14 +02:00
log.Println(
"Refreshing the neighbors store failed for:",
sourceConfig.Name, "(", sourceConfig.Id, ")",
"with:", err,
"- NEXT STATE: ERROR",
)
2017-06-23 17:40:19 +02:00
// That's sad.
2018-06-26 10:51:11 +02:00
self.Lock()
2017-06-23 18:01:49 +02:00
self.statusMap[sourceId] = StoreStatus{
2017-06-23 17:40:19 +02:00
State: STATE_ERROR,
LastError: err,
LastRefresh: time.Now(),
}
2018-06-26 10:51:11 +02:00
self.Unlock()
2018-10-01 12:13:40 +02:00
errorCount++
2017-06-23 17:40:19 +02:00
continue
}
2018-07-13 11:41:00 +02:00
neighbours := neighboursRes.Neighbours
2017-06-23 17:40:19 +02:00
// Update data
// Make neighbours index
index := make(NeighboursIndex)
for _, neighbour := range neighbours {
index[neighbour.Id] = neighbour
}
2018-06-26 10:51:11 +02:00
self.Lock()
2017-06-23 18:01:49 +02:00
self.neighboursMap[sourceId] = index
2017-06-23 17:40:19 +02:00
// Update state
2017-06-23 18:01:49 +02:00
self.statusMap[sourceId] = StoreStatus{
2017-06-23 17:40:19 +02:00
LastRefresh: time.Now(),
State: STATE_READY,
}
2019-10-07 18:29:25 +02:00
self.lastRefresh = time.Now().UTC()
2018-06-26 10:51:11 +02:00
self.Unlock()
2018-10-01 12:13:40 +02:00
successCount++
2017-06-23 17:40:19 +02:00
}
2018-10-01 12:02:14 +02:00
refreshDuration := time.Since(t0)
log.Println(
2018-10-01 12:13:40 +02:00
"Refreshed neighbors store for", successCount, "of", successCount+errorCount,
"sources with", errorCount, "error(s) in", refreshDuration,
2018-10-01 12:02:14 +02:00
)
2017-06-23 17:40:19 +02:00
}
2018-12-09 17:31:02 +01:00
func (self *NeighboursStore) GetNeighborsAt(sourceId string) api.Neighbours {
self.RLock()
neighborsIdx := self.neighboursMap[sourceId]
self.RUnlock()
var neighborsStatus map[string]api.NeighbourStatus
if self.refreshNeighborStatus {
sourceConfig := self.configMap[sourceId]
source := sourceConfig.getInstance()
neighborsStatusData, err := source.NeighboursStatus()
if err == nil {
neighborsStatus = make(map[string]api.NeighbourStatus, len(neighborsStatusData.Neighbours))
for _, neighbor := range neighborsStatusData.Neighbours {
neighborsStatus[neighbor.Id] = *neighbor
}
}
}
neighbors := make(api.Neighbours, 0, len(neighborsIdx))
for _, neighbor := range neighborsIdx {
if self.refreshNeighborStatus {
if _, ok := neighborsStatus[neighbor.Id]; ok {
self.Lock()
neighbor.State = neighborsStatus[neighbor.Id].State
self.Unlock()
}
}
neighbors = append(neighbors, neighbor)
}
return neighbors
}
2017-06-23 17:40:19 +02:00
func (self *NeighboursStore) GetNeighbourAt(
2018-12-09 17:31:02 +01:00
sourceId string,
2017-06-23 17:40:19 +02:00
id string,
2018-07-06 17:04:09 +02:00
) *api.Neighbour {
2017-06-23 17:40:19 +02:00
// Lookup neighbour on RS
2018-06-26 10:51:11 +02:00
self.RLock()
neighborsIdx := self.neighboursMap[sourceId]
2018-06-26 10:51:11 +02:00
self.RUnlock()
return neighborsIdx[id]
2017-06-23 17:40:19 +02:00
}
2017-06-29 14:24:08 +02:00
func (self *NeighboursStore) LookupNeighboursAt(
2018-12-09 17:31:02 +01:00
sourceId string,
2017-06-29 14:24:08 +02:00
query string,
2018-07-07 11:41:00 +02:00
) api.Neighbours {
results := api.Neighbours{}
2017-06-29 14:24:08 +02:00
2018-06-26 10:51:11 +02:00
self.RLock()
neighbours := self.neighboursMap[sourceId]
2018-06-26 10:51:11 +02:00
self.RUnlock()
asn := -1
2018-12-16 16:29:02 +01:00
if REGEX_MATCH_ASLOOKUP.MatchString(query) {
groups := REGEX_MATCH_ASLOOKUP.FindStringSubmatch(query)
if a, err := strconv.Atoi(groups[1]); err == nil {
asn = a
}
}
for _, neighbour := range neighbours {
if asn >= 0 && neighbour.Asn == asn { // only executed if valid AS query is detected
results = append(results, neighbour)
} else if ContainsCi(neighbour.Description, query) {
results = append(results, neighbour)
} else {
continue
}
}
return results
}
func (self *NeighboursStore) LookupNeighbours(
query string,
) api.NeighboursLookupResults {
// Create empty result set
results := make(api.NeighboursLookupResults)
for sourceId, _ := range self.neighboursMap {
results[sourceId] = self.LookupNeighboursAt(sourceId, query)
}
2017-06-29 14:24:08 +02:00
return results
}
2019-10-07 18:13:08 +02:00
/*
Filter neighbors from a single route server.
*/
func (self *NeighboursStore) FilterNeighborsAt(
sourceId string,
filter *api.NeighborFilter,
2019-10-07 23:22:01 +02:00
) api.Neighbours {
2019-10-07 18:13:08 +02:00
results := []*api.Neighbour{}
self.RLock()
neighbors := self.neighboursMap[sourceId]
self.RUnlock()
// Apply filters
for _, neighbor := range neighbors {
if filter.Match(neighbor) {
results = append(results, neighbor)
}
}
return results
}
/*
Filter neighbors by name or by ASN.
Collect results from all routeservers.
*/
func (self *NeighboursStore) FilterNeighbors(
filter *api.NeighborFilter,
2019-10-07 23:22:01 +02:00
) api.Neighbours {
2019-10-07 18:13:08 +02:00
results := []*api.Neighbour{}
// Get neighbors from all routeservers
for sourceId, _ := range self.neighboursMap {
rsResults := self.FilterNeighborsAt(sourceId, filter)
results = append(results, rsResults...)
}
return results
}
2017-06-23 17:40:19 +02:00
// Build some stats for monitoring
func (self *NeighboursStore) Stats() NeighboursStoreStats {
totalNeighbours := 0
rsStats := []RouteServerNeighboursStats{}
2018-06-26 10:51:11 +02:00
self.RLock()
2017-06-23 18:01:49 +02:00
for sourceId, neighbours := range self.neighboursMap {
status := self.statusMap[sourceId]
2017-06-23 17:40:19 +02:00
totalNeighbours += len(neighbours)
serverStats := RouteServerNeighboursStats{
2017-06-23 18:01:49 +02:00
Name: self.configMap[sourceId].Name,
2017-06-23 17:40:19 +02:00
State: stateToString(status.State),
Neighbours: len(neighbours),
UpdatedAt: status.LastRefresh,
}
rsStats = append(rsStats, serverStats)
}
2018-06-26 10:51:11 +02:00
self.RUnlock()
2017-06-23 17:40:19 +02:00
storeStats := NeighboursStoreStats{
TotalNeighbours: totalNeighbours,
RouteServers: rsStats,
}
return storeStats
2017-06-23 16:27:09 +02:00
}
2019-10-07 18:29:25 +02:00
func (self *NeighboursStore) CachedAt() time.Time {
return self.lastRefresh
}
2021-03-22 17:35:20 +01:00
func (self *NeighboursStore) CacheTTL() time.Time {
2019-10-07 18:29:25 +02:00
return self.lastRefresh.Add(self.refreshInterval)
}