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, 183 insertions, 33 deletions
diff --git a/node/Peer.hpp b/node/Peer.hpp
index b6f3c695..b4cbe057 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
+ * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@@ -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"
@@ -108,6 +103,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 +141,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 +284,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 +349,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 +374,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 +414,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(const 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); }
@@ -394,27 +510,38 @@ public:
}
/**
- * Rate gate incoming requests for network COM
+ * Rate limit gate for VERB_ACK
*/
- inline bool rateGateIncomingComRequest(const int64_t now)
+ inline bool rateGateACK(const int64_t now)
{
- if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
- _lastComRequestReceived = now;
- return true;
+ if ((now - _lastACKWindowReset) >= ZT_PATH_QOS_ACK_CUTOFF_TIME) {
+ _lastACKWindowReset = now;
+ _ACKCutoffCount = 0;
+ } else {
+ ++_ACKCutoffCount;
}
- return false;
+ return (_ACKCutoffCount < ZT_PATH_QOS_ACK_CUTOFF_LIMIT);
}
/**
- * Rate gate outgoing requests for network COM
+ * Rate limit gate for VERB_QOS_MEASUREMENT
*/
- inline bool rateGateOutgoingComRequest(const int64_t now)
+ inline bool rateGateQoS(const int64_t now)
{
- if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) {
- _lastComRequestSent = now;
- return true;
+ if ((now - _lastQoSWindowReset) >= ZT_PATH_QOS_ACK_CUTOFF_TIME) {
+ _lastQoSWindowReset = now;
+ _QoSCutoffCount = 0;
+ } else {
+ ++_QoSCutoffCount;
}
- return false;
+ 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;
}
/**
@@ -510,11 +637,21 @@ private:
int64_t _lastCredentialRequestSent;
int64_t _lastWhoisRequestReceived;
int64_t _lastEchoRequestReceived;
- int64_t _lastComRequestReceived;
- int64_t _lastComRequestSent;
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 +665,21 @@ private:
unsigned int _directPathPushCutoffCount;
unsigned int _credentialsCutoffCount;
+ unsigned int _QoSCutoffCount;
+ unsigned int _ACKCutoffCount;
AtomicCounter __refCount;
+
+ RingBuffer<int,ZT_MULTIPATH_PROPORTION_WIN_SZ> _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