Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc0ff77f91 |
No files matched your search
@@ -1,8 +1,8 @@
|
|||||||
// Package routetable holds the whole routing table in memory. For each prefix
|
// Package routetable holds the whole routing table in memory. For each prefix
|
||||||
// and origin AS, it keeps the peers whose current route to the prefix has that
|
// and origin AS it keeps the set of peers whose current route that is, and the
|
||||||
// origin AS. It also keeps the two newest of those routes in full. It applies
|
// two newest of those routes. It applies announcements, withdrawals and peers'
|
||||||
// announcements, withdrawals and peers' sessions going down. It answers the
|
// sessions going down, and it answers the route reads the pages and the API
|
||||||
// route reads that the pages and the API need.
|
// need.
|
||||||
package routetable
|
package routetable
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -326,30 +326,21 @@ func (t *Table) removeOrigin(prefix netip.Prefix, o *origin) {
|
|||||||
// join puts the peer of r in the peer set of o, an origin of prefix, and keeps
|
// join puts the peer of r in the peer set of o, an origin of prefix, and keeps
|
||||||
// r in full when it is one of the two newest routes of o. The peer's earlier
|
// r in full when it is one of the two newest routes of o. The peer's earlier
|
||||||
// route, if o keeps one, is replaced: it is no longer the peer's current route.
|
// route, if o keeps one, is replaced: it is no longer the peer's current route.
|
||||||
// The pair is recorded as changed only when its peer set or kept routes change.
|
|
||||||
func (t *Table) join(prefix netip.Prefix, o *origin, r route) {
|
func (t *Table) join(prefix netip.Prefix, o *origin, r route) {
|
||||||
if slices.ContainsFunc(o.routes, r.equal) {
|
|
||||||
// The peer announced its kept route again.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
wasWithoutKeptRoute := o.withoutKeptRoute()
|
wasWithoutKeptRoute := o.withoutKeptRoute()
|
||||||
|
|
||||||
joined := !o.peers.Test(r.peer)
|
if !o.peers.Test(r.peer) {
|
||||||
if joined {
|
|
||||||
o.peers.Set(r.peer)
|
o.peers.Set(r.peer)
|
||||||
|
|
||||||
t.familyOf(prefix.Addr()).routes++
|
t.familyOf(prefix.Addr()).routes++
|
||||||
t.peerPrefixes[r.peer]++
|
t.peerPrefixes[r.peer]++
|
||||||
}
|
}
|
||||||
|
|
||||||
dropped := t.dropKeptRoute(o, r.peer)
|
t.dropKeptRoute(o, r.peer)
|
||||||
kept := t.keepIfNewest(o, r)
|
t.keepIfNewest(o, r)
|
||||||
|
|
||||||
if joined || dropped || kept {
|
|
||||||
t.recordChange(prefix, o, wasWithoutKeptRoute)
|
t.recordChange(prefix, o, wasWithoutKeptRoute)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// leave takes peer out of the peer set of o, an origin of prefix, and drops
|
// leave takes peer out of the peer set of o, an origin of prefix, and drops
|
||||||
// its kept route, if any.
|
// its kept route, if any.
|
||||||
@@ -365,10 +356,10 @@ func (t *Table) leave(prefix netip.Prefix, o *origin, peer uint) {
|
|||||||
t.recordChange(prefix, o, wasWithoutKeptRoute)
|
t.recordChange(prefix, o, wasWithoutKeptRoute)
|
||||||
}
|
}
|
||||||
|
|
||||||
// keepIfNewest keeps r in o unless both kept routes of o are newer, and says
|
// keepIfNewest keeps r in o unless both kept routes of o are newer. When o
|
||||||
// whether it kept r. When o already keeps two routes, the older one is
|
// already keeps two routes, the older one is dropped, and its peer keeps only
|
||||||
// dropped, and its peer keeps only its bit.
|
// its bit.
|
||||||
func (t *Table) keepIfNewest(o *origin, r route) bool {
|
func (t *Table) keepIfNewest(o *origin, r route) {
|
||||||
// The kept routes stay newest first: r goes before the first one that is
|
// The kept routes stay newest first: r goes before the first one that is
|
||||||
// not newer than it.
|
// not newer than it.
|
||||||
i := 0
|
i := 0
|
||||||
@@ -377,7 +368,7 @@ func (t *Table) keepIfNewest(o *origin, r route) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if i == keptRoutesPerOrigin {
|
if i == keptRoutesPerOrigin {
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.routes) == keptRoutesPerOrigin {
|
if len(o.routes) == keptRoutesPerOrigin {
|
||||||
@@ -386,22 +377,18 @@ func (t *Table) keepIfNewest(o *origin, r route) bool {
|
|||||||
|
|
||||||
o.routes = slices.Insert(o.routes, i, r)
|
o.routes = slices.Insert(o.routes, i, r)
|
||||||
t.countKeptTime(r.time, 1)
|
t.countKeptTime(r.time, 1)
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dropKeptRoute drops the peer's route from the kept routes of o, if o keeps
|
// dropKeptRoute drops the peer's route from the kept routes of o, if o keeps
|
||||||
// one, and says whether it did.
|
// one.
|
||||||
func (t *Table) dropKeptRoute(o *origin, peer uint) bool {
|
func (t *Table) dropKeptRoute(o *origin, peer uint) {
|
||||||
i := slices.IndexFunc(o.routes, func(r route) bool { return r.peer == peer })
|
i := slices.IndexFunc(o.routes, func(r route) bool { return r.peer == peer })
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t.countKeptTime(o.routes[i].time, -1)
|
t.countKeptTime(o.routes[i].time, -1)
|
||||||
o.routes = slices.Delete(o.routes, i, i+1)
|
o.routes = slices.Delete(o.routes, i, i+1)
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// recordChange records that the pair of prefix and the AS of o changed, and
|
// recordChange records that the pair of prefix and the AS of o changed, and
|
||||||
@@ -558,13 +545,6 @@ type route struct {
|
|||||||
time time.Time
|
time time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// equal says whether r and other are the same peer's route with the same path
|
|
||||||
// and time.
|
|
||||||
func (r route) equal(other route) bool {
|
|
||||||
return r.peer == other.peer && r.time.Equal(other.time) &&
|
|
||||||
slices.Equal(r.path, other.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pair names one prefix and origin AS.
|
// pair names one prefix and origin AS.
|
||||||
type pair struct {
|
type pair struct {
|
||||||
prefix netip.Prefix
|
prefix netip.Prefix
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"reflect"
|
"reflect"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -426,96 +425,6 @@ func TestTakeChanges(t *testing.T) {
|
|||||||
}, map[string]uint{})
|
}, map[string]uint{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTakeChangesHoldsOnlyPairsThatChanged(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
table := routetable.New(routetable.Params{})
|
|
||||||
v4 := netip.MustParsePrefix(prefixV4)
|
|
||||||
v6 := netip.MustParsePrefix(prefixV6)
|
|
||||||
|
|
||||||
// peerA, peerB and peerC are numbered 0, 1 and 2. The routes of peerC and
|
|
||||||
// peerB to v4 are kept; peerA keeps only its bit.
|
|
||||||
announceAll(table, prefixV4, asA, 10, peerA, peerB, peerC)
|
|
||||||
table.Announce(v6, asA, routeOf(peerB, asA, 10))
|
|
||||||
table.TakeChanges()
|
|
||||||
|
|
||||||
// peerA announces again, with a time older than both kept routes.
|
|
||||||
table.Announce(v4, asA, routeOf(peerA, asA, 15))
|
|
||||||
checkChanges(t, table, []change{}, map[string]uint{})
|
|
||||||
|
|
||||||
// peerC announces its kept route again.
|
|
||||||
table.Announce(v4, asA, routeOf(peerC, asA, 30))
|
|
||||||
checkChanges(t, table, []change{}, map[string]uint{})
|
|
||||||
|
|
||||||
// peerC announces the same path with a newer time, so its kept route
|
|
||||||
// changes.
|
|
||||||
table.Announce(v4, asA, routeOf(peerC, asA, 40))
|
|
||||||
checkChanges(t, table, []change{
|
|
||||||
{Prefix: prefixV4, OriginASN: asA, Peers: []uint{0, 1, 2},
|
|
||||||
Routes: []routetable.Route{
|
|
||||||
routeOf(peerC, asA, 40), routeOf(peerB, asA, 20),
|
|
||||||
}},
|
|
||||||
}, map[string]uint{})
|
|
||||||
|
|
||||||
// peerA withdraws v6, which it does not carry.
|
|
||||||
table.Withdraw(v6, peerA)
|
|
||||||
checkChanges(t, table, []change{}, map[string]uint{})
|
|
||||||
|
|
||||||
// peerA going down changes v4, the one prefix it carries.
|
|
||||||
table.PeerDown(peerA)
|
|
||||||
checkChanges(t, table, []change{
|
|
||||||
{Prefix: prefixV4, OriginASN: asA, Peers: []uint{1, 2},
|
|
||||||
Routes: []routetable.Route{
|
|
||||||
routeOf(peerC, asA, 40), routeOf(peerB, asA, 20),
|
|
||||||
}},
|
|
||||||
}, map[string]uint{})
|
|
||||||
|
|
||||||
// peerA, which carries nothing now, goes down again.
|
|
||||||
table.PeerDown(peerA)
|
|
||||||
checkChanges(t, table, []change{}, map[string]uint{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestConcurrentUse has goroutines update one table while others read it. The
|
|
||||||
// race detector, which make test runs, fails it when a method uses the table
|
|
||||||
// without its lock.
|
|
||||||
func TestConcurrentUse(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
const (
|
|
||||||
// rounds is how many times each goroutine calls its method.
|
|
||||||
rounds = 1000
|
|
||||||
ipVersion = 4
|
|
||||||
sampleSize = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
table := routetable.New(routetable.Params{})
|
|
||||||
prefix := netip.MustParsePrefix(prefixV4)
|
|
||||||
|
|
||||||
uses := []func(round int){
|
|
||||||
func(round int) { table.Announce(prefix, asA, routeOf(peerA, asA, round)) },
|
|
||||||
func(round int) { table.Announce(prefix, asB, routeOf(peerB, asB, round)) },
|
|
||||||
func(int) { table.Withdraw(prefix, peerA) },
|
|
||||||
func(int) { table.PeerDown(peerB) },
|
|
||||||
func(int) { table.TakeChanges() },
|
|
||||||
func(int) { table.Lookup(prefix.Addr()) },
|
|
||||||
func(int) { table.Origins(prefix) },
|
|
||||||
func(int) { table.OriginatedPrefixes(asA) },
|
|
||||||
func(int) { table.SamplePrefixes(ipVersion, prefix.Bits(), sampleSize) },
|
|
||||||
func(int) { table.Counts() },
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, use := range uses {
|
|
||||||
wg.Go(func() {
|
|
||||||
for round := range rounds {
|
|
||||||
use(round)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkChanges checks that TakeChanges returns want and wantPeers.
|
// checkChanges checks that TakeChanges returns want and wantPeers.
|
||||||
func checkChanges(
|
func checkChanges(
|
||||||
t *testing.T, table *routetable.Table, want []change,
|
t *testing.T, table *routetable.Table, want []change,
|
||||||
|
|||||||
Reference in new issue
Block a user