mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-19 21:03:57 -07:00
GitHub issue #191 - kill intra-network multicast rate limits (which were not well supported or easily configurable anyway) -- this is really left over from the old collaborative multicast propagation algorithm. New algorithm (in for a while) has been sender-side replication in which sender "pays" all bandwidth, which intrinsically limits multicast.
This commit is contained in:
parent
c287ae4d1d
commit
57c7992c78
10 changed files with 4 additions and 140 deletions
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_BWACCOUNT_HPP
|
||||
#define ZT_BWACCOUNT_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#define round(x) ((x-floor(x))>0.5 ? ceil(x) : floor(x))
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Bandwidth account used for rate limiting multicast groups
|
||||
*
|
||||
* This is used to apply a bank account model to multicast groups. Each
|
||||
* multicast packet counts against a balance, which accrues at a given
|
||||
* rate in bytes per second. Debt is possible. These parameters are
|
||||
* configurable.
|
||||
*
|
||||
* A bank account model permits bursting behavior, which correctly models
|
||||
* how OSes and apps typically use multicast. It's common for things to
|
||||
* spew lots of multicast messages at once, wait a while, then do it
|
||||
* again. A consistent bandwidth limit model doesn't fit.
|
||||
*/
|
||||
class BandwidthAccount
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an uninitialized account
|
||||
*
|
||||
* init() must be called before this is used.
|
||||
*/
|
||||
BandwidthAccount() throw() {}
|
||||
|
||||
/**
|
||||
* Create and initialize
|
||||
*
|
||||
* @param preload Initial balance to place in account
|
||||
* @param maxb Maximum allowed balance (> 0)
|
||||
* @param acc Rate of accrual in bytes per second
|
||||
* @param now Current time
|
||||
*/
|
||||
BandwidthAccount(uint32_t preload,uint32_t maxb,uint32_t acc,uint64_t now)
|
||||
throw()
|
||||
{
|
||||
init(preload,maxb,acc,now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize or re-initialize account
|
||||
*
|
||||
* @param preload Initial balance to place in account
|
||||
* @param maxb Maximum allowed balance (> 0)
|
||||
* @param acc Rate of accrual in bytes per second
|
||||
* @param now Current time
|
||||
*/
|
||||
inline void init(uint32_t preload,uint32_t maxb,uint32_t acc,uint64_t now)
|
||||
throw()
|
||||
{
|
||||
_lastTime = ((double)now / 1000.0);
|
||||
_balance = preload;
|
||||
_maxBalance = maxb;
|
||||
_accrual = acc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and retrieve balance of this account
|
||||
*
|
||||
* @param now Current time
|
||||
* @return New balance updated from current clock
|
||||
*/
|
||||
inline uint32_t update(uint64_t now)
|
||||
throw()
|
||||
{
|
||||
double lt = _lastTime;
|
||||
double nowf = ((double)now / 1000.0);
|
||||
_lastTime = nowf;
|
||||
return (_balance = std::min(_maxBalance,(uint32_t)round((double)_balance + ((double)_accrual * (nowf - lt)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update balance and conditionally deduct
|
||||
*
|
||||
* If the deduction amount fits, it is deducted after update. Otherwise
|
||||
* balance is updated and false is returned.
|
||||
*
|
||||
* @param amt Amount to deduct
|
||||
* @param now Current time
|
||||
* @return True if amount fit within balance and was deducted
|
||||
*/
|
||||
inline bool deduct(uint32_t amt,uint64_t now)
|
||||
throw()
|
||||
{
|
||||
if (update(now) >= amt) {
|
||||
_balance -= amt;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Most recent balance without update
|
||||
*/
|
||||
inline uint32_t balance() const
|
||||
throw()
|
||||
{
|
||||
return _balance;
|
||||
}
|
||||
|
||||
private:
|
||||
double _lastTime;
|
||||
uint32_t _balance;
|
||||
uint32_t _maxBalance;
|
||||
uint32_t _accrual;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -357,20 +357,6 @@ void Network::clean()
|
|||
}
|
||||
}
|
||||
|
||||
bool Network::updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes)
|
||||
{
|
||||
const uint64_t now = RR->node->now();
|
||||
Mutex::Lock _l(_lock);
|
||||
if (!_config)
|
||||
return false;
|
||||
std::map< MulticastGroup,BandwidthAccount >::iterator bal(_multicastRateAccounts.find(mg));
|
||||
if (bal == _multicastRateAccounts.end()) {
|
||||
NetworkConfig::MulticastRate r(_config->multicastRate(mg));
|
||||
bal = _multicastRateAccounts.insert(std::pair< MulticastGroup,BandwidthAccount >(mg,BandwidthAccount(r.preload,r.maxBalance,r.accrual,now))).first;
|
||||
}
|
||||
return bal->second.deduct(bytes,now);
|
||||
}
|
||||
|
||||
void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "MulticastGroup.hpp"
|
||||
#include "MAC.hpp"
|
||||
#include "Dictionary.hpp"
|
||||
#include "BandwidthAccount.hpp"
|
||||
#include "Multicaster.hpp"
|
||||
#include "NetworkConfig.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
|
@ -237,15 +236,6 @@ public:
|
|||
_externalConfig(ec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and check multicast rate balance for a multicast group
|
||||
*
|
||||
* @param mg Multicast group
|
||||
* @param bytes Size of packet
|
||||
* @return True if packet is within budget
|
||||
*/
|
||||
bool updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes);
|
||||
|
||||
/**
|
||||
* Get current network config or throw exception
|
||||
*
|
||||
|
@ -370,7 +360,6 @@ private:
|
|||
|
||||
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to including those behind us (updated periodically)
|
||||
std::map< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups bridged to us and when we last saw activity on each
|
||||
std::map< MulticastGroup,BandwidthAccount > _multicastRateAccounts;
|
||||
|
||||
std::map<MAC,Address> _remoteBridgeRoutes; // remote addresses where given MACs are reachable
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
// This is fast enough for things like Apple's mDNS spam, so it should serve
|
||||
// as a good default for your average network.
|
||||
const NetworkConfig::MulticastRate NetworkConfig::DEFAULT_MULTICAST_RATE(40000,60000,80);
|
||||
|
||||
SharedPtr<NetworkConfig> NetworkConfig::createTestNetworkConfig(const Address &self)
|
||||
{
|
||||
SharedPtr<NetworkConfig> nc(new NetworkConfig());
|
||||
|
@ -85,18 +81,6 @@ std::vector<unsigned int> NetworkConfig::allowedEtherTypes() const
|
|||
return ets;
|
||||
}
|
||||
|
||||
const NetworkConfig::MulticastRate &NetworkConfig::multicastRate(const MulticastGroup &mg) const
|
||||
throw()
|
||||
{
|
||||
std::map<MulticastGroup,MulticastRate>::const_iterator r(_multicastRates.find(mg));
|
||||
if (r == _multicastRates.end()) {
|
||||
r = _multicastRates.find(MulticastGroup()); // zero MG signifies network's default rate
|
||||
if (r == _multicastRates.end())
|
||||
return DEFAULT_MULTICAST_RATE; // neither specific nor default found in network config
|
||||
}
|
||||
return r->second;
|
||||
}
|
||||
|
||||
void NetworkConfig::_fromDictionary(const Dictionary &d)
|
||||
{
|
||||
static const std::string zero("0");
|
||||
|
@ -181,13 +165,6 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
|
|||
std::sort(_activeBridges.begin(),_activeBridges.end());
|
||||
std::unique(_activeBridges.begin(),_activeBridges.end());
|
||||
|
||||
Dictionary multicastRateEntries(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES,std::string()));
|
||||
for(Dictionary::const_iterator i(multicastRateEntries.begin());i!=multicastRateEntries.end();++i) {
|
||||
std::vector<std::string> params(Utils::split(i->second.c_str(),",","",""));
|
||||
if (params.size() >= 3)
|
||||
_multicastRates[MulticastGroup(i->first)] = MulticastRate(Utils::hexStrToUInt(params[0].c_str()),Utils::hexStrToUInt(params[1].c_str()),Utils::hexStrToUInt(params[2].c_str()));
|
||||
}
|
||||
|
||||
std::vector<std::string> relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","",""));
|
||||
for(std::vector<std::string>::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) {
|
||||
std::size_t semi(r->find(';')); // address;ip/port,...
|
||||
|
@ -221,14 +198,6 @@ bool NetworkConfig::operator==(const NetworkConfig &nc) const
|
|||
if (_gateways != nc._gateways) return false;
|
||||
if (_activeBridges != nc._activeBridges) return false;
|
||||
if (_relays != nc._relays) return false;
|
||||
if (_multicastRates.size() == nc._multicastRates.size()) {
|
||||
// uclibc++ doesn't seem to implement map<> != map<> correctly, so do
|
||||
// it ourselves. Note that this depends on the maps being sorted.
|
||||
for(std::map<MulticastGroup,MulticastRate>::const_iterator a(_multicastRates.begin()),b(nc._multicastRates.begin());a!=_multicastRates.end();++a,++b) {
|
||||
if ((a->first != b->first)||(a->second != b->second))
|
||||
return false;
|
||||
}
|
||||
} else return false;
|
||||
if (_com != nc._com) return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -68,9 +68,6 @@ namespace ZeroTier {
|
|||
// integer(hex)
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT "ml"
|
||||
|
||||
// dictionary of one or more of: MAC/ADI=preload,maxbalance,accrual
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES "mr"
|
||||
|
||||
// 0/1
|
||||
#define ZT_NETWORKCONFIG_DICT_KEY_PRIVATE "p"
|
||||
|
||||
|
@ -114,27 +111,6 @@ class NetworkConfig
|
|||
friend class SharedPtr<NetworkConfig>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Tuple of multicast rate parameters
|
||||
*/
|
||||
struct MulticastRate
|
||||
{
|
||||
MulticastRate() throw() {}
|
||||
MulticastRate(uint32_t pl,uint32_t maxb,uint32_t acc) throw() : preload(pl),maxBalance(maxb),accrual(acc) {}
|
||||
|
||||
uint32_t preload;
|
||||
uint32_t maxBalance;
|
||||
uint32_t accrual;
|
||||
|
||||
inline bool operator==(const MulticastRate &mr) const { return ((preload == mr.preload)&&(maxBalance == mr.maxBalance)&&(accrual == mr.accrual)); }
|
||||
inline bool operator!=(const MulticastRate &mr) const { return (!(*this == mr)); }
|
||||
};
|
||||
|
||||
/**
|
||||
* A hard-coded default multicast rate for networks that don't specify
|
||||
*/
|
||||
static const MulticastRate DEFAULT_MULTICAST_RATE;
|
||||
|
||||
/**
|
||||
* Create an instance of a NetworkConfig for the test network ID
|
||||
*
|
||||
|
@ -176,7 +152,6 @@ public:
|
|||
inline uint64_t revision() const throw() { return _revision; }
|
||||
inline const Address &issuedTo() const throw() { return _issuedTo; }
|
||||
inline unsigned int multicastLimit() const throw() { return _multicastLimit; }
|
||||
inline const std::map<MulticastGroup,MulticastRate> &multicastRates() const throw() { return _multicastRates; }
|
||||
inline bool allowPassiveBridging() const throw() { return _allowPassiveBridging; }
|
||||
inline bool isPublic() const throw() { return (!_private); }
|
||||
inline bool isPrivate() const throw() { return _private; }
|
||||
|
@ -198,13 +173,6 @@ public:
|
|||
return ( (_allowPassiveBridging) || (std::find(_activeBridges.begin(),_activeBridges.end(),fromPeer) != _activeBridges.end()) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mg Multicast group
|
||||
* @return Multicast rate or DEFAULT_MULTICAST_RATE if not set
|
||||
*/
|
||||
const MulticastRate &multicastRate(const MulticastGroup &mg) const
|
||||
throw();
|
||||
|
||||
bool operator==(const NetworkConfig &nc) const;
|
||||
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
|
||||
|
||||
|
@ -229,7 +197,6 @@ private:
|
|||
std::vector<InetAddress> _gateways;
|
||||
std::vector<Address> _activeBridges;
|
||||
std::vector< std::pair<Address,InetAddress> > _relays;
|
||||
std::map<MulticastGroup,MulticastRate> _multicastRates;
|
||||
CertificateOfMembership _com;
|
||||
|
||||
AtomicCounter __refCount;
|
||||
|
|
|
@ -145,12 +145,6 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
|
|||
if (fromBridged)
|
||||
network->learnBridgedMulticastGroup(mg,RR->node->now());
|
||||
|
||||
// Check multicast/broadcast bandwidth quotas and reject if quota exceeded
|
||||
if (!network->updateAndCheckMulticastBalance(mg,len)) {
|
||||
TRACE("%.16llx: didn't multicast %u bytes, quota exceeded for multicast group %s",network->id(),len,mg.toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
//TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len);
|
||||
|
||||
RR->mc->send(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue