diff --git a/router/fastdp.go b/router/fastdp.go index 31ba9d7b..5e9b6ce0 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -754,6 +754,10 @@ func (fwd *fastDatapathForwarder) handleHeartbeatAck() { } func (fwd *fastDatapathForwarder) Forward(key ForwardPacketKey) FlowOp { + if !key.SrcPeer.HasShortID || !key.DstPeer.HasShortID { + return nil + } + fwd.lock.RLock() defer fwd.lock.RUnlock() diff --git a/router/overlay.go b/router/overlay.go index 824a2b39..3ab9f88d 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -68,7 +68,8 @@ type OverlayCrypto struct { type OverlayForwarder interface { // Forward a packet across the connection. May be called as // soon as the forwarder is created, in particular before - // Confirm(). + // Confirm(). The return value nil means the key could not be + // handled by this forwarder. Forward(ForwardPacketKey) FlowOp // Confirm that the connection is really wanted, and so the diff --git a/router/overlay_switch.go b/router/overlay_switch.go index 553962c4..48296459 100644 --- a/router/overlay_switch.go +++ b/router/overlay_switch.go @@ -124,8 +124,8 @@ type overlaySwitchForwarder struct { lock sync.Mutex - // the forwarder to send on - best OverlayForwarder + // the index of the forwarder to send on + best int // the subsidiary forwarders forwarders []subForwarder @@ -183,6 +183,7 @@ func (osw *OverlaySwitch) MakeForwarder( fwd := &overlaySwitchForwarder{ remotePeer: params.RemotePeer, + best: -1, forwarders: make([]subForwarder, len(overlays)), stopChan: stopChan, @@ -285,9 +286,6 @@ func (fwd *overlaySwitchForwarder) established(index int) { fwd.forwarders[index].established = true - // less preferred forwarders are no longer needed - fwd.stopFrom(index + 1) - if !fwd.alreadyEstablished { fwd.alreadyEstablished = true close(fwd.establishedChan) @@ -323,7 +321,8 @@ func (fwd *overlaySwitchForwarder) stopFrom(index int) { func (fwd *overlaySwitchForwarder) chooseBest() { // the most preferred established forwarder is the best // otherwise, the most preferred working forwarder is the best - var bestEstablished, bestWorking *subForwarder + bestEstablished := -1 + bestWorking := -1 for i := range fwd.forwarders { subFwd := &fwd.forwarders[i] @@ -331,18 +330,18 @@ func (fwd *overlaySwitchForwarder) chooseBest() { continue } - if bestWorking == nil { - bestWorking = subFwd + if bestWorking < 0 { + bestWorking = i } - if bestEstablished == nil && subFwd.established { - bestEstablished = subFwd + if bestEstablished < 0 && subFwd.established { + bestEstablished = i } } best := bestEstablished - if best == nil { - if bestWorking == nil { + if best < 0 { + if bestWorking < 0 { select { case fwd.errorChan <- fmt.Errorf("no working forwarders to %s", fwd.remotePeer): default: @@ -354,9 +353,10 @@ func (fwd *overlaySwitchForwarder) chooseBest() { best = bestWorking } - if fwd.best != best.fwd { - fwd.best = best.fwd - log.Info(fwd.logPrefix(), "using ", best.overlayName) + if fwd.best != best { + fwd.best = best + log.Info(fwd.logPrefix(), + "using ", fwd.forwarders[best].overlayName) } } @@ -378,14 +378,23 @@ func (fwd *overlaySwitchForwarder) Confirm() { func (fwd *overlaySwitchForwarder) Forward(pk ForwardPacketKey) FlowOp { fwd.lock.Lock() - best := fwd.best - fwd.lock.Unlock() - if best == nil { - return nil + if fwd.best >= 0 { + for i := fwd.best; i < len(fwd.forwarders); i++ { + best := fwd.forwarders[i].fwd + if best != nil { + fwd.lock.Unlock() + if op := best.Forward(pk); op != nil { + return op + } + fwd.lock.Lock() + } + } } - return best.Forward(pk) + fwd.lock.Unlock() + + return DiscardingFlowOp{} } func (fwd *overlaySwitchForwarder) EstablishedChannel() <-chan struct{} { @@ -412,13 +421,17 @@ func (fwd *overlaySwitchForwarder) ControlMessage(tag byte, msg []byte) { } func (fwd *overlaySwitchForwarder) DisplayName() string { + var best OverlayForwarder + fwd.lock.Lock() - best := fwd.best + if fwd.best > 0 { + best = fwd.forwarders[fwd.best].fwd + } fwd.lock.Unlock() - if best == nil { - return "none" + if best != nil { + return best.DisplayName() } - return best.DisplayName() + return "none" }