diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-09-26 17:45:19 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-09-26 17:45:19 -0400 |
commit | 4e010da54b3d660376e4d583a2ca3e8befd60899 (patch) | |
tree | ffcd242ca205bb351556b7ba6e24232451042ccc | |
parent | 24bad9f3d1119c4bf80e28f33d4241c7e6221877 (diff) | |
download | infinitytier-4e010da54b3d660376e4d583a2ca3e8befd60899.tar.gz infinitytier-4e010da54b3d660376e4d583a2ca3e8befd60899.zip |
Work in progress...
-rw-r--r-- | node/Address.hpp | 9 | ||||
-rw-r--r-- | node/Constants.hpp | 10 | ||||
-rw-r--r-- | node/Multicaster.cpp | 17 | ||||
-rw-r--r-- | node/Multicaster.hpp | 59 | ||||
-rw-r--r-- | node/Network.cpp | 2 | ||||
-rw-r--r-- | node/Network.hpp | 27 | ||||
-rw-r--r-- | node/Packet.cpp | 4 | ||||
-rw-r--r-- | node/Packet.hpp | 171 | ||||
-rw-r--r-- | node/PacketDecoder.cpp | 187 | ||||
-rw-r--r-- | node/Topology.cpp | 2 |
10 files changed, 231 insertions, 257 deletions
diff --git a/node/Address.hpp b/node/Address.hpp index 51dd84ec..034bc144 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -232,15 +232,6 @@ public: 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 * * The all-zero null address and any address beginning with 0xff are diff --git a/node/Constants.hpp b/node/Constants.hpp index a46937ed..f7000bfe 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -231,6 +231,11 @@ error_no_ZT_ARCH_defined; #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 * * Announcement occurs when a multicast group is locally joined, but all @@ -245,11 +250,6 @@ error_no_ZT_ARCH_defined; #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 */ #define ZT_MULTICAST_LOCAL_POLL_PERIOD 10000 diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index e545289e..36fd98fd 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -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() { Mutex::Lock _l(_lock); @@ -92,14 +83,8 @@ void Multicaster::clean() uint64_t now = Utils::now(); 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();) { - 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)); p->second.erase(s->second.proximitySlot); if (p->second.empty()) diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index fb9bfe2d..2979bc3b 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -41,6 +41,7 @@ #include "Mutex.hpp" #include "MulticastGroup.hpp" #include "Address.hpp" +#include "Buffer.hpp" namespace ZeroTier { @@ -73,20 +74,32 @@ public: 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 + * Erase entries for expired LIKEs and GOT records */ - void got(uint64_t nwid,const Address &peer,uint64_t mcGuid); + void clean(); /** - * Erase entries for expired LIKEs and GOT records + * 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 */ - void clean(); + 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 @@ -96,12 +109,11 @@ public: * * @param nwid Network ID * @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 * @return Number of results returned through function */ 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); @@ -111,16 +123,11 @@ public: std::map< MulticastGroup,std::list< Address > >::iterator p(n->second.proximity.find(mg)); if (p == n->second.proximity.end()) return 0; - std::pair< uint64_t,std::set< Address > > &g = n->second.got[mcGuid]; - g.first = Utils::now(); unsigned int cnt = 0; for(std::list< Address >::iterator a(p->second.begin());a!=p->second.end();++a) { - if (g.second.insert(*a).second) { - ++cnt; - if (!nextHopFunc(*a)) - break; - } + if (!nextHopFunc(*a)) + break; } return cnt; } @@ -141,13 +148,21 @@ private: }; // An address and multicast group tuple - typedef std::pair<Address,MulticastGroup> _Subscription; + typedef std::pair< Address,MulticastGroup > _Subscription; // Multicast info for a given network struct _NetInfo { - // GOTs by multicast GUID: time of last GOT, addresses that GOT - std::map< uint64_t,std::pair< uint64_t,std::set< Address > > > got; + _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; diff --git a/node/Network.cpp b/node/Network.cpp index bfc4b013..65e61738 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -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 // being constructed. C++ edge cases, how I love thee. 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->_r = renv; nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr()); diff --git a/node/Network.hpp b/node/Network.hpp index 993ee6a6..2ed70504 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -52,8 +52,6 @@ #include "InetAddress.hpp" #include "BandwidthAccount.hpp" -#define ZT_NETWORK_MULTICAST_DEDUP_HISTORY_LENGTH 256 - namespace ZeroTier { class RuntimeEnvironment; @@ -586,27 +584,6 @@ public: } /** - * 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 */ inline bool permitsBridging() const @@ -621,10 +598,6 @@ private: 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 std::map< std::pair<Address,MulticastGroup>,BandwidthAccount > _multicastRateAccounts; diff --git a/node/Packet.cpp b/node/Packet.cpp index f9731752..46c55c99 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -42,9 +42,9 @@ const char *Packet::verbString(Verb v) case VERB_WHOIS: return "WHOIS"; case VERB_RENDEZVOUS: return "RENDEZVOUS"; case VERB_FRAME: return "FRAME"; - case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; - case VERB_MULTICAST_GOT: return "MULTICAST_GOT"; + case VERB_PROXY_FRAME: return "PROXY_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_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH"; diff --git a/node/Packet.hpp b/node/Packet.hpp index 0aa6b949..9a90427f 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -98,14 +98,9 @@ #define ZT_PACKET_IDX_PAYLOAD 28 /** - * ZeroTier packet buffer size - * - * 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. + * Packet buffer size (can be changed) */ -#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) @@ -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_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_GOT_IDX_MULTICAST_GUID (ZT_PROTO_VERB_MULTICAST_GOT_IDX_NETWORK_ID + 8) - -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_QUEUE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT + 4) -#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE 320 -#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_SUBMITTER (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET + 5) -#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_NETWORK_ID (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER_UNIQUE_ID + 3) -#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_DESTINATION_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC + 6) -#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_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DESTINATION_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LENGTH (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PAYLOAD_LENGTH + 2) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH (ZT_PACKET_IDX_PAYLOAD) +#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_LEN_PROPAGATION_FIFO 320 +#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_PROPAGATION_BLOOM 1024 +#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_LEN_NETWORK_ID 8 +#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_LEN_PROPAGATION_BLOOM_NONCE 2 +#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_LEN_PROPAGATION_PREFIX_BITS 1 +#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_LEN_PROPAGATION_PREFIX 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_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_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8) @@ -459,35 +469,23 @@ public: */ VERB_FRAME = 6, - /* 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 ...] - * - * 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, + /* TODO: not implemented yet */ + VERB_PROXY_FRAME = 7, /* A multicast frame: - * <[4] 32-bit forwarding counter> - * <[320] FIFO queue of up to 64 ZT addresses, zero address terminated> - * [... start of signed portion, signed by original submitter below ...] - * <[5] ZeroTier address of propagation magnet node> - * <[5] ZeroTier address of original submitter/signer> - * <[3] 24-bit multicast ID, combined with signer address to form GUID> + * <[2] 16-bit propagation depth> + * <[320] propagation FIFO> + * <[1024] propagation bloom filter> + * [... begin signed portion ...] * <[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] 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 length of payload> * <[...] ethernet frame payload> @@ -495,46 +493,57 @@ public: * <[2] 16-bit length of signature> * <[...] signature (currently Ed25519/SHA-512, 96 bytes in length)> * - * Multicast frames are propagated using a graph exploration algorithm in - * which the FIFO queue is embedded in the multicast packet. + * When a multicast frame is received: * - * Upon receipt: - * (1) packet is possibly injected into the local TAP - * (2) send a MULTICAST_GOT message to magnet node with 64-bit - * multicast GUID - * (3) forwarding counter is incremented, STOP of max exceeded - * (4) topmost value is removed from FIFO and saved (next hop) - * (5) deduplicate FIFO (helps prevent floods) - * (6) FIFO is filled with as many known peers that have LIKED this - * multicast group as possible, excluding peers to whom this - * multicast has already been sent or (if magnet node) have GOT - * this multicast - * (7) packet is sent to next hop (if possible) + * (1) Check the signature of the signed portion of packet, discard on fail + * (2) Check for duplicate multicast, STOP if duplicate + * (3) Check rate limits, STOP if over limit + * (4) Inject into tap if member of network and packet passes other checks + * (5) Increment propagation depth, STOP if over limit + * (6) Pop topmost element off FIFO -- this is next hop + * (7) Push suggested next hops onto FIFO until full -- set corresponding + * bits in bloom filter + * (8) Send to next hop, or to a supernode if none * - * If there was no next hop -- empty FIFO -- and no new hops are known, - * the packet is sent to the magnet node. The magnet node must be aware - * of all members of a given multicast group. It is the node responsible - * 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. + * When choosing next hops, exclude addresses corresponding to bits already + * set in the bloom filter and addresses outside the propagation restrict + * prefix. * - * Right now the magnet is a supernode. In the future there may be - * 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. + * Algorithm for setting bits in bloom filter: * - * The multicast GUID is formed by packing the original sender / signer - * address into the most significant 5 bytes of a 64-bit big-endian - * number, and then packing the 24-bit sender unique ID into the least - * significant 3 bytes. This can be used to locally deduplicate, and - * to identify the multicast in a GOT sent to the magnet. The 24-bit - * ID must be unique for a given sender over recent (say, 10min) time - * spans and across networks. Random or sequential values are fine. + * (1) Place the address in the least significant 40 bits of a 64-bit int. + * (2) Add the bloom filter nonce to this value. + * (3) XOR the least significant 13 bits of this value with the next most + * significant 13 bits and so on, 4 times. + * (4) This value ANDed with 0x1fff is the bit to set in the bloom filter. + * (5) Set this bit via: byte[bit >> 3] |= (0x80 >> (bit & 7)) * - * 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 = 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_FRAME = 9, + VERB_MULTICAST_LIKE = 9, /* Network member certificate for sending peer: * <[8] 64-bit network ID> diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 0a360a1f..dc2fe226 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -461,133 +461,136 @@ bool PacketDecoder::_doMULTICAST_GOT(const RuntimeEnvironment *_r,const SharedPt return true; } +// Function used in _doMULTICAST_FRAME +static inline unsigned int _bloomBit(const Address &a,uint16_t bloomNonce) + throw() +{ + uint64_t a = a.toInt() + (uint64_t)bloomNonce; + unsigned int bit = (unsigned int)(a & 0x1fff); + 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 _doMULTICAST_FRAME_fillQueueWithNextHops +struct _PushNextHops { - _doMULTICAST_FRAME_fillQueueWithNextHops(char *nq,unsigned int want) - ptr(nq), - need(want) {} + _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 throw() { - a.copyTo(ptr,ZT_ADDRESS_LENGTH); - ptr += ZT_ADDRESS_LENGTH; - return (--need != 0); + if (a == origin) + return true; + + 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 int need; + unsigned char **ptr; + unsigned char *end; + unsigned char *bloom; + Address origin; + uint16_t bloomNonce; }; bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer) { try { - unsigned int forwardCount = at<uint32_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT); - char *queue = (char *)field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_QUEUE,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE); - Address magnet(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - Address submitterAddr(Address(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH)); - SharedPtr<Peer> submitter(_r->topology->getPeer(submitterAddr)); - if (!submitter) { - _r->sw->requestWhois(submitterAddr); + Address origin(Address(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ORIGIN,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_ORIGIN),ZT_ADDRESS_LENGTH)); + SharedPtr<Peer> originPeer(_r->topology->getPeer(origin)); + if (!originPeer) { + _r->sw->requestWhois(origin); _step = DECODE_WAITING_FOR_MULTICAST_FRAME_ORIGINAL_SENDER_LOOKUP; // causes processing to come back here return false; } - uint64_t guid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SUBMITTER); // 40-bit sender address + 24-bit sender unique ID + + uint16_t depth = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH); + unsigned char *fifo = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO); + 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); - 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)); + 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_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; - if (!submitter->identity().verify(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_MAGNET,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(),submitterAddr.toString().c_str()); + 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; + } + + 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)); if (network) { if (!network->isAllowed(submitterAddr)) { } else if (!dest.mac().isMulticast()) { } else if ((!network->permitsBridging())&&(!submitterAddr.wouldHaveMac(sourceMac))) { } else if (!network->permitsEtherType(etherType)) { - } else if (network->multicastDeduplicate(guid)) { } else if (network->updateAndCheckMulticastBalance(submitterAddr,dest,frameLen)) { network->tap().put(sourceMac,dest.mac(),etherType,frame,frameLen); - } + } else rateLimitsExceeded = true; } - if (magnet != _r->identity.address()) { - Packet outp(magnet,_r->identity.address(),Packet::VERB_MULTICAST_GOT); - outp.append(nwid); - outp.append(guid); - _r->sw->send(outp,true); + if ((rateLimitsExceeded)&&(!_r->topology->amSupernode())) { + 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()); + return true; } - setAt(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FORWARD_COUNT,(uint32_t)++forwardCount); - - char newQueue[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE + ZT_ADDRESS_LENGTH]; // room for an extra if we need a nextHop - unsigned int newQueueLen = 0; - - // Top of FIFO is next hop (if there is one) - Address nextHop(queue,ZT_ADDRESS_LENGTH); - - // Deduplicate the rest of the queue[], adding them to newQueue - if (nextHop) { // there was a next hop, so there was something there - char firstByteSeen[256]; - for(unsigned int j=0;j<(256 / 8);++j) - ((uint64_t *)firstByteSeen)[j] = 0; - for(unsigned int i=ZT_ADDRESS_LENGTH;i<ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE;i+=ZT_ADDRESS_LENGTH) { - 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]; - } - } + ++depth; // TODO: implement max depth + setAt(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH,(uint16_t)depth); + + // New FIFO with room for one extra, since head will be next hop + unsigned char newFifo[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO + ZT_ADDRESS_LENGTH]; + unsigned char *newFifoPtr = newFifo; + unsigned char *newFifoEnd = newFifoPtr + sizeof(newFifo); + for(unsigned int i=0;i<ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO;) { + unsigned char zm = 0; + unsigned int j = i; + i += ZT_ADDRESS_LENGTH; + while (j != i) + zm |= (*(newFifoPtr++) = fifo[j++]); + if (!zm) // stop at zero address + break; } - // Get next hops, including an extra if we don't have a next hop yet - unsigned int needQueueItems = ((ZT_PROTO_VERB_MULTICAST_FRAME_LEN_QUEUE / ZT_ADDRESS_LENGTH) - newQueueLen); - 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 - if (newQueueLen) { - char *nq = newQueue; - 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 - if (!nextHop) - nextHop = magnet; + // Fill remaining part of new fifo + _r->mc->getNextHops(nwid,dest,_PushNextHops(&newFifoPtr,newFifoEnd,bloom,bloomNonce,origin)); + + // Zero-terminate new FIFO if not completely full + while (newFifoPtr != newFifoEnd) + *(newFifoPtr++) = (unsigned char)0; + + // First element in newFifo[] is next hop + Address nextHop(newFifo,ZT_ADDRESS_LENGTH); // Send to next hop, unless it's us of course if (nextHop != _r->identity.address()) { diff --git a/node/Topology.cpp b/node/Topology.cpp index f830cbb6..0185147e 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -33,7 +33,7 @@ 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_VALUE_SIZE ZT_PEER_MAX_SERIALIZED_LENGTH |