From c7d5ecec494d8781c081d4c2fe64561cec18026b Mon Sep 17 00:00:00 2001 From: Josh Deprez Date: Sun, 14 Apr 2024 17:13:12 +1000 Subject: [PATCH] Routing table simplifications --- main.go | 11 +++--- peer.go | 4 +-- route.go | 105 +++++++++++++++++++++++++++++-------------------------- rtmp.go | 12 +++---- 4 files changed, 68 insertions(+), 64 deletions(-) diff --git a/main.go b/main.go index b050760..8178453 100644 --- a/main.go +++ b/main.go @@ -131,10 +131,7 @@ func main() { } // ----------------------------- Routing table ---------------------------- - routing := &routingTable{ - table: make(map[ddp.Network][]*route), - allRoutes: make(map[*route]struct{}), - } + routing := NewRoutingTable() // ------------------------- Configured peer setup ------------------------ for _, peerStr := range cfg.Peers { @@ -250,15 +247,15 @@ func main() { // addressed to a node on the local network." if ddpkt.DstNet != 0 && (ddpkt.DstNet < cfg.EtherTalk.NetStart || ddpkt.DstNet > cfg.EtherTalk.NetEnd) { // Is it for a network in the routing table? - rt := routing.lookupRoute(ddpkt.DstNet) + rt := routing.LookupRoute(ddpkt.DstNet) if rt == nil { log.Printf("DDP: no route for network %d", ddpkt.DstNet) continue } // Encap ethPacket.Payload into an AURP packet - log.Printf("DDP: forwarding to AURP peer %v", rt.peer.tr.RemoteDI) - if _, err := rt.peer.send(rt.peer.tr.NewAppleTalkPacket(ethFrame.Payload)); err != nil { + log.Printf("DDP: forwarding to AURP peer %v", rt.Peer.tr.RemoteDI) + if _, err := rt.Peer.send(rt.Peer.tr.NewAppleTalkPacket(ethFrame.Payload)); err != nil { log.Printf("DDP: Couldn't forward packet to AURP peer: %v", err) } diff --git a/peer.go b/peer.go index 684e901..3eb23ca 100644 --- a/peer.go +++ b/peer.go @@ -82,7 +82,7 @@ type peer struct { raddr *net.UDPAddr recv chan aurp.Packet - routingTable *routingTable + routingTable *RoutingTable } // send encodes and sends pkt to the remote host. @@ -279,7 +279,7 @@ func (p *peer) handle(ctx context.Context) error { log.Printf("Learned about these networks: %v", pkt.Networks) for _, nt := range pkt.Networks { - p.routingTable.upsertRoutes( + p.routingTable.UpsertRoute( nt.Extended, ddp.Network(nt.RangeStart), ddp.Network(nt.RangeEnd), diff --git a/route.go b/route.go index 20f11e0..16c2040 100644 --- a/route.go +++ b/route.go @@ -1,9 +1,7 @@ package main import ( - "cmp" "fmt" - "slices" "sync" "time" @@ -12,74 +10,83 @@ import ( const maxRouteAge = 10 * time.Minute // TODO: confirm -type route struct { - extended bool - netStart ddp.Network - netEnd ddp.Network - peer *peer - metric uint8 - last time.Time +type Route struct { + Extended bool + NetStart ddp.Network + NetEnd ddp.Network + Peer *peer + Distance uint8 + LastSeen time.Time } -type routingTable struct { - tableMu sync.Mutex - table map[ddp.Network][]*route - - allRoutesMu sync.Mutex - allRoutes map[*route]struct{} +type RoutingTable struct { + mu sync.Mutex + routes map[*Route]struct{} } -func (rt *routingTable) lookupRoute(network ddp.Network) *route { - rt.tableMu.Lock() - defer rt.tableMu.Unlock() +func NewRoutingTable() *RoutingTable { + return &RoutingTable{ + routes: make(map[*Route]struct{}), + } +} - for _, rs := range rt.table[network] { - if time.Since(rs.last) > maxRouteAge { +func (rt *RoutingTable) LookupRoute(network ddp.Network) *Route { + rt.mu.Lock() + defer rt.mu.Unlock() + + var bestRoute *Route + for r := range rt.routes { + if r.Peer == nil { continue } - return rs + if network < r.NetStart || network > r.NetEnd { + continue + } + if time.Since(r.LastSeen) > maxRouteAge { + continue + } + if bestRoute == nil { + bestRoute = r + continue + } + if r.Distance < bestRoute.Distance { + bestRoute = r + } } - return nil + return bestRoute } -func (rt *routingTable) upsertRoutes(extended bool, netStart, netEnd ddp.Network, peer *peer, metric uint8) error { +func (rt *RoutingTable) UpsertRoute(extended bool, netStart, netEnd ddp.Network, peer *peer, metric uint8) error { if netStart > netEnd { return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd) } - r := &route{ - extended: extended, - netStart: netStart, - netEnd: netEnd, - peer: peer, - metric: metric, - last: time.Now(), + // TODO: handle the Update part of "Upsert" + + r := &Route{ + Extended: extended, + NetStart: netStart, + NetEnd: netEnd, + Peer: peer, + Distance: metric, + LastSeen: time.Now(), } - rt.allRoutesMu.Lock() - rt.allRoutes[r] = struct{}{} - rt.allRoutesMu.Unlock() - - rt.tableMu.Lock() - defer rt.tableMu.Unlock() - for n := netStart; n <= netEnd; n++ { - rt.table[n] = append(rt.table[n], r) - slices.SortFunc(rt.table[n], func(r, s *route) int { - return cmp.Compare(r.metric, s.metric) - }) - } + rt.mu.Lock() + defer rt.mu.Unlock() + rt.routes[r] = struct{}{} return nil } -func (rt *routingTable) validRoutes() []*route { - rt.allRoutesMu.Lock() - defer rt.allRoutesMu.Unlock() - valid := make([]*route, 0, len(rt.allRoutes)) - for r := range rt.allRoutes { - if r.peer == nil { +func (rt *RoutingTable) ValidRoutes() []*Route { + rt.mu.Lock() + defer rt.mu.Unlock() + valid := make([]*Route, 0, len(rt.routes)) + for r := range rt.routes { + if r.Peer == nil { continue } - if time.Since(r.last) > maxRouteAge { + if time.Since(r.LastSeen) > maxRouteAge { continue } valid = append(valid, r) diff --git a/rtmp.go b/rtmp.go index 61bc0b9..db7cb51 100644 --- a/rtmp.go +++ b/rtmp.go @@ -35,7 +35,7 @@ type RTMPMachine struct { aarp *AARPMachine cfg *config pcapHandle *pcap.Handle - routingTable *routingTable + routingTable *RoutingTable } // Run executes the machine. @@ -214,12 +214,12 @@ func (m *RTMPMachine) dataPacket(myAddr ddp.Addr) *rtmp.DataPacket { }, }, } - for _, rt := range m.routingTable.validRoutes() { + for _, rt := range m.routingTable.ValidRoutes() { p.NetworkTuples = append(p.NetworkTuples, rtmp.NetworkTuple{ - Extended: rt.extended, - RangeStart: rt.netStart, - RangeEnd: rt.netEnd, - Distance: rt.metric + 1, + Extended: rt.Extended, + RangeStart: rt.NetStart, + RangeEnd: rt.NetEnd, + Distance: rt.Distance + 1, }) } return p