diff options
Diffstat (limited to 'node')
-rw-r--r-- | node/Constants.hpp | 11 | ||||
-rw-r--r-- | node/Network.cpp | 3 | ||||
-rw-r--r-- | node/Network.hpp | 9 | ||||
-rw-r--r-- | node/RateLimiter.hpp | 69 |
4 files changed, 58 insertions, 34 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp index 386a1508..67ffeb26 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -274,12 +274,17 @@ error_no_ZT_ARCH_defined; /** * Default balance preload for multicast rate limiters on a network */ -#define ZT_MULTICAST_DEFAULT_RATE_PRELOAD 25.0 +#define ZT_MULTICAST_DEFAULT_RATE_PRELOAD 15000.0 /** - * Absolute maximum balance for multicast rate limiters + * Default maximum balance for multicast rate limiters */ -#define ZT_MULTICAST_DEFAULT_RATE_MAX 75.0 +#define ZT_MULTICAST_DEFAULT_RATE_MAX_BALANCE 15000.0 + +/** + * Default minimum balance for multicast rate limiters (max debt) + */ +#define ZT_MULTICAST_DEFAULT_RATE_MIN_BALANCE -15000.0 /** * Delay between scans of the topology active peer DB for peers that need ping diff --git a/node/Network.cpp b/node/Network.cpp index a93740f8..9227cd34 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -140,6 +140,9 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t // being constructed. C++ edge cases, how I love thee. SharedPtr<Network> nw(new Network()); nw->_r = renv; + nw->_rlLimit.bytesPerSecond = ZT_MULTICAST_DEFAULT_BYTES_PER_SECOND; + nw->_rlLimit.maxBalance = ZT_MULTICAST_DEFAULT_RATE_MAX_BALANCE; + nw->_rlLimit.minBalance = ZT_MULTICAST_DEFAULT_RATE_MIN_BALANCE; nw->_tap = new EthernetTap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr()); nw->_id = id; nw->_lastConfigUpdate = 0; diff --git a/node/Network.hpp b/node/Network.hpp index 7945569c..312912db 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -440,10 +440,10 @@ public: std::map<Address,RateLimiter>::iterator rl(_multicastRateLimiters.find(addr)); if (rl == _multicastRateLimiters.end()) { RateLimiter &newrl = _multicastRateLimiters[addr]; - newrl.init(ZT_MULTICAST_DEFAULT_BYTES_PER_SECOND,ZT_MULTICAST_DEFAULT_RATE_PRELOAD,ZT_MULTICAST_DEFAULT_RATE_MAX); - return newrl.gate((double)bytes); + newrl.init(ZT_MULTICAST_DEFAULT_RATE_PRELOAD); + return newrl.gate(_rlLimit,(double)bytes); } - return rl->second.gate((double)bytes); + return rl->second.gate(_rlLimit,(double)bytes); } private: @@ -452,6 +452,9 @@ private: const RuntimeEnvironment *_r; + // Rate limits for this network + RateLimiter::Limit _rlLimit; + // Tap and tap multicast memberships EthernetTap *_tap; std::set<MulticastGroup> _multicastGroups; diff --git a/node/RateLimiter.hpp b/node/RateLimiter.hpp index 7f7dfbdb..4ee0cec7 100644 --- a/node/RateLimiter.hpp +++ b/node/RateLimiter.hpp @@ -47,6 +47,31 @@ class RateLimiter { public: /** + * Limits to apply to a rate limiter + * + * Since many rate limiters may share the same fixed limit values, + * save memory by breaking this out into a struct parameter that + * can be passed into RateLimiter's methods. + */ + struct Limit + { + /** + * Speed in bytes per second, or rate of balance accrual + */ + double bytesPerSecond; + + /** + * Maximum balance that can ever be accrued (should be > 0.0) + */ + double maxBalance; + + /** + * Minimum balance, or maximum allowable "debt" (should be <= 0.0) + */ + double minBalance; + }; + + /** * Create an uninitialized rate limiter * * init() must be called before this is used. @@ -54,70 +79,58 @@ public: RateLimiter() throw() {} /** - * @param bytesPerSecond Bytes per second to permit (average) * @param preload Initial balance to place in account - * @param max Maximum balance to permit to ever accrue (max burst) */ - RateLimiter(double bytesPerSecond,double preload,double max) + RateLimiter(double preload) throw() { - init(bytesPerSecond,preload,max); + init(preload); } /** * Initialize or re-initialize rate limiter * - * @param bytesPerSecond Bytes per second to permit (average) * @param preload Initial balance to place in account - * @param max Maximum balance to permit to ever accrue (max burst) */ - inline void init(double bytesPerSecond,double preload,double max) + inline void init(double preload) throw() { - _bytesPerSecond = bytesPerSecond; _lastTime = Utils::nowf(); _balance = preload; - _max = max; } /** - * Update balance based on current clock - * - * This can be called at any time to check the current balance without - * affecting the behavior of gate(). + * Update balance based on current clock and supplied Limits bytesPerSecond and maxBalance * + * @param lim Current limits in effect * @return New balance */ - inline double updateBalance() + inline double updateBalance(const Limit &lim) throw() { - double now = Utils::nowf(); - double b = _balance = fmin(_max,_balance + (_bytesPerSecond * (now - _lastTime))); - _lastTime = now; - return b; + double lt = _lastTime; + double now = _lastTime = Utils::nowf(); + return (_balance = fmin(lim.maxBalance,_balance + (lim.bytesPerSecond * (now - lt)))); } /** - * Test balance and update / deduct if there is enough to transfer 'bytes' + * Update balance and test if a block of 'bytes' should be permitted to be transferred * + * @param lim Current limits in effect * @param bytes Number of bytes that we wish to transfer - * @return True if balance was sufficient (balance is updated), false if not (balance unchanged) + * @return True if balance was sufficient */ - inline bool gate(double bytes) + inline bool gate(const Limit &lim,double bytes) throw() { - if (updateBalance() >= bytes) { - _balance -= bytes; - return true; - } - return false; + bool allow = (updateBalance(lim) >= bytes); + _balance = fmax(lim.minBalance,_balance - bytes); + return allow; } private: - double _bytesPerSecond; double _lastTime; double _balance; - double _max; }; } // namespace ZeroTier |