Selaa lähdekoodia

Each peer now tracks the last time it announced multicast LIKEs independently and does so frequently enough to prevent expires. Also add a multicast debug facility for use on the testnet.

Adam Ierymenko 12 vuotta sitten
vanhempi
commit
3443b203e4
10 muutettua tiedostoa jossa 105 lisäystä ja 40 poistoa
  1. 1 10
      node/Constants.hpp
  2. 3 0
      node/Defaults.cpp
  3. 8 0
      node/Defaults.hpp
  4. 6 0
      node/InetAddress.hpp
  5. 5 18
      node/Node.cpp
  6. 14 2
      node/PacketDecoder.cpp
  7. 7 0
      node/Peer.cpp
  8. 22 8
      node/Peer.hpp
  9. 25 0
      node/Switch.cpp
  10. 14 2
      node/Switch.hpp

+ 1 - 10
node/Constants.hpp

@@ -250,19 +250,10 @@ error_no_ZT_ARCH_defined;
  */
 #define ZT_MULTICAST_GLOBAL_MAX_DEPTH 500
 
-/**
- * Period between announcements of all multicast 'likes' in ms
- *
- * Announcement occurs when a multicast group is locally joined, but all
- * memberships are periodically re-broadcast. If they're not they will
- * expire.
- */
-#define ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD 120000
-
 /**
  * Expire time for multicast 'likes' in ms
  */
-#define ZT_MULTICAST_LIKE_EXPIRE ((ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD * 2) + 1000)
+#define ZT_MULTICAST_LIKE_EXPIRE 120000
 
 /**
  * Time between polls of local taps for multicast membership changes

+ 3 - 0
node/Defaults.cpp

@@ -101,6 +101,9 @@ static inline std::string _mkDefaultHomePath()
 
 Defaults::Defaults()
 	throw(std::runtime_error) :
+#ifdef ZT_TRACE_MULTICAST
+	multicastTraceWatcher(ZT_TRACE_MULTICAST),
+#endif
 	defaultHomePath(_mkDefaultHomePath()),
 	supernodes(_mkSupernodeMap())
 {

+ 8 - 0
node/Defaults.hpp

@@ -33,6 +33,7 @@
 #include <vector>
 #include <map>
 
+#include "Constants.hpp"
 #include "Identity.hpp"
 #include "InetAddress.hpp"
 
@@ -52,6 +53,13 @@ public:
 		throw(std::runtime_error);
 	~Defaults() {}
 
+#ifdef ZT_TRACE_MULTICAST
+	/**
+	 * Host to send UDP multicast trace messages to (human readable)
+	 */
+	const InetAddress multicastTraceWatcher;
+#endif
+
 	/**
 	 * Default home path for this platform
 	 */

+ 6 - 0
node/InetAddress.hpp

@@ -109,6 +109,12 @@ public:
 		this->fromString(ipSlashPort);
 	}
 
