check / check (push) Canceled after 0s
The IP lookups, the AS and prefix pages and their API answers, the prefix-length pages and the stats read routes only from the routing table the prefix handler keeps. fx reads the table at startup and gives it to both. AS names, WHOIS details and first-seen times still come from the database. The IP lookup names the origin AS most peers carry, with the time of the newest kept route. The prefix answers list peers whose routes are not kept without a path or time. The stats gain origins_without_kept_route. They no longer read route times from the per-peer tables, so the two helpers that did are gone. Model: opus-5-5
115 lines
4.2 KiB
Go
115 lines
4.2 KiB
Go
// Package database provides SQLite storage for BGP routing data including ASNs,
|
|
// prefixes, announcements, peerings, and live route tables. Its routes table
|
|
// holds a copy of the whole routing table that internal/routetable keeps in
|
|
// memory.
|
|
package database
|
|
|
|
import (
|
|
"context"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"git.eeqj.de/sneak/routewatch/internal/routetable"
|
|
)
|
|
|
|
// Stats contains database statistics including counts for ASNs, prefixes,
|
|
// peerings, peers, and live routes, as well as file size and prefix distribution data.
|
|
type Stats struct {
|
|
ASNs int
|
|
Prefixes int
|
|
IPv4Prefixes int
|
|
IPv6Prefixes int
|
|
Peerings int
|
|
Peers int
|
|
FileSizeBytes int64
|
|
LiveRoutes int
|
|
IPv4Routes int
|
|
IPv6Routes int
|
|
IPv4PrefixDistribution []PrefixDistribution
|
|
IPv6PrefixDistribution []PrefixDistribution
|
|
}
|
|
|
|
// Store defines the interface for database operations. It provides methods for
|
|
// managing ASNs, prefixes, announcements, peerings, BGP peers, and live routes.
|
|
// Implementations must be safe for concurrent use.
|
|
//
|
|
//nolint:interfacebloat // the one seam handlers and tests depend on
|
|
type Store interface {
|
|
// ASN operations
|
|
GetOrCreateASN(number int, timestamp time.Time) (*ASN, error)
|
|
GetOrCreateASNBatch(asns map[int]SeenTimes) error
|
|
|
|
// Prefix operations
|
|
GetOrCreatePrefix(prefix string, timestamp time.Time) (*Prefix, error)
|
|
UpdatePrefixesBatch(prefixes map[string]time.Time) error
|
|
|
|
// Announcement operations
|
|
RecordAnnouncement(announcement *Announcement) error
|
|
|
|
// Peering operations
|
|
RecordPeering(asA, asB int, seen SeenTimes) error
|
|
|
|
// Statistics
|
|
GetStats() (Stats, error)
|
|
GetStatsContext(ctx context.Context) (Stats, error)
|
|
|
|
// Peer operations
|
|
UpdatePeer(peerIP string, peerASN int, messageType string, timestamp time.Time) error
|
|
UpdatePeerBatch(peers map[string]PeerUpdate) error
|
|
|
|
// Live route operations
|
|
UpsertLiveRoute(route *LiveRoute) error
|
|
UpsertLiveRouteBatch(routes []*LiveRoute) error
|
|
DeleteLiveRoute(prefix, peerIP string) error
|
|
DeleteLiveRouteBatch(deletions []LiveRouteDeletion) error
|
|
DeleteLiveRoutesOfPeer(peerIP string) (deleted int, err error)
|
|
GetPrefixDistribution() (
|
|
ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error)
|
|
GetPrefixDistributionContext(ctx context.Context) (
|
|
ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error)
|
|
GetLiveRouteCounts() (ipv4Count, ipv6Count int, err error)
|
|
GetLiveRouteCountsContext(ctx context.Context) (ipv4Count, ipv6Count int, err error)
|
|
|
|
// Routing table operations: the database's copy of the table in memory
|
|
WriteRouteChanges(changes []routetable.Change, newPeers map[string]uint) error
|
|
ReadRouteTable(ctx context.Context) (*routetable.Table, error)
|
|
|
|
// IP lookup operations
|
|
GetIPInfo(ip string) (*IPInfo, error)
|
|
GetIPInfoContext(ctx context.Context, ip string) (*IPInfo, error)
|
|
|
|
// ASN WHOIS operations
|
|
GetNextStaleASN(ctx context.Context, staleThreshold time.Duration) (int, error)
|
|
UpdateASNWHOIS(ctx context.Context, update *ASNWHOISUpdate) error
|
|
GetWHOISStats(ctx context.Context, staleThreshold time.Duration) (*WHOISStats, error)
|
|
|
|
// AS and prefix detail operations
|
|
GetAS(ctx context.Context, asn int) (*ASN, bool, error)
|
|
GetASWHOIS(ctx context.Context, asn int) (*ASN, error)
|
|
GetPrefixFirstSeen(ctx context.Context, prefix netip.Prefix) (time.Time, error)
|
|
GetASDetails(asn int) (*ASN, []LiveRoute, error)
|
|
GetASDetailsContext(ctx context.Context, asn int) (*ASN, []LiveRoute, error)
|
|
GetASPeers(asn int) ([]ASPeer, error)
|
|
GetASPeersContext(ctx context.Context, asn int) ([]ASPeer, error)
|
|
GetPrefixDetails(prefix string) ([]LiveRoute, map[int]ASN, error)
|
|
GetPrefixDetailsContext(
|
|
ctx context.Context, prefix string,
|
|
) ([]LiveRoute, map[int]ASN, error)
|
|
GetRandomPrefixesByLength(maskLength, ipVersion, limit int) ([]LiveRoute, error)
|
|
GetRandomPrefixesByLengthContext(
|
|
ctx context.Context, maskLength, ipVersion, limit int,
|
|
) ([]LiveRoute, error)
|
|
|
|
// Lifecycle
|
|
Close() error
|
|
|
|
// Maintenance operations
|
|
Vacuum(ctx context.Context) error
|
|
Analyze(ctx context.Context) error
|
|
Checkpoint(ctx context.Context) error
|
|
Ping(ctx context.Context) error
|
|
}
|
|
|
|
// Ensure Database implements Store
|
|
var _ Store = (*Database)(nil)
|