mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-21 05:53:09 +00:00
Work on defining new direct broadcast multicast algorithm.
This commit is contained in:
parent
d37c3ad30f
commit
d9abd4d9be
@ -228,37 +228,20 @@
|
||||
#define ZT_RELAY_MAX_HOPS 3
|
||||
|
||||
/**
|
||||
* Size of multicast deduplication ring buffer in 64-bit ints
|
||||
* Expire time for multicast 'likes' and indirect multicast memberships in ms
|
||||
*/
|
||||
#define ZT_MULTICAST_DEDUP_HISTORY_LENGTH 512
|
||||
|
||||
/**
|
||||
* Default number of bits in multicast propagation prefix
|
||||
*/
|
||||
#define ZT_DEFAULT_MULTICAST_PREFIX_BITS 2
|
||||
|
||||
/**
|
||||
* Default max depth (TTL) for multicast propagation
|
||||
*/
|
||||
#define ZT_DEFAULT_MULTICAST_DEPTH 32
|
||||
|
||||
/**
|
||||
* Global maximum for multicast propagation depth
|
||||
*
|
||||
* This is kind of an insane value, meant as a sanity check.
|
||||
*/
|
||||
#define ZT_MULTICAST_GLOBAL_MAX_DEPTH 500
|
||||
|
||||
/**
|
||||
* Expire time for multicast 'likes' in ms
|
||||
*/
|
||||
#define ZT_MULTICAST_LIKE_EXPIRE 120000
|
||||
#define ZT_MULTICAST_LIKE_EXPIRE 600000
|
||||
|
||||
/**
|
||||
* Time between polls of local tap devices for multicast membership changes
|
||||
*/
|
||||
#define ZT_MULTICAST_LOCAL_POLL_PERIOD 10000
|
||||
|
||||
/**
|
||||
* Minimum delay between attempts to gather multicast topology info if members > 0
|
||||
*/
|
||||
#define ZT_MULTICAST_TOPOLOGY_RESEARCH_RATE_THROTTLE 120000
|
||||
|
||||
/**
|
||||
* Delay between scans of the topology active peer DB for peers that need ping
|
||||
*/
|
||||
|
88
node/MulticastTopology.cpp
Normal file
88
node/MulticastTopology.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* ZeroTier One - Global Peer to Peer Ethernet
|
||||
* Copyright (C) 2011-2014 ZeroTier Networks LLC
|
||||
*
|
||||
* 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/
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "MulticastTopology.hpp"
|
||||
#include "Topology.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
MulticastTopology::MulticastTopology()
|
||||
{
|
||||
}
|
||||
|
||||
MulticastTopology::~MulticastTopology()
|
||||
{
|
||||
}
|
||||
|
||||
void MulticastTopology::clean(const Topology &topology)
|
||||
{
|
||||
uint64_t now = Utils::now();
|
||||
|
||||
for(std::map< MulticastGroup,std::vector<MulticastGroupMember> >::iterator mm(_members.begin());mm!=_members.end();) {
|
||||
std::vector<MulticastGroupMember>::iterator reader(mm->second.begin());
|
||||
std::vector<MulticastGroupMember>::iterator writer(mm->second.begin());
|
||||
unsigned long count = 0;
|
||||
while (reader != mm->second.end()) {
|
||||
if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) {
|
||||
*writer = *reader;
|
||||
|
||||
/* We sort in ascending order of most recent relevant activity. For peers we've learned
|
||||
* about by direct LIKEs, we do this in order of their own activity. For indirectly
|
||||
* acquired peers we do this minus a constant to place these categorically below directly
|
||||
* learned peers. For peers with no active Peer record, we use the time we last learned
|
||||
* about them minus one day (a large constant) to put these at the bottom of the list.
|
||||
* List is sorted in ascending order of rank and multicasts are sent last-to-first. */
|
||||
if (writer->learnedFrom) {
|
||||
SharedPtr<Peer> p(topology.getPeer(writer->learnedFrom));
|
||||
if (p)
|
||||
writer->rank = p->lastUnicastFrame() - ZT_MULTICAST_LIKE_EXPIRE;
|
||||
else writer->rank = writer->timestamp - 86400000;
|
||||
} else {
|
||||
SharedPtr<Peer> p(topology.getPeer(writer->address));
|
||||
if (p)
|
||||
writer->rank = p->lastUnicastFrame();
|
||||
else writer->rank = writer->timestamp - 86400000;
|
||||
}
|
||||
|
||||
++writer;
|
||||
++count;
|
||||
}
|
||||
++reader;
|
||||
}
|
||||
|
||||
if (count) {
|
||||
mm->second.resize(count);
|
||||
std::sort(mm->second.begin(),mm->second.end()); // sorts in ascending order of rank
|
||||
++mm;
|
||||
} else _members.erase(mm++);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
162
node/MulticastTopology.hpp
Normal file
162
node/MulticastTopology.hpp
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* ZeroTier One - Global Peer to Peer Ethernet
|
||||
* Copyright (C) 2011-2014 ZeroTier Networks LLC
|
||||
*
|
||||
* 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_MULTICASTTOPOLOGY_HPP
|
||||
#define ZT_MULTICASTTOPOLOGY_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Topology;
|
||||
|
||||
/**
|
||||
* Database of known multicast peers within a network
|
||||
*/
|
||||
class MulticastTopology
|
||||
{
|
||||
private:
|
||||
struct MulticastGroupMember
|
||||
{
|
||||
MulticastGroupMember() {}
|
||||
MulticastGroupMember(const Address &a,const Address &lf,uint64_t ts) : address(a),learnedFrom(lf),timestamp(ts) {}
|
||||
|
||||
Address address;
|
||||
Address learnedFrom; // NULL/0 for addresses directly learned from LIKE
|
||||
uint64_t timestamp; // time of last LIKE or OK response to MULTICAST_LONELY
|
||||
uint64_t rank; // used by sorting algorithm in clean()
|
||||
|
||||
// for sorting in ascending order of rank
|
||||
inline bool operator<(const MulticastGroupMember &m) const throw() { return (rank < m.rank); }
|
||||
};
|
||||
|
||||
public:
|
||||
MulticastTopology();
|
||||
~MulticastTopology();
|
||||
|
||||
/**
|
||||
* Add or update a member in a multicast group
|
||||
*
|
||||
* @param mg Multicast group
|
||||
* @param member Member to add/update
|
||||
* @param learnedFrom Address from which we learned this member or NULL/0 Address if direct
|
||||
*/
|
||||
inline void add(const MulticastGroup &mg,const Address &member,const Address &learnedFrom)
|
||||
{
|
||||
Mutex::Lock _l(_members_m);
|
||||
std::vector<MulticastGroupMember> &mv = _members[mg];
|
||||
for(std::vector<MulticastGroupMember>::iterator m(mv.begin());m!=mv.end();++m) {
|
||||
if (m->address == member) {
|
||||
if (m->learnedFrom) // once a member has been seen directly, we keep its status as direct
|
||||
m->learnedFrom = learnedFrom;
|
||||
m->timestamp = Utils::now();
|
||||
return;
|
||||
}
|
||||
}
|
||||
mv.push_back(MulticastGroupMember(member,learnedFrom,Utils::now()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a member from a multicast group (if present)
|
||||
*
|
||||
* @param mg Multicast group
|
||||
* @param member Member to erase
|
||||
*/
|
||||
inline void erase(const MulticastGroup &mg,const Address &member)
|
||||
{
|
||||
Mutex::Lock _l(_members_m);
|
||||
std::map< MulticastGroup,std::vector<MulticastGroupMember> >::iterator r(_members.find(mg));
|
||||
if (r != _members.end()) {
|
||||
for(std::vector<MulticastGroupMember>::iterator m(r->second.begin());m!=r->second.end();++m) {
|
||||
if (m->address == member) {
|
||||
r->second.erase(m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mg Multicast group
|
||||
* @return Number of known peers in group
|
||||
*/
|
||||
inline unsigned int memberCount(const MulticastGroup &mg) const
|
||||
{
|
||||
Mutex::Lock _l(_members_m);
|
||||
std::map< MulticastGroup,std::vector<MulticastGroupMember> >::const_iterator r(_members.find(mg));
|
||||
return ((r != _members.end()) ? (unsigned int)r->second.size() : (unsigned int)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over the known members of a multicast group
|
||||
*
|
||||
* @param mg Multicast group
|
||||
* @param func Function to be called with multicast group and address of member
|
||||
* @tparam F Function type (explicitly template on "FuncObj &" if reference instead of copy should be passed)
|
||||
* @return Number of members in multicast group for which function was called
|
||||
*/
|
||||
template<typename F>
|
||||
inline unsigned int eachMember(const MulticastGroup &mg,F func) const
|
||||
{
|
||||
Mutex::Lock _l(_members_m);
|
||||
std::map< MulticastGroup,std::vector<MulticastGroupMember> >::const_iterator r(_members.find(mg));
|
||||
if (r != _members.end()) {
|
||||
// We go in reverse order because most recently learned members are pushed to the end
|
||||
// of the vector. The priority resort algorithm in clean() sorts in ascending order
|
||||
// of propagation priority too.
|
||||
for(std::vector<MulticastGroupMember>::const_reverse_iterator m(r->second.rbegin());m!=r->second.rend();++m) {
|
||||
func(mg,m->address);
|
||||
}
|
||||
return (unsigned int)r->second.size();
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up and resort database
|
||||
*
|
||||
* @param topology Global peer topology
|
||||
*/
|
||||
void clean(const Topology &topology);
|
||||
|
||||
private:
|
||||
std::map< MulticastGroup,std::vector<MulticastGroupMember> > _members;
|
||||
Mutex _members_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Global Peer to Peer Ethernet
|
||||
* Copyright (C) 2011-2014 ZeroTier Networks LLC
|
||||
*
|
||||
* 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/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Multicaster.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
Multicaster::Multicaster()
|
||||
{
|
||||
}
|
||||
|
||||
Multicaster::~Multicaster()
|
||||
{
|
||||
}
|
||||
|
||||
void Multicaster::likesGroup(uint64_t nwid,const Address &a,const MulticastGroup &mg,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_NetInfo &n = _nets[nwid];
|
||||
_SubInfo &si = n.subscriptions[_Subscription(a,mg)];
|
||||
if (!si.lastLike) { // on first LIKE, we must add to _proximity[mg]
|
||||
std::list< Address > &p = n.proximity[mg];
|
||||
p.push_front(a);
|
||||
si.proximitySlot = p.begin(); // list's iterators remain valid until erase()
|
||||
}
|
||||
si.lastLike = now;
|
||||
}
|
||||
|
||||
void Multicaster::bringCloser(uint64_t nwid,const Address &a)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
std::map< uint64_t,_NetInfo >::iterator n(_nets.find(nwid));
|
||||
if (n == _nets.end())
|
||||
return;
|
||||
|
||||
/* _subscriptions contains pairs of <Address,MulticastGroup>, so we can
|
||||
* easily iterate through all subscriptions for a given address by
|
||||
* starting with the default all-zero MulticastGroup() as lower bound
|
||||
* and stopping when we're not looking at the right address anymore.
|
||||
* Then we can look up _proximity and rapidly splice() the list using
|
||||
* the saved iterator in _SubInfo. */
|
||||
|
||||
std::map< _Subscription,_SubInfo >::iterator s(n->second.subscriptions.lower_bound(_Subscription(a,MulticastGroup())));
|
||||
while ((s != n->second.subscriptions.end())&&(s->first.first == a)) {
|
||||
std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(s->first.second));
|
||||
if (s->second.proximitySlot != p->second.begin())
|
||||
p->second.splice(p->second.begin(),p->second,s->second.proximitySlot);
|
||||
++s;
|
||||
}
|
||||
}
|
||||
|
||||
void Multicaster::clean()
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
uint64_t now = Utils::now();
|
||||
|
||||
for(std::map< uint64_t,_NetInfo >::iterator n(_nets.begin());n!=_nets.end();) {
|
||||
for(std::map< _Subscription,_SubInfo >::iterator s(n->second.subscriptions.begin());s!=n->second.subscriptions.end();) {
|
||||
if ((now - s->second.lastLike) >= ZT_MULTICAST_LIKE_EXPIRE) {
|
||||
std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(s->first.second));
|
||||
p->second.erase(s->second.proximitySlot);
|
||||
if (p->second.empty())
|
||||
n->second.proximity.erase(p);
|
||||
n->second.subscriptions.erase(s++);
|
||||
} else ++s;
|
||||
}
|
||||
|
||||
if (n->second.proximity.empty()&&n->second.subscriptions.empty())
|
||||
_nets.erase(n++);
|
||||
else ++n;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -1,275 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Global Peer to Peer Ethernet
|
||||
* Copyright (C) 2011-2014 ZeroTier Networks LLC
|
||||
*
|
||||
* 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_MULTICASTER_HPP
|
||||
#define ZT_MULTICASTER_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Buffer.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Multicast propagation algorithm core and database
|
||||
*/
|
||||
class Multicaster
|
||||
{
|
||||
public:
|
||||
Multicaster();
|
||||
~Multicaster();
|
||||
|
||||
/**
|
||||
* Add or renew a peer's subscription to a multicast group
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param a Address that LIKEd
|
||||
* @param mg Multicast group
|
||||
* @param now Current time
|
||||
*/
|
||||
void likesGroup(uint64_t nwid,const Address &a,const MulticastGroup &mg,uint64_t now);
|
||||
|
||||
/**
|
||||
* Bring a peer closer in terms of propagation priority
|
||||
*
|
||||
* This gets called from PacketDecoder when a unicast frame is received.
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param a Address to bring closer (e.g. due to unicast message)
|
||||
* @param now Current time
|
||||
*/
|
||||
void bringCloser(uint64_t nwid,const Address &a);
|
||||
|
||||
/**
|
||||
* Erase entries for expired LIKEs and GOT records
|
||||
*/
|
||||
void clean();
|
||||
|
||||
/**
|
||||
* Multicast deduplicator
|
||||
*
|
||||
* This checks to see if a multicast GUID has been seen before. If not, it
|
||||
* adds it to the history and returns false.
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param mcGuid Multicast GUID (sender address + sender unique ID)
|
||||
* @return True if multicast IS a duplicate, false otherwise
|
||||
*/
|
||||
inline bool deduplicate(uint64_t nwid,uint64_t mcGuid)
|
||||
throw()
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_NetInfo &n = _nets[nwid];
|
||||
for(unsigned int i=0;i<ZT_MULTICAST_DEDUP_HISTORY_LENGTH;++i) {
|
||||
if (n.multicastHistory[i] == mcGuid)
|
||||
return true;
|
||||
}
|
||||
n.multicastHistory[n.multicastHistoryPtr++ % ZT_MULTICAST_DEDUP_HISTORY_LENGTH] = mcGuid;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick next hops for a multicast by proximity
|
||||
*
|
||||
* The function or function object must return true if more hops are desired
|
||||
* or false to stop finding new hops and return.
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param mg Multicast group
|
||||
* @param nextHopFunc Function to call for each address, search stops if it returns false
|
||||
* @tparam F Function to receive each next hop address
|
||||
*/
|
||||
template<typename F>
|
||||
inline void getNextHops(uint64_t nwid,const MulticastGroup &mg,F nextHopFunc)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
std::map< uint64_t,_NetInfo >::iterator n(_nets.find(nwid));
|
||||
if (n == _nets.end())
|
||||
return;
|
||||
std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(mg));
|
||||
if (p == n->second.proximity.end())
|
||||
return;
|
||||
|
||||
for(std::list< Address >::iterator a(p->second.begin());a!=p->second.end();++a) {
|
||||
if (!nextHopFunc(*a))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functor to add addresses to multicast frame propagation queues
|
||||
*
|
||||
* This function object checks the origin, bloom filter, and restriction
|
||||
* prefix for each address and if all these pass it adds the address and
|
||||
* increments the pointer pointed to by ptr. It stops (returns false) when
|
||||
* *ptr reaches end. It's used in PacketDecoder and Switch with getNextHops()
|
||||
* to compose multicast frame headers.
|
||||
*/
|
||||
class AddToPropagationQueue
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param ptr Pointer to pointer to current position in queue
|
||||
* @param end End of queue
|
||||
* @param bloom Bloom filter field (must be 1024 bytes in length)
|
||||
* @param bloomNonce Random nonce for bloom filter randomization
|
||||
* @param origin Originating address
|
||||
* @param prefixBits Number of bits in propagation restriction prefix
|
||||
* @param prefix Propagation restrition prefix
|
||||
* @param topology Topology database
|
||||
* @param now Current time
|
||||
*/
|
||||
AddToPropagationQueue(
|
||||
unsigned char **ptr,
|
||||
unsigned char *end,
|
||||
unsigned char *bloom,
|
||||
uint16_t bloomNonce,
|
||||
const Address &origin,
|
||||
unsigned int prefixBits,
|
||||
uint64_t prefix,
|
||||
const Topology *topology,
|
||||
uint64_t now)
|
||||
throw() :
|
||||
_origin(origin),
|
||||
_bloomNonce((uint64_t)bloomNonce),
|
||||
_prefix(prefix),
|
||||
_now(now),
|
||||
_ptr(ptr),
|
||||
_end(end),
|
||||
_bloom(bloom),
|
||||
_topology(topology),
|
||||
_prefixBits(prefixBits) {}
|
||||
|
||||
/**
|
||||
* @param a Address to (possibly) add
|
||||
* @return True if FIFO still contains room for more possible addresses
|
||||
*/
|
||||
inline bool operator()(const Address &a)
|
||||
throw()
|
||||
{
|
||||
if (*_ptr >= _end)
|
||||
return false;
|
||||
|
||||
// Exclude original sender -- obviously they've already seen it
|
||||
if (a == _origin)
|
||||
return true;
|
||||
|
||||
// Exclude addresses not in this prefix domain
|
||||
if (!a.withinMulticastPropagationPrefix(_prefix,_prefixBits))
|
||||
return true;
|
||||
|
||||
// Exclude addresses remembered in bloom filter
|
||||
uint64_t aint = a.toInt() + _bloomNonce;
|
||||
const unsigned int bit = (unsigned int)(aint ^ (aint >> 13) ^ (aint >> 26) ^ (aint >> 39)) & 0x1fff;
|
||||
unsigned char *const bbyte = _bloom + (bit >> 3); // note: bloom filter size == 1024 is hard-coded here
|
||||
const unsigned char bmask = 1 << (bit & 7);
|
||||
if ((*bbyte & bmask))
|
||||
return true; // address already visited
|
||||
|
||||
// Exclude peers that don't appear to be online
|
||||
SharedPtr<Peer> p(_topology->getPeer(a));
|
||||
if ((!p)||(!p->alive(_now)))
|
||||
return true;
|
||||
|
||||
// Remember address in bloom filter
|
||||
*bbyte |= bmask;
|
||||
|
||||
a.copyTo(*_ptr,ZT_ADDRESS_LENGTH);
|
||||
return ((*_ptr += ZT_ADDRESS_LENGTH) < _end);
|
||||
}
|
||||
|
||||
private:
|
||||
const Address _origin;
|
||||
const uint64_t _bloomNonce;
|
||||
const uint64_t _prefix;
|
||||
const uint64_t _now;
|
||||
unsigned char **const _ptr;
|
||||
unsigned char *const _end;
|
||||
unsigned char *const _bloom;
|
||||
const Topology *const _topology;
|
||||
const unsigned int _prefixBits;
|
||||
};
|
||||
|
||||
private:
|
||||
// Information about a subscription
|
||||
struct _SubInfo
|
||||
{
|
||||
_SubInfo() :
|
||||
lastLike(0),
|
||||
proximitySlot() {}
|
||||
|
||||
// Time of last MULTICAST_LIKE for this group
|
||||
uint64_t lastLike;
|
||||
|
||||
// Slot in corresponding list in _proximity
|
||||
std::list< Address >::iterator proximitySlot;
|
||||
};
|
||||
|
||||
// An address and multicast group tuple
|
||||
typedef std::pair< Address,MulticastGroup > _Subscription;
|
||||
|
||||
// Multicast info for a given network
|
||||
struct _NetInfo
|
||||
{
|
||||
_NetInfo()
|
||||
throw()
|
||||
{
|
||||
memset(multicastHistory,0,sizeof(multicastHistory));
|
||||
multicastHistoryPtr = 0;
|
||||
}
|
||||
|
||||
// Ring buffer of most recently injected multicast packet GUIDs
|
||||
uint64_t multicastHistory[ZT_MULTICAST_DEDUP_HISTORY_LENGTH];
|
||||
unsigned int multicastHistoryPtr;
|
||||
|
||||
// Peer proximity ordering for peers subscribed to each group
|
||||
std::map< MulticastGroup,std::list< Address > > proximity;
|
||||
|
||||
// Peer subscriptions to multicast groups
|
||||
std::map< _Subscription,_SubInfo > subscriptions;
|
||||
};
|
||||
|
||||
std::map< uint64_t,_NetInfo > _nets;
|
||||
Mutex _lock;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -117,23 +117,23 @@ bool Network::updateMulticastGroups()
|
||||
EthernetTap *t = _tap;
|
||||
if (t) {
|
||||
// Grab current groups from the local tap
|
||||
bool updated = t->updateMulticastGroups(_multicastGroups);
|
||||
bool updated = t->updateMulticastGroups(_myMulticastGroups);
|
||||
|
||||
// Merge in learned groups from any hosts bridged in behind us
|
||||
for(std::map<MulticastGroup,uint64_t>::const_iterator mg(_bridgedMulticastGroups.begin());mg!=_bridgedMulticastGroups.end();++mg)
|
||||
_multicastGroups.insert(mg->first);
|
||||
for(std::map<MulticastGroup,uint64_t>::const_iterator mg(_multicastGroupsBehindMe.begin());mg!=_multicastGroupsBehindMe.end();++mg)
|
||||
_myMulticastGroups.insert(mg->first);
|
||||
|
||||
// Add or remove BROADCAST group based on broadcast enabled netconf flag
|
||||
if ((_config)&&(_config->enableBroadcast())) {
|
||||
if (_multicastGroups.count(BROADCAST))
|
||||
if (_myMulticastGroups.count(BROADCAST))
|
||||
return updated;
|
||||
else {
|
||||
_multicastGroups.insert(BROADCAST);
|
||||
_myMulticastGroups.insert(BROADCAST);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (_multicastGroups.count(BROADCAST)) {
|
||||
_multicastGroups.erase(BROADCAST);
|
||||
if (_myMulticastGroups.count(BROADCAST)) {
|
||||
_myMulticastGroups.erase(BROADCAST);
|
||||
return true;
|
||||
} else return updated;
|
||||
}
|
||||
@ -311,9 +311,9 @@ void Network::clean()
|
||||
}
|
||||
|
||||
// Clean learned multicast groups if we haven't heard from them in a while
|
||||
for(std::map<MulticastGroup,uint64_t>::iterator mg(_bridgedMulticastGroups.begin());mg!=_bridgedMulticastGroups.end();) {
|
||||
for(std::map<MulticastGroup,uint64_t>::iterator mg(_multicastGroupsBehindMe.begin());mg!=_multicastGroupsBehindMe.end();) {
|
||||
if ((now - mg->second) > (ZT_MULTICAST_LIKE_EXPIRE * 2))
|
||||
_bridgedMulticastGroups.erase(mg++);
|
||||
_multicastGroupsBehindMe.erase(mg++);
|
||||
else ++mg;
|
||||
}
|
||||
}
|
||||
@ -419,23 +419,23 @@ void Network::threadMain()
|
||||
void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_bridgeRoutes[mac] = addr;
|
||||
_remoteBridgeRoutes[mac] = addr;
|
||||
|
||||
// If _bridgeRoutes exceeds sanity limit, trim worst offenders until below -- denial of service circuit breaker
|
||||
while (_bridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
|
||||
// If _remoteBridgeRoutes exceeds sanity limit, trim worst offenders until below -- denial of service circuit breaker
|
||||
while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
|
||||
std::map<Address,unsigned long> counts;
|
||||
Address maxAddr;
|
||||
unsigned long maxCount = 0;
|
||||
for(std::map<MAC,Address>::iterator br(_bridgeRoutes.begin());br!=_bridgeRoutes.end();++br) {
|
||||
for(std::map<MAC,Address>::iterator br(_remoteBridgeRoutes.begin());br!=_remoteBridgeRoutes.end();++br) {
|
||||
unsigned long c = ++counts[br->second];
|
||||
if (c > maxCount) {
|
||||
maxCount = c;
|
||||
maxAddr = br->second;
|
||||
}
|
||||
}
|
||||
for(std::map<MAC,Address>::iterator br(_bridgeRoutes.begin());br!=_bridgeRoutes.end();) {
|
||||
for(std::map<MAC,Address>::iterator br(_remoteBridgeRoutes.begin());br!=_remoteBridgeRoutes.end();) {
|
||||
if (br->second == maxAddr)
|
||||
_bridgeRoutes.erase(br++);
|
||||
_remoteBridgeRoutes.erase(br++);
|
||||
else ++br;
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ public:
|
||||
inline std::set<MulticastGroup> multicastGroups() const
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
return _multicastGroups;
|
||||
return _myMulticastGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -378,8 +378,8 @@ public:
|
||||
inline Address findBridgeTo(const MAC &mac) const
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
std::map<MAC,Address>::const_iterator br(_bridgeRoutes.find(mac));
|
||||
if (br == _bridgeRoutes.end())
|
||||
std::map<MAC,Address>::const_iterator br(_remoteBridgeRoutes.find(mac));
|
||||
if (br == _remoteBridgeRoutes.end())
|
||||
return Address();
|
||||
return br->second;
|
||||
}
|
||||
@ -401,7 +401,7 @@ public:
|
||||
inline void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_bridgedMulticastGroups[mg] = now;
|
||||
_multicastGroupsBehindMe[mg] = now;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -445,16 +445,20 @@ private:
|
||||
EthernetTap *volatile _tap; // tap device or NULL if not initialized yet
|
||||
volatile bool _enabled;
|
||||
|
||||
std::set<MulticastGroup> _multicastGroups;
|
||||
std::set<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<MAC,Address> _remoteBridgeRoutes; // remote addresses where given MACs are reachable
|
||||
|
||||
// Deprecated, but will be kept around until P5_MULTICAST_FRAME is gone -- but the
|
||||
// entry for us is still used by both. Eventually there will only be one BandwidthAccount,
|
||||
// namely ours.
|
||||
std::map< std::pair<Address,MulticastGroup>,BandwidthAccount > _multicastRateAccounts;
|
||||
|
||||
std::map<Address,CertificateOfMembership> _membershipCertificates;
|
||||
std::map<Address,uint64_t> _lastPushedMembershipCertificate;
|
||||
std::map<Address,CertificateOfMembership> _membershipCertificates; // Other members' certificates of membership
|
||||
std::map<Address,uint64_t> _lastPushedMembershipCertificate; // When did we last push our certificate to each remote member?
|
||||
|
||||
std::map<MAC,Address> _bridgeRoutes; // remote addresses where given MACs are reachable
|
||||
std::map<MulticastGroup,uint64_t> _bridgedMulticastGroups; // multicast groups of interest on our side of the bridge
|
||||
|
||||
SharedPtr<NetworkConfig> _config;
|
||||
SharedPtr<NetworkConfig> _config; // Most recent network configuration, which is an immutable value-object
|
||||
volatile uint64_t _lastConfigUpdate;
|
||||
|
||||
volatile bool _destroyed;
|
||||
|
@ -70,7 +70,6 @@
|
||||
#include "Network.hpp"
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "Multicaster.hpp"
|
||||
#include "Service.hpp"
|
||||
#include "SoftwareUpdater.hpp"
|
||||
#include "Buffer.hpp"
|
||||
@ -113,7 +112,6 @@ struct _NodeImpl
|
||||
delete renv.topology; renv.topology = (Topology *)0; // now we no longer need routing info
|
||||
delete renv.sm; renv.sm = (SocketManager *)0; // close all sockets
|
||||
delete renv.sw; renv.sw = (Switch *)0; // order matters less from here down
|
||||
delete renv.mc; renv.mc = (Multicaster *)0;
|
||||
delete renv.antiRec; renv.antiRec = (AntiRecursion *)0;
|
||||
delete renv.http; renv.http = (HttpClient *)0;
|
||||
delete renv.prng; renv.prng = (CMWC4096 *)0;
|
||||
@ -382,7 +380,6 @@ Node::ReasonForTermination Node::run()
|
||||
|
||||
_r->http = new HttpClient();
|
||||
_r->antiRec = new AntiRecursion();
|
||||
_r->mc = new Multicaster();
|
||||
_r->sw = new Switch(_r);
|
||||
_r->sm = new SocketManager(impl->udpPort,impl->tcpPort,&_CBztTraffic,_r);
|
||||
_r->topology = new Topology(_r,Utils::fileExists((_r->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str()));
|
||||
|
@ -43,11 +43,13 @@ const char *Packet::verbString(Verb v)
|
||||
case VERB_RENDEZVOUS: return "RENDEZVOUS";
|
||||
case VERB_FRAME: return "FRAME";
|
||||
case VERB_EXT_FRAME: return "EXT_FRAME";
|
||||
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
|
||||
case VERB_P5_MULTICAST_FRAME: return "P5_MULTICAST_FRAME";
|
||||
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
|
||||
case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";
|
||||
case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
|
||||
case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
|
||||
case VERB_MULTICAST_LONELY: return "MULTICAST_LONELY";
|
||||
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
|
||||
}
|
||||
return "(unknown)";
|
||||
}
|
||||
@ -64,6 +66,7 @@ const char *Packet::errorString(ErrorCode e)
|
||||
case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION";
|
||||
case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE";
|
||||
case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED";
|
||||
case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST";
|
||||
}
|
||||
return "(unknown)";
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ public:
|
||||
*/
|
||||
VERB_EXT_FRAME = 7,
|
||||
|
||||
/* A multicast frame:
|
||||
/* A multicast frame [old multicast protocol, deprecated]:
|
||||
* <[2] 16-bit propagation depth or 0xffff for "do not forward">
|
||||
* <[320] propagation FIFO>
|
||||
* <[1024] propagation bloom filter>
|
||||
@ -593,7 +593,7 @@ public:
|
||||
* ERROR may be generated if a membership certificate is needed for a
|
||||
* closed network. Payload will be network ID.
|
||||
*/
|
||||
VERB_MULTICAST_FRAME = 8,
|
||||
VERB_P5_MULTICAST_FRAME = 8,
|
||||
|
||||
/* Announce interest in multicast group(s):
|
||||
* <[8] 64-bit network ID>
|
||||
@ -657,7 +657,60 @@ public:
|
||||
* It does not generate an OK or ERROR message, and is treated only as
|
||||
* a hint to refresh now.
|
||||
*/
|
||||
VERB_NETWORK_CONFIG_REFRESH = 12
|
||||
VERB_NETWORK_CONFIG_REFRESH = 12,
|
||||
|
||||
/* Request endpoints for multicast distribution:
|
||||
* <[1] flags>
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
* <[4] 32-bit ADI for multicast group being queried>
|
||||
* <[2] 16-bit (suggested) max number of multicast peers desired>
|
||||
* [<[...] network membership certificate (optional)>]
|
||||
*
|
||||
* Flags are:
|
||||
* 0x01 - network membership certificate is included
|
||||
*
|
||||
* This message asks a peer for additional known endpoints that have
|
||||
* LIKEd a given multicast group. It's sent when the sender wishes
|
||||
* to send multicast but does not have the desired number of recipient
|
||||
* peers. (Hence it is "lonely." :)
|
||||
*
|
||||
* OK response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
* <[4] 32-bit ADI for multicast group being queried>
|
||||
* <[2] 16-bit total number of known members in this multicast group>
|
||||
* <[2] 16-bit number of members enumerated in this packet>
|
||||
* <[...] series of 5-byte ZeroTier addresses of enumerated members>
|
||||
*
|
||||
* ERROR response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
* <[4] 32-bit ADI for multicast group being queried>
|
||||
*
|
||||
* ERRORs are optional and are only generated if permission is denied,
|
||||
* certificate of membership is out of date, etc.
|
||||
*/
|
||||
VERB_MULTICAST_LONELY = 13,
|
||||
|
||||
/* Multicast frame:
|
||||
* <[1] flags (currently unused, must be 0)>
|
||||
* <[4] 32-bit multicast ADI (note that this is out of order here -- it precedes MAC)>
|
||||
* <[6] destination MAC or all zero for destination node>
|
||||
* <[6] source MAC or all zero for node of origin>
|
||||
* <[2] 16-bit ethertype>
|
||||
* <[...] ethernet payload>
|
||||
*
|
||||
* This is similar to EXT_FRAME but carries a multicast, and is sent
|
||||
* out to recipients on a multicast list.
|
||||
*
|
||||
* OK is not generated.
|
||||
*
|
||||
* ERROR response payload:
|
||||
* <[6] multicast group MAC>
|
||||
* <[4] 32-bit multicast group ADI>
|
||||
*/
|
||||
VERB_MULTICAST_FRAME = 14
|
||||
};
|
||||
|
||||
/**
|
||||
@ -687,7 +740,10 @@ public:
|
||||
ERROR_NEED_MEMBERSHIP_CERTIFICATE = 6,
|
||||
|
||||
/* Tried to join network, but you're not a member */
|
||||
ERROR_NETWORK_ACCESS_DENIED_ = 7 /* extra _ to avoid Windows name conflict */
|
||||
ERROR_NETWORK_ACCESS_DENIED_ = 7, /* extra _ to avoid Windows name conflict */
|
||||
|
||||
/* Multicasts to this group are not wanted */
|
||||
ERROR_UNWANTED_MULTICAST = 8
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -42,7 +42,6 @@ class Topology;
|
||||
class CMWC4096;
|
||||
class Service;
|
||||
class Node;
|
||||
class Multicaster;
|
||||
class SoftwareUpdater;
|
||||
class SocketManager;
|
||||
class AntiRecursion;
|
||||
@ -79,7 +78,6 @@ public:
|
||||
prng((CMWC4096 *)0),
|
||||
http((HttpClient *)0),
|
||||
antiRec((AntiRecursion *)0),
|
||||
mc((Multicaster *)0),
|
||||
sw((Switch *)0),
|
||||
sm((SocketManager *)0),
|
||||
topology((Topology *)0),
|
||||
@ -129,7 +127,6 @@ public:
|
||||
CMWC4096 *prng;
|
||||
HttpClient *http;
|
||||
AntiRecursion *antiRec;
|
||||
Multicaster *mc;
|
||||
Switch *sw;
|
||||
SocketManager *sm;
|
||||
Topology *topology;
|
||||
|
@ -151,6 +151,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
|
||||
|
||||
TRACE("%s: MULTICAST %s -> %s %s %d",network->tapDeviceName().c_str(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),(int)data.size());
|
||||
|
||||
/* old P5 multicast algorithm
|
||||
const unsigned int mcid = ++_multicastIdCounter & 0xffffff;
|
||||
const uint16_t bloomNonce = (uint16_t)(_r->prng->next32() & 0xffff); // doesn't need to be cryptographically strong
|
||||
unsigned char bloom[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM];
|
||||
@ -226,6 +227,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
|
||||
outp.compress();
|
||||
send(outp,true);
|
||||
}
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "Array.hpp"
|
||||
#include "Network.hpp"
|
||||
#include "SharedPtr.hpp"
|
||||
#include "Multicaster.hpp"
|
||||
#include "PacketDecoder.hpp"
|
||||
#include "Socket.hpp"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user