Merge master into multipath
This commit is contained in:
commit
77ae929eb3
300 changed files with 20343 additions and 34032 deletions
110
node/Peer.cpp
110
node/Peer.cpp
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -13,7 +13,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
|
@ -41,6 +41,8 @@
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
static unsigned char s_freeRandomByteCounter = 0;
|
||||
|
||||
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) :
|
||||
RR(renv),
|
||||
_lastReceive(0),
|
||||
|
@ -51,15 +53,13 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
|
|||
_lastCredentialRequestSent(0),
|
||||
_lastWhoisRequestReceived(0),
|
||||
_lastEchoRequestReceived(0),
|
||||
_lastComRequestReceived(0),
|
||||
_lastComRequestSent(0),
|
||||
_lastCredentialsReceived(0),
|
||||
_lastTrustEstablishedPacketReceived(0),
|
||||
_lastSentFullHello(0),
|
||||
_lastACKWindowReset(0),
|
||||
_lastQoSWindowReset(0),
|
||||
_lastMultipathCompatibilityCheck(0),
|
||||
_freeRandomByte(0),
|
||||
_freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter),
|
||||
_uniqueAlivePathCount(0),
|
||||
_localMultipathSupported(false),
|
||||
_remoteMultipathSupported(false),
|
||||
|
@ -77,10 +77,8 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
|
|||
_lastAggregateStatsReport(0),
|
||||
_lastAggregateAllocation(0)
|
||||
{
|
||||
Utils::getSecureRandom(&_freeRandomByte, 1);
|
||||
if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
|
||||
throw ZT_EXCEPTION_INVALID_ARGUMENT;
|
||||
_pathChoiceHist = new RingBuffer<int>(ZT_MULTIPATH_PROPORTION_WIN_SZ);
|
||||
}
|
||||
|
||||
void Peer::received(
|
||||
|
@ -106,7 +104,8 @@ void Peer::received(
|
|||
case Packet::VERB_MULTICAST_FRAME:
|
||||
_lastNontrivialReceive = now;
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (trustEstablished) {
|
||||
|
@ -162,12 +161,13 @@ void Peer::received(
|
|||
break;
|
||||
}
|
||||
// If the path is the same address and port, simply assume this is a replacement
|
||||
if ( (_paths[i].p->address().ipsEqual2(path->address()) && (_paths[i].p->address().port() == path->address().port()))) {
|
||||
if ( (_paths[i].p->address().ipsEqual2(path->address()))) {
|
||||
replacePath = i;
|
||||
break;
|
||||
}
|
||||
} else break;
|
||||
}
|
||||
|
||||
// If the path isn't a duplicate of the same localSocket AND we haven't already determined a replacePath,
|
||||
// then find the worst path and replace it.
|
||||
if (!redundant && replacePath == ZT_MAX_PEER_NETWORK_PATHS) {
|
||||
|
@ -185,6 +185,7 @@ void Peer::received(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) {
|
||||
if (verb == Packet::VERB_OK) {
|
||||
RR->t->peerLearnedNewPath(tPtr,networkId,*this,path,packetId);
|
||||
|
@ -205,39 +206,20 @@ void Peer::received(
|
|||
}
|
||||
|
||||
// If we have a trust relationship periodically push a message enumerating
|
||||
// all known external addresses for ourselves. We now do this even if we
|
||||
// have a current path since we'll want to use new ones too.
|
||||
// all known external addresses for ourselves. If we already have a path this
|
||||
// is done less frequently.
|
||||
if (this->trustEstablished(now)) {
|
||||
if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) {
|
||||
const int64_t sinceLastPush = now - _lastDirectPathPushSent;
|
||||
if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH : ZT_DIRECT_PATH_PUSH_INTERVAL)) {
|
||||
_lastDirectPathPushSent = now;
|
||||
|
||||
std::vector<InetAddress> pathsToPush;
|
||||
|
||||
std::vector<InetAddress> dps(RR->node->directPaths());
|
||||
for(std::vector<InetAddress>::const_iterator i(dps.begin());i!=dps.end();++i)
|
||||
pathsToPush.push_back(*i);
|
||||
|
||||
// Do symmetric NAT prediction if we are communicating indirectly.
|
||||
if (hops > 0) {
|
||||
std::vector<InetAddress> sym(RR->sa->getSymmetricNatPredictions());
|
||||
for(unsigned long i=0,added=0;i<sym.size();++i) {
|
||||
InetAddress tmp(sym[(unsigned long)RR->node->prng() % sym.size()]);
|
||||
if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) {
|
||||
pathsToPush.push_back(tmp);
|
||||
if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<InetAddress> pathsToPush(RR->node->directPaths());
|
||||
if (pathsToPush.size() > 0) {
|
||||
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
|
||||
while (p != pathsToPush.end()) {
|
||||
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
|
||||
outp.addSize(2); // leave room for count
|
||||
|
||||
Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
|
||||
outp->addSize(2); // leave room for count
|
||||
unsigned int count = 0;
|
||||
while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) {
|
||||
while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) {
|
||||
uint8_t addressType = 4;
|
||||
switch(p->ss_family) {
|
||||
case AF_INET:
|
||||
|
@ -250,22 +232,23 @@ void Peer::received(
|
|||
continue;
|
||||
}
|
||||
|
||||
outp.append((uint8_t)0); // no flags
|
||||
outp.append((uint16_t)0); // no extensions
|
||||
outp.append(addressType);
|
||||
outp.append((uint8_t)((addressType == 4) ? 6 : 18));
|
||||
outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16));
|
||||
outp.append((uint16_t)p->port());
|
||||
outp->append((uint8_t)0); // no flags
|
||||
outp->append((uint16_t)0); // no extensions
|
||||
outp->append(addressType);
|
||||
outp->append((uint8_t)((addressType == 4) ? 6 : 18));
|
||||
outp->append(p->rawIpData(),((addressType == 4) ? 4 : 16));
|
||||
outp->append((uint16_t)p->port());
|
||||
|
||||
++count;
|
||||
++p;
|
||||
}
|
||||
|
||||
if (count) {
|
||||
outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
|
||||
outp.armor(_key,true);
|
||||
path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
|
||||
outp->compress();
|
||||
outp->armor(_key,true);
|
||||
path->send(RR,tPtr,outp->data(),outp->size(),now);
|
||||
}
|
||||
delete outp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,8 +258,7 @@ void Peer::received(
|
|||
void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
|
||||
uint16_t payloadLength, const Packet::Verb verb, int64_t now)
|
||||
{
|
||||
// Grab second byte from packetId to use as a source of entropy in the next path selection
|
||||
_freeRandomByte = (packetId & 0xFF00) >> 8;
|
||||
_freeRandomByte += (unsigned char)(packetId >> 8); // grab entropy to use in path selection logic for multipath
|
||||
if (_canUseMultipath) {
|
||||
path->recordOutgoingPacket(now, packetId, payloadLength, verb);
|
||||
}
|
||||
|
@ -307,7 +289,7 @@ void Peer::computeAggregateProportionalAllocation(int64_t now)
|
|||
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||
if (_paths[i].p) {
|
||||
relStability[i] = _paths[i].p->lastComputedStability();
|
||||
relThroughput[i] = _paths[i].p->maxLifetimeThroughput();
|
||||
relThroughput[i] = (float)_paths[i].p->maxLifetimeThroughput();
|
||||
maxStability = relStability[i] > maxStability ? relStability[i] : maxStability;
|
||||
maxThroughput = relThroughput[i] > maxThroughput ? relThroughput[i] : maxThroughput;
|
||||
maxScope = _paths[i].p->ipScope() > maxScope ? _paths[i].p->ipScope() : maxScope;
|
||||
|
@ -318,17 +300,17 @@ void Peer::computeAggregateProportionalAllocation(int64_t now)
|
|||
if (_paths[i].p) {
|
||||
relStability[i] /= maxStability ? maxStability : 1;
|
||||
relThroughput[i] /= maxThroughput ? maxThroughput : 1;
|
||||
float normalized_ma = Utils::normalize(_paths[i].p->ackAge(now), 0, ZT_PATH_MAX_AGE, 0, 10);
|
||||
float normalized_ma = Utils::normalize((float)_paths[i].p->ackAge(now), 0, ZT_PATH_MAX_AGE, 0, 10);
|
||||
float age_contrib = exp((-1)*normalized_ma);
|
||||
float relScope = ((float)(_paths[i].p->ipScope()+1) / (maxScope + 1));
|
||||
float relQuality =
|
||||
(relStability[i] * ZT_PATH_CONTRIB_STABILITY)
|
||||
+ (fmax(1, relThroughput[i]) * ZT_PATH_CONTRIB_THROUGHPUT)
|
||||
+ relScope * ZT_PATH_CONTRIB_SCOPE;
|
||||
(relStability[i] * (float)ZT_PATH_CONTRIB_STABILITY)
|
||||
+ (fmaxf(1.0f, relThroughput[i]) * (float)ZT_PATH_CONTRIB_THROUGHPUT)
|
||||
+ relScope * (float)ZT_PATH_CONTRIB_SCOPE;
|
||||
relQuality *= age_contrib;
|
||||
// Arbitrary cutoffs
|
||||
relQuality = relQuality > (1.00 / 100.0) ? relQuality : 0.0;
|
||||
relQuality = relQuality < (99.0 / 100.0) ? relQuality : 1.0;
|
||||
relQuality = relQuality > (1.00f / 100.0f) ? relQuality : 0.0f;
|
||||
relQuality = relQuality < (99.0f / 100.0f) ? relQuality : 1.0f;
|
||||
totalRelativeQuality += relQuality;
|
||||
_paths[i].p->updateRelativeQuality(relQuality);
|
||||
}
|
||||
|
@ -336,7 +318,7 @@ void Peer::computeAggregateProportionalAllocation(int64_t now)
|
|||
// Convert set of relative performances into an allocation set
|
||||
for(uint16_t i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||
if (_paths[i].p) {
|
||||
_paths[i].p->updateComponentAllocationOfAggregateLink((_paths[i].p->relativeQuality() / totalRelativeQuality) * 255);
|
||||
_paths[i].p->updateComponentAllocationOfAggregateLink((unsigned char)((_paths[i].p->relativeQuality() / totalRelativeQuality) * 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -349,7 +331,7 @@ int Peer::computeAggregateLinkPacketDelayVariance()
|
|||
pdv += _paths[i].p->relativeQuality() * _paths[i].p->packetDelayVariance();
|
||||
}
|
||||
}
|
||||
return pdv;
|
||||
return (int)pdv;
|
||||
}
|
||||
|
||||
int Peer::computeAggregateLinkMeanLatency()
|
||||
|
@ -359,7 +341,7 @@ int Peer::computeAggregateLinkMeanLatency()
|
|||
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||
if (_paths[i].p) {
|
||||
pathCount++;
|
||||
ml += _paths[i].p->relativeQuality() * _paths[i].p->meanLatency();
|
||||
ml += (int)(_paths[i].p->relativeQuality() * _paths[i].p->meanLatency());
|
||||
}
|
||||
}
|
||||
return ml / pathCount;
|
||||
|
@ -475,7 +457,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired)
|
|||
if (_paths[i].p) {
|
||||
if (rf < _paths[i].p->allocation()) {
|
||||
bestPath = i;
|
||||
_pathChoiceHist->push(bestPath); // Record which path we chose
|
||||
_pathChoiceHist.push(bestPath); // Record which path we chose
|
||||
break;
|
||||
}
|
||||
rf -= _paths[i].p->allocation();
|
||||
|
@ -501,10 +483,10 @@ char *Peer::interfaceListStr()
|
|||
if (_paths[i].p && _paths[i].p->alive(now)) {
|
||||
int ipv = _paths[i].p->address().isV4();
|
||||
// If this is acting as an aggregate link, check allocations
|
||||
float targetAllocation = 1.0 / alivePathCount;
|
||||
float currentAllocation = 1.0;
|
||||
float targetAllocation = 1.0f / (float)alivePathCount;
|
||||
float currentAllocation = 1.0f;
|
||||
if (alivePathCount > 1) {
|
||||
currentAllocation = (float)_pathChoiceHist->countValue(i) / (float)_pathChoiceHist->count();
|
||||
currentAllocation = (float)_pathChoiceHist.countValue(i) / (float)_pathChoiceHist.count();
|
||||
if (fabs(targetAllocation - currentAllocation) > ZT_PATH_IMBALANCE_THRESHOLD) {
|
||||
imbalanced = true;
|
||||
}
|
||||
|
@ -652,10 +634,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
|
|||
}
|
||||
}
|
||||
|
||||
inline void Peer::processBackgroundPeerTasks(int64_t now)
|
||||
inline void Peer::processBackgroundPeerTasks(const int64_t now)
|
||||
{
|
||||
// Determine current multipath compatibility with other peer
|
||||
if ((now - _lastMultipathCompatibilityCheck) >= ZT_PATH_QUALITY_COMPUTE_INTERVAL) {
|
||||
//
|
||||
// Cache number of available paths so that we can short-circuit multipath logic elsewhere
|
||||
//
|
||||
// We also take notice of duplicate paths (same IP only) because we may have
|
||||
|
@ -665,6 +648,7 @@ inline void Peer::processBackgroundPeerTasks(int64_t now)
|
|||
//
|
||||
// This is done to support the behavior of auto multipath enable/disable
|
||||
// without user intervention.
|
||||
//
|
||||
int currAlivePathCount = 0;
|
||||
int duplicatePathsFound = 0;
|
||||
for (unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue