From 3c9ea2b6674819612cd88a2e141e0f8f633b06cd Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Mon, 5 Dec 2022 13:21:05 -0800 Subject: [PATCH] Add low-bandwidth mode --- node/Multicaster.cpp | 3 ++- node/Node.cpp | 20 ++++++++++++++++---- node/Node.hpp | 11 +++++++++++ node/Peer.cpp | 15 ++++++++++----- node/Peer.hpp | 2 ++ service/OneService.cpp | 1 + 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 4856b88ee..d93b2ae10 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -268,7 +268,8 @@ void Multicaster::send( const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; - if ((gs.members.empty())||((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY)) { + int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1; + if ((gs.members.empty())||((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) { gs.lastExplicitGather = now; Address explicitGatherPeers[16]; diff --git a/node/Node.cpp b/node/Node.cpp index 019a8afca..7bdf331dc 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -202,6 +202,14 @@ public: { const std::vector *const alwaysContactEndpoints = _alwaysContact.get(p->address()); if (alwaysContactEndpoints) { + + // Contact upstream peers as infrequently as possible + ZT_PeerRole role = RR->topology->role(p->address()); + int roleBasedTimerScale = (role == ZT_PEER_ROLE_LEAF) ? 2 : 16; + if ((RR->node->now() - p->lastSentFullHello()) <= (ZT_PATH_HEARTBEAT_PERIOD * roleBasedTimerScale)) { + return; + } + const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now); bool contacted = (sent != 0); @@ -262,7 +270,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 } } - unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL; + unsigned long timeUntilNextPingCheck = _lowBandwidthMode ? (ZT_PING_CHECK_INVERVAL * 5) : ZT_PING_CHECK_INVERVAL; const int64_t timeSinceLastPingCheck = now - _lastPingCheck; if (timeSinceLastPingCheck >= timeUntilNextPingCheck) { try { @@ -309,6 +317,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 // Get peers we should stay connected to according to network configs // Also get networks and whether they need config so we only have to do one pass over networks + int timerScale = _lowBandwidthMode ? 64 : 1; std::vector< std::pair< SharedPtr,bool > > networkConfigNeeded; { Mutex::Lock l(_networks_m); @@ -317,7 +326,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 SharedPtr *network = (SharedPtr *)0; while (i.next(nwid,network)) { (*network)->config().alwaysContactAddresses(alwaysContact); - networkConfigNeeded.push_back( std::pair< SharedPtr,bool >(*network,(((now - (*network)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!(*network)->hasConfig()))) ); + networkConfigNeeded.push_back( std::pair< SharedPtr,bool >(*network,(((now - (*network)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY * timerScale)||(!(*network)->hasConfig()))) ); } } @@ -336,9 +345,12 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 // Refresh network config or broadcast network updates to members as needed for(std::vector< std::pair< SharedPtr,bool > >::const_iterator n(networkConfigNeeded.begin());n!=networkConfigNeeded.end();++n) { - if (n->second) + if (n->second) { n->first->requestConfiguration(tptr); - n->first->sendUpdatesToMembers(tptr); + } + if (! _lowBandwidthMode) { + n->first->sendUpdatesToMembers(tptr); + } } // Update online status, post status change as event diff --git a/node/Node.hpp b/node/Node.hpp index 834f50cc9..0ddd5cb7b 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -269,6 +269,16 @@ public: _stats.inVerbBytes[v] += (uint64_t)bytes; } + inline void setLowBandwidthMode(bool isEnabled) + { + _lowBandwidthMode = isEnabled; + } + + inline bool lowBandwidthModeEnabled() + { + return _lowBandwidthMode; + } + private: RuntimeEnvironment _RR; RuntimeEnvironment *RR; @@ -316,6 +326,7 @@ private: int64_t _lastMemoizedTraceSettings; volatile int64_t _prngState[2]; bool _online; + bool _lowBandwidthMode; }; } // namespace ZeroTier diff --git a/node/Peer.cpp b/node/Peer.cpp index 99fa8d277..c1dc124c6 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -219,11 +219,15 @@ void Peer::received( // is done less frequently. if (this->trustEstablished(now)) { const int64_t sinceLastPush = now - _lastDirectPathPushSent; - if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH : ZT_DIRECT_PATH_PUSH_INTERVAL)) { + bool lowBandwidth = RR->node->lowBandwidthModeEnabled(); + int timerScale = lowBandwidth ? 16 : 1; + if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH * timerScale : ZT_DIRECT_PATH_PUSH_INTERVAL)) { _lastDirectPathPushSent = now; std::vector pathsToPush(RR->node->directPaths()); - std::vector ma = RR->sa->whoami(); - pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end()); + if (! lowBandwidth) { + std::vector ma = RR->sa->whoami(); + pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end()); + } if (!pathsToPush.empty()) { std::vector::const_iterator p(pathsToPush.begin()); while (p != pathsToPush.end()) { @@ -453,7 +457,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,-1,atAddress,outp.data(),outp.size()); + RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -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 @@ -477,8 +481,9 @@ void Peer::tryMemorizedPath(void *tPtr,int64_t now) if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { _lastTriedMemorizedPath = now; InetAddress mp; - if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) + if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) { attemptToContactAt(tPtr,-1,mp,now,true); + } } } diff --git a/node/Peer.hpp b/node/Peer.hpp index 0192143e3..668bbbee9 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -302,6 +302,8 @@ public: */ inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } + inline int64_t lastSentFullHello() { return _lastSentFullHello; } + /** * @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths */ diff --git a/service/OneService.cpp b/service/OneService.cpp index daba4d99b..21717e3a5 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2122,6 +2122,7 @@ public: fprintf(stderr,"WARNING: using manually-specified secondary and/or tertiary ports. This can cause NAT issues." ZT_EOL_S); } _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true); + _node->setLowBandwidthMode(OSUtils::jsonBool(settings["lowBandwidthMode"],false)); #ifndef ZT_SDK const std::string up(OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT));