mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 15:20:30 +00:00
Merge pull request #209 from Arceliar/switch-tune
Adjust switch parent selection behavior
This commit is contained in:
commit
5a7c2b250c
@ -21,6 +21,7 @@ import (
|
|||||||
const switch_timeout = time.Minute
|
const switch_timeout = time.Minute
|
||||||
const switch_updateInterval = switch_timeout / 2
|
const switch_updateInterval = switch_timeout / 2
|
||||||
const switch_throttle = switch_updateInterval / 2
|
const switch_throttle = switch_updateInterval / 2
|
||||||
|
const switch_max_time = time.Hour
|
||||||
|
|
||||||
// The switch locator represents the topology and network state dependent info about a node, minus the signatures that go with it.
|
// The switch locator represents the topology and network state dependent info about a node, minus the signatures that go with it.
|
||||||
// Nodes will pick the best root they see, provided that the root continues to push out updates with new timestamps.
|
// Nodes will pick the best root they see, provided that the root continues to push out updates with new timestamps.
|
||||||
@ -390,39 +391,55 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort) {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}()
|
}()
|
||||||
|
// Get the time we've known about the sender (or old parent's) current coords, up to a maximum of `switch_max_time`.
|
||||||
sTime := now.Sub(sender.firstSeen)
|
sTime := now.Sub(sender.firstSeen)
|
||||||
pTime := oldParent.time.Sub(oldParent.firstSeen) + switch_timeout
|
if sTime > switch_max_time {
|
||||||
|
sTime = switch_max_time
|
||||||
|
}
|
||||||
|
pTime := now.Sub(oldParent.firstSeen)
|
||||||
|
if pTime > switch_max_time {
|
||||||
|
pTime = switch_max_time
|
||||||
|
}
|
||||||
// Really want to compare sLen/sTime and pLen/pTime
|
// Really want to compare sLen/sTime and pLen/pTime
|
||||||
// Cross multiplied to avoid divide-by-zero
|
// Cross multiplied to avoid divide-by-zero
|
||||||
cost := len(sender.locator.coords) * int(pTime.Seconds())
|
cost := float64(len(sender.locator.coords)) * pTime.Seconds()
|
||||||
pCost := len(t.data.locator.coords) * int(sTime.Seconds())
|
pCost := float64(len(t.data.locator.coords)) * sTime.Seconds()
|
||||||
dropTstamp, isIn := t.drop[sender.locator.root]
|
dropTstamp, isIn := t.drop[sender.locator.root]
|
||||||
// Here be dragons
|
|
||||||
switch {
|
switch {
|
||||||
case !noLoop: // do nothing
|
case !noLoop:
|
||||||
case isIn && dropTstamp >= sender.locator.tstamp: // do nothing
|
// This route loops, so we can't use the sender as our parent.
|
||||||
|
case isIn && dropTstamp >= sender.locator.tstamp:
|
||||||
|
// This is a known root with a timestamp older than a known timeout, so we can't trust it to be a new announcement.
|
||||||
case firstIsBetter(&sender.locator.root, &t.data.locator.root):
|
case firstIsBetter(&sender.locator.root, &t.data.locator.root):
|
||||||
|
// This is a better root than what we're currently using, so we should update.
|
||||||
updateRoot = true
|
updateRoot = true
|
||||||
case t.data.locator.root != sender.locator.root: // do nothing
|
case t.data.locator.root != sender.locator.root:
|
||||||
case t.data.locator.tstamp > sender.locator.tstamp: // do nothing
|
// This is not the same root, and it's apparently not better (from the above), so we should ignore it.
|
||||||
|
case t.data.locator.tstamp > sender.locator.tstamp:
|
||||||
|
// This timetsamp is older than the most recently seen one from this root, so we should ignore it.
|
||||||
case noParent:
|
case noParent:
|
||||||
|
// We currently have no working parent, and at this point in the switch statement, anything is better than nothing.
|
||||||
updateRoot = true
|
updateRoot = true
|
||||||
case cost < pCost:
|
case cost < pCost:
|
||||||
|
// The sender has a better combination of path length and reliability than the current parent.
|
||||||
updateRoot = true
|
updateRoot = true
|
||||||
case sender.port != t.parent: // do nothing
|
case sender.port != t.parent:
|
||||||
|
// Ignore further cases if the sender isn't our parent.
|
||||||
case !equiv(&sender.locator, &t.data.locator):
|
case !equiv(&sender.locator, &t.data.locator):
|
||||||
// Special case
|
// Special case:
|
||||||
// If coords changed, then this may now be a worse parent than before
|
// If coords changed, then this may now be a worse parent than before.
|
||||||
// Re-parent the node (de-parent and reprocess the message)
|
// Re-parent the node (de-parent and reprocess the message).
|
||||||
// Then reprocess *all* messages to look for a better parent
|
// Then reprocess *all* messages to look for a better parent.
|
||||||
// This is so we don't keep using this node as our parent if there's something better
|
// This is so we don't keep using this node as our parent if there's something better.
|
||||||
t.parent = 0
|
t.parent = 0
|
||||||
t.unlockedHandleMsg(msg, fromPort)
|
t.unlockedHandleMsg(msg, fromPort)
|
||||||
for _, info := range t.data.peers {
|
for _, info := range t.data.peers {
|
||||||
t.unlockedHandleMsg(&info.msg, info.port)
|
t.unlockedHandleMsg(&info.msg, info.port)
|
||||||
}
|
}
|
||||||
case now.Sub(t.time) < switch_throttle: // do nothing
|
case now.Sub(t.time) < switch_throttle:
|
||||||
|
// We've already gotten an update from this root recently, so ignore this one to avoid flooding.
|
||||||
case sender.locator.tstamp > t.data.locator.tstamp:
|
case sender.locator.tstamp > t.data.locator.tstamp:
|
||||||
|
// The timestamp was updated, so we need to update locally and send to our peers.
|
||||||
updateRoot = true
|
updateRoot = true
|
||||||
}
|
}
|
||||||
if updateRoot {
|
if updateRoot {
|
||||||
|
Loading…
Reference in New Issue
Block a user