Compare commits
7 commits
8ce8f52776
...
f9d63e8358
Author | SHA1 | Date | |
---|---|---|---|
f9d63e8358 | |||
376c09d189 | |||
c1f84c3f29 | |||
95eec9564f | |||
10d4610e0d | |||
5f3bfe2f76 | |||
7e9fe4ff98 |
10 changed files with 257 additions and 234 deletions
49
main.go
49
main.go
|
@ -50,6 +50,7 @@ const routingTableTemplate = `
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
<th>Network range</th>
|
<th>Network range</th>
|
||||||
<th>Extended?</th>
|
<th>Extended?</th>
|
||||||
|
<th>Zone names</th>
|
||||||
<th>Distance</th>
|
<th>Distance</th>
|
||||||
<th>Last seen</th>
|
<th>Last seen</th>
|
||||||
<th>Port</th>
|
<th>Port</th>
|
||||||
|
@ -58,7 +59,8 @@ const routingTableTemplate = `
|
||||||
{{range $route := . }}
|
{{range $route := . }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{$route.NetStart}}{{if not (eq $route.NetStart $route.NetEnd)}} - {{$route.NetEnd}}{{end}}</td>
|
<td>{{$route.NetStart}}{{if not (eq $route.NetStart $route.NetEnd)}} - {{$route.NetEnd}}{{end}}</td>
|
||||||
<td>{{if $route.Extended}}✅{{else}}❌{{end}}</td>
|
<td>{{if $route.Extended}}✅{{else}}-{{end}}</td>
|
||||||
|
<td>{{range $route.ZoneNames.ToSlice}}{{.}}<br>{{end}}</td>
|
||||||
<td>{{$route.Distance}}</td>
|
<td>{{$route.Distance}}</td>
|
||||||
<td>{{$route.LastSeenAgo}}</td>
|
<td>{{$route.LastSeenAgo}}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -78,27 +80,6 @@ const routingTableTemplate = `
|
||||||
</table>
|
</table>
|
||||||
`
|
`
|
||||||
|
|
||||||
const zoneTableTemplate = `
|
|
||||||
<table>
|
|
||||||
<thead><tr>
|
|
||||||
<th>Network</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Local Port</th>
|
|
||||||
<th>Last seen</th>
|
|
||||||
</tr></thead>
|
|
||||||
<tbody>
|
|
||||||
{{range $zone := . }}
|
|
||||||
<tr>
|
|
||||||
<td>{{$zone.Network}}</td>
|
|
||||||
<td>{{$zone.Name}}</td>
|
|
||||||
<td>{{with $zone.LocalPort}}{{.Device}}{{else}}-{{end}}</td>
|
|
||||||
<td>{{$zone.LastSeenAgo}}</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
`
|
|
||||||
|
|
||||||
const peerTableTemplate = `
|
const peerTableTemplate = `
|
||||||
<table>
|
<table>
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
|
@ -220,15 +201,6 @@ func main() {
|
||||||
return rs, nil
|
return rs, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
zones := router.NewZoneTable()
|
|
||||||
status.AddItem(ctx, "Zone table", zoneTableTemplate, func(context.Context) (any, error) {
|
|
||||||
zs := zones.Dump()
|
|
||||||
slices.SortFunc(zs, func(za, zb router.Zone) int {
|
|
||||||
return cmp.Compare(za.Name, zb.Name)
|
|
||||||
})
|
|
||||||
return zs, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// -------------------------------- Peers ---------------------------------
|
// -------------------------------- Peers ---------------------------------
|
||||||
var peersMu sync.Mutex
|
var peersMu sync.Mutex
|
||||||
peers := make(map[udpAddr]*router.AURPPeer)
|
peers := make(map[udpAddr]*router.AURPPeer)
|
||||||
|
@ -316,7 +288,6 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
peer := &router.AURPPeer{
|
peer := &router.AURPPeer{
|
||||||
Config: cfg,
|
|
||||||
Transport: &aurp.Transport{
|
Transport: &aurp.Transport{
|
||||||
LocalDI: localDI,
|
LocalDI: localDI,
|
||||||
RemoteDI: aurp.IPDomainIdentifier(raddr.IP),
|
RemoteDI: aurp.IPDomainIdentifier(raddr.IP),
|
||||||
|
@ -326,8 +297,7 @@ func main() {
|
||||||
ConfiguredAddr: peerStr,
|
ConfiguredAddr: peerStr,
|
||||||
RemoteAddr: raddr,
|
RemoteAddr: raddr,
|
||||||
ReceiveCh: make(chan aurp.Packet, 1024),
|
ReceiveCh: make(chan aurp.Packet, 1024),
|
||||||
RoutingTable: routes,
|
RouteTable: routes,
|
||||||
ZoneTable: zones,
|
|
||||||
}
|
}
|
||||||
aurp.Inc(&nextConnID)
|
aurp.Inc(&nextConnID)
|
||||||
peersMu.Lock()
|
peersMu.Lock()
|
||||||
|
@ -344,7 +314,7 @@ func main() {
|
||||||
rooter := &router.Router{
|
rooter := &router.Router{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
RouteTable: routes,
|
RouteTable: routes,
|
||||||
ZoneTable: zones,
|
// ZoneTable: zones,
|
||||||
}
|
}
|
||||||
|
|
||||||
etherTalkPort := &router.EtherTalkPort{
|
etherTalkPort := &router.EtherTalkPort{
|
||||||
|
@ -353,16 +323,13 @@ func main() {
|
||||||
NetStart: cfg.EtherTalk.NetStart,
|
NetStart: cfg.EtherTalk.NetStart,
|
||||||
NetEnd: cfg.EtherTalk.NetEnd,
|
NetEnd: cfg.EtherTalk.NetEnd,
|
||||||
DefaultZoneName: cfg.EtherTalk.ZoneName,
|
DefaultZoneName: cfg.EtherTalk.ZoneName,
|
||||||
AvailableZones: []string{cfg.EtherTalk.ZoneName},
|
AvailableZones: router.SetFromSlice([]string{cfg.EtherTalk.ZoneName}),
|
||||||
PcapHandle: pcapHandle,
|
PcapHandle: pcapHandle,
|
||||||
AARPMachine: aarpMachine,
|
AARPMachine: aarpMachine,
|
||||||
Router: rooter,
|
Router: rooter,
|
||||||
}
|
}
|
||||||
rooter.Ports = append(rooter.Ports, etherTalkPort)
|
rooter.Ports = append(rooter.Ports, etherTalkPort)
|
||||||
routes.InsertEtherTalkDirect(etherTalkPort)
|
routes.InsertEtherTalkDirect(etherTalkPort)
|
||||||
for _, az := range etherTalkPort.AvailableZones {
|
|
||||||
zones.Upsert(etherTalkPort.NetStart, az, etherTalkPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------- RTMP ---------------------------------
|
// --------------------------------- RTMP ---------------------------------
|
||||||
go etherTalkPort.RunRTMP(ctx)
|
go etherTalkPort.RunRTMP(ctx)
|
||||||
|
@ -428,7 +395,6 @@ func main() {
|
||||||
}
|
}
|
||||||
// New peer!
|
// New peer!
|
||||||
pr = &router.AURPPeer{
|
pr = &router.AURPPeer{
|
||||||
Config: cfg,
|
|
||||||
Transport: &aurp.Transport{
|
Transport: &aurp.Transport{
|
||||||
LocalDI: localDI,
|
LocalDI: localDI,
|
||||||
RemoteDI: dh.SourceDI, // platinum rule
|
RemoteDI: dh.SourceDI, // platinum rule
|
||||||
|
@ -437,8 +403,7 @@ func main() {
|
||||||
UDPConn: ln,
|
UDPConn: ln,
|
||||||
RemoteAddr: raddr,
|
RemoteAddr: raddr,
|
||||||
ReceiveCh: make(chan aurp.Packet, 1024),
|
ReceiveCh: make(chan aurp.Packet, 1024),
|
||||||
RoutingTable: routes,
|
RouteTable: routes,
|
||||||
ZoneTable: zones,
|
|
||||||
}
|
}
|
||||||
aurp.Inc(&nextConnID)
|
aurp.Inc(&nextConnID)
|
||||||
peers[ra] = pr
|
peers[ra] = pr
|
||||||
|
|
52
router/misc.go
Normal file
52
router/misc.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright 2024 Josh Deprez
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package router
|
||||||
|
|
||||||
|
// StringSet is a set of strings.
|
||||||
|
// Yep, yet another string set implementation. Took me 2 minutes to write *shrug*
|
||||||
|
type StringSet map[string]struct{}
|
||||||
|
|
||||||
|
func (set StringSet) ToSlice() []string {
|
||||||
|
ss := make([]string, 0, len(set))
|
||||||
|
for s := range set {
|
||||||
|
ss = append(ss, s)
|
||||||
|
}
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
func (set StringSet) Contains(s string) bool {
|
||||||
|
_, c := set[s]
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (set StringSet) Insert(ss ...string) {
|
||||||
|
for _, s := range ss {
|
||||||
|
set[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (set StringSet) Add(t StringSet) {
|
||||||
|
for s := range t {
|
||||||
|
set[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetFromSlice(ss []string) StringSet {
|
||||||
|
set := make(StringSet, len(ss))
|
||||||
|
set.Insert(ss...)
|
||||||
|
return set
|
||||||
|
}
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"slices"
|
|
||||||
|
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk"
|
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk/nbp"
|
"gitea.drjosh.dev/josh/jrouter/atalk/nbp"
|
||||||
|
@ -74,10 +73,10 @@ func (port *EtherTalkPort) handleNBPBrRq(ctx context.Context, ddpkt *ddp.ExtPack
|
||||||
// tuple.Zone = port.DefaultZoneName
|
// tuple.Zone = port.DefaultZoneName
|
||||||
// }
|
// }
|
||||||
|
|
||||||
zones := port.Router.ZoneTable.LookupName(tuple.Zone)
|
routes := port.Router.RouteTable.RoutesForZone(tuple.Zone)
|
||||||
|
|
||||||
for _, z := range zones {
|
for _, route := range routes {
|
||||||
if outPort := z.LocalPort; outPort != nil {
|
if outPort := route.EtherTalkDirect; outPort != nil {
|
||||||
// If it's for a local zone, translate it to a LkUp and broadcast
|
// If it's for a local zone, translate it to a LkUp and broadcast
|
||||||
// out the corresponding EtherTalk port.
|
// out the corresponding EtherTalk port.
|
||||||
// "Note: On an internet, nodes on extended networks performing lookups in
|
// "Note: On an internet, nodes on extended networks performing lookups in
|
||||||
|
@ -147,7 +146,7 @@ func (port *EtherTalkPort) handleNBPBrRq(ctx context.Context, ddpkt *ddp.ExtPack
|
||||||
SrcNet: ddpkt.SrcNet,
|
SrcNet: ddpkt.SrcNet,
|
||||||
SrcNode: ddpkt.SrcNode,
|
SrcNode: ddpkt.SrcNode,
|
||||||
SrcSocket: ddpkt.SrcSocket,
|
SrcSocket: ddpkt.SrcSocket,
|
||||||
DstNet: z.Network,
|
DstNet: route.NetStart,
|
||||||
DstNode: 0x00, // Any router for the dest network
|
DstNode: 0x00, // Any router for the dest network
|
||||||
DstSocket: 2,
|
DstSocket: 2,
|
||||||
Proto: ddp.ProtoNBP,
|
Proto: ddp.ProtoNBP,
|
||||||
|
@ -170,7 +169,7 @@ func (rtr *Router) handleNBPFwdReq(ctx context.Context, ddpkt *ddp.ExtPacket, nb
|
||||||
tuple := &nbpkt.Tuples[0]
|
tuple := &nbpkt.Tuples[0]
|
||||||
|
|
||||||
for _, outPort := range rtr.Ports {
|
for _, outPort := range rtr.Ports {
|
||||||
if !slices.Contains(outPort.AvailableZones, tuple.Zone) {
|
if !outPort.AvailableZones.Contains(tuple.Zone) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Printf("NBP: Converting FwdReq to LkUp (%v)", tuple)
|
log.Printf("NBP: Converting FwdReq to LkUp (%v)", tuple)
|
||||||
|
|
|
@ -94,9 +94,6 @@ func (ss SenderState) String() string {
|
||||||
|
|
||||||
// AURPPeer handles the peering with a peer AURP router.
|
// AURPPeer handles the peering with a peer AURP router.
|
||||||
type AURPPeer struct {
|
type AURPPeer struct {
|
||||||
// Whole router config.
|
|
||||||
Config *Config
|
|
||||||
|
|
||||||
// AURP-Tr state for producing packets.
|
// AURP-Tr state for producing packets.
|
||||||
Transport *aurp.Transport
|
Transport *aurp.Transport
|
||||||
|
|
||||||
|
@ -114,11 +111,8 @@ type AURPPeer struct {
|
||||||
// Incoming packet channel.
|
// Incoming packet channel.
|
||||||
ReceiveCh chan aurp.Packet
|
ReceiveCh chan aurp.Packet
|
||||||
|
|
||||||
// Routing table (the peer will add/remove/update routes)
|
// Route table (the peer will add/remove/update routes and zones)
|
||||||
RoutingTable *RouteTable
|
RouteTable *RouteTable
|
||||||
|
|
||||||
// Zone table (the peer will add/remove/update zones)
|
|
||||||
ZoneTable *ZoneTable
|
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
rstate ReceiverState
|
rstate ReceiverState
|
||||||
|
@ -253,7 +247,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
if sendRetries >= tickleRetryLimit {
|
if sendRetries >= tickleRetryLimit {
|
||||||
log.Printf("AURP Peer: Send retry limit reached while waiting for Tickle-Ack, closing connection")
|
log.Printf("AURP Peer: Send retry limit reached while waiting for Tickle-Ack, closing connection")
|
||||||
p.setRState(ReceiverUnconnected)
|
p.setRState(ReceiverUnconnected)
|
||||||
p.RoutingTable.DeleteAURPPeer(p)
|
p.RouteTable.DeleteAURPPeer(p)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +266,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
if sendRetries >= sendRetryLimit {
|
if sendRetries >= sendRetryLimit {
|
||||||
log.Printf("AURP Peer: Send retry limit reached while waiting for RI-Rsp, closing connection")
|
log.Printf("AURP Peer: Send retry limit reached while waiting for RI-Rsp, closing connection")
|
||||||
p.setRState(ReceiverUnconnected)
|
p.setRState(ReceiverUnconnected)
|
||||||
p.RoutingTable.DeleteAURPPeer(p)
|
p.RouteTable.DeleteAURPPeer(p)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,15 +437,17 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
log.Printf("AURP Peer: Received RI-Req but was not expecting one (sender state was %v)", p.sstate)
|
log.Printf("AURP Peer: Received RI-Req but was not expecting one (sender state was %v)", p.sstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
nets := aurp.NetworkTuples{
|
var nets aurp.NetworkTuples
|
||||||
{
|
for _, r := range p.RouteTable.ValidNonAURPRoutes() {
|
||||||
Extended: true,
|
nets = append(nets, aurp.NetworkTuple{
|
||||||
RangeStart: p.Config.EtherTalk.NetStart,
|
Extended: r.Extended,
|
||||||
RangeEnd: p.Config.EtherTalk.NetEnd,
|
RangeStart: r.NetStart,
|
||||||
Distance: 0,
|
RangeEnd: r.NetEnd,
|
||||||
},
|
Distance: r.Distance,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
p.Transport.LocalSeq = 1
|
p.Transport.LocalSeq = 1
|
||||||
|
// TODO: Split tuples across multiple packets as required
|
||||||
lastRISent = p.Transport.NewRIRspPacket(aurp.RoutingFlagLast, nets)
|
lastRISent = p.Transport.NewRIRspPacket(aurp.RoutingFlagLast, nets)
|
||||||
if _, err := p.Send(lastRISent); err != nil {
|
if _, err := p.Send(lastRISent); err != nil {
|
||||||
log.Printf("AURP Peer: Couldn't send RI-Rsp packet: %v", err)
|
log.Printf("AURP Peer: Couldn't send RI-Rsp packet: %v", err)
|
||||||
|
@ -467,7 +463,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
log.Printf("AURP Peer: Learned about these networks: %v", pkt.Networks)
|
log.Printf("AURP Peer: Learned about these networks: %v", pkt.Networks)
|
||||||
|
|
||||||
for _, nt := range pkt.Networks {
|
for _, nt := range pkt.Networks {
|
||||||
p.RoutingTable.InsertAURPRoute(
|
p.RouteTable.InsertAURPRoute(
|
||||||
p,
|
p,
|
||||||
nt.Extended,
|
nt.Extended,
|
||||||
ddp.Network(nt.RangeStart),
|
ddp.Network(nt.RangeStart),
|
||||||
|
@ -507,11 +503,28 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
sendRetries = 0
|
sendRetries = 0
|
||||||
|
|
||||||
// If SZI flag is set, send ZI-Rsp (transaction)
|
// If SZI flag is set, send ZI-Rsp (transaction)
|
||||||
// TODO: split ZI-Rsp packets similarly to ZIP Replies
|
|
||||||
if pkt.Flags&aurp.RoutingFlagSendZoneInfo != 0 {
|
if pkt.Flags&aurp.RoutingFlagSendZoneInfo != 0 {
|
||||||
zones := map[ddp.Network][]string{
|
// Inspect last routing info packet sent to determine
|
||||||
p.Config.EtherTalk.NetStart: {p.Config.EtherTalk.ZoneName},
|
// networks to gather names for
|
||||||
|
var nets []ddp.Network
|
||||||
|
switch last := lastRISent.(type) {
|
||||||
|
case *aurp.RIRspPacket:
|
||||||
|
for _, nt := range last.Networks {
|
||||||
|
nets = append(nets, nt.RangeStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case *aurp.RIUpdPacket:
|
||||||
|
for _, et := range last.Events {
|
||||||
|
// Only networks that were added
|
||||||
|
if et.EventCode != aurp.EventCodeNA {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
nets = append(nets, et.RangeStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
zones := p.RouteTable.ZonesForNetworks(nets)
|
||||||
|
// TODO: split ZI-Rsp packets similarly to ZIP Replies
|
||||||
if _, err := p.Send(p.Transport.NewZIRspPacket(zones)); err != nil {
|
if _, err := p.Send(p.Transport.NewZIRspPacket(zones)); err != nil {
|
||||||
log.Printf("AURP Peer: Couldn't send ZI-Rsp packet: %v", err)
|
log.Printf("AURP Peer: Couldn't send ZI-Rsp packet: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -543,7 +556,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
// Do nothing except respond with RI-Ack
|
// Do nothing except respond with RI-Ack
|
||||||
|
|
||||||
case aurp.EventCodeNA:
|
case aurp.EventCodeNA:
|
||||||
if err := p.RoutingTable.InsertAURPRoute(
|
if err := p.RouteTable.InsertAURPRoute(
|
||||||
p,
|
p,
|
||||||
et.Extended,
|
et.Extended,
|
||||||
et.RangeStart,
|
et.RangeStart,
|
||||||
|
@ -555,10 +568,10 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
ackFlag = aurp.RoutingFlagSendZoneInfo
|
ackFlag = aurp.RoutingFlagSendZoneInfo
|
||||||
|
|
||||||
case aurp.EventCodeND:
|
case aurp.EventCodeND:
|
||||||
p.RoutingTable.DeleteAURPPeerNetwork(p, et.RangeStart)
|
p.RouteTable.DeleteAURPPeerNetwork(p, et.RangeStart)
|
||||||
|
|
||||||
case aurp.EventCodeNDC:
|
case aurp.EventCodeNDC:
|
||||||
p.RoutingTable.UpdateAURPRouteDistance(p, et.RangeStart, et.Distance+1)
|
p.RouteTable.UpdateAURPRouteDistance(p, et.RangeStart, et.Distance+1)
|
||||||
|
|
||||||
case aurp.EventCodeNRC:
|
case aurp.EventCodeNRC:
|
||||||
// "An exterior router sends a Network Route Change
|
// "An exterior router sends a Network Route Change
|
||||||
|
@ -566,7 +579,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
// through its local internet changes to a path through
|
// through its local internet changes to a path through
|
||||||
// a tunneling port, causing split-horizoned processing
|
// a tunneling port, causing split-horizoned processing
|
||||||
// to eliminate that network’s routing information."
|
// to eliminate that network’s routing information."
|
||||||
p.RoutingTable.DeleteAURPPeerNetwork(p, et.RangeStart)
|
p.RouteTable.DeleteAURPPeerNetwork(p, et.RangeStart)
|
||||||
|
|
||||||
case aurp.EventCodeZC:
|
case aurp.EventCodeZC:
|
||||||
// "This event is reserved for future use."
|
// "This event is reserved for future use."
|
||||||
|
@ -584,7 +597,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("AURP Peer: Router Down: error code %d %s", pkt.ErrorCode, pkt.ErrorCode)
|
log.Printf("AURP Peer: Router Down: error code %d %s", pkt.ErrorCode, pkt.ErrorCode)
|
||||||
p.RoutingTable.DeleteAURPPeer(p)
|
p.RouteTable.DeleteAURPPeer(p)
|
||||||
|
|
||||||
// Respond with RI-Ack
|
// Respond with RI-Ack
|
||||||
if _, err := p.Send(p.Transport.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, 0)); err != nil {
|
if _, err := p.Send(p.Transport.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, 0)); err != nil {
|
||||||
|
@ -596,7 +609,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
|
|
||||||
case *aurp.ZIReqPacket:
|
case *aurp.ZIReqPacket:
|
||||||
// TODO: split ZI-Rsp packets similarly to ZIP Replies
|
// TODO: split ZI-Rsp packets similarly to ZIP Replies
|
||||||
zones := p.ZoneTable.Query(pkt.Networks)
|
zones := p.RouteTable.ZonesForNetworks(pkt.Networks)
|
||||||
if _, err := p.Send(p.Transport.NewZIRspPacket(zones)); err != nil {
|
if _, err := p.Send(p.Transport.NewZIRspPacket(zones)); err != nil {
|
||||||
log.Printf("AURP Peer: Couldn't send ZI-Rsp packet: %v", err)
|
log.Printf("AURP Peer: Couldn't send ZI-Rsp packet: %v", err)
|
||||||
return err
|
return err
|
||||||
|
@ -605,7 +618,7 @@ func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
case *aurp.ZIRspPacket:
|
case *aurp.ZIRspPacket:
|
||||||
log.Printf("AURP Peer: Learned about these zones: %v", pkt.Zones)
|
log.Printf("AURP Peer: Learned about these zones: %v", pkt.Zones)
|
||||||
for _, zt := range pkt.Zones {
|
for _, zt := range pkt.Zones {
|
||||||
p.ZoneTable.Upsert(ddp.Network(zt.Network), zt.Name, nil)
|
p.RouteTable.AddZonesToNetwork(zt.Network, zt.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *aurp.GDZLReqPacket:
|
case *aurp.GDZLReqPacket:
|
||||||
|
|
|
@ -37,7 +37,7 @@ type EtherTalkPort struct {
|
||||||
NetEnd ddp.Network
|
NetEnd ddp.Network
|
||||||
MyAddr ddp.Addr
|
MyAddr ddp.Addr
|
||||||
DefaultZoneName string
|
DefaultZoneName string
|
||||||
AvailableZones []string
|
AvailableZones StringSet
|
||||||
PcapHandle *pcap.Handle
|
PcapHandle *pcap.Handle
|
||||||
AARPMachine *AARPMachine
|
AARPMachine *AARPMachine
|
||||||
Router *Router
|
Router *Router
|
||||||
|
|
|
@ -34,6 +34,10 @@ type Route struct {
|
||||||
|
|
||||||
LastSeen time.Time
|
LastSeen time.Time
|
||||||
|
|
||||||
|
// ZoneNames may be empty between learning the existence of a route and
|
||||||
|
// receiving zone information.
|
||||||
|
ZoneNames StringSet
|
||||||
|
|
||||||
// Exactly one of the following should be set
|
// Exactly one of the following should be set
|
||||||
AURPPeer *AURPPeer // Next hop is this peer router (over AURP)
|
AURPPeer *AURPPeer // Next hop is this peer router (over AURP)
|
||||||
EtherTalkPeer *EtherTalkPeer // Next hop is this peer router (over EtherTalk)
|
EtherTalkPeer *EtherTalkPeer // Next hop is this peer router (over EtherTalk)
|
||||||
|
@ -47,6 +51,13 @@ func (r Route) LastSeenAgo() string {
|
||||||
return fmt.Sprintf("%v ago", time.Since(r.LastSeen).Truncate(time.Millisecond))
|
return fmt.Sprintf("%v ago", time.Since(r.LastSeen).Truncate(time.Millisecond))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Valid reports whether the route is valid.
|
||||||
|
// A valid route has one or more zone names, and if it is learned from a peer
|
||||||
|
// router over EtherTalk is not too old.
|
||||||
|
func (r *Route) Valid() bool {
|
||||||
|
return len(r.ZoneNames) > 0 && (r.EtherTalkPeer == nil || time.Since(r.LastSeen) <= maxRouteAge)
|
||||||
|
}
|
||||||
|
|
||||||
type RouteTable struct {
|
type RouteTable struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
routes map[*Route]struct{}
|
routes map[*Route]struct{}
|
||||||
|
@ -65,6 +76,7 @@ func (rt *RouteTable) InsertEtherTalkDirect(port *EtherTalkPort) {
|
||||||
NetEnd: port.NetEnd,
|
NetEnd: port.NetEnd,
|
||||||
Distance: 0, // we're connected directly
|
Distance: 0, // we're connected directly
|
||||||
LastSeen: time.Now(),
|
LastSeen: time.Now(),
|
||||||
|
ZoneNames: port.AvailableZones,
|
||||||
EtherTalkDirect: port,
|
EtherTalkDirect: port,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +105,7 @@ func (rt *RouteTable) LookupRoute(network ddp.Network) *Route {
|
||||||
if network < r.NetStart || network > r.NetEnd {
|
if network < r.NetStart || network > r.NetEnd {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Exclude EtherTalk routes that are too old
|
if !r.Valid() {
|
||||||
if r.EtherTalkPeer != nil && time.Since(r.LastSeen) > maxRouteAge {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if bestRoute == nil {
|
if bestRoute == nil {
|
||||||
|
@ -142,12 +153,12 @@ func (rt *RouteTable) UpdateAURPRouteDistance(peer *AURPPeer, network ddp.Networ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *RouteTable) UpsertEtherTalkRoute(peer *EtherTalkPeer, extended bool, netStart, netEnd ddp.Network, metric uint8) error {
|
func (rt *RouteTable) UpsertEtherTalkRoute(peer *EtherTalkPeer, extended bool, netStart, netEnd ddp.Network, metric uint8) (*Route, error) {
|
||||||
if netStart > netEnd {
|
if netStart > netEnd {
|
||||||
return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
|
return nil, fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
|
||||||
}
|
}
|
||||||
if netStart != netEnd && !extended {
|
if netStart != netEnd && !extended {
|
||||||
return fmt.Errorf("invalid network range [%d, %d] for nonextended network", netStart, netEnd)
|
return nil, fmt.Errorf("invalid network range [%d, %d] for nonextended network", netStart, netEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.mu.Lock()
|
rt.mu.Lock()
|
||||||
|
@ -169,7 +180,7 @@ func (rt *RouteTable) UpsertEtherTalkRoute(peer *EtherTalkPeer, extended bool, n
|
||||||
}
|
}
|
||||||
r.Distance = metric
|
r.Distance = metric
|
||||||
r.LastSeen = time.Now()
|
r.LastSeen = time.Now()
|
||||||
return nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert.
|
// Insert.
|
||||||
|
@ -182,7 +193,7 @@ func (rt *RouteTable) UpsertEtherTalkRoute(peer *EtherTalkPeer, extended bool, n
|
||||||
EtherTalkPeer: peer,
|
EtherTalkPeer: peer,
|
||||||
}
|
}
|
||||||
rt.routes[r] = struct{}{}
|
rt.routes[r] = struct{}{}
|
||||||
return nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *RouteTable) InsertAURPRoute(peer *AURPPeer, extended bool, netStart, netEnd ddp.Network, metric uint8) error {
|
func (rt *RouteTable) InsertAURPRoute(peer *AURPPeer, extended bool, netStart, netEnd ddp.Network, metric uint8) error {
|
||||||
|
@ -208,13 +219,29 @@ func (rt *RouteTable) InsertAURPRoute(peer *AURPPeer, extended bool, netStart, n
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidRoutes returns all valid routes.
|
||||||
func (rt *RouteTable) ValidRoutes() []*Route {
|
func (rt *RouteTable) ValidRoutes() []*Route {
|
||||||
rt.mu.Lock()
|
rt.mu.Lock()
|
||||||
defer rt.mu.Unlock()
|
defer rt.mu.Unlock()
|
||||||
valid := make([]*Route, 0, len(rt.routes))
|
valid := make([]*Route, 0, len(rt.routes))
|
||||||
for r := range rt.routes {
|
for r := range rt.routes {
|
||||||
// Exclude EtherTalk routes that are too old
|
if r.Valid() {
|
||||||
if r.EtherTalkPeer != nil && time.Since(r.LastSeen) > maxRouteAge {
|
valid = append(valid, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidNonAURPRoutes returns all valid routes that were not learned via AURP.
|
||||||
|
func (rt *RouteTable) ValidNonAURPRoutes() []*Route {
|
||||||
|
rt.mu.Lock()
|
||||||
|
defer rt.mu.Unlock()
|
||||||
|
valid := make([]*Route, 0, len(rt.routes))
|
||||||
|
for r := range rt.routes {
|
||||||
|
if r.AURPPeer != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !r.Valid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
valid = append(valid, r)
|
valid = append(valid, r)
|
||||||
|
|
|
@ -26,7 +26,6 @@ import (
|
||||||
type Router struct {
|
type Router struct {
|
||||||
Config *Config
|
Config *Config
|
||||||
RouteTable *RouteTable
|
RouteTable *RouteTable
|
||||||
ZoneTable *ZoneTable
|
|
||||||
Ports []*EtherTalkPort
|
Ports []*EtherTalkPort
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
|
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk"
|
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk/rtmp"
|
"gitea.drjosh.dev/josh/jrouter/atalk/rtmp"
|
||||||
|
"gitea.drjosh.dev/josh/jrouter/atalk/zip"
|
||||||
"gitea.drjosh.dev/josh/jrouter/status"
|
"gitea.drjosh.dev/josh/jrouter/status"
|
||||||
|
|
||||||
"github.com/sfiera/multitalk/pkg/ddp"
|
"github.com/sfiera/multitalk/pkg/ddp"
|
||||||
|
@ -101,8 +102,7 @@ func (port *EtherTalkPort) HandleRTMP(ctx context.Context, pkt *ddp.ExtPacket) e
|
||||||
}
|
}
|
||||||
|
|
||||||
case rtmp.FunctionLoopProbe:
|
case rtmp.FunctionLoopProbe:
|
||||||
log.Print("RTMP: TODO: handle Loop Probes")
|
return fmt.Errorf("TODO: handle Loop Probes")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ddp.ProtoRTMPResp:
|
case ddp.ProtoRTMPResp:
|
||||||
|
@ -110,22 +110,51 @@ func (port *EtherTalkPort) HandleRTMP(ctx context.Context, pkt *ddp.ExtPacket) e
|
||||||
log.Print("RTMP: Got Response or Data")
|
log.Print("RTMP: Got Response or Data")
|
||||||
dataPkt, err := rtmp.UnmarshalDataPacket(pkt.Data)
|
dataPkt, err := rtmp.UnmarshalDataPacket(pkt.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("RTMP: Couldn't unmarshal RTMP Data packet: %v", err)
|
return fmt.Errorf("unmarshal RTMP Data packet: %w", err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
peer := &EtherTalkPeer{
|
peer := &EtherTalkPeer{
|
||||||
Port: port,
|
Port: port,
|
||||||
PeerAddr: dataPkt.RouterAddr,
|
PeerAddr: dataPkt.RouterAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rt := range dataPkt.NetworkTuples {
|
var noZones []ddp.Network
|
||||||
if err := port.Router.RouteTable.UpsertEtherTalkRoute(peer, rt.Extended, rt.RangeStart, rt.RangeEnd, rt.Distance+1); err != nil {
|
for _, nt := range dataPkt.NetworkTuples {
|
||||||
log.Printf("RTMP: Couldn't upsert EtherTalk route: %v", err)
|
route, err := port.Router.RouteTable.UpsertEtherTalkRoute(peer, nt.Extended, nt.RangeStart, nt.RangeEnd, nt.Distance+1)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("upsert EtherTalk route: %v", err)
|
||||||
|
}
|
||||||
|
if len(route.ZoneNames) == 0 {
|
||||||
|
noZones = append(noZones, route.NetStart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(noZones) > 0 {
|
||||||
|
// Send a ZIP Query for all networks we don't have zone names for.
|
||||||
|
// TODO: split networks to fit in multiple packets as needed
|
||||||
|
qryPkt, err := (&zip.QueryPacket{Networks: noZones}).Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshal ZIP Query packet: %w", err)
|
||||||
|
}
|
||||||
|
outDDP := &ddp.ExtPacket{
|
||||||
|
ExtHeader: ddp.ExtHeader{
|
||||||
|
Size: uint16(len(qryPkt)) + atalk.DDPExtHeaderSize,
|
||||||
|
Cksum: 0,
|
||||||
|
SrcNet: port.MyAddr.Network,
|
||||||
|
SrcNode: port.MyAddr.Node,
|
||||||
|
SrcSocket: 6,
|
||||||
|
DstNet: pkt.SrcNet,
|
||||||
|
DstNode: pkt.SrcNode,
|
||||||
|
DstSocket: 6, // ZIP socket
|
||||||
|
Proto: ddp.ProtoZIP,
|
||||||
|
},
|
||||||
|
Data: qryPkt,
|
||||||
|
}
|
||||||
|
if err := port.Send(ctx, outDDP); err != nil {
|
||||||
|
return fmt.Errorf("sending ZIP Query: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Printf("RTMP: invalid DDP type %d on socket 1", pkt.Proto)
|
return fmt.Errorf("invalid DDP type %d on socket 1", pkt.Proto)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"slices"
|
|
||||||
|
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk"
|
"gitea.drjosh.dev/josh/jrouter/atalk"
|
||||||
"gitea.drjosh.dev/josh/jrouter/atalk/atp"
|
"gitea.drjosh.dev/josh/jrouter/atalk/atp"
|
||||||
|
@ -52,6 +51,9 @@ func (port *EtherTalkPort) handleZIPZIP(ctx context.Context, ddpkt *ddp.ExtPacke
|
||||||
case *zip.QueryPacket:
|
case *zip.QueryPacket:
|
||||||
return port.handleZIPQuery(ctx, ddpkt, zipkt)
|
return port.handleZIPQuery(ctx, ddpkt, zipkt)
|
||||||
|
|
||||||
|
case *zip.ReplyPacket:
|
||||||
|
return port.handleZIPReply(zipkt)
|
||||||
|
|
||||||
case *zip.GetNetInfoPacket:
|
case *zip.GetNetInfoPacket:
|
||||||
return port.handleZIPGetNetInfo(ctx, ddpkt, zipkt)
|
return port.handleZIPGetNetInfo(ctx, ddpkt, zipkt)
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ func (port *EtherTalkPort) handleZIPZIP(ctx context.Context, ddpkt *ddp.ExtPacke
|
||||||
|
|
||||||
func (port *EtherTalkPort) handleZIPQuery(ctx context.Context, ddpkt *ddp.ExtPacket, zipkt *zip.QueryPacket) error {
|
func (port *EtherTalkPort) handleZIPQuery(ctx context.Context, ddpkt *ddp.ExtPacket, zipkt *zip.QueryPacket) error {
|
||||||
log.Printf("ZIP: Got Query for networks %v", zipkt.Networks)
|
log.Printf("ZIP: Got Query for networks %v", zipkt.Networks)
|
||||||
networks := port.Router.ZoneTable.Query(zipkt.Networks)
|
networks := port.Router.RouteTable.ZonesForNetworks(zipkt.Networks)
|
||||||
|
|
||||||
sendReply := func(resp *zip.ReplyPacket) error {
|
sendReply := func(resp *zip.ReplyPacket) error {
|
||||||
respRaw, err := resp.Marshal()
|
respRaw, err := resp.Marshal()
|
||||||
|
@ -156,11 +158,21 @@ func (port *EtherTalkPort) handleZIPQuery(ctx context.Context, ddpkt *ddp.ExtPac
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (port *EtherTalkPort) handleZIPReply(zipkt *zip.ReplyPacket) error {
|
||||||
|
log.Printf("ZIP: Got Reply containing %v", zipkt.Networks)
|
||||||
|
|
||||||
|
// Integrate new zone information into route table.
|
||||||
|
for n, zs := range zipkt.Networks {
|
||||||
|
port.Router.RouteTable.AddZonesToNetwork(n, zs...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (port *EtherTalkPort) handleZIPGetNetInfo(ctx context.Context, ddpkt *ddp.ExtPacket, zipkt *zip.GetNetInfoPacket) error {
|
func (port *EtherTalkPort) handleZIPGetNetInfo(ctx context.Context, ddpkt *ddp.ExtPacket, zipkt *zip.GetNetInfoPacket) error {
|
||||||
log.Printf("ZIP: Got GetNetInfo for zone %q", zipkt.ZoneName)
|
log.Printf("ZIP: Got GetNetInfo for zone %q", zipkt.ZoneName)
|
||||||
|
|
||||||
// The request is zoneValid if the zone name is available on this network.
|
// The request is zoneValid if the zone name is available on this network.
|
||||||
zoneValid := slices.Contains(port.AvailableZones, zipkt.ZoneName)
|
zoneValid := port.AvailableZones.Contains(zipkt.ZoneName)
|
||||||
|
|
||||||
// The multicast address we return depends on the validity of the zone
|
// The multicast address we return depends on the validity of the zone
|
||||||
// name.
|
// name.
|
||||||
|
@ -258,10 +270,10 @@ func (port *EtherTalkPort) handleZIPTReq(ctx context.Context, ddpkt *ddp.ExtPack
|
||||||
|
|
||||||
switch gzl.Function {
|
switch gzl.Function {
|
||||||
case zip.FunctionGetZoneList:
|
case zip.FunctionGetZoneList:
|
||||||
resp.Zones = port.Router.ZoneTable.AllNames()
|
resp.Zones = port.Router.RouteTable.AllZoneNames()
|
||||||
|
|
||||||
case zip.FunctionGetLocalZones:
|
case zip.FunctionGetLocalZones:
|
||||||
resp.Zones = port.AvailableZones
|
resp.Zones = port.AvailableZones.ToSlice()
|
||||||
|
|
||||||
case zip.FunctionGetMyZone:
|
case zip.FunctionGetMyZone:
|
||||||
// Note: This shouldn't happen on extended networks (e.g. EtherTalk)
|
// Note: This shouldn't happen on extended networks (e.g. EtherTalk)
|
||||||
|
|
189
router/zones.go
189
router/zones.go
|
@ -17,145 +17,72 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sfiera/multitalk/pkg/ddp"
|
"github.com/sfiera/multitalk/pkg/ddp"
|
||||||
)
|
)
|
||||||
|
|
||||||
//const maxZoneAge = 10 * time.Minute // TODO: confirm
|
func (rt *RouteTable) AddZonesToNetwork(n ddp.Network, zs ...string) {
|
||||||
|
rt.mu.Lock()
|
||||||
type Zone struct {
|
defer rt.mu.Unlock()
|
||||||
Network ddp.Network
|
for r := range rt.routes {
|
||||||
Name string
|
if n < r.NetStart || n > r.NetEnd {
|
||||||
LocalPort *EtherTalkPort // nil if remote (local to another router)
|
|
||||||
LastSeen time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (z Zone) LastSeenAgo() string {
|
|
||||||
if z.LastSeen.IsZero() {
|
|
||||||
return "never"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%v ago", time.Since(z.LastSeen).Truncate(time.Millisecond))
|
|
||||||
}
|
|
||||||
|
|
||||||
type zoneKey struct {
|
|
||||||
network ddp.Network
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZoneTable struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
zones map[zoneKey]*Zone
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewZoneTable() *ZoneTable {
|
|
||||||
return &ZoneTable{
|
|
||||||
zones: make(map[zoneKey]*Zone),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (zt *ZoneTable) Dump() []Zone {
|
|
||||||
zt.mu.Lock()
|
|
||||||
defer zt.mu.Unlock()
|
|
||||||
zs := make([]Zone, 0, len(zt.zones))
|
|
||||||
for _, z := range zt.zones {
|
|
||||||
zs = append(zs, *z)
|
|
||||||
}
|
|
||||||
return zs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (zt *ZoneTable) Upsert(network ddp.Network, name string, localPort *EtherTalkPort) {
|
|
||||||
zt.mu.Lock()
|
|
||||||
defer zt.mu.Unlock()
|
|
||||||
key := zoneKey{network, name}
|
|
||||||
z := zt.zones[key]
|
|
||||||
if z != nil {
|
|
||||||
z.LocalPort = localPort
|
|
||||||
z.LastSeen = time.Now()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
zt.zones[key] = &Zone{
|
|
||||||
Network: network,
|
|
||||||
Name: name,
|
|
||||||
LocalPort: localPort,
|
|
||||||
LastSeen: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (zt *ZoneTable) Query(ns []ddp.Network) map[ddp.Network][]string {
|
|
||||||
slices.Sort(ns)
|
|
||||||
zs := make(map[ddp.Network][]string)
|
|
||||||
|
|
||||||
zt.mu.Lock()
|
|
||||||
defer zt.mu.Unlock()
|
|
||||||
for _, z := range zt.zones {
|
|
||||||
// if time.Since(z.LastSeen) > maxZoneAge {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
if _, ok := slices.BinarySearch(ns, z.Network); ok {
|
|
||||||
zs[z.Network] = append(zs[z.Network], z.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return zs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (zt *ZoneTable) LookupName(name string) []*Zone {
|
|
||||||
zt.mu.Lock()
|
|
||||||
defer zt.mu.Unlock()
|
|
||||||
|
|
||||||
var zs []*Zone
|
|
||||||
for _, z := range zt.zones {
|
|
||||||
if z.Name == name {
|
|
||||||
zs = append(zs, z)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return zs
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (zt *ZoneTable) LocalNames() []string {
|
|
||||||
// zt.mu.Lock()
|
|
||||||
// seen := make(map[string]struct{})
|
|
||||||
// zs := make([]string, 0, len(zt.zones))
|
|
||||||
// for _, z := range zt.zones {
|
|
||||||
// // if time.Since(z.LastSeen) > maxZoneAge {
|
|
||||||
// // continue
|
|
||||||
// // }
|
|
||||||
// if z.Local != nil {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// if _, s := seen[z.Name]; s {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// seen[z.Name] = struct{}{}
|
|
||||||
// zs = append(zs, z.Name)
|
|
||||||
|
|
||||||
// }
|
|
||||||
// zt.mu.Unlock()
|
|
||||||
|
|
||||||
// sort.Strings(zs)
|
|
||||||
// return zs
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (zt *ZoneTable) AllNames() []string {
|
|
||||||
zt.mu.Lock()
|
|
||||||
seen := make(map[string]struct{})
|
|
||||||
zs := make([]string, 0, len(zt.zones))
|
|
||||||
for _, z := range zt.zones {
|
|
||||||
// if time.Since(z.LastSeen) > maxZoneAge {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
if _, s := seen[z.Name]; s {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seen[z.Name] = struct{}{}
|
if r.ZoneNames == nil {
|
||||||
zs = append(zs, z.Name)
|
r.ZoneNames = make(StringSet)
|
||||||
|
}
|
||||||
|
r.ZoneNames.Insert(zs...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zt.mu.Unlock()
|
|
||||||
|
|
||||||
sort.Strings(zs)
|
func (rt *RouteTable) ZonesForNetworks(ns []ddp.Network) map[ddp.Network][]string {
|
||||||
|
zs := make(map[ddp.Network][]string)
|
||||||
|
|
||||||
|
rt.mu.Lock()
|
||||||
|
defer rt.mu.Unlock()
|
||||||
|
for r := range rt.routes {
|
||||||
|
if !r.Valid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := slices.BinarySearch(ns, r.NetStart); ok {
|
||||||
|
for z := range r.ZoneNames {
|
||||||
|
zs[r.NetStart] = append(zs[r.NetStart], z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return zs
|
return zs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rt *RouteTable) RoutesForZone(zone string) []*Route {
|
||||||
|
rt.mu.Lock()
|
||||||
|
defer rt.mu.Unlock()
|
||||||
|
|
||||||
|
var routes []*Route
|
||||||
|
for r := range rt.routes {
|
||||||
|
if !r.Valid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r.ZoneNames.Contains(zone) {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *RouteTable) AllZoneNames() (zones []string) {
|
||||||
|
defer slices.Sort(zones)
|
||||||
|
|
||||||
|
rt.mu.Lock()
|
||||||
|
defer rt.mu.Unlock()
|
||||||
|
|
||||||
|
zs := make(StringSet)
|
||||||
|
for r := range rt.routes {
|
||||||
|
if !r.Valid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
zs.Add(r.ZoneNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
return zs.ToSlice()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue