summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Constants.hpp11
-rw-r--r--node/Defaults.cpp3
-rw-r--r--node/Defaults.hpp8
-rw-r--r--node/InetAddress.hpp6
-rw-r--r--node/Node.cpp23
-rw-r--r--node/PacketDecoder.cpp16
-rw-r--r--node/Peer.cpp7
-rw-r--r--node/Peer.hpp30
-rw-r--r--node/Switch.cpp25
-rw-r--r--node/Switch.hpp16
10 files changed, 105 insertions, 40 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp
index 08ec2243..6b2f6d40 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -251,18 +251,9 @@ 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
diff --git a/node/Defaults.cpp b/node/Defaults.cpp
index 733832f3..9ce72b30 100644
--- a/node/Defaults.cpp
+++ b/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())
{
diff --git a/node/Defaults.hpp b/node/Defaults.hpp
index 787193dc..4937ec03 100644
--- a/node/Defaults.hpp
+++ b/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
*/
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index 6f21cc7f..54fbc395 100644
--- a/node/InetAddress.hpp
+++ b/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()
{
diff --git a/node/Node.cpp b/node/Node.cpp
index 954f4cba..ef0598de 100644
--- a/node/Node.cpp
+++ b/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 ( ... ) {
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp
index a2b827c0..3269504b 100644
--- a/node/PacketDecoder.cpp
+++ b/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();
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 1d22fd1f..1c7eec34 100644
--- a/node/Peer.cpp
+++ b/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;
}
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 38b93a32..e9b24bd8 100644
--- a/node/Peer.hpp
+++ b/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 {
@@ -214,6 +214,15 @@ public:
}
/**
+ * @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
*/
unsigned int latency() const
@@ -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;
};
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 14b658a7..896c6435 100644
--- a/node/Switch.cpp
+++ b/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());
diff --git a/node/Switch.hpp b/node/Switch.hpp
index bac12a50..d9032a27 100644
--- a/node/Switch.hpp
+++ b/node/Switch.hpp
@@ -153,14 +153,26 @@ 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
*
* @param addr Address to look up