Merge branch 'dev' of github.com:zerotier/ZeroTierOne into dev

This commit is contained in:
Adam Ierymenko 2022-03-03 18:30:19 -05:00
commit 297869163e
No known key found for this signature in database
GPG Key ID: C8877CF2D7A5D7F3
14 changed files with 106 additions and 108 deletions

View File

@ -777,6 +777,7 @@ void PostgreSQL::initializeMembers()
std::string assignedAddresses = std::get<20>(row);
config["id"] = memberId;
config["address"] = memberId;
config["nwid"] = networkId;
config["activeBridge"] = activeBridge.value_or(false);
config["authorized"] = authorized.value_or(false);

View File

@ -1404,11 +1404,6 @@ typedef struct
*/
int bondingPolicy;
/**
* The health status of the bond to this peer
*/
bool isHealthy;
/**
* The number of links that comprise the bond to this peer that are considered alive
*/

View File

@ -90,7 +90,7 @@ SharedPtr<Bond> Bond::getBondByPeerId(int64_t identity)
return _bonds.count(identity) ? _bonds[identity] : SharedPtr<Bond>();
}
SharedPtr<Bond> Bond::createTransportTriggeredBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer)
SharedPtr<Bond> Bond::createBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer)
{
Mutex::Lock _l(_bonds_m);
int64_t identity = peer->identity().address().toInt();
@ -145,6 +145,12 @@ SharedPtr<Bond> Bond::createTransportTriggeredBond(const RuntimeEnvironment* ren
return SharedPtr<Bond>();
}
void Bond::destroyBond(uint64_t peerId)
{
Mutex::Lock _l(_bonds_m);
_bonds.erase(peerId);
}
SharedPtr<Link> Bond::getLinkBySocket(const std::string& policyAlias, uint64_t localSocket)
{
Mutex::Lock _l(_links_m);
@ -717,6 +723,7 @@ void Bond::sendPATH_NEGOTIATION_REQUEST(void* tPtr, int pathIdx)
if (_paths[pathIdx].p->address()) {
outp.armor(_peer->key(), false, _peer->aesKeysIfSupported());
RR->node->putPacket(tPtr, _paths[pathIdx].p->localSocket(), _paths[pathIdx].p->address(), outp.data(), outp.size());
_overheadBytes += outp.size();
}
}
@ -726,7 +733,6 @@ void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, con
Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_QOS_MEASUREMENT);
char qosData[ZT_QOS_MAX_PACKET_SIZE];
int16_t len = generateQoSPacket(pathIdx, _now, qosData);
_overheadBytes += len;
if (len) {
outp.append(qosData, len);
if (atAddress) {
@ -738,6 +744,7 @@ void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, con
}
_paths[pathIdx].packetsReceivedSinceLastQoS = 0;
_paths[pathIdx].lastQoSMeasurement = now;
_overheadBytes += outp.size();
}
// debug("send QOS via link %s (len=%d)", pathToStr(_paths[pathIdx].p).c_str(), len);
}
@ -761,7 +768,7 @@ void Bond::processBackgroundBondTasks(void* tPtr, int64_t now)
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p && _paths[i].allowed()) {
if (_isLeaf) {
if ((_monitorInterval > 0) && (((now - _paths[i].p->_lastIn) >= _monitorInterval) /*|| ((now - _paths[i].p->_lastOut) >= _monitorInterval)*/)) {
if ((_monitorInterval > 0) && (((now - _paths[i].p->_lastIn) >= (_paths[i].alive ? _monitorInterval : _failoverInterval)))) {
if ((_peer->remoteVersionProtocol() >= 5) && (! ((_peer->remoteVersionMajor() == 1) && (_peer->remoteVersionMinor() == 1) && (_peer->remoteVersionRevision() == 0)))) {
Packet outp(_peer->address(), RR->identity.address(), Packet::VERB_ECHO); // ECHO (this is our bond's heartbeat)
outp.armor(_peer->key(), true, _peer->aesKeysIfSupported());
@ -815,6 +822,17 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
if (! _paths[i].p) {
continue;
}
/**
* Remove expired links from bond
*/
if ((now - _paths[i].p->_lastIn) > (ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD)) {
log("link %s has expired, removing from bond", pathToStr(_paths[i].p).c_str());
_paths[i] = NominatedPath();
_paths[i].p = SharedPtr<Path>();
continue;
}
tmpNumTotalLinks++;
if (_paths[i].eligible) {
tmpNumAliveLinks++;
@ -875,42 +893,18 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
}
/**
* Determine health status to report to user
* Trigger status report if number of links change
*/
_numAliveLinks = tmpNumAliveLinks;
_numTotalLinks = tmpNumTotalLinks;
bool tmpHealthStatus = true;
if (_policy == ZT_BOND_POLICY_BROADCAST) {
if (_numAliveLinks < 1) {
// Considered healthy if we're able to send frames at all
tmpHealthStatus = false;
}
}
if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE || (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP))) {
if (_numAliveLinks < _numTotalLinks) {
tmpHealthStatus = false;
}
}
if (tmpHealthStatus != _isHealthy) {
std::string healthStatusStr;
if (tmpHealthStatus == true) {
healthStatusStr = "HEALTHY";
}
else {
healthStatusStr = "DEGRADED";
}
log("bond is %s (%d/%d links)", healthStatusStr.c_str(), _numAliveLinks, _numTotalLinks);
if ((_numAliveLinks != tmpNumAliveLinks) || (_numTotalLinks != tmpNumTotalLinks)) {
dumpInfo(now, true);
}
_isHealthy = tmpHealthStatus;
/**
* Curate the set of paths that are part of the bond proper. Select a set of paths
* per logical link according to eligibility and user-specified constraints.
*/
if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE)) {
if (! _numBondedPaths) {
rebuildBond = true;
@ -1008,14 +1002,14 @@ void Bond::estimatePathQuality(int64_t now)
uint32_t totUserSpecifiedLinkSpeed = 0;
if (_numBondedPaths) { // Compute relative user-specified speeds of links
for (unsigned int i = 0; i < _numBondedPaths; ++i) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (_paths[i].p && _paths[i].allowed()) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
totUserSpecifiedLinkSpeed += link->speed();
}
}
for (unsigned int i = 0; i < _numBondedPaths; ++i) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (_paths[i].p && _paths[i].allowed()) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
link->setRelativeSpeed((uint8_t)round(((float)link->speed() / (float)totUserSpecifiedLinkSpeed) * 255));
}
}
@ -1212,6 +1206,11 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
int nonPreferredPathIdx;
bool bFoundPrimaryLink = false;
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && !_paths[_abPathIdx].p) {
_abPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
log("main active-backup path has been removed");
}
/**
* Generate periodic status report
*/
@ -1241,7 +1240,6 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
* simply find the next eligible path.
*/
if (! userHasSpecifiedLinks()) {
debug("no user-specified links");
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p && _paths[i].eligible) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
@ -1574,7 +1572,6 @@ void Bond::setBondParameters(int policy, SharedPtr<Bond> templateBond, bool useT
// Bond status
_isHealthy = false;
_numAliveLinks = 0;
_numTotalLinks = 0;
_numBondedPaths = 0;
@ -1684,11 +1681,14 @@ SharedPtr<Link> Bond::getLink(const SharedPtr<Path>& path)
std::string Bond::pathToStr(const SharedPtr<Path>& path)
{
#ifdef ZT_TRACE
char pathStr[64] = { 0 };
char fullPathStr[384] = { 0 };
path->address().toString(pathStr);
snprintf(fullPathStr, 384, "%.16llx-%s/%s", (unsigned long long)(path->localSocket()), getLink(path)->ifname().c_str(), pathStr);
return std::string(fullPathStr);
if (path) {
char pathStr[64] = { 0 };
char fullPathStr[384] = { 0 };
path->address().toString(pathStr);
snprintf(fullPathStr, 384, "%.16llx-%s/%s", (unsigned long long)(path->localSocket()), getLink(path)->ifname().c_str(), pathStr);
return std::string(fullPathStr);
}
return "";
#else
return "";
#endif
@ -1727,7 +1727,7 @@ void Bond::dumpInfo(int64_t now, bool force)
_lastSummaryDump = now;
float overhead = (_overheadBytes / (timeSinceLastDump / 1000.0f) / 1000.0f);
_overheadBytes = 0;
log("bond: bp=%d, fi=%d, mi=%d, ud=%d, dd=%d, flows=%lu, leaf=%d, overhead=%f KB/s",
log("bond: bp=%d, fi=%d, mi=%d, ud=%d, dd=%d, flows=%lu, leaf=%d, overhead=%f KB/s, links=(%d/%d)",
_policy,
_failoverInterval,
_monitorInterval,
@ -1735,7 +1735,9 @@ void Bond::dumpInfo(int64_t now, bool force)
_downDelay,
(unsigned long)_flows.size(),
_isLeaf,
overhead);
overhead,
_numAliveLinks,
_numTotalLinks);
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
dumpPathStatus(now, i);

View File

@ -436,7 +436,14 @@ class Bond {
* @param peer Remote peer that this bond services
* @return A pointer to the newly created Bond
*/
static SharedPtr<Bond> createTransportTriggeredBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer);
static SharedPtr<Bond> createBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer);
/**
* Remove a bond from the bond controller.
*
* @param peerId Remote peer that this bond services
*/
static void destroyBond(uint64_t peerId);
/**
* Periodically perform maintenance tasks for the bonding layer.
@ -1020,14 +1027,6 @@ class Bond {
return _policy;
}
/**
* @return the health status of the bond
*/
inline bool isHealthy()
{
return _isHealthy;
}
/**
* @return the number of links comprising this bond which are considered alive
*/
@ -1344,7 +1343,7 @@ class Bond {
int packetsIn;
int packetsOut;
AtomicCounter __refCount;
//AtomicCounter __refCount;
SharedPtr<Path> p;
void set(uint64_t now, const SharedPtr<Path>& path)
@ -1490,7 +1489,6 @@ class Bond {
/**
* Link state reporting
*/
bool _isHealthy;
uint8_t _numAliveLinks;
uint8_t _numTotalLinks;

View File

@ -571,13 +571,13 @@
* Anything below this value gets into thrashing territory since we divide
* this value by ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL to send ECHOs often.
*/
#define ZT_BOND_FAILOVER_MIN_INTERVAL 250
#define ZT_BOND_FAILOVER_MIN_INTERVAL 500
/**
* How many times per failover interval that an ECHO is sent. This should be
* at least 2. Anything more then 4 starts to increase overhead significantly.
*/
#define ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL 4
#define ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL 3
/**
* A defensive timer to prevent path quality metrics from being

View File

@ -860,7 +860,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
uint64_t now = RR->node->now();
if (!peer->rateGateEchoRequest(now)) {
if (!_path->rateGateEchoRequest(now)) {
return true;
}

View File

@ -509,7 +509,6 @@ ZT_PeerList *Node::peers() const
if (pi->second->bond()) {
p->isBonded = pi->second->bond();
p->bondingPolicy = pi->second->bond()->policy();
p->isHealthy = pi->second->bond()->isHealthy();
p->numAliveLinks = pi->second->bond()->getNumAliveLinks();
p->numTotalLinks = pi->second->bond()->getNumTotalLinks();
}

View File

@ -83,6 +83,7 @@ public:
_lastOut(0),
_lastIn(0),
_lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localSocket(-1),
_latency(0xffff),
_addr(),
@ -93,6 +94,7 @@ public:
_lastOut(0),
_lastIn(0),
_lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localSocket(localSocket),
_latency(0xffff),
_addr(addr),
@ -266,6 +268,18 @@ public:
*/
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
/**
* Rate limit gate for inbound ECHO requests
*/
inline bool rateGateEchoRequest(const int64_t now)
{
if ((now - _lastEchoRequestReceived) >= (ZT_PEER_GENERAL_RATE_LIMIT / 6)) {
_lastEchoRequestReceived = now;
return true;
}
return false;
}
void *_bondingMetricPtr;
private:
@ -273,6 +287,9 @@ private:
volatile int64_t _lastOut;
volatile int64_t _lastIn;
volatile int64_t _lastTrustEstablishedPacketReceived;
int64_t _lastEchoRequestReceived;
int64_t _localSocket;
volatile unsigned int _latency;
InetAddress _addr;

View File

@ -34,7 +34,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_lastTriedMemorizedPath(0),
_lastDirectPathPushSent(0),
_lastDirectPathPushReceive(0),
_lastEchoRequestReceived(0),
_lastCredentialRequestSent(0),
_lastWhoisRequestReceived(0),
_lastCredentialsReceived(0),
@ -224,6 +223,8 @@ void Peer::received(
if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH : ZT_DIRECT_PATH_PUSH_INTERVAL)) {
_lastDirectPathPushSent = now;
std::vector<InetAddress> pathsToPush(RR->node->directPaths());
std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) {
@ -453,7 +454,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
if (atAddress) {
outp.armor(_key,false,nullptr); // false == don't encrypt full payload, but add MAC
RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size());
RR->node->putPacket(tPtr,-1,atAddress,outp.data(),outp.size());
} else {
RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC
@ -502,7 +503,7 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
_localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9));
if (_localMultipathSupported && !_bond) {
if (RR->bc) {
_bond = RR->bc->createTransportTriggeredBond(RR, this);
_bond = RR->bc->createBond(RR, this);
/**
* Allow new bond to retroactively learn all paths known to this peer
*/

View File

@ -53,7 +53,10 @@ private:
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
public:
~Peer() { Utils::burn(_key,sizeof(_key)); }
~Peer() {
Utils::burn(_key,sizeof(_key));
RR->bc->destroyBond(_id.address().toInt());
}
/**
* Construct a new peer
@ -418,18 +421,6 @@ public:
return false;
}
/**
* Rate limit gate for inbound ECHO requests
*/
inline bool rateGateEchoRequest(const int64_t now)
{
if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastEchoRequestReceived = now;
return true;
}
return false;
}
/**
* Serialize a peer for storage in local cache
*
@ -546,7 +537,6 @@ private:
int64_t _lastTriedMemorizedPath;
int64_t _lastDirectPathPushSent;
int64_t _lastDirectPathPushReceive;
int64_t _lastEchoRequestReceived;
int64_t _lastCredentialRequestSent;
int64_t _lastWhoisRequestReceived;
int64_t _lastCredentialsReceived;

View File

@ -99,6 +99,21 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
}
}
std::vector<InetAddress> SelfAwareness::whoami()
{
std::vector<InetAddress> surfaceAddresses;
Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) {
surfaceAddresses.push_back(e->mySurface);
}
}
return surfaceAddresses;
}
void SelfAwareness::clean(int64_t now)
{
Mutex::Lock _l(_phy_m);

View File

@ -44,6 +44,13 @@ public:
*/
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
/**
* Return all known external surface addresses reported by peers
*
* @return A vector of InetAddress(es)
*/
std::vector<InetAddress> whoami();
/**
* Clean up database periodically
*

33
one.cpp
View File

@ -523,31 +523,23 @@ static int cli(int argc,char **argv)
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
} else {
bool bFoundBond = false;
printf(" <peer> <bondtype> <status> <links>" ZT_EOL_S);
printf(" <peer> <bondtype> <links>" ZT_EOL_S);
if (j.is_array()) {
for(unsigned long k=0;k<j.size();++k) {
nlohmann::json &p = j[k];
bool isBonded = p["isBonded"];
if (isBonded) {
int8_t bondingPolicy = p["bondingPolicy"];
bool isHealthy = p["isHealthy"];
int8_t numAliveLinks = p["numAliveLinks"];
int8_t numTotalLinks = p["numTotalLinks"];
bFoundBond = true;
std::string healthStr;
if (isHealthy) {
healthStr = "HEALTHY";
} else {
healthStr = "DEGRADED";
}
std::string policyStr = "none";
if (bondingPolicy >= ZT_BOND_POLICY_NONE && bondingPolicy <= ZT_BOND_POLICY_BALANCE_AWARE) {
policyStr = Bond::getPolicyStrByCode(bondingPolicy);
}
printf("%10s %32s %8s %d/%d" ZT_EOL_S,
printf("%10s %32s %d/%d" ZT_EOL_S,
OSUtils::jsonString(p ["address"],"-").c_str(),
policyStr.c_str(),
healthStr.c_str(),
numAliveLinks,
numTotalLinks);
}
@ -617,12 +609,6 @@ static int cli(int argc,char **argv)
if (json) {
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
} else {
std::string healthStr;
if (OSUtils::jsonInt(j["isHealthy"],0)) {
healthStr = "Healthy";
} else {
healthStr = "Degraded";
}
int numAliveLinks = OSUtils::jsonInt(j["numAliveLinks"],0);
int numTotalLinks = OSUtils::jsonInt(j["numTotalLinks"],0);
printf("Peer : %s\n", arg1.c_str());
@ -630,7 +616,6 @@ static int cli(int argc,char **argv)
//if (bondingPolicy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
printf("Link Select Method : %d\n", (int)OSUtils::jsonInt(j["linkSelectMethod"],0));
//}
printf("Status : %s\n", healthStr.c_str());
printf("Links : %d/%d\n", numAliveLinks, numTotalLinks);
printf("Failover Interval : %d (ms)\n", (int)OSUtils::jsonInt(j["failoverInterval"],0));
printf("Up Delay : %d (ms)\n", (int)OSUtils::jsonInt(j["upDelay"],0));
@ -705,33 +690,23 @@ static int cli(int argc,char **argv)
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
} else {
bool bFoundBond = false;
printf(" <peer> <bondtype> <status> <links>" ZT_EOL_S);
printf(" <peer> <bondtype> <links>" ZT_EOL_S);
if (j.is_array()) {
for(unsigned long k=0;k<j.size();++k) {
nlohmann::json &p = j[k];
bool isBonded = p["isBonded"];
if (isBonded) {
int8_t bondingPolicy = p["bondingPolicy"];
bool isHealthy = p["isHealthy"];
int8_t numAliveLinks = p["numAliveLinks"];
int8_t numTotalLinks = p["numTotalLinks"];
bFoundBond = true;
std::string healthStr;
if (isHealthy) {
healthStr = "Healthy";
} else {
healthStr = "Degraded";
}
std::string policyStr = "none";
if (bondingPolicy >= ZT_BOND_POLICY_NONE && bondingPolicy <= ZT_BOND_POLICY_BALANCE_AWARE) {
policyStr = Bond::getPolicyStrByCode(bondingPolicy);
}
printf("%10s %32s %8s %d/%d" ZT_EOL_S,
printf("%10s %32s %d/%d" ZT_EOL_S,
OSUtils::jsonString(p["address"],"-").c_str(),
policyStr.c_str(),
healthStr.c_str(),
numAliveLinks,
numTotalLinks);
}

View File

@ -510,7 +510,6 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer)
pj["isBonded"] = peer->isBonded;
if (peer->isBonded) {
pj["bondingPolicy"] = peer->bondingPolicy;
pj["isHealthy"] = peer->isHealthy;
pj["numAliveLinks"] = peer->numAliveLinks;
pj["numTotalLinks"] = peer->numTotalLinks;
}
@ -542,7 +541,6 @@ static void _bondToJson(nlohmann::json &pj, SharedPtr<Bond> &bond)
return;
}
pj["isHealthy"] = bond->isHealthy();
pj["numAliveLinks"] = bond->getNumAliveLinks();
pj["numTotalLinks"] = bond->getNumTotalLinks();
pj["failoverInterval"] = bond->getFailoverInterval();