Add live routing table with CIDR mask length tracking
- Added new live_routes table with mask_length column for tracking CIDR prefix lengths - Updated PrefixHandler to maintain live routing table with additions and deletions - Added route expiration functionality (5 minute timeout) to in-memory routing table - Added prefix distribution stats showing count of prefixes by mask length - Added IPv4/IPv6 prefix distribution cards to status page - Updated database interface with UpsertLiveRoute, DeleteLiveRoute, and GetPrefixDistribution - Set all handler queue depths to 50000 for consistency - Doubled DBHandler batch size to 32000 for better throughput - Fixed withdrawal handling to delete routes when origin ASN is available
This commit is contained in:
@@ -64,18 +64,26 @@ type RoutingTable struct {
|
||||
lastMetricsReset time.Time
|
||||
|
||||
// Configuration
|
||||
snapshotDir string
|
||||
snapshotDir string
|
||||
routeExpirationTimeout time.Duration
|
||||
logger *logger.Logger
|
||||
|
||||
// Expiration management
|
||||
stopExpiration chan struct{}
|
||||
}
|
||||
|
||||
// New creates a new routing table, loading from snapshot if available
|
||||
func New(cfg *config.Config, logger *logger.Logger) *RoutingTable {
|
||||
rt := &RoutingTable{
|
||||
routes: make(map[RouteKey]*Route),
|
||||
byPrefix: make(map[uuid.UUID]map[RouteKey]*Route),
|
||||
byOriginASN: make(map[uuid.UUID]map[RouteKey]*Route),
|
||||
byPeerASN: make(map[int]map[RouteKey]*Route),
|
||||
lastMetricsReset: time.Now(),
|
||||
snapshotDir: cfg.GetStateDir(),
|
||||
routes: make(map[RouteKey]*Route),
|
||||
byPrefix: make(map[uuid.UUID]map[RouteKey]*Route),
|
||||
byOriginASN: make(map[uuid.UUID]map[RouteKey]*Route),
|
||||
byPeerASN: make(map[int]map[RouteKey]*Route),
|
||||
lastMetricsReset: time.Now(),
|
||||
snapshotDir: cfg.GetStateDir(),
|
||||
routeExpirationTimeout: cfg.RouteExpirationTimeout,
|
||||
logger: logger,
|
||||
stopExpiration: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Try to load from snapshot
|
||||
@@ -83,6 +91,9 @@ func New(cfg *config.Config, logger *logger.Logger) *RoutingTable {
|
||||
logger.Warn("Failed to load routing table from snapshot", "error", err)
|
||||
}
|
||||
|
||||
// Start expiration goroutine
|
||||
go rt.expireRoutesLoop()
|
||||
|
||||
return rt
|
||||
}
|
||||
|
||||
@@ -522,3 +533,72 @@ func (rt *RoutingTable) loadFromSnapshot(logger *logger.Logger) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// expireRoutesLoop periodically removes expired routes
|
||||
func (rt *RoutingTable) expireRoutesLoop() {
|
||||
// Run every minute to check for expired routes
|
||||
ticker := time.NewTicker(1 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
rt.expireStaleRoutes()
|
||||
case <-rt.stopExpiration:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expireStaleRoutes removes routes that haven't been updated recently
|
||||
func (rt *RoutingTable) expireStaleRoutes() {
|
||||
rt.mu.Lock()
|
||||
defer rt.mu.Unlock()
|
||||
|
||||
now := time.Now().UTC()
|
||||
cutoffTime := now.Add(-rt.routeExpirationTimeout)
|
||||
expiredCount := 0
|
||||
|
||||
// Collect keys to delete (can't delete while iterating)
|
||||
var keysToDelete []RouteKey
|
||||
for key, route := range rt.routes {
|
||||
// Use AnnouncedAt as the last update time
|
||||
if route.AnnouncedAt.Before(cutoffTime) {
|
||||
keysToDelete = append(keysToDelete, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete expired routes
|
||||
for _, key := range keysToDelete {
|
||||
route, exists := rt.routes[key]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
rt.removeFromIndexes(key, route)
|
||||
delete(rt.routes, key)
|
||||
expiredCount++
|
||||
|
||||
// Update metrics
|
||||
if isIPv6(route.Prefix) {
|
||||
rt.ipv6Routes--
|
||||
} else {
|
||||
rt.ipv4Routes--
|
||||
}
|
||||
}
|
||||
|
||||
if expiredCount > 0 {
|
||||
rt.logger.Info("Expired stale routes",
|
||||
"count", expiredCount,
|
||||
"timeout", rt.routeExpirationTimeout,
|
||||
"remaining_routes", len(rt.routes),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop gracefully stops the routing table background tasks
|
||||
func (rt *RoutingTable) Stop() {
|
||||
if rt.stopExpiration != nil {
|
||||
close(rt.stopExpiration)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user