From d7f2287ce960b3a4917699e7c9c98ac26bfb8ca7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 5 Sep 2016 15:47:22 -0700 Subject: [PATCH] More tweaks to path behavior. --- node/Path.hpp | 10 ++-------- node/Peer.cpp | 39 +++++++++++++++++++++++++++------------ node/Peer.hpp | 4 ++-- node/Utils.cpp | 1 + service/ControlPlane.cpp | 4 ++-- 5 files changed, 34 insertions(+), 24 deletions(-) diff --git a/node/Path.hpp b/node/Path.hpp index d0e1d7378..718e1cddb 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -152,16 +152,10 @@ public: inline InetAddress::IpScope ipScope() const { return _ipScope; } /** - * @return Preference rank, higher == better (will be less than 255) + * @return Preference rank, higher == better */ inline unsigned int preferenceRank() const { - /* First, since the scope enum values in InetAddress.hpp are in order of - * use preference rank, we take that. Then we multiple by two, yielding - * a sequence like 0, 2, 4, 6, etc. Then if it's IPv6 we add one. This - * makes IPv6 addresses of a given scope outrank IPv4 addresses of the - * same scope -- e.g. 1 outranks 0. This makes us prefer IPv6, but not - * if the address scope/class is of a fundamentally lower rank. */ return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); } @@ -213,7 +207,7 @@ public: /** * @return True if this path needs a heartbeat */ - inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) > ZT_PATH_HEARTBEAT_PERIOD); } + inline bool needsHeartbeat(const uint64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } /** * @return Last time we sent something diff --git a/node/Peer.cpp b/node/Peer.cpp index 0cb55fd83..3701d9a1a 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -134,24 +134,38 @@ void Peer::received( } } - if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address()))) { + if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(path->localAddress(),path->address())) ) { if (verb == Packet::VERB_OK) { Mutex::Lock _l(_paths_m); - unsigned int slot = 0; + unsigned int slot; if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) { slot = _numPaths++; } else { + // First try to replace the worst within the same address family, if possible + int worstSlot = -1; uint64_t worstScore = 0xffffffffffffffffULL; - unsigned int worstPath = ZT_MAX_PEER_NETWORK_PATHS-1; for(unsigned int p=0;p<_numPaths;++p) { - const uint64_t s = _pathScore(p); - if (s < worstScore) { - worstScore = s; - worstPath = p; + if (_paths[p].path->address().ss_family == path->address().ss_family) { + const uint64_t s = _pathScore(p); + if (s < worstScore) { + worstScore = s; + worstSlot = (int)p; + } + } + } + if (worstSlot >= 0) { + slot = (unsigned int)worstSlot; + } else { + slot = ZT_MAX_PEER_NETWORK_PATHS - 1; + for(unsigned int p=0;p<_numPaths;++p) { + const uint64_t s = _pathScore(p); + if (s < worstScore) { + worstScore = s; + slot = p; + } } } - slot = worstPath; } _paths[slot].lastReceive = now; @@ -164,20 +178,21 @@ void Peer::received( _paths[slot].clusterWeights = 1; #endif } else { - - TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str()); + TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str()); if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) { + // Newer than 1.1.0 can use ECHO, which is smaller Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); outp.armor(_key,true); path->send(RR,outp.data(),outp.size(),now); } else { + // For backward compatibility we send HELLO to ancient nodes sendHELLO(path->localAddress(),path->address(),now); } - } } } else if (trustEstablished) { + // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) _pushDirectPaths(path,now); } @@ -286,7 +301,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily) int bestp = -1; uint64_t best = 0ULL; for(unsigned int p=0;p<_numPaths;++p) { - if ((inetAddressFamily < 0)||(_paths[p].path->address().ss_family == inetAddressFamily)) { + if ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) { const uint64_t s = _pathScore(p); if (s >= best) { best = s; diff --git a/node/Peer.hpp b/node/Peer.hpp index 8286bfff0..25ef72b7b 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -164,7 +164,7 @@ public: * * @param now Current time * @param inetAddressFamily Keep this address family alive, or -1 for any - * @return True if we have at least one direct path + * @return True if we have at least one direct path of the given family (or any if family is -1) */ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily); @@ -367,7 +367,7 @@ private: inline uint64_t _pathScore(const unsigned int p) const { - return ( _paths[p].path->lastIn() + + return ( _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK)) + (uint64_t)(_paths[p].clusterWeights * ZT_PEER_PING_PERIOD) ); } diff --git a/node/Utils.cpp b/node/Utils.cpp index 2d9515eed..9d67fc22e 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -292,6 +292,7 @@ unsigned int Utils::snprintf(char *buf,unsigned int len,const char *fmt,...) if ((n >= (int)len)||(n < 0)) { if (len) buf[len - 1] = (char)0; + abort(); throw std::length_error("buf[] overflow in Utils::snprintf"); } diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 03c5942d4..a24e3eb4d 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -165,7 +165,7 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_VirtualNetw static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath *pp,unsigned int count) { - char json[1024]; + char json[2048]; char prefix[32]; if (depth >= sizeof(prefix)) // sanity check -- shouldn't be possible @@ -201,7 +201,7 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath * static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer) { - char json[1024]; + char json[2048]; char prefix[32]; if (depth >= sizeof(prefix)) // sanity check -- shouldn't be possible