Work in progress...

This commit is contained in:
Adam Ierymenko 2013-09-26 17:45:19 -04:00
parent 24bad9f3d1
commit 4e010da54b
10 changed files with 231 additions and 257 deletions

View File

@ -231,15 +231,6 @@ public:
*/ */
inline operator bool() const throw() { return (_a != 0); } inline operator bool() const throw() { return (_a != 0); }
/**
* @return Sum of all bytes in address
*/
inline unsigned int sum() const
throw()
{
return (unsigned int)(((_a >> 32) & 0xff) + ((_a >> 24) & 0xff) + ((_a >> 16) & 0xff) + ((_a >> 8) & 0xff) + (_a & 0xff));
}
/** /**
* Check if this address is reserved * Check if this address is reserved
* *

View File

@ -230,6 +230,11 @@ error_no_ZT_ARCH_defined;
*/ */
#define ZT_RELAY_MAX_HOPS 3 #define ZT_RELAY_MAX_HOPS 3
/**
* Size of multicast deduplication ring buffer in 64-bit ints
*/
#define ZT_MULTICAST_DEDUP_HISTORY_LENGTH 512
/** /**
* Period between announcements of all multicast 'likes' in ms * Period between announcements of all multicast 'likes' in ms
* *
@ -244,11 +249,6 @@ error_no_ZT_ARCH_defined;
*/ */
#define ZT_MULTICAST_LIKE_EXPIRE ((ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD * 2) + 1000) #define ZT_MULTICAST_LIKE_EXPIRE ((ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD * 2) + 1000)
/**
* Expiration for remembered MULTICAST_GOTs, in ms
*/
#define ZT_MULTICAST_MAGNET_STATE_EXPIRE 30000
/** /**
* Time between polls of local taps for multicast membership changes * Time between polls of local taps for multicast membership changes
*/ */

View File

@ -76,15 +76,6 @@ void Multicaster::bringCloser(uint64_t nwid,const Address &a)
} }
} }
void Multicaster::got(uint64_t nwid,const Address &peer,uint64_t mcGuid)
{
Mutex::Lock _l(_lock);
_NetInfo &n = _nets[nwid];
std::pair< uint64_t,std::set<Address> > &g = n.got[mcGuid];
g.first = Utils::now();
g.second.insert(peer);
}
void Multicaster::clean() void Multicaster::clean()
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
@ -92,14 +83,8 @@ void Multicaster::clean()
uint64_t now = Utils::now(); uint64_t now = Utils::now();
for(std::map< uint64_t,_NetInfo >::iterator n(_nets.begin());n!=_nets.end();) { for(std::map< uint64_t,_NetInfo >::iterator n(_nets.begin());n!=_nets.end();) {
for(std::map< uint64_t,std::pair< uint64_t,std::set<Address> > >::iterator g(n->second.got.begin());g!=n->second.got.end();) {
if ((now - g->second.first) > ZT_MULTICAST_MAGNET_STATE_EXPIRE)
n->second.got.erase(g++);
else ++g;
}
for(std::map< _Subscription,_SubInfo >::iterator s(n->second.subscriptions.begin());s!=n->second.subscriptions.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) { if ((now - s->second.lastLike) >= ZT_MULTICAST_LIKE_EXPIRE) {
std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(s->first.second)); std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(s->first.second));
p->second.erase(s->second.proximitySlot); p->second.erase(s->second.proximitySlot);
if (p->second.empty()) if (p->second.empty())

View File

@ -41,6 +41,7 @@
#include "Mutex.hpp" #include "Mutex.hpp"
#include "MulticastGroup.hpp" #include "MulticastGroup.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buffer.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -72,22 +73,34 @@ public:
*/ */
void bringCloser(uint64_t nwid,const Address &a); void bringCloser(uint64_t nwid,const Address &a);
/**
* Indicate that a peer reported that it GOT a multicast
*
* This only happens on magnet nodes for a propagation.
*
* @param nwid Network ID
* @param mcGuid Multicast GUID
* @param peer Peer that GOT multicast
*/
void got(uint64_t nwid,const Address &peer,uint64_t mcGuid);
/** /**
* Erase entries for expired LIKEs and GOT records * Erase entries for expired LIKEs and GOT records
*/ */
void clean(); 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_NETWORK_MULTICAST_DEDUP_HISTORY_LENGTH] = mcGuid;
return false;
}
/** /**
* Pick next hops for a multicast by proximity * Pick next hops for a multicast by proximity
* *
@ -96,12 +109,11 @@ public:
* *
* @param nwid Network ID * @param nwid Network ID
* @param mg Multicast group * @param mg Multicast group
* @param mcGuid Multicast message GUID (signer and signer unique ID)
* @param nextHopFunc Function to call for each address, search stops if it returns false * @param nextHopFunc Function to call for each address, search stops if it returns false
* @return Number of results returned through function * @return Number of results returned through function
*/ */
template<typename F> template<typename F>
inline unsigned int getNextHops(uint64_t nwid,const MulticastGroup &mg,uint64_t mcGuid,F nextHopFunc) inline unsigned int getNextHops(uint64_t nwid,const MulticastGroup &mg,F nextHopFunc)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
@ -111,16 +123,11 @@ public:
std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(mg)); std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(mg));
if (p == n->second.proximity.end()) if (p == n->second.proximity.end())
return 0; return 0;
std::pair< uint64_t,std::set< Address > > &g = n->second.got[mcGuid];
g.first = Utils::now();
unsigned int cnt = 0; unsigned int cnt = 0;
for(std::list< Address >::iterator a(p->second.begin());a!=p->second.end();++a) { for(std::list< Address >::iterator a(p->second.begin());a!=p->second.end();++a) {
if (g.second.insert(*a).second) { if (!nextHopFunc(*a))
++cnt; break;
if (!nextHopFunc(*a))
break;
}
} }
return cnt; return cnt;
} }
@ -141,13 +148,21 @@ private:
}; };
// An address and multicast group tuple // An address and multicast group tuple
typedef std::pair<Address,MulticastGroup> _Subscription; typedef std::pair< Address,MulticastGroup > _Subscription;
// Multicast info for a given network // Multicast info for a given network
struct _NetInfo struct _NetInfo
{ {
// GOTs by multicast GUID: time of last GOT, addresses that GOT _NetInfo()
std::map< uint64_t,std::pair< uint64_t,std::set< Address > > > got; 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 // Peer proximity ordering for peers subscribed to each group
std::map< MulticastGroup,std::list< Address > > proximity; std::map< MulticastGroup,std::list< Address > > proximity;

View File

@ -157,8 +157,6 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t
// that then causes the Network instance to be deleted before it is finished // that then causes the Network instance to be deleted before it is finished
// being constructed. C++ edge cases, how I love thee. // being constructed. C++ edge cases, how I love thee.
SharedPtr<Network> nw(new Network()); SharedPtr<Network> nw(new Network());
memset(nw->_multicastHistory,0,sizeof(nw->_multicastHistory));
nw->_multicastHistoryPtr = 0;
nw->_ready = false; // disable handling of Ethernet frames during construct nw->_ready = false; // disable handling of Ethernet frames during construct
nw->_r = renv; nw->_r = renv;
nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr()); nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());

View File

@ -52,8 +52,6 @@
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "BandwidthAccount.hpp" #include "BandwidthAccount.hpp"
#define ZT_NETWORK_MULTICAST_DEDUP_HISTORY_LENGTH 256
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
@ -585,27 +583,6 @@ public:
//return tmp; //return tmp;
} }
/**
* 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 mcGuid Multicast GUID (sender address + sender unique ID)
* @return True if multicast IS a duplicate, false otherwise
*/
inline bool multicastDeduplicate(uint64_t mcGuid)
throw()
{
Mutex::Lock _l(_lock);
for(unsigned int i=0;i<ZT_NETWORK_MULTICAST_DEDUP_HISTORY_LENGTH;++i) {
if (_multicastHistory[i] == mcGuid)
return true;
}
_multicastHistory[_multicastHistoryPtr++ % ZT_NETWORK_MULTICAST_DEDUP_HISTORY_LENGTH] = mcGuid;
return false;
}
/** /**
* @return True if this network allows bridging * @return True if this network allows bridging
*/ */
@ -621,10 +598,6 @@ private:
const RuntimeEnvironment *_r; const RuntimeEnvironment *_r;
// Ring buffer of most recently injected multicast packet GUIDs
uint64_t _multicastHistory[ZT_NETWORK_MULTICAST_DEDUP_HISTORY_LENGTH];
unsigned int _multicastHistoryPtr;
// Multicast bandwidth accounting for peers on this network // Multicast bandwidth accounting for peers on this network
std::map< std::pair<Address,MulticastGroup>,BandwidthAccount > _multicastRateAccounts; std::map< std::pair<Address,MulticastGroup>,BandwidthAccount > _multicastRateAccounts;

