WIP: routers on ethertalk
This commit is contained in:
parent
da4c729912
commit
7f8b0cb451
7 changed files with 197 additions and 64 deletions
86
main.go
86
main.go
|
@ -224,18 +224,18 @@ func main() {
|
||||||
|
|
||||||
// -------------------------------- Peers ---------------------------------
|
// -------------------------------- Peers ---------------------------------
|
||||||
var peersMu sync.Mutex
|
var peersMu sync.Mutex
|
||||||
peers := make(map[udpAddr]*router.Peer)
|
peers := make(map[udpAddr]*router.AURPPeer)
|
||||||
status.AddItem(ctx, "AURP Peers", peerTableTemplate, func(context.Context) (any, error) {
|
status.AddItem(ctx, "AURP Peers", peerTableTemplate, func(context.Context) (any, error) {
|
||||||
var peerInfo []*router.Peer
|
var peerInfo []*router.AURPPeer
|
||||||
func() {
|
func() {
|
||||||
peersMu.Lock()
|
peersMu.Lock()
|
||||||
defer peersMu.Unlock()
|
defer peersMu.Unlock()
|
||||||
peerInfo = make([]*router.Peer, 0, len(peers))
|
peerInfo = make([]*router.AURPPeer, 0, len(peers))
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
peerInfo = append(peerInfo, p)
|
peerInfo = append(peerInfo, p)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
slices.SortFunc(peerInfo, func(pa, pb *router.Peer) int {
|
slices.SortFunc(peerInfo, func(pa, pb *router.AURPPeer) int {
|
||||||
return cmp.Or(
|
return cmp.Or(
|
||||||
-cmp.Compare(
|
-cmp.Compare(
|
||||||
bool2Int(pa.ReceiverState() == router.ReceiverConnected),
|
bool2Int(pa.ReceiverState() == router.ReceiverConnected),
|
||||||
|
@ -257,7 +257,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
goPeerHandler := func(p *router.Peer) {
|
goPeerHandler := func(p *router.AURPPeer) {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
@ -308,7 +308,7 @@ func main() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
peer := &router.Peer{
|
peer := &router.AURPPeer{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Transport: &aurp.Transport{
|
Transport: &aurp.Transport{
|
||||||
LocalDI: localDI,
|
LocalDI: localDI,
|
||||||
|
@ -434,18 +434,29 @@ func main() {
|
||||||
// TODO: more generic routing
|
// TODO: more generic routing
|
||||||
if ddpkt.DstNet != 0 && !(ddpkt.DstNet >= cfg.EtherTalk.NetStart && ddpkt.DstNet <= cfg.EtherTalk.NetEnd) {
|
if ddpkt.DstNet != 0 && !(ddpkt.DstNet >= cfg.EtherTalk.NetStart && ddpkt.DstNet <= cfg.EtherTalk.NetEnd) {
|
||||||
// Is it for a network in the routing table?
|
// Is it for a network in the routing table?
|
||||||
rt := routes.LookupRoute(ddpkt.DstNet)
|
route := routes.LookupRoute(ddpkt.DstNet)
|
||||||
if rt == nil {
|
if route == nil {
|
||||||
log.Printf("DDP: no route for network %d", ddpkt.DstNet)
|
log.Printf("DDP: no route for network %d", ddpkt.DstNet)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encap ethPacket.Payload into an AURP packet
|
switch {
|
||||||
log.Printf("DDP: forwarding to AURP peer %v", rt.Peer.RemoteAddr)
|
case route.AURPPeer != nil:
|
||||||
if _, err := rt.Peer.Send(rt.Peer.Transport.NewAppleTalkPacket(ethFrame.Payload)); err != nil {
|
// Encap ethPacket.Payload into an AURP packet
|
||||||
log.Printf("DDP: Couldn't forward packet to AURP peer: %v", err)
|
log.Printf("DDP: forwarding to AURP peer %v", route.AURPPeer.RemoteAddr)
|
||||||
}
|
if _, err := route.AURPPeer.Send(route.AURPPeer.Transport.NewAppleTalkPacket(ethFrame.Payload)); err != nil {
|
||||||
|
log.Printf("DDP: Couldn't forward packet to AURP peer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case route.EtherTalkPeer != nil:
|
||||||
|
// Route payload to another router over EtherTalk
|
||||||
|
// TODO: this is unlikely because we currenly only support 1 EtherTalk port
|
||||||
|
log.Printf("DDP: forwarding to EtherTalk peer %v", route.EtherTalkPeer.PeerAddr)
|
||||||
|
// Note: resolving AARP can block
|
||||||
|
if err := route.EtherTalkPeer.Forward(ctx, ddpkt); err != nil {
|
||||||
|
log.Printf("DDP: Couldn't forward packet to EtherTalk peer: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +545,7 @@ func main() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// New peer!
|
// New peer!
|
||||||
pr = &router.Peer{
|
pr = &router.AURPPeer{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Transport: &aurp.Transport{
|
Transport: &aurp.Transport{
|
||||||
LocalDI: localDI,
|
LocalDI: localDI,
|
||||||
|
@ -584,14 +595,7 @@ func main() {
|
||||||
ddpkt.DstNet, ddpkt.DstNode, ddpkt.DstSocket,
|
ddpkt.DstNet, ddpkt.DstNode, ddpkt.DstSocket,
|
||||||
ddpkt.Proto, len(ddpkt.Data))
|
ddpkt.Proto, len(ddpkt.Data))
|
||||||
|
|
||||||
// "Route" the packet
|
// Route the packet
|
||||||
// Since for now there's only one local network, the routing
|
|
||||||
// decision is pretty easy
|
|
||||||
// TODO: Fix this to support other AppleTalk routers
|
|
||||||
if ddpkt.DstNet < cfg.EtherTalk.NetStart || ddpkt.DstNet > cfg.EtherTalk.NetEnd {
|
|
||||||
log.Print("DDP/AURP: dropping packet not addressed to our EtherTalk range")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and adjust the Hop Count
|
// Check and adjust the Hop Count
|
||||||
// Note the ddp package doesn't make this simple
|
// Note the ddp package doesn't make this simple
|
||||||
|
@ -604,8 +608,44 @@ func main() {
|
||||||
ddpkt.Size &^= 0x3C00
|
ddpkt.Size &^= 0x3C00
|
||||||
ddpkt.Size |= hopCount << 10
|
ddpkt.Size |= hopCount << 10
|
||||||
|
|
||||||
|
if ddpkt.DstNet < cfg.EtherTalk.NetStart || ddpkt.DstNet > cfg.EtherTalk.NetEnd {
|
||||||
|
// Is it a network in the routing table?
|
||||||
|
route := routes.LookupRoute(ddpkt.DstNet)
|
||||||
|
if route == nil {
|
||||||
|
log.Printf("DDP/AURP: no route for packet (dstnet %d); dropping packet", ddpkt.DstNet)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case route.AURPPeer != nil:
|
||||||
|
// Routing between AURP peers... bit weird but OK
|
||||||
|
log.Printf("DDP/AURP: forwarding to AURP peer %v", route.AURPPeer.RemoteAddr)
|
||||||
|
outPkt, err := ddp.ExtMarshal(*ddpkt)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("DDP/AURP: Couldn't re-marshal packet: %v", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err := route.AURPPeer.Send(route.AURPPeer.Transport.NewAppleTalkPacket(outPkt)); err != nil {
|
||||||
|
log.Printf("DDP/AURP: Couldn't forward packet to AURP peer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case route.EtherTalkPeer != nil:
|
||||||
|
// AURP peer -> EtherTalk peer
|
||||||
|
// Note: resolving AARP can block
|
||||||
|
log.Printf("DDP/AURP: forwarding to EtherTalk peer %v", route.EtherTalkPeer.PeerAddr)
|
||||||
|
if err := route.EtherTalkPeer.Forward(ctx, ddpkt); err != nil {
|
||||||
|
log.Printf("DDP/AURP: Couldn't forward packet to EtherTalk peer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Print("DDP/AURP: no forwarding mechanism for route; dropping packet")
|
||||||
|
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Is it addressed to me? Is it NBP?
|
// Is it addressed to me? Is it NBP?
|
||||||
if ddpkt.DstNode == 0 { // Node 0 = the router for the network
|
if ddpkt.DstNode == 0 { // Node 0 = any router for the network = me
|
||||||
if ddpkt.DstSocket != 2 {
|
if ddpkt.DstSocket != 2 {
|
||||||
// Something else?? TODO
|
// Something else?? TODO
|
||||||
log.Printf("DDP/AURP: I don't have anything 'listening' on socket %d", ddpkt.DstSocket)
|
log.Printf("DDP/AURP: I don't have anything 'listening' on socket %d", ddpkt.DstSocket)
|
||||||
|
|
|
@ -110,7 +110,7 @@ func (rtr *Router) HandleNBP(srcHWAddr ethernet.Addr, ddpkt *ddp.ExtPacket) erro
|
||||||
if route == nil {
|
if route == nil {
|
||||||
return fmt.Errorf("no route for network %d", z.Network)
|
return fmt.Errorf("no route for network %d", z.Network)
|
||||||
}
|
}
|
||||||
peer := route.Peer
|
peer := route.AURPPeer
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
return fmt.Errorf("nil peer for route for network %d", z.Network)
|
return fmt.Errorf("nil peer for route for network %d", z.Network)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/sfiera/multitalk/pkg/ddp"
|
"github.com/sfiera/multitalk/pkg/ddp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (rtr *Router) HandleNBPInAURP(peer *Peer, ddpkt *ddp.ExtPacket) error {
|
func (rtr *Router) HandleNBPInAURP(peer *AURPPeer, ddpkt *ddp.ExtPacket) error {
|
||||||
if ddpkt.Proto != ddp.ProtoNBP {
|
if ddpkt.Proto != ddp.ProtoNBP {
|
||||||
return fmt.Errorf("invalid DDP type %d on socket 2", ddpkt.Proto)
|
return fmt.Errorf("invalid DDP type %d on socket 2", ddpkt.Proto)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,8 +92,8 @@ func (ss SenderState) String() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer handles the peering with a peer AURP router.
|
// AURPPeer handles the peering with a peer AURP router.
|
||||||
type Peer struct {
|
type AURPPeer struct {
|
||||||
// Whole router config.
|
// Whole router config.
|
||||||
Config *Config
|
Config *Config
|
||||||
|
|
||||||
|
@ -125,31 +125,31 @@ type Peer struct {
|
||||||
sstate SenderState
|
sstate SenderState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) ReceiverState() ReceiverState {
|
func (p *AURPPeer) ReceiverState() ReceiverState {
|
||||||
p.mu.RLock()
|
p.mu.RLock()
|
||||||
defer p.mu.RUnlock()
|
defer p.mu.RUnlock()
|
||||||
return p.rstate
|
return p.rstate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) SenderState() SenderState {
|
func (p *AURPPeer) SenderState() SenderState {
|
||||||
p.mu.RLock()
|
p.mu.RLock()
|
||||||
defer p.mu.RUnlock()
|
defer p.mu.RUnlock()
|
||||||
return p.sstate
|
return p.sstate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) setRState(rstate ReceiverState) {
|
func (p *AURPPeer) setRState(rstate ReceiverState) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
p.rstate = rstate
|
p.rstate = rstate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) setSState(sstate SenderState) {
|
func (p *AURPPeer) setSState(sstate SenderState) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
p.sstate = sstate
|
p.sstate = sstate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) disconnect() {
|
func (p *AURPPeer) disconnect() {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
p.rstate = ReceiverUnconnected
|
p.rstate = ReceiverUnconnected
|
||||||
|
@ -157,7 +157,7 @@ func (p *Peer) disconnect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send encodes and sends pkt to the remote host.
|
// Send encodes and sends pkt to the remote host.
|
||||||
func (p *Peer) Send(pkt aurp.Packet) (int, error) {
|
func (p *AURPPeer) Send(pkt aurp.Packet) (int, error) {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if _, err := pkt.WriteTo(&b); err != nil {
|
if _, err := pkt.WriteTo(&b); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -166,7 +166,7 @@ func (p *Peer) Send(pkt aurp.Packet) (int, error) {
|
||||||
return p.UDPConn.WriteToUDP(b.Bytes(), p.RemoteAddr)
|
return p.UDPConn.WriteToUDP(b.Bytes(), p.RemoteAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Peer) Handle(ctx context.Context) error {
|
func (p *AURPPeer) Handle(ctx context.Context) error {
|
||||||
rticker := time.NewTicker(1 * time.Second)
|
rticker := time.NewTicker(1 * time.Second)
|
||||||
defer rticker.Stop()
|
defer rticker.Stop()
|
||||||
sticker := time.NewTicker(1 * time.Second)
|
sticker := time.NewTicker(1 * time.Second)
|
||||||
|
@ -244,7 +244,7 @@ func (p *Peer) 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.DeletePeer(p)
|
p.RoutingTable.DeleteAURPPeer(p)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ func (p *Peer) 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.DeletePeer(p)
|
p.RoutingTable.DeleteAURPPeer(p)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,7 +458,7 @@ func (p *Peer) 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.InsertRoute(
|
p.RoutingTable.InsertAURPRoute(
|
||||||
p,
|
p,
|
||||||
nt.Extended,
|
nt.Extended,
|
||||||
ddp.Network(nt.RangeStart),
|
ddp.Network(nt.RangeStart),
|
||||||
|
@ -534,7 +534,7 @@ func (p *Peer) 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.InsertRoute(
|
if err := p.RoutingTable.InsertAURPRoute(
|
||||||
p,
|
p,
|
||||||
et.Extended,
|
et.Extended,
|
||||||
et.RangeStart,
|
et.RangeStart,
|
||||||
|
@ -546,10 +546,10 @@ func (p *Peer) Handle(ctx context.Context) error {
|
||||||
ackFlag = aurp.RoutingFlagSendZoneInfo
|
ackFlag = aurp.RoutingFlagSendZoneInfo
|
||||||
|
|
||||||
case aurp.EventCodeND:
|
case aurp.EventCodeND:
|
||||||
p.RoutingTable.DeletePeerNetwork(p, et.RangeStart)
|
p.RoutingTable.DeleteAURPPeerNetwork(p, et.RangeStart)
|
||||||
|
|
||||||
case aurp.EventCodeNDC:
|
case aurp.EventCodeNDC:
|
||||||
p.RoutingTable.UpdateRouteDistance(p, et.RangeStart, et.Distance+1)
|
p.RoutingTable.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
|
||||||
|
@ -557,7 +557,7 @@ func (p *Peer) 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.DeletePeerNetwork(p, et.RangeStart)
|
p.RoutingTable.DeleteAURPPeerNetwork(p, et.RangeStart)
|
||||||
|
|
||||||
case aurp.EventCodeZC:
|
case aurp.EventCodeZC:
|
||||||
// "This event is reserved for future use."
|
// "This event is reserved for future use."
|
||||||
|
@ -575,7 +575,7 @@ func (p *Peer) 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.DeletePeer(p)
|
p.RoutingTable.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 {
|
54
router/peer_eth.go
Normal file
54
router/peer_eth.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/gopacket/pcap"
|
||||||
|
"github.com/sfiera/multitalk/pkg/ddp"
|
||||||
|
"github.com/sfiera/multitalk/pkg/ethernet"
|
||||||
|
"github.com/sfiera/multitalk/pkg/ethertalk"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EtherTalkPeer holds data needed to exchange routes and zones with another
|
||||||
|
// router on the EtherTalk network.
|
||||||
|
type EtherTalkPeer struct {
|
||||||
|
PcapHandle *pcap.Handle
|
||||||
|
MyHWAddr ethernet.Addr
|
||||||
|
AARP *AARPMachine
|
||||||
|
PeerAddr ddp.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward forwards a DDP packet to the next router.
|
||||||
|
func (p *EtherTalkPeer) Forward(ctx context.Context, pkt *ddp.ExtPacket) error {
|
||||||
|
// TODO: AARP resolution can block
|
||||||
|
de, err := p.AARP.Resolve(ctx, p.PeerAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outFrame, err := ethertalk.AppleTalk(p.MyHWAddr, *pkt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outFrame.Dst = de
|
||||||
|
outFrameRaw, err := ethertalk.Marshal(*outFrame)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.PcapHandle.WritePacketData(outFrameRaw)
|
||||||
|
}
|
|
@ -24,15 +24,18 @@ import (
|
||||||
"github.com/sfiera/multitalk/pkg/ddp"
|
"github.com/sfiera/multitalk/pkg/ddp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// const maxRouteAge = 10 * time.Minute // TODO: confirm
|
const maxRouteAge = 10 * time.Minute // TODO: confirm
|
||||||
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Extended bool
|
Extended bool
|
||||||
NetStart ddp.Network
|
NetStart ddp.Network
|
||||||
NetEnd ddp.Network
|
NetEnd ddp.Network
|
||||||
Peer *Peer
|
|
||||||
Distance uint8
|
Distance uint8
|
||||||
LastSeen time.Time
|
LastSeen time.Time
|
||||||
|
|
||||||
|
// Exactly one of the following should be set
|
||||||
|
AURPPeer *AURPPeer
|
||||||
|
EtherTalkPeer *EtherTalkPeer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Route) LastSeenAgo() string {
|
func (r Route) LastSeenAgo() string {
|
||||||
|
@ -70,15 +73,13 @@ func (rt *RoutingTable) LookupRoute(network ddp.Network) *Route {
|
||||||
|
|
||||||
var bestRoute *Route
|
var bestRoute *Route
|
||||||
for r := range rt.routes {
|
for r := range rt.routes {
|
||||||
if r.Peer == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if network < r.NetStart || network > r.NetEnd {
|
if network < r.NetStart || network > r.NetEnd {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if time.Since(r.LastSeen) > maxRouteAge {
|
// Exclude EtherTalk routes that are too old
|
||||||
// continue
|
if r.EtherTalkPeer != nil && time.Since(r.LastSeen) > maxRouteAge {
|
||||||
// }
|
continue
|
||||||
|
}
|
||||||
if bestRoute == nil {
|
if bestRoute == nil {
|
||||||
bestRoute = r
|
bestRoute = r
|
||||||
continue
|
continue
|
||||||
|
@ -90,41 +91,65 @@ func (rt *RoutingTable) LookupRoute(network ddp.Network) *Route {
|
||||||
return bestRoute
|
return bestRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *RoutingTable) DeletePeer(peer *Peer) {
|
func (rt *RoutingTable) DeleteAURPPeer(peer *AURPPeer) {
|
||||||
rt.mu.Lock()
|
rt.mu.Lock()
|
||||||
defer rt.mu.Unlock()
|
defer rt.mu.Unlock()
|
||||||
|
|
||||||
for route := range rt.routes {
|
for route := range rt.routes {
|
||||||
if route.Peer == peer {
|
if route.AURPPeer == peer {
|
||||||
delete(rt.routes, route)
|
delete(rt.routes, route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *RoutingTable) DeletePeerNetwork(peer *Peer, network ddp.Network) {
|
func (rt *RoutingTable) DeleteAURPPeerNetwork(peer *AURPPeer, network ddp.Network) {
|
||||||
rt.mu.Lock()
|
rt.mu.Lock()
|
||||||
defer rt.mu.Unlock()
|
defer rt.mu.Unlock()
|
||||||
|
|
||||||
for route := range rt.routes {
|
for route := range rt.routes {
|
||||||
if route.Peer == peer && route.NetStart == network {
|
if route.AURPPeer == peer && route.NetStart == network {
|
||||||
delete(rt.routes, route)
|
delete(rt.routes, route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *RoutingTable) UpdateRouteDistance(peer *Peer, network ddp.Network, distance uint8) {
|
func (rt *RoutingTable) UpdateAURPRouteDistance(peer *AURPPeer, network ddp.Network, distance uint8) {
|
||||||
rt.mu.Lock()
|
rt.mu.Lock()
|
||||||
defer rt.mu.Unlock()
|
defer rt.mu.Unlock()
|
||||||
|
|
||||||
for route := range rt.routes {
|
for route := range rt.routes {
|
||||||
if route.Peer == peer && route.NetStart == network {
|
if route.AURPPeer == peer && route.NetStart == network {
|
||||||
route.Distance = distance
|
route.Distance = distance
|
||||||
route.LastSeen = time.Now()
|
route.LastSeen = time.Now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *RoutingTable) InsertRoute(peer *Peer, extended bool, netStart, netEnd ddp.Network, metric uint8) error {
|
func (rt *RoutingTable) UpsertEthRoute(peer *EtherTalkPeer, extended bool, netStart, netEnd ddp.Network, metric uint8) error {
|
||||||
|
if netStart > netEnd {
|
||||||
|
return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
|
||||||
|
}
|
||||||
|
if netStart != netEnd && !extended {
|
||||||
|
return fmt.Errorf("invalid network range [%d, %d] for nonextended network", netStart, netEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &Route{
|
||||||
|
Extended: extended,
|
||||||
|
NetStart: netStart,
|
||||||
|
NetEnd: netEnd,
|
||||||
|
Distance: metric,
|
||||||
|
LastSeen: time.Now(),
|
||||||
|
EtherTalkPeer: peer,
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.mu.Lock()
|
||||||
|
defer rt.mu.Unlock()
|
||||||
|
// TODO: update if present rather than insert
|
||||||
|
rt.routes[r] = struct{}{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *RoutingTable) InsertAURPRoute(peer *AURPPeer, extended bool, netStart, netEnd ddp.Network, metric uint8) error {
|
||||||
if netStart > netEnd {
|
if netStart > netEnd {
|
||||||
return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
|
return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
|
||||||
}
|
}
|
||||||
|
@ -136,9 +161,9 @@ func (rt *RoutingTable) InsertRoute(peer *Peer, extended bool, netStart, netEnd
|
||||||
Extended: extended,
|
Extended: extended,
|
||||||
NetStart: netStart,
|
NetStart: netStart,
|
||||||
NetEnd: netEnd,
|
NetEnd: netEnd,
|
||||||
Peer: peer,
|
|
||||||
Distance: metric,
|
Distance: metric,
|
||||||
LastSeen: time.Now(),
|
LastSeen: time.Now(),
|
||||||
|
AURPPeer: peer,
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.mu.Lock()
|
rt.mu.Lock()
|
||||||
|
@ -152,12 +177,10 @@ func (rt *RoutingTable) ValidRoutes() []*Route {
|
||||||
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 {
|
||||||
if r.Peer == nil {
|
// Exclude EtherTalk routes that are too old
|
||||||
|
if r.EtherTalkPeer != nil && time.Since(r.LastSeen) > maxRouteAge {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// if time.Since(r.LastSeen) > maxRouteAge {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
valid = append(valid, r)
|
valid = append(valid, r)
|
||||||
}
|
}
|
||||||
return valid
|
return valid
|
||||||
|
|
|
@ -159,14 +159,30 @@ func (m *RTMPMachine) Run(ctx context.Context, incomingCh <-chan *ddp.ExtPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
case rtmp.FunctionLoopProbe:
|
case rtmp.FunctionLoopProbe:
|
||||||
log.Printf("RTMP: TODO: handle Loop Probes")
|
log.Print("RTMP: TODO: handle Loop Probes")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ddp.ProtoRTMPResp:
|
case ddp.ProtoRTMPResp:
|
||||||
// It's a peer router on the AppleTalk network!
|
// It's a peer router on the AppleTalk network!
|
||||||
// TODO: integrate this information with the routing table?
|
|
||||||
log.Print("RTMP: Got Response or Data")
|
log.Print("RTMP: Got Response or Data")
|
||||||
|
dataPkt, err := rtmp.UnmarshalDataPacket(pkt.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("RTMP: Couldn't unmarshal RTMP Data packet: %v", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
peer := &EtherTalkPeer{
|
||||||
|
PcapHandle: m.PcapHandle,
|
||||||
|
MyHWAddr: m.AARP.myAddr.Hardware,
|
||||||
|
AARP: m.AARP,
|
||||||
|
PeerAddr: dataPkt.RouterAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rt := range dataPkt.NetworkTuples {
|
||||||
|
if err := m.RoutingTable.UpsertEthRoute(peer, rt.Extended, rt.RangeStart, rt.RangeEnd, rt.Distance+1); err != nil {
|
||||||
|
log.Printf("RTMP: Couldn't upsert EtherTalk route: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Printf("RTMP: invalid DDP type %d on socket 1", pkt.Proto)
|
log.Printf("RTMP: invalid DDP type %d on socket 1", pkt.Proto)
|
||||||
|
|
Loading…
Reference in a new issue