- Create internal/logger package with Logger wrapper around slog - Logger automatically adds source file, line number, and function name to all log entries - Use golang.org/x/term to properly detect if stdout is a terminal - Replace all slog.Logger usage with logger.Logger throughout the codebase - Remove verbose logging from database GetStats() method - Update all constructors and dependencies to use the new logger
132 lines
4.0 KiB
Go
132 lines
4.0 KiB
Go
package routewatch
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"git.eeqj.de/sneak/routewatch/internal/logger"
|
|
"git.eeqj.de/sneak/routewatch/internal/ristypes"
|
|
"git.eeqj.de/sneak/routewatch/internal/routingtable"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
// routingTableHandlerQueueSize is the queue capacity for in-memory routing table operations
|
|
routingTableHandlerQueueSize = 10000
|
|
)
|
|
|
|
// RoutingTableHandler handles BGP messages and updates the in-memory routing table
|
|
type RoutingTableHandler struct {
|
|
rt *routingtable.RoutingTable
|
|
logger *logger.Logger
|
|
}
|
|
|
|
// NewRoutingTableHandler creates a new routing table handler
|
|
func NewRoutingTableHandler(rt *routingtable.RoutingTable, logger *logger.Logger) *RoutingTableHandler {
|
|
return &RoutingTableHandler{
|
|
rt: rt,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// WantsMessage returns true if this handler wants to process messages of the given type
|
|
func (h *RoutingTableHandler) WantsMessage(messageType string) bool {
|
|
// We only care about UPDATE messages for the routing table
|
|
return messageType == "UPDATE"
|
|
}
|
|
|
|
// QueueCapacity returns the desired queue capacity for this handler
|
|
func (h *RoutingTableHandler) QueueCapacity() int {
|
|
// In-memory operations are very fast, so use a large queue
|
|
return routingTableHandlerQueueSize
|
|
}
|
|
|
|
// HandleMessage processes a RIS message and updates the routing table
|
|
func (h *RoutingTableHandler) HandleMessage(msg *ristypes.RISMessage) {
|
|
// Use the pre-parsed timestamp
|
|
timestamp := msg.ParsedTimestamp
|
|
|
|
// Parse peer ASN
|
|
peerASN, err := strconv.Atoi(msg.PeerASN)
|
|
if err != nil {
|
|
h.logger.Error("Failed to parse peer ASN", "peer_asn", msg.PeerASN, "error", err)
|
|
|
|
return
|
|
}
|
|
|
|
// Get origin ASN from path (last element)
|
|
var originASN int
|
|
if len(msg.Path) > 0 {
|
|
originASN = msg.Path[len(msg.Path)-1]
|
|
}
|
|
|
|
// Process announcements
|
|
for _, announcement := range msg.Announcements {
|
|
for _, prefix := range announcement.Prefixes {
|
|
// Generate deterministic UUIDs based on the prefix and origin ASN
|
|
// This ensures consistency across restarts
|
|
prefixID := uuid.NewSHA1(uuid.NameSpaceURL, []byte(prefix))
|
|
originASNID := uuid.NewSHA1(uuid.NameSpaceOID, []byte(strconv.Itoa(originASN)))
|
|
|
|
// Create route for the routing table
|
|
route := &routingtable.Route{
|
|
PrefixID: prefixID,
|
|
Prefix: prefix,
|
|
OriginASNID: originASNID,
|
|
OriginASN: originASN,
|
|
PeerASN: peerASN,
|
|
ASPath: msg.Path,
|
|
NextHop: announcement.NextHop,
|
|
AnnouncedAt: timestamp,
|
|
}
|
|
|
|
// Add route to routing table
|
|
h.rt.AddRoute(route)
|
|
}
|
|
}
|
|
|
|
// Process withdrawals
|
|
for _, prefix := range msg.Withdrawals {
|
|
// Generate deterministic UUID for the prefix
|
|
prefixID := uuid.NewSHA1(uuid.NameSpaceURL, []byte(prefix))
|
|
|
|
// Withdraw all routes for this prefix from this peer
|
|
h.rt.WithdrawRoutesByPrefixAndPeer(prefixID, peerASN)
|
|
}
|
|
}
|
|
|
|
// GetRoutingTableStats returns statistics about the routing table
|
|
func (h *RoutingTableHandler) GetRoutingTableStats() map[string]int {
|
|
return h.rt.Stats()
|
|
}
|
|
|
|
// GetActiveRouteCount returns the number of active routes
|
|
func (h *RoutingTableHandler) GetActiveRouteCount() int {
|
|
return h.rt.Size()
|
|
}
|
|
|
|
// GetRoutesByPrefix returns all routes for a specific prefix
|
|
func (h *RoutingTableHandler) GetRoutesByPrefix(prefixID uuid.UUID) []*routingtable.Route {
|
|
return h.rt.GetRoutesByPrefix(prefixID)
|
|
}
|
|
|
|
// GetRoutesByOriginASN returns all routes originated by a specific ASN
|
|
func (h *RoutingTableHandler) GetRoutesByOriginASN(originASNID uuid.UUID) []*routingtable.Route {
|
|
return h.rt.GetRoutesByOriginASN(originASNID)
|
|
}
|
|
|
|
// GetRoutesByPeerASN returns all routes received from a specific peer ASN
|
|
func (h *RoutingTableHandler) GetRoutesByPeerASN(peerASN int) []*routingtable.Route {
|
|
return h.rt.GetRoutesByPeerASN(peerASN)
|
|
}
|
|
|
|
// GetAllRoutes returns all active routes
|
|
func (h *RoutingTableHandler) GetAllRoutes() []*routingtable.Route {
|
|
return h.rt.GetAllRoutes()
|
|
}
|
|
|
|
// ClearRoutingTable clears all routes from the routing table
|
|
func (h *RoutingTableHandler) ClearRoutingTable() {
|
|
h.rt.Clear()
|
|
h.logger.Info("Cleared routing table")
|
|
}
|