View File

@ -42,9 +42,9 @@ const char *Packet::verbString(Verb v)
case VERB_WHOIS: return "WHOIS"; case VERB_WHOIS: return "WHOIS";
case VERB_RENDEZVOUS: return "RENDEZVOUS"; case VERB_RENDEZVOUS: return "RENDEZVOUS";
case VERB_FRAME: return "FRAME"; case VERB_FRAME: return "FRAME";
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; case VERB_PROXY_FRAME: return "PROXY_FRAME";
case VERB_MULTICAST_GOT: return "MULTICAST_GOT";
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE"; case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";
case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";

View File

@ -98,14 +98,9 @@
#define ZT_PACKET_IDX_PAYLOAD 28 #define ZT_PACKET_IDX_PAYLOAD 28
/** /**
* ZeroTier packet buffer size * Packet buffer size (can be changed)
*
* This can be changed. This provides enough room for MTU-size packet
* payloads plus some overhead. The subtraction of sizeof(unsigned int)
* makes it an even multiple of 1024 (see Buffer), which might reduce
* memory use a little.
*/ */
#define ZT_PROTO_MAX_PACKET_LENGTH (3072 - sizeof(unsigned int)) #define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_UDP_DEFAULT_PAYLOAD_MTU)
/** /**
* Minimum viable packet length (also length of header) * Minimum viable packet length (also length of header)
@ -164,22 +159,37 @@
#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8) #define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2) #define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2)
#define ZT_PROTO_VERB_MULTICAST_GOT_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_GOT_IDX_MULTICAST_GUID (ZT_PROTO_VERB_MULTICAST_GOT_IDX_NETWORK_ID + 8) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_DEPTH 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_DEPTH)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO 320
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_QUEUE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT + 4) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE 320 #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM 1024
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_QUEUE + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET + 5) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_NETWORK_ID 8
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER_UNIQUE_ID (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER + 5) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM_NONCE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_NETWORK_ID)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER_UNIQUE_ID + 3) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM_NONCE 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX_BITS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM_NONCE + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM_NONCE)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC + 6) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_PREFIX_BITS 1
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_MAC + 6) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX_BITS + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_PREFIX_BITS)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_ADI + 4) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_PREFIX 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LENGTH (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_PREFIX)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LENGTH + 2) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN 5
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN_MCID (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN_MCID 3
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GUID (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_GUID 8
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN_MCID + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN_MCID)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_SOURCE_MAC 6
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_SOURCE_MAC)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_MAC 6
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_MAC)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_ADI 4
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_ADI)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ETHERTYPE 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME_LEN (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ETHERTYPE)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_FRAME_LEN 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LEN + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PAYLOAD_LEN)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8) #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8)
@ -459,35 +469,23 @@ public:
*/ */
VERB_FRAME = 6, VERB_FRAME = 6,
/* Announce interest in multicast group(s): /* TODO: not implemented yet */
* <[8] 64-bit network ID> VERB_PROXY_FRAME = 7,
* <[6] multicast Ethernet address>
* <[4] multicast additional distinguishing information (ADI)>
* [... additional tuples of network/address/adi ...]
*
* OK/ERROR are not generated.
*/
VERB_MULTICAST_LIKE = 7,
/* Announce receipt of a multicast to propagation magnet node:
* <[8] 64-bit network ID>
* <[8] 64-bit multicast GUID>
*
* OK/ERROR are not generated.
*/
VERB_MULTICAST_GOT = 8,
/* A multicast frame: /* A multicast frame:
* <[4] 32-bit forwarding counter> * <[2] 16-bit propagation depth>
* <[320] FIFO queue of up to 64 ZT addresses, zero address terminated> * <[320] propagation FIFO>
* [... start of signed portion, signed by original submitter below ...] * <[1024] propagation bloom filter>
* <[5] ZeroTier address of propagation magnet node> * [... begin signed portion ...]
* <[5] ZeroTier address of original submitter/signer>
* <[3] 24-bit multicast ID, combined with signer address to form GUID>
* <[8] 64-bit network ID> * <[8] 64-bit network ID>
* <[2] 16-bit random propagation bloom filter nonce>
* <[1] number of significant bits in propagation restrict prefix>
* <[2] 16-bit propagation restriction prefix (left to right)>
* <[5] ZeroTier address of node of origin>
* <[3] 24-bit multicast ID, together with origin forms GUID>
* <[6] source MAC address> * <[6] source MAC address>
* <[6] destination multicast group MAC address> * <[6] destination multicast group MAC address>
* <[4] destination multicast group 32-bit ADI field> * <[4] destination multicast group ADI field>
* <[2] 16-bit frame ethertype> * <[2] 16-bit frame ethertype>
* <[2] 16-bit length of payload> * <[2] 16-bit length of payload>
* <[...] ethernet frame payload> * <[...] ethernet frame payload>
@ -495,46 +493,57 @@ public:
* <[2] 16-bit length of signature> * <[2] 16-bit length of signature>
* <[...] signature (currently Ed25519/SHA-512, 96 bytes in length)> * <[...] signature (currently Ed25519/SHA-512, 96 bytes in length)>
* *
* Multicast frames are propagated using a graph exploration algorithm in * When a multicast frame is received:
* which the FIFO queue is embedded in the multicast packet.
* *
* Upon receipt: * (1) Check the signature of the signed portion of packet, discard on fail
* (1) packet is possibly injected into the local TAP * (2) Check for duplicate multicast, STOP if duplicate
* (2) send a MULTICAST_GOT message to magnet node with 64-bit * (3) Check rate limits, STOP if over limit
* multicast GUID * (4) Inject into tap if member of network and packet passes other checks
* (3) forwarding counter is incremented, STOP of max exceeded * (5) Increment propagation depth, STOP if over limit
* (4) topmost value is removed from FIFO and saved (next hop) * (6) Pop topmost element off FIFO -- this is next hop
* (5) deduplicate FIFO (helps prevent floods) * (7) Push suggested next hops onto FIFO until full -- set corresponding
* (6) FIFO is filled with as many known peers that have LIKED this * bits in bloom filter
* multicast group as possible, excluding peers to whom this * (8) Send to next hop, or to a supernode if none
* multicast has already been sent or (if magnet node) have GOT
* this multicast
* (7) packet is sent to next hop (if possible)
* *
* If there was no next hop -- empty FIFO -- and no new hops are known, * When choosing next hops, exclude addresses corresponding to bits already
* the packet is sent to the magnet node. The magnet node must be aware * set in the bloom filter and addresses outside the propagation restrict
* of all members of a given multicast group. It is the node responsible * prefix.
* for bridging sparse multicast groups. When other nodes receive the
* multicast, they send GOT to the magnet node so that it will not
* send it back to them.
* *
* Right now the magnet is a supernode. In the future there may be * Algorithm for setting bits in bloom filter:
* dedicated magnets and/or magnets elected via some kind of DHT or
* something to act as such for given multicast groups. This latter
* might happen if we evolve more toward a totally decentralized model
* instead of today's partially decentralized model.
* *
* The multicast GUID is formed by packing the original sender / signer * (1) Place the address in the least significant 40 bits of a 64-bit int.
* address into the most significant 5 bytes of a 64-bit big-endian * (2) Add the bloom filter nonce to this value.
* number, and then packing the 24-bit sender unique ID into the least * (3) XOR the least significant 13 bits of this value with the next most
* significant 3 bytes. This can be used to locally deduplicate, and * significant 13 bits and so on, 4 times.
* to identify the multicast in a GOT sent to the magnet. The 24-bit * (4) This value ANDed with 0x1fff is the bit to set in the bloom filter.
* ID must be unique for a given sender over recent (say, 10min) time * (5) Set this bit via: byte[bit >> 3] |= (0x80 >> (bit & 7))
* spans and across networks. Random or sequential values are fine.
* *
* OK/ERROR are not generated, but GOT is sent to magnet. * To check bits in bloom filter perform the same computation but mask the
* bit instead of ORing it.
*
* Propagation occurs within a restrict prefix. The restrict prefix is
* applied to the least significant 16 bits of an address. The original
* sender of the multicast sets the restrict prefix and sends 2^N copies
* of the multicast frame, one for each address prefix. This permits
* propagation to be partitioned into realms, and places the majority of
* the burden for this upon the sender.
*
* OK/ERROR are not generated.
*/ */
VERB_MULTICAST_FRAME = 9, VERB_MULTICAST_FRAME = 8,
/* Announce interest in multicast group(s):
* <[8] 64-bit network ID>
* <[6] multicast Ethernet address>
* <[4] multicast additional distinguishing information (ADI)>
* [... additional tuples of network/address/adi ...]
*
* LIKEs are sent to peers with whom you have a direct peer to peer
* connection, and always including supernodes.
*
* OK/ERROR are not generated.
*/
VERB_MULTICAST_LIKE = 9,
/* Network member certificate for sending peer: /* Network member certificate for sending peer:
* <[8] 64-bit network ID> * <[8] 64-bit network ID>

View File

@ -461,133 +461,136 @@ bool PacketDecoder::_doMULTICAST_GOT(const RuntimeEnvironment *_r,const SharedPt
return true; return true;
} }
// Function object used in _doMULTICAST_FRAME // Function used in _doMULTICAST_FRAME
struct _doMULTICAST_FRAME_fillQueueWithNextHops static inline unsigned int _bloomBit(const Address &a,uint16_t bloomNonce)
throw()
{ {
_doMULTICAST_FRAME_fillQueueWithNextHops(char *nq,unsigned int want) uint64_t a = a.toInt() + (uint64_t)bloomNonce;
ptr(nq), unsigned int bit = (unsigned int)(a & 0x1fff);
need(want) {} bit ^= (unsigned int)((a >> 13) & 0x1fff);
bit ^= (unsigned int)((a >> 26) & 0x1fff);
bit ^= (unsigned int)((a >> 39) & 0x1fff);
return bit;
}
// Function object used in _doMULTICAST_FRAME
struct _PushNextHops
{
_PushNextHops(unsigned char **ptr_,unsigned char *end_,unsigned char *bloom_,uint16_t bloomNonce_const Address &origin_)
ptr(ptr_),
end(end_),
bloom(bloom_),
origin(origin_),
bloomNonce(bloomNonce_) throw() {}
inline bool operator()(const Address &a) const inline bool operator()(const Address &a) const
throw() throw()
{ {
a.copyTo(ptr,ZT_ADDRESS_LENGTH); if (a == origin)
ptr += ZT_ADDRESS_LENGTH; return true;
return (--need != 0);
unsigned int bb = _bloomBit(a,bloomNonce);
unsigned char *bbyte = bloom + (bb >> 3);
unsigned char bmask = 0x80 >> (bb & 7);
if ((*bbyte & bmask))
return true;
else *bbyte |= bmask;
a.copyTo(*ptr,ZT_ADDRESS_LENGTH);
*ptr += ZT_ADDRESS_LENGTH;
return (*ptr != end);
} }
char *ptr; unsigned char **ptr;
unsigned int need; unsigned char *end;
unsigned char *bloom;
Address origin;
uint16_t bloomNonce;
}; };
bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer) bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
{ {
try { try {
unsigned int forwardCount = at<uint32_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT); Address origin(Address(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN),ZT_ADDRESS_LENGTH));
char *queue = (char *)field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_QUEUE,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE); SharedPtr<Peer> originPeer(_r->topology->getPeer(origin));
Address magnet(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); if (!originPeer) {
Address submitterAddr(Address(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH)); _r->sw->requestWhois(origin);
SharedPtr<Peer> submitter(_r->topology->getPeer(submitterAddr));
if (!submitter) {
_r->sw->requestWhois(submitterAddr);
_step = DECODE_WAITING_FOR_MULTICAST_FRAME_ORIGINAL_SENDER_LOOKUP; // causes processing to come back here _step = DECODE_WAITING_FOR_MULTICAST_FRAME_ORIGINAL_SENDER_LOOKUP; // causes processing to come back here
return false; return false;
} }
uint64_t guid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER); // 40-bit sender address + 24-bit sender unique ID
uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID);
MAC sourceMac(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6));
MulticastGroup dest(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_MAC,6)),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_ADI));
unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE);
unsigned int frameLen = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LENGTH);
unsigned char *frame = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD,frameLen);
unsigned int signatureLen = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD + frameLen);
unsigned char *signature = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD + frameLen + 2,signatureLen);
unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD - ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET) + frameLen; uint16_t depth = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH);
if (!submitter->identity().verify(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET,signedPartLen),signedPartLen,signature,signatureLen)) { unsigned char *fifo = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO);
TRACE("dropped MULTICAST_FRAME from %s(%s): failed signature verification, claims to be from %s",source().toString().c_str(),_remoteAddress.toString().c_str(),submitterAddr.toString().c_str()); unsigned char *bloom = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM);
uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID);
uint16_t bloomNonce = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM_NONCE);
unsigned int prefixBits = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX_BITS];
uint16_t prefix = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX);
uint64_t guid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GUID);
MAC sourceMac(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_SOURCE_MAC));
MulticastGroup dest(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_DEST_MAC)),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI));
unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE);
unsigned int frameLen = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME_LEN);
unsigned char *frame = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen);
unsigned int signatureLen = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen);
unsigned char *signature = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen + 2,signatureLen);
unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID) + frameLen;
if (!submitter->identity().verify(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID,signedPartLen),signedPartLen,signature,signatureLen)) {
TRACE("dropped MULTICAST_FRAME from %s(%s): failed signature verification, claims to be from %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
return true; return true;
} }
if (_r->mc->deduplicate(nwid,guid)) {
TRACE("dropped MULTICAST_FRAME from %s(%s): duplicate",source().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
bool rateLimitsExceeded = false;
SharedPtr<Network> network(_r->nc->network(nwid)); SharedPtr<Network> network(_r->nc->network(nwid));
if (network) { if (network) {
if (!network->isAllowed(submitterAddr)) { if (!network->isAllowed(submitterAddr)) {
} else if (!dest.mac().isMulticast()) { } else if (!dest.mac().isMulticast()) {
} else if ((!network->permitsBridging())&&(!submitterAddr.wouldHaveMac(sourceMac))) { } else if ((!network->permitsBridging())&&(!submitterAddr.wouldHaveMac(sourceMac))) {
} else if (!network->permitsEtherType(etherType)) { } else if (!network->permitsEtherType(etherType)) {
} else if (network->multicastDeduplicate(guid)) {
} else if (network->updateAndCheckMulticastBalance(submitterAddr,dest,frameLen)) { } else if (network->updateAndCheckMulticastBalance(submitterAddr,dest,frameLen)) {
network->tap().put(sourceMac,dest.mac(),etherType,frame,frameLen); network->tap().put(sourceMac,dest.mac(),etherType,frame,frameLen);
} } else rateLimitsExceeded = true;
} }
if (magnet != _r->identity.address()) { if ((rateLimitsExceeded)&&(!_r->topology->amSupernode())) {
Packet outp(magnet,_r->identity.address(),Packet::VERB_MULTICAST_GOT); TRACE("dropped MULTICAST_FRAME from %s(%s): rate limit exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
outp.append(nwid); return true;
outp.append(guid);
_r->sw->send(outp,true);
} }
setAt(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT,(uint32_t)++forwardCount); ++depth; // TODO: implement max depth
setAt(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH,(uint16_t)depth);
char newQueue[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE + ZT_ADDRESS_LENGTH]; // room for an extra if we need a nextHop // New FIFO with room for one extra, since head will be next hop
unsigned int newQueueLen = 0; unsigned char newFifo[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO + ZT_ADDRESS_LENGTH];
unsigned char *newFifoPtr = newFifo;
// Top of FIFO is next hop (if there is one) unsigned char *newFifoEnd = newFifoPtr + sizeof(newFifo);
Address nextHop(queue,ZT_ADDRESS_LENGTH); for(unsigned int i=0;i<ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO;) {
unsigned char zm = 0;
// Deduplicate the rest of the queue[], adding them to newQueue unsigned int j = i;
if (nextHop) { // there was a next hop, so there was something there i += ZT_ADDRESS_LENGTH;
char firstByteSeen[256]; while (j != i)
for(unsigned int j=0;j<(256 / 8);++j) zm |= (*(newFifoPtr++) = fifo[j++]);
((uint64_t *)firstByteSeen)[j] = 0; if (!zm) // stop at zero address
for(unsigned int i=ZT_ADDRESS_LENGTH;i<ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE;i+=ZT_ADDRESS_LENGTH) { break;
char *qs = queue + i;
if (Utils::isZero(qs,ZT_ADDRESS_LENGTH)) // zero terminates queue
break;
bool isdup = false;
if (firstByteSeen[(unsigned int)queue[i]]) {
for(unsigned int i2=ZT_ADDRESS_LENGTH;i2<ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE;i2+=ZT_ADDRESS_LENGTH) {
if ((i2 != i)&&(!memcmp(qs,queue + i2,ZT_ADDRESS_LENGTH))) {
isdup = true;
break;
}
}
} else firstByteSeen[(unsigned int)queue[i]] = 1;
if (!isdup) {
char *nq = newQueue + (newQueueLen++ * ZT_ADDRESS_LENGTH);
for(unsigned int j=0;j<ZT_ADDRESS_LENGTH;++j)
nq[j] = qs[j];
}
}
} }
// Get next hops, including an extra if we don't have a next hop yet // Fill remaining part of new fifo
unsigned int needQueueItems = ((ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE / ZT_ADDRESS_LENGTH) - newQueueLen); _r->mc->getNextHops(nwid,dest,_PushNextHops(&newFifoPtr,newFifoEnd,bloom,bloomNonce,origin));
if (!nextHop)
++needQueueItems;
if (needQueueItems)
newQueueLen += _r->mc->getNextHops(nwid,dest,guid,_doMULTICAST_FRAME_fillQueueWithNextHops(newQueue,needQueueItems));
// Copy new queue over old queue, and pick off next hop if we need one // Zero-terminate new FIFO if not completely full
if (newQueueLen) { while (newFifoPtr != newFifoEnd)
char *nq = newQueue; *(newFifoPtr++) = (unsigned char)0;
if (!nextHop) {
nextHop.setTo(nq,ZT_ADDRESS_LENGTH);
nq += ZT_ADDRESS_LENGTH;
--newQueueLen;
}
unsigned int i = 0;
unsigned int k = ZT_ADDRESS_LENGTH * newQueueLen;
while (i < k)
nq[i] = newQueue[i];
while (i < ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE)
nq[i] = 0;
} else memset(queue,0,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE);
// If there's still no next hop, it's the magnet // First element in newFifo[] is next hop
if (!nextHop) Address nextHop(newFifo,ZT_ADDRESS_LENGTH);
nextHop = magnet;
// Send to next hop, unless it's us of course // Send to next hop, unless it's us of course
if (nextHop != _r->identity.address()) { if (nextHop != _r->identity.address()) {

View File

@ -33,7 +33,7 @@
namespace ZeroTier { namespace ZeroTier {
#define ZT_KISSDB_HASH_TABLE_SIZE 131072 #define ZT_KISSDB_HASH_TABLE_SIZE 32768
#define ZT_KISSDB_KEY_SIZE ZT_ADDRESS_LENGTH #define ZT_KISSDB_KEY_SIZE ZT_ADDRESS_LENGTH
#define ZT_KISSDB_VALUE_SIZE ZT_PEER_MAX_SERIALIZED_LENGTH #define ZT_KISSDB_VALUE_SIZE ZT_PEER_MAX_SERIALIZED_LENGTH