summaryrefslogtreecommitdiff
path: root/node/Multicaster.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Multicaster.hpp')
-rw-r--r--node/Multicaster.hpp84
1 files changed, 48 insertions, 36 deletions
diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp
index 9a7000af..b3c16185 100644
--- a/node/Multicaster.hpp
+++ b/node/Multicaster.hpp
@@ -52,7 +52,7 @@
#include "Identity.hpp"
// Maximum sample size to pick during choice of multicast propagation peers
-#define ZT_MULTICAST_PICK_MAX_SAMPLE_SIZE 64
+#define ZT_MULTICAST_PICK_MAX_SAMPLE_SIZE 32
namespace ZeroTier {
@@ -75,6 +75,7 @@ public:
throw()
{
memset(_multicastHistory,0,sizeof(_multicastHistory));
+ _multicastHistoryPtr = 0;
}
/**
@@ -131,55 +132,68 @@ public:
}
/**
- * Check multicast history to see if this is a duplicate, and add/update entry
+ * Compute the CRC64 code for multicast deduplication
*
- * @param from Ultimate sending MAC address
- * @param to Destination multicast group
- * @param payload Multicast packet payload
- * @param len Length of packet
* @param nwid Network ID
- * @param now Current time
- * @return True if this appears to be a duplicate to within history expiration time
+ * @param from Sender MAC
+ * @param to Destination multicast group
+ * @param etherType Ethernet frame type
+ * @param payload Multicast frame data
+ * @param len Length of frame
*/
- inline bool checkAndUpdateMulticastHistory(
+ static inline uint64_t computeMulticastDedupCrc(
+ uint64_t nwid,
const MAC &from,
const MulticastGroup &to,
+ unsigned int etherType,
const void *payload,
- unsigned int len,
- const uint64_t nwid,
- const uint64_t now)
+ unsigned int len)
throw()
{
- // Note: CRCs aren't transmitted over the network, so portability and
- // byte order don't matter. This calculation can be changed. We just
- // want a unique code.
+ // This CRC is only used locally, so byte order issues and
+ // such don't matter. It can also be changed without protocol
+ // impact.
uint64_t crc = Utils::crc64(0,from.data,6);
crc = Utils::crc64(crc,to.mac().data,6);
crc ^= (uint64_t)to.adi();
+ crc ^= (uint64_t)etherType;
crc = Utils::crc64(crc,payload,len);
crc ^= nwid; // also include network ID in CRC
+ return crc;
+ }
- // Replace existing entry or pick one to replace with new entry
- uint64_t earliest = 0xffffffffffffffffULL;
- unsigned long earliestIdx = 0;
+ /**
+ * Check multicast history to see if this is a duplicate
+ *
+ * @param crc Multicast CRC
+ * @param now Current time
+ * @return True if this appears to be a duplicate to within history expiration time
+ */
+ inline bool checkDuplicate(uint64_t crc,uint64_t now) const
+ throw()
+ {
for(unsigned int i=0;i<ZT_MULTICAST_DEDUP_HISTORY_LENGTH;++i) {
- if (_multicastHistory[i][0] == crc) {
- uint64_t then = _multicastHistory[i][1];
- _multicastHistory[i][1] = now;
- return ((now - then) < ZT_MULTICAST_DEDUP_HISTORY_EXPIRE);
- } else if (_multicastHistory[i][1] < earliest) {
- earliest = _multicastHistory[i][1];
- earliestIdx = i;
- }
+ if ((_multicastHistory[i][0] == crc)&&((now - _multicastHistory[i][1]) < ZT_MULTICAST_DEDUP_HISTORY_EXPIRE))
+ return true;
}
-
- _multicastHistory[earliestIdx][0] = crc; // replace oldest entry
- _multicastHistory[earliestIdx][1] = now;
-
return false;
}
/**
+ * Add a multicast CRC to the multicast deduplication history
+ *
+ * @param crc Multicast CRC
+ * @param now Current time
+ */
+ inline void addToDedupHistory(uint64_t crc,uint64_t now)
+ throw()
+ {
+ unsigned int mhi = ++_multicastHistoryPtr % ZT_MULTICAST_DEDUP_HISTORY_LENGTH;
+ _multicastHistory[mhi][0] = crc;
+ _multicastHistory[mhi][1] = now;
+ }
+
+ /**
* Choose peers to send a propagating multicast to
*
* @param topology Topology object or mock thereof
@@ -248,7 +262,7 @@ public:
// a fact they've already seen this.
if ((channelMemberEntry->first != originalSubmitter)&&(channelMemberEntry->first != upstream)) {
P peer = topology.getPeer(channelMemberEntry->first);
- if (peer) {
+ if ((peer)&&(peer->hasActiveDirectPath(now))) {
toConsider[sampleSize++] = peer;
if (sampleSize >= ZT_MULTICAST_PICK_MAX_SAMPLE_SIZE)
break; // abort if we have enough candidates
@@ -289,10 +303,7 @@ public:
// Add a supernode if there's nowhere else to go. Supernodes know of all multicast
// LIKEs and so can act to bridge sparse multicast groups.
if (!picked) {
- Address avoid[2];
- avoid[0] = upstream;
- avoid[1] = originalSubmitter; // otherwise supernodes will play ping pong
- P peer = topology.getBestSupernode(avoid,2,true);
+ P peer = topology.getBestSupernode(&originalSubmitter,1,true);
if (peer)
peers[picked++] = peer;
}
@@ -334,8 +345,9 @@ private:
SHA256_Final(digest,&sha);
}
- // [0] - CRC, [1] - timestamp
+ // ring buffer: [0] - CRC, [1] - timestamp
uint64_t _multicastHistory[ZT_MULTICAST_DEDUP_HISTORY_LENGTH][2];
+ volatile unsigned int _multicastHistoryPtr;
// A multicast channel, essentially a pub/sub channel. It consists of a
// network ID and a multicast group within that network.