summaryrefslogtreecommitdiff
path: root/node/Peer.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Peer.hpp')
-rw-r--r--node/Peer.hpp216
1 files changed, 198 insertions, 18 deletions
diff --git a/node/Peer.hpp b/node/Peer.hpp
index b6f3c695..a32eaad0 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -27,18 +27,13 @@
#ifndef ZT_PEER_HPP
#define ZT_PEER_HPP
-#include <stdint.h>
-
-#include "Constants.hpp"
-
-#include <algorithm>
-#include <utility>
#include <vector>
-#include <stdexcept>
#include "../include/ZeroTierOne.h"
+#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
#include "Path.hpp"
#include "Address.hpp"
#include "Utils.hpp"
@@ -65,7 +60,11 @@ private:
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
public:
- ~Peer() { Utils::burn(_key,sizeof(_key)); }
+ ~Peer() {
+ Utils::burn(_key,sizeof(_key));
+ delete _pathChoiceHist;
+ _pathChoiceHist = NULL;
+ }
/**
* Construct a new peer
@@ -108,6 +107,7 @@ public:
const SharedPtr<Path> &path,
const unsigned int hops,
const uint64_t packetId,
+ const unsigned int payloadLength,
const Packet::Verb verb,
const uint64_t inRePacketId,
const Packet::Verb inReVerb,
@@ -145,20 +145,95 @@ public:
*/
inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
{
- SharedPtr<Path> bp(getBestPath(now,force));
+ SharedPtr<Path> bp(getAppropriatePath(now,force));
if (bp)
return bp->send(RR,tPtr,data,len,now);
return false;
}
/**
- * Get the best current direct path
+ * Record statistics on outgoing packets
+ *
+ * @param path Path over which packet was sent
+ * @param id Packet ID
+ * @param len Length of packet payload
+ * @param verb Packet verb
+ * @param now Current time
+ */
+ void recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
+
+ /**
+ * Record statistics on incoming packets
+ *
+ * @param path Path over which packet was sent
+ * @param id Packet ID
+ * @param len Length of packet payload
+ * @param verb Packet verb
+ * @param now Current time
+ */
+ void recordIncomingPacket(void *tPtr, const SharedPtr<Path> &path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
+
+ /**
+ * Send an ACK to peer for the most recent packets received
+ *
+ * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
+ * @param localSocket Raw socket the ACK packet will be sent over
+ * @param atAddress Destination for the ACK packet
+ * @param now Current time
+ */
+ void sendACK(void *tPtr, const SharedPtr<Path> &path, const int64_t localSocket,const InetAddress &atAddress,int64_t now);
+
+ /**
+ * Send a QoS packet to peer so that it can evaluate the quality of this link
+ *
+ * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
+ * @param localSocket Raw socket the QoS packet will be sent over
+ * @param atAddress Destination for the QoS packet
+ * @param now Current time
+ */
+ void sendQOS_MEASUREMENT(void *tPtr, const SharedPtr<Path> &path, const int64_t localSocket,const InetAddress &atAddress,int64_t now);
+
+ /**
+ * Compute relative quality values and allocations for the components of the aggregate link
+ *
+ * @param now Current time
+ */
+ void computeAggregateProportionalAllocation(int64_t now);
+
+ /**
+ * @return The aggregate link Packet Delay Variance (PDV)
+ */
+ int computeAggregateLinkPacketDelayVariance();
+
+ /**
+ * @return The aggregate link mean latency
+ */
+ int computeAggregateLinkMeanLatency();
+
+ /**
+ * @return The number of currently alive "physical" paths in the aggregate link
+ */
+ int aggregateLinkPhysicalPathCount();
+
+ /**
+ * @return The number of currently alive "logical" paths in the aggregate link
+ */
+ int aggregateLinkLogicalPathCount();
+
+ /**
+ * Get the most appropriate direct path based on current multipath and QoS configuration
*
* @param now Current time
* @param includeExpired If true, include even expired paths
* @return Best current path or NULL if none
*/
- SharedPtr<Path> getBestPath(int64_t now,bool includeExpired) const;
+ SharedPtr<Path> getAppropriatePath(int64_t now, bool includeExpired);
+
+ /**
+ * Generate a human-readable string of interface names making up the aggregate link, also include
+ * moving allocation and IP version number for each (for tracing)
+ */
+ char *interfaceListStr();
/**
* Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path
@@ -213,6 +288,16 @@ public:
unsigned int doPingAndKeepalive(void *tPtr,int64_t now);
/**
+ * Clear paths whose localSocket(s) are in a CLOSED state or have an otherwise INVALID state.
+ * This should be called frequently so that we can detect and remove unproductive or invalid paths.
+ *
+ * Under the hood this is done periodically based on ZT_CLOSED_PATH_PRUNING_INTERVAL.
+ *
+ * @return Number of paths that were pruned this round
+ */
+ unsigned int prunePaths();
+
+ /**
* Process a cluster redirect sent by this peer
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
@@ -268,14 +353,18 @@ public:
inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
/**
- * @return Latency in milliseconds of best path or 0xffff if unknown / no paths
+ * @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths
*/
- inline unsigned int latency(const int64_t now) const
+ inline unsigned int latency(const int64_t now)
{
- SharedPtr<Path> bp(getBestPath(now,false));
- if (bp)
- return bp->latency();
- return 0xffff;
+ if (_canUseMultipath) {
+ return (int)computeAggregateLinkMeanLatency();
+ } else {
+ SharedPtr<Path> bp(getAppropriatePath(now,false));
+ if (bp)
+ return bp->latency();
+ return 0xffff;
+ }
}
/**
@@ -289,7 +378,7 @@ public:
*
* @return Relay quality score computed from latency and other factors, lower is better
*/
- inline unsigned int relayQuality(const int64_t now) const
+ inline unsigned int relayQuality(const int64_t now)
{
const uint64_t tsr = now - _lastReceive;
if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
@@ -329,6 +418,37 @@ public:
inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
/**
+ * Periodically update known multipath activation constraints. This is done so that we know when and when
+ * not to use multipath logic. Doing this once every few seconds is sufficient.
+ *
+ * @param now Current time
+ */
+ inline void processBackgroundPeerTasks(int64_t now);
+
+ /**
+ * Record that the remote peer does have multipath enabled. As is evident by the receipt of a VERB_ACK
+ * or a VERB_QOS_MEASUREMENT packet at some point in the past. Until this flag is set, the local client
+ * shall assume that multipath is not enabled and should only use classical Protocol 9 logic.
+ */
+ inline void inferRemoteMultipathEnabled() { _remotePeerMultipathEnabled = true; }
+
+ /**
+ * @return Whether the local client supports and is configured to use multipath
+ */
+ inline bool localMultipathSupport() { return _localMultipathSupported; }
+
+ /**
+ * @return Whether the remote peer supports and is configured to use multipath
+ */
+ inline bool remoteMultipathSupport() { return _remoteMultipathSupported; }
+
+ /**
+ * @return Whether this client can use multipath to communicate with this peer. True if both peers are using
+ * the correct protocol and if both peers have multipath enabled. False if otherwise.
+ */
+ inline bool canUseMultipath() { return _canUseMultipath; }
+
+ /**
* @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
@@ -418,6 +538,41 @@ public:
}
/**
+ * Rate limit gate for VERB_ACK
+ */
+ inline bool rateGateACK(const int64_t now)
+ {
+ if ((now - _lastACKWindowReset) >= ZT_PATH_QOS_ACK_CUTOFF_TIME) {
+ _lastACKWindowReset = now;
+ _ACKCutoffCount = 0;
+ } else {
+ ++_ACKCutoffCount;
+ }
+ return (_ACKCutoffCount < ZT_PATH_QOS_ACK_CUTOFF_LIMIT);
+ }
+
+ /**
+ * Rate limit gate for VERB_QOS_MEASUREMENT
+ */
+ inline bool rateGateQoS(const int64_t now)
+ {
+ if ((now - _lastQoSWindowReset) >= ZT_PATH_QOS_ACK_CUTOFF_TIME) {
+ _lastQoSWindowReset = now;
+ _QoSCutoffCount = 0;
+ } else {
+ ++_QoSCutoffCount;
+ }
+ return (_QoSCutoffCount < ZT_PATH_QOS_ACK_CUTOFF_LIMIT);
+ }
+
+ /**
+ * @return Whether this peer is reachable via an aggregate link
+ */
+ inline bool hasAggregateLink() {
+ return _localMultipathSupported && _remoteMultipathSupported && _remotePeerMultipathEnabled;
+ }
+
+ /**
* Serialize a peer for storage in local cache
*
* This does not serialize everything, just non-ephemeral information.
@@ -515,6 +670,18 @@ private:
int64_t _lastCredentialsReceived;
int64_t _lastTrustEstablishedPacketReceived;
int64_t _lastSentFullHello;
+ int64_t _lastPathPrune;
+ int64_t _lastACKWindowReset;
+ int64_t _lastQoSWindowReset;
+ int64_t _lastMultipathCompatibilityCheck;
+
+ unsigned char _freeRandomByte;
+
+ int _uniqueAlivePathCount;
+
+ bool _localMultipathSupported;
+ bool _remoteMultipathSupported;
+ bool _canUseMultipath;
uint16_t _vProto;
uint16_t _vMajor;
@@ -528,8 +695,21 @@ private:
unsigned int _directPathPushCutoffCount;
unsigned int _credentialsCutoffCount;
+ unsigned int _QoSCutoffCount;
+ unsigned int _ACKCutoffCount;
AtomicCounter __refCount;
+
+ RingBuffer<int> *_pathChoiceHist;
+
+ bool _linkIsBalanced;
+ bool _linkIsRedundant;
+ bool _remotePeerMultipathEnabled;
+
+ int64_t _lastAggregateStatsReport;
+ int64_t _lastAggregateAllocation;
+
+ char _interfaceListStr[256]; // 16 characters * 16 paths in a link
};
} // namespace ZeroTier