summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2014-06-30 11:31:04 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2014-06-30 11:31:04 -0700
commit88bdb81791e7879c6c199d6e9d03a326ec786484 (patch)
treec22c9e36e803ba820c55ca04a82ba204ff906ade /node
parent458f6ae7c37c7877a842e7931edc67d9fed201cd (diff)
downloadinfinitytier-88bdb81791e7879c6c199d6e9d03a326ec786484.tar.gz
infinitytier-88bdb81791e7879c6c199d6e9d03a326ec786484.zip
Keep track of basic aliveness for peers regardless if direct or indirect connectivity and use this for multicast propagation. Also consolidate adding of active bridges via the same functor as regular multicast next hops.
Diffstat (limited to 'node')
-rw-r--r--node/Constants.hpp13
-rw-r--r--node/Multicaster.hpp43
-rw-r--r--node/PacketDecoder.cpp140
-rw-r--r--node/Peer.cpp5
-rw-r--r--node/Peer.hpp20
-rw-r--r--node/Switch.cpp34
-rw-r--r--node/Topology.cpp2
-rw-r--r--node/Topology.hpp2
8 files changed, 167 insertions, 92 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp
index 4d720d5d..1745ef6b 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -314,14 +314,19 @@ error_no_byte_order_defined;
#define ZT_TCP_TUNNEL_FAILOVER_TIMEOUT (ZT_STARTUP_AGGRO * 5)
/**
+ * Timeout for overall peer activity (measured from last receive)
+ */
+#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 2) + ZT_PING_CHECK_DELAY)
+
+/**
* Path activity timeout (for non-fixed paths)
*/
-#define ZT_PEER_PATH_ACTIVITY_TIMEOUT ((ZT_PEER_DIRECT_PING_DELAY * 2) + ZT_PING_CHECK_DELAY)
+#define ZT_PEER_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT
/**
* Close TCP sockets if unused for this long (SocketManager)
*/
-#define ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT ZT_PEER_PATH_ACTIVITY_TIMEOUT
+#define ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT
/**
* Stop relaying via peers that have not responded to direct sends
@@ -387,14 +392,14 @@ error_no_byte_order_defined;
#define ZT_UPDATE_MIN_INTERVAL 120000
/**
- * Maximum interval between checks for new versions (2 hours)
+ * Maximum interval between checks for new versions
*/
#define ZT_UPDATE_MAX_INTERVAL 7200000
/**
* Software update HTTP timeout in seconds
*/
-#define ZT_UPDATE_HTTP_TIMEOUT 30
+#define ZT_UPDATE_HTTP_TIMEOUT 120
/**
* Sanity limit on maximum bridge routes
diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp
index 7d67aada..262f0304 100644
--- a/node/Multicaster.hpp
+++ b/node/Multicaster.hpp
@@ -40,6 +40,7 @@
#include "Constants.hpp"
#include "Mutex.hpp"
#include "MulticastGroup.hpp"
+#include "Topology.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
@@ -112,6 +113,7 @@ public:
* @param nwid Network ID
* @param mg Multicast group
* @param nextHopFunc Function to call for each address, search stops if it returns false
+ * @tparam F Function to receive each next hop address
*/
template<typename F>
inline void getNextHops(uint64_t nwid,const MulticastGroup &mg,F nextHopFunc)
@@ -151,20 +153,40 @@ public:
* @param origin Originating address
* @param prefixBits Number of bits in propagation restriction prefix
* @param prefix Propagation restrition prefix
+ * @param topology Topology database
+ * @param now Current time
*/
- AddToPropagationQueue(unsigned char **ptr,unsigned char *end,unsigned char *bloom,uint16_t bloomNonce,const Address &origin,unsigned int prefixBits,uint64_t prefix)
- throw() :
+ AddToPropagationQueue(
+ unsigned char **ptr,
+ unsigned char *end,
+ unsigned char *bloom,
+ uint16_t bloomNonce,
+ const Address &origin,
+ unsigned int prefixBits,
+ uint64_t prefix,
+ const Topology *topology,
+ uint64_t now)
+ throw() :
_origin(origin),
_bloomNonce((uint64_t)bloomNonce),
_prefix(prefix),
+ _now(now),
_ptr(ptr),
_end(end),
_bloom(bloom),
+ _topology(topology),
_prefixBits(prefixBits) {}
+ /**
+ * @param a Address to (possibly) add
+ * @return True if FIFO still contains room for more possible addresses
+ */
inline bool operator()(const Address &a)
throw()
{
+ if (*_ptr >= _end)
+ return false;
+
// Exclude original sender -- obviously they've already seen it
if (a == _origin)
return true;
@@ -173,27 +195,36 @@ public:
if (!a.withinMulticastPropagationPrefix(_prefix,_prefixBits))
return true;
- // Exclude addresses remembered in bloom filter -- or else remember them
+ // Exclude addresses remembered in bloom filter
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 = 1 << (bit & 7);
if ((*bbyte & bmask))
+ return true; // address already visited
+
+ // Exclude peers that don't appear to be online
+ SharedPtr<Peer> p(_topology->getPeer(a));
+ if ((!p)||(!p->alive(_now)))
return true;
- else *bbyte |= bmask;
+
+ // Remember address in bloom filter
+ *bbyte |= bmask;
a.copyTo(*_ptr,ZT_ADDRESS_LENGTH);
- return ((*_ptr += ZT_ADDRESS_LENGTH) != _end);
+ return ((*_ptr += ZT_ADDRESS_LENGTH) < _end);
}
private:
const Address _origin;
const uint64_t _bloomNonce;
const uint64_t _prefix;
+ const uint64_t _now;
unsigned char **const _ptr;
unsigned char *const _end;
unsigned char *const _bloom;
- unsigned int _prefixBits;
+ const Topology *const _topology;
+ const unsigned int _prefixBits;
};
private:
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp
index 1e62664e..369eda7b 100644
--- a/node/PacketDecoder.cpp
+++ b/node/PacketDecoder.cpp
@@ -530,7 +530,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
return false;
}
- // These fields change
+ // These fields in the packet are changed by each forwarder
unsigned int depth = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH);
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);
@@ -568,6 +568,9 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
*/
SharedPtr<Network> network(_r->nc->network(nwid));
+ SharedPtr<NetworkConfig> nconf;
+ if (network)
+ nconf = network->config2();
/* Grab, verify, and learn certificate of network membership if any -- provided we are
* a member of this network. Note: we can do this before verification of the actual
@@ -679,50 +682,30 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
// be the case unless we're a supernode), check to see if we should
// inject the packet. This also gives us an opportunity to check things
// like multicast bandwidth constraints.
- if (network) {
- SharedPtr<NetworkConfig> nconf(network->config2());
- if (nconf) {
- // Learn real maxDepth from netconf
- maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,nconf->multicastDepth());
- if (!maxDepth)
- maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH;
-
- if (!network->isAllowed(origin)) {
- // Papers, please...
- Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME);
- outp.append(packetId());
- outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
- outp.append(nwid);
- outp.armor(peer->key(),true);
- _fromSock->send(_remoteAddress,outp.data(),outp.size());
- TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,origin.toString().c_str());
- return true;
- }
-
- if (MAC(origin,network->id()) != sourceMac) {
- if (!nconf->permitsBridging(origin)) {
-#ifdef ZT_TRACE_MULTICAST
- Utils::snprintf(mct,sizeof(mct),
- "%.16llx %.2u %.3u%s %c %s dropped: bridging not allowed",
- guid,
- prefix,
- depth,
- mctdepth,
- (_r->topology->amSupernode() ? 'S' : '-'),
- _r->identity.address().toString().c_str());
- _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
-#endif
- TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str());
- return true;
- }
- network->learnBridgeRoute(sourceMac,origin);
- }
+ if ((network)&&(nconf)) {
+ // Learn real maxDepth from netconf
+ maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,nconf->multicastDepth());
+ if (!maxDepth)
+ maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH;
+
+ if (!network->isAllowed(origin)) {
+ // Papers, please...
+ Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME);
+ outp.append(packetId());
+ outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ _fromSock->send(_remoteAddress,outp.data(),outp.size());
+ TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,origin.toString().c_str());
+ return true;
+ }
- if (!nconf->permitsEtherType(etherType)) {
+ if (MAC(origin,network->id()) != sourceMac) {
+ if (!nconf->permitsBridging(origin)) {
#ifdef ZT_TRACE_MULTICAST
Utils::snprintf(mct,sizeof(mct),
- "%.16llx %.2u %.3u%s %c %s dropped: ethertype not allowed",
+ "%.16llx %.2u %.3u%s %c %s dropped: bridging not allowed",
guid,
prefix,
depth,
@@ -731,31 +714,48 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
_r->identity.address().toString().c_str());
_r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
#endif
- TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType);
+ TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str());
return true;
}
+ network->learnBridgeRoute(sourceMac,origin);
+ }
- if (!network->updateAndCheckMulticastBalance(origin,dest,frameLen)) {
- // Rate limits can only be checked by members of this network, but
- // there should be enough of them that over-limit multicasts get
- // their propagation aborted.
+ if (!nconf->permitsEtherType(etherType)) {
#ifdef ZT_TRACE_MULTICAST
- Utils::snprintf(mct,sizeof(mct),
- "%.16llx %.2u %.3u%s %c %s dropped: rate limits exceeded",
- guid,
- prefix,
- depth,
- mctdepth,
- (_r->topology->amSupernode() ? 'S' : '-'),
- _r->identity.address().toString().c_str());
- _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
+ Utils::snprintf(mct,sizeof(mct),
+ "%.16llx %.2u %.3u%s %c %s dropped: ethertype not allowed",
+ guid,
+ prefix,
+ depth,
+ mctdepth,
+ (_r->topology->amSupernode() ? 'S' : '-'),
+ _r->identity.address().toString().c_str());
+ _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
#endif
- TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
- return true;
- }
+ TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType);
+ return true;
+ }
- network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen);
+ if (!network->updateAndCheckMulticastBalance(origin,dest,frameLen)) {
+ // Rate limits can only be checked by members of this network, but
+ // there should be enough of them that over-limit multicasts get
+ // their propagation aborted.
+#ifdef ZT_TRACE_MULTICAST
+ Utils::snprintf(mct,sizeof(mct),
+ "%.16llx %.2u %.3u%s %c %s dropped: rate limits exceeded",
+ guid,
+ prefix,
+ depth,
+ mctdepth,
+ (_r->topology->amSupernode() ? 'S' : '-'),
+ _r->identity.address().toString().c_str());
+ _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
+#endif
+ TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
+ return true;
}
+
+ network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen);
}
}
@@ -816,11 +816,27 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
} else break;
}
- // Add any next hops we know about to FIFO
+ // Add any other next hops we know about to FIFO
#ifdef ZT_TRACE_MULTICAST
unsigned char *beforeAdd = newFifoPtr;
#endif
- _r->mc->getNextHops(nwid,dest,Multicaster::AddToPropagationQueue(&newFifoPtr,newFifoEnd,bloom,bloomNonce,origin,prefixBits,prefix));
+ Multicaster::AddToPropagationQueue appender(
+ &newFifoPtr,
+ newFifoEnd,
+ bloom,
+ bloomNonce,
+ origin,
+ prefixBits,
+ prefix,
+ _r->topology,
+ Utils::now());
+ if (nconf) {
+ for(std::set<Address>::const_iterator ab(nconf->activeBridges().begin());ab!=nconf->activeBridges().end();++ab) {
+ if (!appender(*ab))
+ break;
+ }
+ }
+ _r->mc->getNextHops(nwid,dest,appender);
#ifdef ZT_TRACE_MULTICAST
unsigned int numAdded = (unsigned int)(newFifoPtr - beforeAdd) / ZT_ADDRESS_LENGTH;
#endif
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 54e30a74..e61631e2 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -35,6 +35,7 @@ namespace ZeroTier {
Peer::Peer() :
_lastUsed(0),
+ _lastReceive(0),
_lastUnicastFrame(0),
_lastMulticastFrame(0),
_lastAnnouncedTo(0),
@@ -47,6 +48,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
throw(std::runtime_error) :
_id(peerIdentity),
_lastUsed(0),
+ _lastReceive(0),
_lastUnicastFrame(0),
_lastMulticastFrame(0),
_lastAnnouncedTo(0),
@@ -73,6 +75,9 @@ void Peer::receive(
// Update system-wide last packet receive time
*((const_cast<uint64_t *>(&(_r->timeOfLastPacketReceived)))) = now;
+ // Global last receive time regardless of path
+ _lastReceive = now;
+
// Learn paths from direct packets (hops == 0)
if (!hops) {
{
diff --git a/node/Peer.hpp b/node/Peer.hpp
index a950b2fc..edb66e21 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -50,7 +50,7 @@
#include "NonCopyable.hpp"
#include "Mutex.hpp"
-#define ZT_PEER_SERIALIZATION_VERSION 8
+#define ZT_PEER_SERIALIZATION_VERSION 9
namespace ZeroTier {
@@ -247,6 +247,11 @@ public:
}
/**
+ * @return Time of last receive of anything, whether direct or relayed
+ */
+ inline uint64_t lastReceive() const throw() { return _lastReceive; }
+
+ /**
* @return Time of most recent unicast frame received
*/
inline uint64_t lastUnicastFrame() const throw() { return _lastUnicastFrame; }
@@ -267,6 +272,16 @@ public:
inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; }
/**
+ * @param now Current time
+ * @return True if peer has received something within ZT_PEER_ACTIVITY_TIMEOUT ms
+ */
+ inline bool alive(uint64_t now) const
+ throw()
+ {
+ return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
+ }
+
+ /**
* @return Current latency or 0 if unknown (max: 65535)
*/
inline unsigned int latency() const
@@ -424,6 +439,7 @@ public:
_id.serialize(b,false);
b.append(_key,sizeof(_key));
b.append(_lastUsed);
+ b.append(_lastReceive);
b.append(_lastUnicastFrame);
b.append(_lastMulticastFrame);
b.append(_lastAnnouncedTo);
@@ -448,6 +464,7 @@ public:
p += _id.deserialize(b,p);
memcpy(_key,b.field(p,sizeof(_key)),sizeof(_key)); p += sizeof(_key);
_lastUsed = b.template at<uint64_t>(p); p += sizeof(uint64_t);
+ _lastReceive = b.template at<uint64_t>(p); p += sizeof(uint64_t);
_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);
@@ -472,6 +489,7 @@ private:
std::vector<Path> _paths;
volatile uint64_t _lastUsed;
+ volatile uint64_t _lastReceive; // direct or indirect
volatile uint64_t _lastUnicastFrame;
volatile uint64_t _lastMulticastFrame;
volatile uint64_t _lastAnnouncedTo;
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 46fb0b49..9b0e3e6e 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -164,26 +164,26 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
memset(bloom,0,sizeof(bloom));
unsigned char *fifoPtr = fifo;
- // All multicasts visit all active bridges first -- this is one of the two active/passive bridge differences
+ // Add all active bridges and then next hops we know about to propagation queue
+ Multicaster::AddToPropagationQueue appender(
+ &fifoPtr,
+ fifoEnd,
+ bloom,
+ bloomNonce,
+ _r->identity.address(),
+ nconf->multicastPrefixBits(),
+ prefix,
+ _r->topology,
+ now);
for(std::set<Address>::const_iterator ab(nconf->activeBridges().begin());ab!=nconf->activeBridges().end();++ab) {
- if ((*ab != _r->identity.address())&&(ab->withinMulticastPropagationPrefix(prefix,nconf->multicastPrefixBits()))) {
- SharedPtr<Peer> abPeer(_r->topology->getPeer(*ab));
- if ((abPeer)&&(abPeer->hasActiveDirectPath(now))) {
- ab->copyTo(fifoPtr,ZT_ADDRESS_LENGTH);
- if ((fifoPtr += ZT_ADDRESS_LENGTH) == fifoEnd)
- break;
- }
- }
+ if (!appender(*ab))
+ break;
}
+ _r->mc->getNextHops(network->id(),mg,appender);
- // Then visit next hops according to multicaster (if there's room... almost certainly will be)
- if (fifoPtr != fifoEnd) {
- _r->mc->getNextHops(network->id(),mg,Multicaster::AddToPropagationQueue(&fifoPtr,fifoEnd,bloom,bloomNonce,_r->identity.address(),nconf->multicastPrefixBits(),prefix));
-
- // Pad remainder of FIFO with zeroes
- while (fifoPtr != fifoEnd)
- *(fifoPtr++) = (unsigned char)0;
- }
+ // Pad remainder of FIFO with zeroes
+ while (fifoPtr != fifoEnd)
+ *(fifoPtr++) = (unsigned char)0;
// First element in FIFO is first hop, rest of FIFO is sent in packet *to* first hop
Address firstHop(fifo,ZT_ADDRESS_LENGTH);
diff --git a/node/Topology.cpp b/node/Topology.cpp
index d88b64ca..d74179fe 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -89,7 +89,7 @@ SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
return p;
}
-SharedPtr<Peer> Topology::getPeer(const Address &zta)
+SharedPtr<Peer> Topology::getPeer(const Address &zta) const
{
if (zta == _r->identity.address()) {
TRACE("BUG: ignored attempt to getPeer() for self, returned NULL");
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 74db8b50..293ac446 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -82,7 +82,7 @@ public:
* @param zta ZeroTier address of peer
* @return Peer or NULL if not found
*/
- SharedPtr<Peer> getPeer(const Address &zta);
+ SharedPtr<Peer> getPeer(const Address &zta) const;
/**
* Get an identity if cached or available in a peer record