+	InetAddress(const char *ipSlashPort)
+		throw()
+	{
+		this->fromString(std::string(ipSlashPort));
+	}
+
 	inline InetAddress &operator=(const InetAddress &a)
 		throw()
 	{

+ 5 - 18
node/Node.cpp

@@ -425,7 +425,6 @@ Node::ReasonForTermination Node::run()
 		uint64_t lastNetworkFingerprintCheck = 0;
 		uint64_t networkConfigurationFingerprint = _r->sysEnv->getNetworkConfigurationFingerprint();
 		uint64_t lastMulticastCheck = 0;
-		uint64_t lastMulticastAnnounceAll = 0;
 		long lastDelayDelta = 0;
 
 		while (impl->reasonForTermination == NODE_RUNNING) {
@@ -468,27 +467,15 @@ Node::ReasonForTermination Node::run()
 			// those changes to peers.
 			if ((resynchronize)||((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD)) {
 				lastMulticastCheck = now;
-				bool announceAll = ((resynchronize)||((now - lastMulticastAnnounceAll) >= ZT_MULTICAST_LIKE_ANNOUNCE_ALL_PERIOD));
 				try {
 					std::map< SharedPtr<Network>,std::set<MulticastGroup> > toAnnounce;
-					{
-						std::vector< SharedPtr<Network> > networks(_r->nc->networks());
-						for(std::vector< SharedPtr<Network> >::const_iterator nw(networks.begin());nw!=networks.end();++nw) {
-							if (((*nw)->updateMulticastGroups())||(announceAll))
-								toAnnounce.insert(std::pair< SharedPtr<Network>,std::set<MulticastGroup> >(*nw,(*nw)->multicastGroups()));
-						}
+					std::vector< SharedPtr<Network> > networks(_r->nc->networks());
+					for(std::vector< SharedPtr<Network> >::const_iterator nw(networks.begin());nw!=networks.end();++nw) {
+						if ((*nw)->updateMulticastGroups())
+							toAnnounce.insert(std::pair< SharedPtr<Network>,std::set<MulticastGroup> >(*nw,(*nw)->multicastGroups()));
 					}
-
-					if (toAnnounce.size()) {
+					if (toAnnounce.size())
 						_r->sw->announceMulticastGroups(toAnnounce);
-
-						// Only update lastMulticastAnnounceAll if we've announced something. This keeps
-						// the announceAll condition true during startup when there are no multicast
-						// groups until there is at least one. Technically this shouldn't be required as
-						// updateMulticastGroups() should return true on any change, but why not?
-						if (announceAll)
-							lastMulticastAnnounceAll = now;
-					}
 				} catch (std::exception &exc) {
 					LOG("unexpected exception announcing multicast groups: %s",exc.what());
 				} catch ( ... ) {

+ 14 - 2
node/PacketDecoder.cpp

@@ -28,6 +28,7 @@
 #include "../version.h"
 
 #include "Constants.hpp"
+#include "Defaults.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "Topology.hpp"
 #include "PacketDecoder.hpp"
@@ -36,6 +37,7 @@
 #include "NodeConfig.hpp"
 #include "Filter.hpp"
 #include "Service.hpp"
+#include "Demarc.hpp"
 
 namespace ZeroTier {
 
@@ -461,7 +463,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			return false;
 		}
 
-		uint16_t depth = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH);
+		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);
@@ -483,6 +485,12 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			return true;
 		}
 
+#ifdef ZT_TRACE_MULTICAST
+		char mct[256];
+		Utils::snprintf(mct,sizeof(mct),"%s <- %.16llx %.16llx %s via %s depth:%u len:%u",_r->identity.address().toString().c_str(),nwid,guid,origin.toString().c_str(),source().toString().c_str(),depth,frameLen);
+		_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+#endif
+
 		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;
@@ -589,7 +597,11 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 		// The rest of newFifo[] goes back into the packet
 		memcpy(fifo,newFifo + ZT_ADDRESS_LENGTH,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO);
 
-		//TRACE("forwarding MULTICAST_FRAME from %s(%s) to %s, original sender %s, current depth: %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nextHop.toString().c_str(),origin.toString().c_str(),depth);
+#ifdef ZT_TRACE_MULTICAST
+		char mct[256];
+		Utils::snprintf(mct,sizeof(mct),"%s -> %.16llx %.16llx %s via %s",_r->identity.address().toString().c_str(),nwid,guid,origin.toString().c_str(),nextHop.toString().c_str());
+		_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+#endif
 
 		// Send to next hop, reusing this packet as scratch space
 		newInitializationVector();

+ 7 - 0
node/Peer.cpp

@@ -26,6 +26,7 @@
  */
 
 #include "Peer.hpp"
+#include "Switch.hpp"
 
 namespace ZeroTier {
 
@@ -66,6 +67,12 @@ void Peer::onReceive(const RuntimeEnvironment *_r,Demarc::Port localPort,const I
 		wp->localPort = localPort;
 		if (!wp->fixed)
 			wp->addr = remoteAddr;
+
+		if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) {
+			_lastAnnouncedTo = now;
+			_r->sw->announceMulticastGroups(SharedPtr<Peer>(this));
+		}
+
 		_dirty = true;
 	}
 

+ 22 - 8
node/Peer.hpp

@@ -62,8 +62,8 @@
 		16 + \
 		1 \
 	) * 2) + \
-	sizeof(uint64_t) + \
-	sizeof(uint64_t) \
+	(sizeof(uint64_t) * 3) + \
+	(sizeof(uint16_t) * 3) \
 )
 
 namespace ZeroTier {
@@ -213,6 +213,15 @@ public:
 		return std::max(_lastUnicastFrame,_lastMulticastFrame);
 	}
 
+	/**
+	 * @return Time we last announced state TO this peer, such as multicast LIKEs
+	 */
+	uint64_t lastAnnouncedTo() const
+		throw()
+	{
+		return _lastAnnouncedTo;
+	}
+
 	/**
 	 * @return Lowest of measured latencies of all paths or 0 if unknown
 	 */
