2014-09-19 01:28:14 +00:00
|
|
|
/*
|
2019-08-23 16:23:39 +00:00
|
|
|
* Copyright (c)2019 ZeroTier, Inc.
|
2014-09-19 01:28:14 +00:00
|
|
|
*
|
2019-08-23 16:23:39 +00:00
|
|
|
* Use of this software is governed by the Business Source License included
|
|
|
|
* in the LICENSE.TXT file in the project's root directory.
|
2014-09-19 01:28:14 +00:00
|
|
|
*
|
2019-08-23 16:23:39 +00:00
|
|
|
* Change Date: 2023-01-01
|
2014-09-19 01:28:14 +00:00
|
|
|
*
|
2019-08-23 16:23:39 +00:00
|
|
|
* On the date above, in accordance with the Business Source License, use
|
|
|
|
* of this software will be governed by version 2.0 of the Apache License.
|
2014-09-19 01:28:14 +00:00
|
|
|
*/
|
2019-08-23 16:23:39 +00:00
|
|
|
/****/
|
2014-09-19 01:28:14 +00:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include "Constants.hpp"
|
2014-10-10 00:58:31 +00:00
|
|
|
#include "RuntimeEnvironment.hpp"
|
2014-09-24 21:02:16 +00:00
|
|
|
#include "Multicaster.hpp"
|
2019-09-09 22:49:17 +00:00
|
|
|
#include "Network.hpp"
|
2014-09-19 01:28:14 +00:00
|
|
|
#include "Topology.hpp"
|
2014-09-25 22:08:29 +00:00
|
|
|
#include "Switch.hpp"
|
2014-09-19 01:28:14 +00:00
|
|
|
|
|
|
|
namespace ZeroTier {
|
|
|
|
|
2014-10-01 21:05:25 +00:00
|
|
|
Multicaster::Multicaster(const RuntimeEnvironment *renv) :
|
2015-08-27 23:17:21 +00:00
|
|
|
RR(renv),
|
2019-09-08 02:15:21 +00:00
|
|
|
_groups(32) {}
|
2014-09-19 01:28:14 +00:00
|
|
|
|
2019-09-08 02:15:21 +00:00
|
|
|
Multicaster::~Multicaster() {}
|
2014-09-19 01:28:14 +00:00
|
|
|
|
2014-09-30 23:28:25 +00:00
|
|
|
void Multicaster::send(
|
2017-03-28 00:03:17 +00:00
|
|
|
void *tPtr,
|
2017-10-02 22:52:57 +00:00
|
|
|
int64_t now,
|
2018-01-27 01:38:44 +00:00
|
|
|
const SharedPtr<Network> &network,
|
2014-09-30 23:28:25 +00:00
|
|
|
const MulticastGroup &mg,
|
|
|
|
const MAC &src,
|
|
|
|
unsigned int etherType,
|
2019-09-09 22:49:17 +00:00
|
|
|
const unsigned int existingBloomMultiplier,
|
|
|
|
const uint8_t existingBloom[ZT_MULTICAST_BLOOM_FILTER_SIZE_BITS / 8],
|
|
|
|
const void *const data,
|
2014-09-30 23:28:25 +00:00
|
|
|
unsigned int len)
|
2014-09-22 20:18:24 +00:00
|
|
|
{
|
2019-09-09 22:49:17 +00:00
|
|
|
static const unsigned int PRIMES[16] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53 };
|
|
|
|
|
|
|
|
if (unlikely(len > ZT_MAX_MTU)) return; // sanity check
|
|
|
|
|
|
|
|
const NetworkConfig &config = network->config();
|
|
|
|
if (config.multicastLimit == 0) return; // multicast disabled
|
|
|
|
Address bridges[ZT_MAX_NETWORK_SPECIALISTS],multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS];
|
|
|
|
unsigned int bridgeCount = 0,multicastReplicatorCount = 0;
|
|
|
|
for(unsigned int i=0;i<config.specialistCount;++i) {
|
|
|
|
if ((config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
|
|
|
|
bridges[bridgeCount++] = config.specialists[i];
|
|
|
|
if ((config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)
|
|
|
|
multicastReplicators[multicastReplicatorCount++] = config.specialists[i];
|
|
|
|
}
|
2015-11-02 23:15:20 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
std::vector< std::pair<int64_t,Address> > recipients;
|
|
|
|
bool needMoar = false;
|
|
|
|
for(unsigned int i=0;i<bridgeCount;++i)
|
|
|
|
recipients.push_back(std::pair<int64_t,Address>(9223372036854775807LL,bridges[i]));
|
|
|
|
{
|
|
|
|
Mutex::Lock l2(_groups_l);
|
|
|
|
_getMembersByTime(network->id(),mg,recipients);
|
|
|
|
}
|
|
|
|
std::sort(recipients.begin() + bridgeCount,recipients.end(),std::greater< std::pair<int64_t,Address> >());
|
|
|
|
recipients.erase(std::unique(recipients.begin(),recipients.end()),recipients.end());
|
|
|
|
if (recipients.size() > config.multicastLimit) {
|
|
|
|
recipients.resize(config.multicastLimit);
|
|
|
|
} else if (recipients.size() < config.multicastLimit) {
|
|
|
|
needMoar = true;
|
|
|
|
}
|
2015-11-02 23:15:20 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
_txQueue_l.lock();
|
|
|
|
_OM *om = &(_txQueue[_txQueuePtr++ % ZT_TX_QUEUE_SIZE]);
|
|
|
|
Mutex::Lock ql(om->lock);
|
|
|
|
_txQueue_l.unlock();
|
|
|
|
|
|
|
|
om->nwid = network->id();
|
|
|
|
om->src = src;
|
|
|
|
om->mg = mg;
|
|
|
|
om->etherType = etherType;
|
|
|
|
om->dataSize = len;
|
|
|
|
memcpy(om->data,data,len);
|
|
|
|
|
|
|
|
if (existingBloom) {
|
|
|
|
om->bloomFilterMultiplier = existingBloomMultiplier;
|
|
|
|
memcpy(om->bloomFilter,existingBloom,sizeof(om->bloomFilter));
|
|
|
|
} else {
|
|
|
|
om->bloomFilterMultiplier = 1;
|
|
|
|
memset(om->bloomFilter,0,sizeof(om->bloomFilter));
|
|
|
|
|
|
|
|
if (recipients.size() > 1) {
|
|
|
|
unsigned int mult = 1;
|
|
|
|
unsigned int bestMultColl = 0xffffffff;
|
|
|
|
for(int k=0;k<16;++k) { // 16 == arbitrary limit on iterations for this search, also must be <= size of PRIMES
|
|
|
|
unsigned int coll = 0;
|
|
|
|
for(std::vector< std::pair<int64_t,Address> >::const_iterator r(recipients.begin());r!=recipients.end();++r) {
|
|
|
|
const unsigned int bfi = mult * (unsigned int)r->second.toInt();
|
|
|
|
const unsigned int byte = (bfi >> 3) % sizeof(om->bloomFilter);
|
|
|
|
const uint8_t bit = 1 << (bfi & 7);
|
|
|
|
coll += ((om->bloomFilter[byte] & bit) != 0);
|
|
|
|
om->bloomFilter[byte] |= bit;
|
|
|
|
}
|
|
|
|
memset(om->bloomFilter,0,sizeof(om->bloomFilter));
|
2015-11-02 23:15:20 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
if (coll <= bestMultColl) {
|
|
|
|
om->bloomFilterMultiplier = mult;
|
|
|
|
if (coll == 0) // perfect score, no need to continue searching
|
2015-11-02 23:15:20 +00:00
|
|
|
break;
|
2019-09-09 22:49:17 +00:00
|
|
|
bestMultColl = coll;
|
2015-11-02 23:15:20 +00:00
|
|
|
}
|
2014-10-04 05:30:10 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
mult = PRIMES[k];
|
2019-08-14 17:52:21 +00:00
|
|
|
}
|
2019-09-09 22:49:17 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-14 17:52:21 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
if (multicastReplicatorCount > 0) {
|
|
|
|
// SEND
|
|
|
|
return;
|
|
|
|
}
|
2018-01-27 01:38:44 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
SharedPtr<Peer> nextHops[2]; // these by definition are protocol version >= 11
|
|
|
|
unsigned int nextHopsBestLatency[2] = { 0xffff,0xffff };
|
|
|
|
for(std::vector< std::pair<int64_t,Address> >::const_iterator r(recipients.begin());r!=recipients.end();++r) {
|
|
|
|
const unsigned int bfi = om->bloomFilterMultiplier * (unsigned int)r->second.toInt();
|
|
|
|
const unsigned int bfbyte = (bfi >> 3) % sizeof(om->bloomFilter);
|
|
|
|
const uint8_t bfbit = 1 << (bfi & 7);
|
|
|
|
if ((om->bloomFilter[bfbyte] & bfbit) != 0) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
SharedPtr<Peer> peer(RR->topology->get(r->second));
|
|
|
|
if (peer) {
|
|
|
|
if (peer->remoteVersionProtocol() < 11) {
|
|
|
|
// SEND
|
|
|
|
|
|
|
|
om->bloomFilter[bfbyte] |= bfbit;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
const unsigned int lat = peer->latency(now);
|
|
|
|
for(unsigned int nh=0;nh<2;++nh) {
|
|
|
|
if (lat <= nextHopsBestLatency[nh]) {
|
|
|
|
nextHopsBestLatency[nh] = lat;
|
|
|
|
nextHops[nh] = peer;
|
2018-01-27 01:38:44 +00:00
|
|
|
break;
|
2019-09-09 22:49:17 +00:00
|
|
|
}
|
2016-08-23 18:29:02 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-28 18:43:09 +00:00
|
|
|
}
|
2019-09-09 22:49:17 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-04 05:30:10 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
for(unsigned int nh=0;nh<2;++nh) {
|
|
|
|
if (nextHops[nh]) {
|
|
|
|
const unsigned int bfi = om->bloomFilterMultiplier * (unsigned int)nextHops[nh]->address().toInt();
|
|
|
|
om->bloomFilter[(bfi >> 3) % sizeof(om->bloomFilter)] |= 1 << (bfi & 7);
|
2014-11-21 19:27:53 +00:00
|
|
|
}
|
2019-09-09 22:49:17 +00:00
|
|
|
}
|
2014-10-04 20:46:29 +00:00
|
|
|
|
2019-09-09 22:49:17 +00:00
|
|
|
for(unsigned int nh=0;nh<2;++nh) {
|
|
|
|
if (nextHops[nh]) {
|
|
|
|
}
|
|
|
|
}
|
2014-09-22 20:18:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 22:52:57 +00:00
|
|
|
void Multicaster::clean(int64_t now)
|
2014-09-22 20:18:24 +00:00
|
|
|
{
|
2014-09-19 01:28:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace ZeroTier
|