Fix prefix distribution bug and add prefix length pages
- Fix GetPrefixDistribution to count unique prefixes using COUNT(DISTINCT prefix) instead of COUNT(*) - Add /prefixlength/<length> route showing random sample of 500 prefixes - Make prefix counts on status page clickable links to prefix length pages - Add GetRandomPrefixesByLength database method - Create prefix_length.html template with sortable table - Show prefix age and origin AS with descriptions
This commit is contained in:
@@ -884,11 +884,11 @@ func (d *Database) DeleteLiveRoute(prefix string, originASN int, peerIP string)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetPrefixDistribution returns the distribution of prefixes by mask length
|
||||
// GetPrefixDistribution returns the distribution of unique prefixes by mask length
|
||||
func (d *Database) GetPrefixDistribution() (ipv4 []PrefixDistribution, ipv6 []PrefixDistribution, err error) {
|
||||
// IPv4 distribution
|
||||
// IPv4 distribution - count unique prefixes, not routes
|
||||
query := `
|
||||
SELECT mask_length, COUNT(*) as count
|
||||
SELECT mask_length, COUNT(DISTINCT prefix) as count
|
||||
FROM live_routes
|
||||
WHERE ip_version = 4
|
||||
GROUP BY mask_length
|
||||
@@ -908,9 +908,9 @@ func (d *Database) GetPrefixDistribution() (ipv4 []PrefixDistribution, ipv6 []Pr
|
||||
ipv4 = append(ipv4, dist)
|
||||
}
|
||||
|
||||
// IPv6 distribution
|
||||
// IPv6 distribution - count unique prefixes, not routes
|
||||
query = `
|
||||
SELECT mask_length, COUNT(*) as count
|
||||
SELECT mask_length, COUNT(DISTINCT prefix) as count
|
||||
FROM live_routes
|
||||
WHERE ip_version = 6
|
||||
GROUP BY mask_length
|
||||
@@ -1227,3 +1227,51 @@ func (d *Database) GetPrefixDetails(prefix string) ([]LiveRoute, error) {
|
||||
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// GetRandomPrefixesByLength returns a random sample of prefixes with the specified mask length
|
||||
func (d *Database) GetRandomPrefixesByLength(maskLength, ipVersion, limit int) ([]LiveRoute, error) {
|
||||
query := `
|
||||
SELECT DISTINCT
|
||||
prefix, mask_length, ip_version, origin_asn, as_path,
|
||||
peer_ip, last_updated
|
||||
FROM live_routes
|
||||
WHERE mask_length = ? AND ip_version = ?
|
||||
ORDER BY RANDOM()
|
||||
LIMIT ?
|
||||
`
|
||||
|
||||
rows, err := d.db.Query(query, maskLength, ipVersion, limit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query random prefixes: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = rows.Close()
|
||||
}()
|
||||
|
||||
var routes []LiveRoute
|
||||
for rows.Next() {
|
||||
var route LiveRoute
|
||||
var pathJSON string
|
||||
err := rows.Scan(
|
||||
&route.Prefix,
|
||||
&route.MaskLength,
|
||||
&route.IPVersion,
|
||||
&route.OriginASN,
|
||||
&pathJSON,
|
||||
&route.PeerIP,
|
||||
&route.LastUpdated,
|
||||
)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode AS path
|
||||
if err := json.Unmarshal([]byte(pathJSON), &route.ASPath); err != nil {
|
||||
route.ASPath = []int{}
|
||||
}
|
||||
|
||||
routes = append(routes, route)
|
||||
}
|
||||
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ type Store interface {
|
||||
// AS and prefix detail operations
|
||||
GetASDetails(asn int) (*ASN, []LiveRoute, error)
|
||||
GetPrefixDetails(prefix string) ([]LiveRoute, error)
|
||||
GetRandomPrefixesByLength(maskLength, ipVersion, limit int) ([]LiveRoute, error)
|
||||
|
||||
// Lifecycle
|
||||
Close() error
|
||||
|
||||
Reference in New Issue
Block a user