Store the routing table in the database (part of #122)
check / check (push) Canceled after 0s

A new routes table holds one row per prefix and origin AS: the peer set
as the bitset's bytes, and the two kept routes, each with its peer's
number, AS path and time in seconds. A new route_peers table holds each
peer's number and address.

WriteRouteChanges writes one TakeChanges result in a transaction.
ReadRouteTable reads both tables into a new routing table, through the
new Table.Load, which records no change. It fails on a row that names a
peer number missing from route_peers. Nothing uses them yet.

Model: opus-5-5
This commit was merged in pull request #186.
This commit is contained in:
2026-10-27 08:54:57 +01:00
parent 7a34a46c4d
commit eda37da369
7 changed files with 1010 additions and 8 deletions
+58 -4
View File
@@ -218,6 +218,53 @@ func (t *Table) PeerDown(peer string) {
}
}
// Load puts one prefix and origin AS pair that the database holds into the
// table, as startup does with each row it reads. The change's peers join the
// pair's peer set, and its routes are kept as an announcement's would be.
// Unlike an update, Load records no change, so TakeChanges does not hand the
// pair back to be written again. Loading a pair twice changes nothing.
//
// The caller makes sure that every peer change names, in its peer set or in
// its routes, has a number in Params.PeerNumbers.
func (t *Table) Load(change Change) {
t.mu.Lock()
defer t.mu.Unlock()
// A removed pair has no peers, and a pair without peers is not in the
// table.
if change.Peers == nil || change.Peers.None() || !change.Prefix.IsValid() {
return
}
prefix := change.Prefix.Masked()
o := t.findOrAddOrigin(prefix, change.OriginASN)
wasWithoutKeptRoute := o.withoutKeptRoute()
for peer := range change.Peers.EachSet() {
if !o.peers.Test(peer) {
o.peers.Set(peer)
t.familyOf(prefix.Addr()).routes++
t.peerPrefixes[peer]++
}
}
// Oldest first, as they were announced, so that two routes with the same
// time are kept in the order they had.
for _, r := range slices.Backward(change.Routes) {
peer := t.peerNumbers[r.Peer]
t.dropKeptRoute(o, peer)
t.keepIfNewest(o, route{
peer: peer,
path: slices.Clone(r.ASPath),
time: r.Time,
})
}
t.countOriginWithoutKeptRoute(o, wasWithoutKeptRoute)
}
// TakeChanges returns the prefix and origin AS pairs that changed since it last
// ran, in prefix order, each with its current content. It also returns the
// peers numbered since then, by address. It then clears both records.
@@ -413,6 +460,17 @@ func (t *Table) recordChange(
) {
t.changed[pair{prefix: prefix, asn: o.asn}] = struct{}{}
t.countOriginWithoutKeptRoute(o, wasWithoutKeptRoute)
if o.peers.None() {
t.removeOrigin(prefix, o)
}
}
// countOriginWithoutKeptRoute brings the count of origins without a kept route
// up to date after a change to o. wasWithoutKeptRoute says whether o was such
// an origin before the change.
func (t *Table) countOriginWithoutKeptRoute(o *origin, wasWithoutKeptRoute bool) {
if wasWithoutKeptRoute {
t.originsWithoutKeptRoute--
}
@@ -420,10 +478,6 @@ func (t *Table) recordChange(
if o.withoutKeptRoute() {
t.originsWithoutKeptRoute++
}
if o.peers.None() {
t.removeOrigin(prefix, o)
}
}
// countKeptTime adds delta to the number of kept routes with time at.