Browse Source

Multicast propagation is now working from non-supernodes, and working quite well. Time for some more simulation before 0.5.0!

Adam Ierymenko 12 years ago
parent
commit
2cfa76fa8b
5 changed files with 71 additions and 44 deletions
  1. 2 0
      node/Multicaster.cpp
  2. 1 1
      node/Multicaster.hpp
  3. 39 25
      node/PacketDecoder.cpp
  4. 21 9
      node/Peer.hpp
  5. 8 9
      node/Switch.cpp

+ 2 - 0
node/Multicaster.cpp

@@ -25,6 +25,8 @@
  * LLC. Start here: http://www.zerotier.com/
  */
 
+#include <stdio.h>
+
 #include "Constants.hpp"
 #include "Multicaster.hpp"
 #include "Utils.hpp"

+ 1 - 1
node/Multicaster.hpp

@@ -177,7 +177,7 @@ public:
 			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 = 0x80 >> (bit & 7);
+			const unsigned char bmask = 1 << (bit & 7);
 			if ((*bbyte & bmask))
 				return true;
 			else *bbyte |= bmask;

+ 39 - 25
node/PacketDecoder.cpp

@@ -25,6 +25,10 @@
  * LLC. Start here: http://www.zerotier.com/
  */
 
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
 #include "../version.h"
 
 #include "Constants.hpp"
@@ -463,23 +467,27 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			return false;
 		}
 
+		// These fields change
 		unsigned int 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);
-		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];
-		unsigned int prefix = (*this)[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__START_OF_SIGNED_PORTION) + frameLen;
+		unsigned char *const fifo = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO);
+		unsigned char *const bloom = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM);
+
+		// These fields don't -- they're signed by the original sender
+		// const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS];
+		const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID);
+		const uint16_t bloomNonce = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_BLOOM_NONCE);
+		const unsigned int prefixBits = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX_BITS];
+		const unsigned int prefix = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_PREFIX];
+		const uint64_t guid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GUID);
+		const MAC sourceMac(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_SOURCE_MAC));
+		const 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));
+		const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE);
+		const unsigned int frameLen = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME_LEN);
+		const unsigned char *const frame = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen);
+		const unsigned int signatureLen = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen);
+		const unsigned char *const signature = field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME + frameLen + 2,signatureLen);
+
+		const unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + frameLen;
 		if (!originPeer->identity().verify(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION,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;
@@ -491,6 +499,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 		_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
 #endif
 
+		// Security check to prohibit multicasts that are really Ethernet unicasts
 		if (!dest.mac().isMulticast()) {
 			TRACE("dropped MULTICAST_FRAME from %s(%s): %s is not a multicast/broadcast address",source().toString().c_str(),_remoteAddress.toString().c_str(),dest.mac().toString().c_str());
 			return true;
@@ -564,15 +573,20 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 		// 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 *const newFifoEnd = newFifoPtr + sizeof(newFifo);
-		for(unsigned int i=0;i<ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO;) {
-			unsigned int j = i;
-			i += ZT_ADDRESS_LENGTH;
-			unsigned char zm = 0;
-			while (j != i)
-				zm |= (*(newFifoPtr++) = fifo[j++]);
-			if (!zm) // stop at zero address
-				break;
+		unsigned char *const newFifoEnd = newFifo + sizeof(newFifo);
+
+		// Copy old FIFO into new buffer, terminating at first NULL address
+		for(unsigned char *f=fifo,*const fifoEnd=(fifo + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO);f!=fifoEnd;) {
+			unsigned char *nf = newFifoPtr;
+			unsigned char *e = nf + ZT_ADDRESS_LENGTH;
+			unsigned char *ftmp = f;
+			unsigned char zeroCheckMask = 0;
+			while (nf != e)
+				zeroCheckMask |= (*(nf++) = *(ftmp++));
+			if (zeroCheckMask) {
+				f = ftmp;
+				newFifoPtr = nf;
+			} else break;
 		}
 
 		// Add any next hops we know about to FIFO

+ 21 - 9
node/Peer.hpp

@@ -162,7 +162,7 @@ public:
 	/**
 	 * @return Last successfully sent firewall opener
 	 */
-	uint64_t lastFirewallOpener() const
+	inline uint64_t lastFirewallOpener() const
 		throw()
 	{
 		return std::max(_ipv4p.lastFirewallOpener,_ipv6p.lastFirewallOpener);
@@ -171,7 +171,7 @@ public:
 	/**
 	 * @return Time of last direct packet receive
 	 */
-	uint64_t lastDirectReceive() const
+	inline uint64_t lastDirectReceive() const
 		throw()
 	{
 		return std::max(_ipv4p.lastReceive,_ipv6p.lastReceive);
@@ -180,7 +180,7 @@ public:
 	/**
 	 * @return Time of last direct packet send
 	 */
-	uint64_t lastDirectSend() const
+	inline uint64_t lastDirectSend() const
 		throw()
 	{
 		return std::max(_ipv4p.lastSend,_ipv6p.lastSend);
@@ -189,7 +189,7 @@ public:
 	/**
 	 * @return Time of most recent unicast frame received
 	 */
-	uint64_t lastUnicastFrame() const
+	inline uint64_t lastUnicastFrame() const
 		throw()
 	{
 		return _lastUnicastFrame;
@@ -198,7 +198,7 @@ public:
 	/**
 	 * @return Time of most recent multicast frame received
 	 */
-	uint64_t lastMulticastFrame() const
+	inline uint64_t lastMulticastFrame() const
 		throw()
 	{
 		return _lastMulticastFrame;
@@ -207,7 +207,7 @@ public:
 	/**
 	 * @return Time of most recent frame of any kind (unicast or multicast)
 	 */
-	uint64_t lastFrame() const
+	inline uint64_t lastFrame() const
 		throw()
 	{
 		return std::max(_lastUnicastFrame,_lastMulticastFrame);
@@ -216,16 +216,28 @@ public:
 	/**
 	 * @return Time we last announced state TO this peer, such as multicast LIKEs
 	 */
-	uint64_t lastAnnouncedTo() const
+	inline uint64_t lastAnnouncedTo() const
 		throw()
 	{
 		return _lastAnnouncedTo;
 	}
 
+	/**
+	 * Set the time of last announcement
+	 *
+	 * @param t Time, typically current
+	 */
+	inline void setLastAnnouncedTo(const uint64_t t)
+		throw()
+	{
+		_lastAnnouncedTo = t;
+		_dirty = true;
+	}
+
 	/**
 	 * @return Lowest of measured latencies of all paths or 0 if unknown
 	 */
-	unsigned int latency() const
+	inline unsigned int latency() const
 		throw()
 	{
 		if (_ipv4p.latency) {
@@ -241,7 +253,7 @@ public:
 	 * @param addr Remote address
 	 * @param latency Latency measurment
 	 */
-	void setLatency(const InetAddress &addr,unsigned int latency)
+	inline void setLatency(const InetAddress &addr,unsigned int latency)
 	{
 		if (addr == _ipv4p.addr) {
 			_ipv4p.latency = latency;

+ 8 - 9
node/Switch.cpp

@@ -107,27 +107,27 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 				mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(data.field(24,4),4,0));
 		}
 
-		unsigned int mcid = ++_multicastIdCounter & 0xffffff;
-		uint16_t bloomNonce = (uint16_t)_r->prng->next32(); // doesn't need to be cryptographically strong
+		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];
 		unsigned char fifo[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO + ZT_ADDRESS_LENGTH];
+		unsigned char *const fifoEnd = fifo + sizeof(fifo);
+		const unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + data.size();
+		const SharedPtr<Peer> supernode(_r->topology->getBestSupernode());
 
 		for(unsigned int prefix=0,np=((unsigned int)2 << (network->multicastPrefixBits() - 1));prefix<np;++prefix) {
 			memset(bloom,0,sizeof(bloom));
 
 			unsigned char *fifoPtr = fifo;
-			unsigned char *fifoEnd = fifo + sizeof(fifo);
-
 			_r->mc->getNextHops(network->id(),mg,Multicaster::AddToPropagationQueue(&fifoPtr,fifoEnd,bloom,bloomNonce,_r->identity.address(),network->multicastPrefixBits(),prefix));
 			while (fifoPtr != fifoEnd)
 				*(fifoPtr++) = (unsigned char)0;
 
 			Address firstHop(fifo,ZT_ADDRESS_LENGTH); // fifo is +1 in size, with first element being used here
 			if (!firstHop) {
-				SharedPtr<Peer> sn(_r->topology->getBestSupernode());
-				if (sn)
-					firstHop = sn->address();
-				else break;
+				if (supernode)
+					firstHop = supernode->address();
+				else continue;
 			}
 
 			Packet outp(firstHop,_r->identity.address(),Packet::VERB_MULTICAST_FRAME);
@@ -150,7 +150,6 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 			outp.append((uint16_t)data.size());
 			outp.append(data);
 
-			unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + data.size();
 			C25519::Signature sig(_r->identity.sign(outp.field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION,signedPartLen),signedPartLen));
 			outp.append((uint16_t)sig.size());
 			outp.append(sig.data,sig.size());