@@ -367,6 +376,10 @@ public:
 		_ipv6p.serialize(b);
 		b.append(_lastUnicastFrame);
 		b.append(_lastMulticastFrame);
+		b.append(_lastAnnouncedTo);
+		b.append((uint16_t)_vMajor);
+		b.append((uint16_t)_vMinor);
+		b.append((uint16_t)_vRevision);
 	}
 
 	template<unsigned int C>
@@ -384,10 +397,11 @@ public:
 		p += _ipv6p.deserialize(b,p);
 		_lastUnicastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t);
 		_lastMulticastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t);
+		_lastAnnouncedTo = b.template at<uint64_t>(p); p += sizeof(uint64_t);
+		_vMajor = b.template at<uint16_t>(p); p += sizeof(uint16_t);
+		_vMinor = b.template at<uint16_t>(p); p += sizeof(uint16_t);
+		_vRevision = b.template at<uint16_t>(p); p += sizeof(uint16_t);
 
-		_vMajor = 0;
-		_vMinor = 0;
-		_vRevision = 0;
 		_dirty = false;
 
 		return (p - startAt);
@@ -516,12 +530,12 @@ private:
 
 	uint64_t _lastUnicastFrame;
 	uint64_t _lastMulticastFrame;
+	uint64_t _lastAnnouncedTo;
+	unsigned int _vMajor,_vMinor,_vRevision;
 
-	// Fields below this line are not persisted with serialize()
+	// Fields below this line are not persisted with serialize() ---------------
 
-	unsigned int _vMajor,_vMinor,_vRevision;
 	bool _dirty;
-
 	AtomicCounter __refCount;
 };
 

+ 25 - 0
node/Switch.cpp

@@ -400,6 +400,7 @@ void Switch::announceMulticastGroups(const std::map< SharedPtr<Network>,std::set
 						outp.reset((*p)->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE);
 					}
 
+					// network ID, MAC, ADI
 					outp.append((uint64_t)nwmgs->first->id());
 					outp.append(mg->mac().data,6);
 					outp.append((uint32_t)mg->adi());
@@ -412,6 +413,30 @@ void Switch::announceMulticastGroups(const std::map< SharedPtr<Network>,std::set
 	}
 }
 
+void Switch::announceMulticastGroups(const SharedPtr<Peer> &peer)
+{
+	Packet outp(peer->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE);
+	std::vector< SharedPtr<Network> > networks(_r->nc->networks());
+	for(std::vector< SharedPtr<Network> >::iterator n(networks.begin());n!=networks.end();++n) {
+		if (((*n)->isAllowed(peer->address()))||(_r->topology->isSupernode(peer->address()))) {
+			std::set<MulticastGroup> mgs((*n)->multicastGroups());
+			for(std::set<MulticastGroup>::iterator mg(mgs.begin());mg!=mgs.end();++mg) {
+				if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
+					send(outp,true);
+					outp.reset(peer->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE);
+				}
+
+				// network ID, MAC, ADI
+				outp.append((uint64_t)(*n)->id());
+				outp.append(mg->mac().data,6);
+				outp.append((uint32_t)mg->adi());
+			}
+		}
+	}
+	if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH)
+		send(outp,true);
+}
+
 void Switch::requestWhois(const Address &addr)
 {
 	TRACE("requesting WHOIS for %s",addr.toString().c_str());

+ 14 - 2
node/Switch.hpp

@@ -153,13 +153,25 @@ public:
 	/**
 	 * Announce multicast group memberships
 	 *
-	 * This efficiently announces memberships, sending single packets with
-	 * many LIKEs.
+	 * This announces all the groups for all the networks in the supplied map to
+	 * all peers with whom we have an active direct link. Only isAllowed() peers
+	 * and supernodes get announcements for each given network.
 	 *
 	 * @param allMemberships Memberships for a number of networks
 	 */
 	void announceMulticastGroups(const std::map< SharedPtr<Network>,std::set<MulticastGroup> > &allMemberships);
 
+	/**
+	 * Announce multicast group memberships
+	 *
+	 * This announces all current multicast memberships to a single peer. Only
+	 * memberships for networks where the peer isAllowed() are included, unless
+	 * the peer is a supernode.
+	 *
+	 * @param peer Peer to announce all memberships to
+	 */
+	void announceMulticastGroups(const SharedPtr<Peer> &peer);
+
 	/**
 	 * Request WHOIS on a given address
 	 *