mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-24 07:06:39 +00:00
Prevent path-learning loops (#1914)
* Prevent path-learning loops * Only allow new overwrite if not bonded
This commit is contained in:
parent
b2a981f353
commit
ce9330e9bb
@ -109,6 +109,13 @@ void Peer::received(
|
|||||||
havePath = true;
|
havePath = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop)
|
||||||
|
if (_paths[i].p->address().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) {
|
||||||
|
if (_paths[i].p->alive(now) && !_bond) {
|
||||||
|
havePath = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -116,69 +123,37 @@ void Peer::received(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( (!havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()) ) {
|
if ( (!havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()) ) {
|
||||||
|
|
||||||
/**
|
|
||||||
* First, fill all free slots before attempting to replace a path
|
|
||||||
* - If the above fails, attempt to replace the path that has been dead the longest
|
|
||||||
* - If there are no free slots, and no dead paths (unlikely), then replace old path most similar to new path
|
|
||||||
* - If all of the above fails to yield a suitable replacement. Replace first path found to have lower `(quality / priority)`
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (verb == Packet::VERB_OK) {
|
if (verb == Packet::VERB_OK) {
|
||||||
Mutex::Lock _l(_paths_m);
|
Mutex::Lock _l(_paths_m);
|
||||||
|
unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
|
||||||
|
unsigned int oldestPathAge = 0;
|
||||||
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS;
|
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS;
|
||||||
uint64_t maxScore = 0;
|
|
||||||
uint64_t currScore;
|
|
||||||
long replacePathQuality = 0;
|
|
||||||
bool foundFreeSlot = false;
|
|
||||||
|
|
||||||
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||||
currScore = 0;
|
|
||||||
if (_paths[i].p) {
|
if (_paths[i].p) {
|
||||||
// Reward dead paths
|
// Keep track of oldest path as a last resort option
|
||||||
if (!_paths[i].p->alive(now)) {
|
unsigned int currAge = _paths[i].p->age(now);
|
||||||
currScore = _paths[i].p->age(now) / 1000;
|
if (currAge > oldestPathAge) {
|
||||||
|
oldestPathAge = currAge;
|
||||||
|
oldestPathIdx = i;
|
||||||
}
|
}
|
||||||
// Reward as similarity increases
|
|
||||||
if (_paths[i].p->address().ipsEqual(path->address())) {
|
if (_paths[i].p->address().ipsEqual(path->address())) {
|
||||||
currScore++;
|
if (_paths[i].p->localSocket() == path->localSocket()) {
|
||||||
if (_paths[i].p->address().port() == path->address().port()) {
|
if (!_paths[i].p->alive(now)) {
|
||||||
currScore++;
|
replacePath = i;
|
||||||
if (_paths[i].p->localSocket() == path->localSocket()) {
|
break;
|
||||||
currScore++; // max score (3)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If best so far, mark for replacement
|
|
||||||
if (currScore > maxScore) {
|
|
||||||
maxScore = currScore;
|
|
||||||
replacePath = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
foundFreeSlot = true;
|
|
||||||
replacePath = i;
|
replacePath = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundFreeSlot) {
|
|
||||||
if (maxScore > 3) {
|
|
||||||
// Do nothing. We found a dead path and have already marked it as a candidate
|
|
||||||
}
|
|
||||||
// If we couldn't find a replacement by matching, replacing a dead path, or taking a free slot, then replace by quality
|
|
||||||
else if (maxScore == 0) {
|
|
||||||
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
|
||||||
if (_paths[i].p) {
|
|
||||||
const long q = _paths[i].p->quality(now) / _paths[i].priority;
|
|
||||||
if (q > replacePathQuality) {
|
|
||||||
replacePathQuality = q;
|
|
||||||
replacePath = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If we didn't find a good candidate then resort to replacing oldest path
|
||||||
|
replacePath = (replacePath == ZT_MAX_PEER_NETWORK_PATHS) ? oldestPathIdx : replacePath;
|
||||||
if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) {
|
if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) {
|
||||||
RR->t->peerLearnedNewPath(tPtr, networkId, *this, path, packetId);
|
RR->t->peerLearnedNewPath(tPtr, networkId, *this, path, packetId);
|
||||||
_paths[replacePath].lr = now;
|
_paths[replacePath].lr = now;
|
||||||
@ -540,11 +515,15 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
|
|||||||
// let those old links expire.
|
// let those old links expire.
|
||||||
long maxPriority = 0;
|
long maxPriority = 0;
|
||||||
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||||
if (_paths[i].p)
|
if (_paths[i].p) {
|
||||||
maxPriority = std::max(_paths[i].priority,maxPriority);
|
maxPriority = std::max(_paths[i].priority,maxPriority);
|
||||||
else break;
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool deletionOccurred = false;
|
||||||
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||||
if (_paths[i].p) {
|
if (_paths[i].p) {
|
||||||
// Clean expired and reduced priority paths
|
// Clean expired and reduced priority paths
|
||||||
@ -554,10 +533,22 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
|
|||||||
_paths[i].p->sent(now);
|
_paths[i].p->sent(now);
|
||||||
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
|
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
_paths[i] = _PeerPath();
|
|
||||||
}
|
}
|
||||||
} else break;
|
else {
|
||||||
|
_paths[i] = _PeerPath();
|
||||||
|
deletionOccurred = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_paths[i].p || deletionOccurred) {
|
||||||
|
for(unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) {
|
||||||
|
if (_paths[j].p && i != j) {
|
||||||
|
_paths[i] = _paths[j];
|
||||||
|
_paths[j] = _PeerPath();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deletionOccurred = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user