5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-14 16:10:29 +00:00

Merge pull request #209 from Arceliar/switch-tune

Adjust switch parent selection behavior
This commit is contained in:
Neil Alexander 2018-11-24 23:21:45 +00:00 committed by GitHub
commit 5a7c2b250c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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 {