summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Constants.hpp11
-rw-r--r--node/Network.cpp3
-rw-r--r--node/Network.hpp9
-rw-r--r--node/RateLimiter.hpp69
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