Significant simplification to path logic.

This commit is contained in:
Adam Ierymenko 2017-04-14 17:53:32 -07:00
parent 645bf4a764
commit 139c4b5633
6 changed files with 184 additions and 268 deletions

View file

@ -108,20 +108,10 @@ public:
* @param addr Remote address
* @return True if we have an active path to this destination
*/
bool hasActivePathTo(uint64_t now,const InetAddress &addr) const;
/**
* Set which known path for an address family is optimal
*
* @param addr Address to make exclusive
*/
inline void setClusterOptimal(const InetAddress &addr)
inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const
{
if (addr.ss_family == AF_INET) {
_remoteClusterOptimal4 = (uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr;
} else if (addr.ss_family == AF_INET6) {
memcpy(_remoteClusterOptimal6,reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr,16);
}
Mutex::Lock _l(_paths_m);
return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) );
}
/**
@ -131,14 +121,17 @@ public:
* @param data Packet data
* @param len Packet length
* @param now Current time
* @param forceEvenIfDead If true, send even if the path is not 'alive'
* @param force If true, send even if path is not alive
* @return True if we actually sent something
*/
bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead);
bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force);
/**
* Get the best current direct path
*
* This does not check Path::alive(), but does return the most recently
* active path and does check expiration (which is a longer timeout).
*
* @param now Current time
* @param includeExpired If true, include even expired paths
* @return Best current path or NULL if none
@ -192,12 +185,6 @@ public:
*/
bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily);
/**
* @param now Current time
* @return True if this peer has at least one active and alive direct path
*/
bool hasActiveDirectPath(uint64_t now) const;
/**
* Reset paths within a given IP scope and address family
*
@ -209,30 +196,48 @@ public:
* @param inetAddressFamily Family e.g. AF_INET
* @param now Current time
*/
void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now);
inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now)
{
Mutex::Lock _l(_paths_m);
if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) {
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
_v4Path.p->sent(now);
_v4Path.lr = 0; // path will not be used unless it speaks again
} else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) {
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
_v6Path.p->sent(now);
_v6Path.lr = 0; // path will not be used unless it speaks again
}
}
/**
* Get most recently active path addresses for IPv4 and/or IPv6
*
* Note that v4 and v6 are not modified if they are not found, so
* initialize these to a NULL address to be able to check.
* Fill parameters with V4 and V6 addresses if known and alive
*
* @param now Current time
* @param v4 Result parameter to receive active IPv4 address, if any
* @param v6 Result parameter to receive active IPv6 address, if any
*/
void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
{
Mutex::Lock _l(_paths_m);
if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now)))
v4 = _v4Path.p->address();
if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now)))
v6 = _v6Path.p->address();
}
/**
* @param now Current time
* @return All known direct paths to this peer and whether they are expired (true == expired)
* @return All known paths to this peer
*/
inline std::vector< std::pair< SharedPtr<Path>,bool > > paths(const uint64_t now) const
inline std::vector< SharedPtr<Path> > paths(const uint64_t now) const
{
std::vector< std::pair< SharedPtr<Path>,bool > > pp;
std::vector< SharedPtr<Path> > pp;
Mutex::Lock _l(_paths_m);
for(unsigned int p=0,np=_numPaths;p<np;++p)
pp.push_back(std::pair< SharedPtr<Path>,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION));
if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now)))
pp.push_back(_v4Path.p);
if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now)))
pp.push_back(_v6Path.p);
return pp;
}
@ -424,32 +429,19 @@ public:
}
private:
inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const
struct _PeerPath
{
uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK));
if (_paths[p].path->address().ss_family == AF_INET) {
s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast<const struct sockaddr_in *>(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4));
} else if (_paths[p].path->address().ss_family == AF_INET6) {
uint64_t clusterWeight = ZT_PEER_PING_PERIOD;
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(_paths[p].path->address()))->sin6_addr.s6_addr);
for(long i=0;i<16;++i) {
if (a[i] != _remoteClusterOptimal6[i]) {
clusterWeight = 0;
break;
}
}
s += clusterWeight;
}
s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now);
#ifdef ZT_ENABLE_CLUSTER
s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal;
_PeerPath() : lr(0),p(),localClusterSuboptimal(false) {}
#else
_PeerPath() : lr(0),p() {}
#endif
return s;
}
uint64_t lr; // time of last valid ZeroTier packet
SharedPtr<Path> p;
#ifdef ZT_ENABLE_CLUSTER
bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer
#endif
};
uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH];
@ -468,26 +460,17 @@ private:
uint64_t _lastCredentialsReceived;
uint64_t _lastTrustEstablishedPacketReceived;
uint8_t _remoteClusterOptimal6[16];
uint32_t _remoteClusterOptimal4;
uint16_t _vProto;
uint16_t _vMajor;
uint16_t _vMinor;
uint16_t _vRevision;
Identity _id;
struct {
uint64_t lastReceive;
SharedPtr<Path> path;
#ifdef ZT_ENABLE_CLUSTER
bool localClusterSuboptimal;
#endif
} _paths[ZT_MAX_PEER_NETWORK_PATHS];
_PeerPath _v4Path; // IPv4 direct path
_PeerPath _v6Path; // IPv6 direct path
Mutex _paths_m;
unsigned int _numPaths;
Identity _id;
unsigned int _latency;
unsigned int _directPathPushCutoffCount;
unsigned int _credentialsCutoffCount;