@ -15,10 +15,10 @@
# include "Switch.hpp"
# include "Switch.hpp"
# include <cinttypes> // for PRId64, etc. macros
# include <cmath>
# include <cmath>
# include <cstdio>
# include <cstdio>
# include <string>
# include <string>
# include <cinttypes> // for PRId64, etc. macros
// FIXME: remove this suppression and actually fix warnings
// FIXME: remove this suppression and actually fix warnings
# ifdef __GNUC__
# ifdef __GNUC__
@ -108,7 +108,7 @@ bool Bond::setAllMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::s
std : : map < int64_t , SharedPtr < Bond > > : : iterator bondItr = _bonds . begin ( ) ;
std : : map < int64_t , SharedPtr < Bond > > : : iterator bondItr = _bonds . begin ( ) ;
bool found = false ;
bool found = false ;
while ( bondItr ! = _bonds . end ( ) ) {
while ( bondItr ! = _bonds . end ( ) ) {
if ( bondItr - > second - > setMtuByTuple ( mtu , ifStr , ipStr ) ) {
if ( bondItr - > second - > setMtuByTuple ( mtu , ifStr , ipStr ) ) {
found = true ;
found = true ;
}
}
+ + bondItr ;
+ + bondItr ;
@ -154,11 +154,13 @@ SharedPtr<Bond> Bond::createBond(const RuntimeEnvironment* renv, const SharedPtr
bond = new Bond ( renv , _bondPolicyTemplates [ _defaultPolicyStr ] . ptr ( ) , peer ) ;
bond = new Bond ( renv , _bondPolicyTemplates [ _defaultPolicyStr ] . ptr ( ) , peer ) ;
bond - > debug ( " new default custom bond (based on %s) " , bond - > getPolicyStrByCode ( bond - > policy ( ) ) . c_str ( ) ) ;
bond - > debug ( " new default custom bond (based on %s) " , bond - > getPolicyStrByCode ( bond - > policy ( ) ) . c_str ( ) ) ;
}
}
} else {
}
else {
if ( ! _bondPolicyTemplates [ _policyTemplateAssignments [ identity ] ] ) {
if ( ! _bondPolicyTemplates [ _policyTemplateAssignments [ identity ] ] ) {
bond = new Bond ( renv , _defaultPolicy , peer ) ;
bond = new Bond ( renv , _defaultPolicy , peer ) ;
bond - > debug ( " peer-specific bond, was specified as %s but the bond definition was not found, using default %s " , _policyTemplateAssignments [ identity ] . c_str ( ) , getPolicyStrByCode ( _defaultPolicy ) . c_str ( ) ) ;
bond - > debug ( " peer-specific bond, was specified as %s but the bond definition was not found, using default %s " , _policyTemplateAssignments [ identity ] . c_str ( ) , getPolicyStrByCode ( _defaultPolicy ) . c_str ( ) ) ;
} else {
}
else {
bond = new Bond ( renv , _bondPolicyTemplates [ _policyTemplateAssignments [ identity ] ] . ptr ( ) , peer ) ;
bond = new Bond ( renv , _bondPolicyTemplates [ _policyTemplateAssignments [ identity ] ] . ptr ( ) , peer ) ;
bond - > debug ( " new default bond " ) ;
bond - > debug ( " new default bond " ) ;
}
}
@ -227,10 +229,12 @@ SharedPtr<Link> Bond::getLinkBySocket(const std::string& policyAlias, uint64_t l
SharedPtr < Link > s = new Link ( ifnameStr , 0 , 0 , 0 , true , ZT_BOND_SLAVE_MODE_PRIMARY , " " ) ;
SharedPtr < Link > s = new Link ( ifnameStr , 0 , 0 , 0 , true , ZT_BOND_SLAVE_MODE_PRIMARY , " " ) ;
_interfaceToLinkMap [ policyAlias ] . insert ( std : : pair < std : : string , SharedPtr < Link > > ( ifnameStr , s ) ) ;
_interfaceToLinkMap [ policyAlias ] . insert ( std : : pair < std : : string , SharedPtr < Link > > ( ifnameStr , s ) ) ;
return s ;
return s ;
} else {
}
else {
return SharedPtr < Link > ( ) ;
return SharedPtr < Link > ( ) ;
}
}
} else {
}
else {
return search - > second ;
return search - > second ;
}
}
}
}
@ -340,6 +344,7 @@ void Bond::nominatePathToBond(const SharedPtr<Path>& path, int64_t now)
_paths [ i ] . ipvPref = sl - > ipvPref ( ) ;
_paths [ i ] . ipvPref = sl - > ipvPref ( ) ;
_paths [ i ] . mode = sl - > mode ( ) ;
_paths [ i ] . mode = sl - > mode ( ) ;
_paths [ i ] . enabled = sl - > enabled ( ) ;
_paths [ i ] . enabled = sl - > enabled ( ) ;
_paths [ i ] . localPort = _phy - > getLocalPort ( ( PhySocket * ) ( ( uintptr_t ) path - > localSocket ( ) ) ) ;
_paths [ i ] . onlyPathOnLink = ! bFoundCommonLink ;
_paths [ i ] . onlyPathOnLink = ! bFoundCommonLink ;
}
}
}
}
@ -397,7 +402,8 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
_rrPacketsSentOnCurrLink = 0 ;
_rrPacketsSentOnCurrLink = 0 ;
if ( _numBondedPaths = = 1 | | _rrIdx > = ( ZT_MAX_PEER_NETWORK_PATHS - 1 ) ) {
if ( _numBondedPaths = = 1 | | _rrIdx > = ( ZT_MAX_PEER_NETWORK_PATHS - 1 ) ) {
_rrIdx = 0 ;
_rrIdx = 0 ;
} else {
}
else {
int _tempIdx = _rrIdx ;
int _tempIdx = _rrIdx ;
for ( int searchCount = 0 ; searchCount < ( _numBondedPaths - 1 ) ; searchCount + + ) {
for ( int searchCount = 0 ; searchCount < ( _numBondedPaths - 1 ) ; searchCount + + ) {
_tempIdx = ( _tempIdx = = ( _numBondedPaths - 1 ) ) ? 0 : _tempIdx + 1 ;
_tempIdx = ( _tempIdx = = ( _numBondedPaths - 1 ) ) ? 0 : _tempIdx + 1 ;
@ -427,7 +433,8 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
if ( likely ( it ! = _flows . end ( ) ) ) {
if ( likely ( it ! = _flows . end ( ) ) ) {
it - > second - > lastActivity = now ;
it - > second - > lastActivity = now ;
return _paths [ it - > second - > assignedPath ] . p ;
return _paths [ it - > second - > assignedPath ] . p ;
} else {
}
else {
unsigned char entropy ;
unsigned char entropy ;
Utils : : getSecureRandom ( & entropy , 1 ) ;
Utils : : getSecureRandom ( & entropy , 1 ) ;
SharedPtr < Flow > flow = createFlow ( ZT_MAX_PEER_NETWORK_PATHS , flowId , entropy , now ) ;
SharedPtr < Flow > flow = createFlow ( ZT_MAX_PEER_NETWORK_PATHS , flowId , entropy , now ) ;
@ -505,7 +512,8 @@ void Bond::recordIncomingPacket(const SharedPtr<Path>& path, uint64_t packetId,
_paths [ pathIdx ] . qosStatsIn [ packetId ] = now ;
_paths [ pathIdx ] . qosStatsIn [ packetId ] = now ;
+ + ( _paths [ pathIdx ] . packetsReceivedSinceLastQoS ) ;
+ + ( _paths [ pathIdx ] . packetsReceivedSinceLastQoS ) ;
//_paths[pathIdx].packetValiditySamples.push(true);
//_paths[pathIdx].packetValiditySamples.push(true);
} else {
}
else {
// debug("QoS buffer full, will not record information");
// debug("QoS buffer full, will not record information");
}
}
/*
/*
@ -532,7 +540,8 @@ void Bond::recordIncomingPacket(const SharedPtr<Path>& path, uint64_t packetId,
SharedPtr < Flow > flow ;
SharedPtr < Flow > flow ;
if ( ! _flows . count ( flowId ) ) {
if ( ! _flows . count ( flowId ) ) {
flow = createFlow ( pathIdx , flowId , 0 , now ) ;
flow = createFlow ( pathIdx , flowId , 0 , now ) ;
} else {
}
else {
flow = _flows [ flowId ] ;
flow = _flows [ flowId ] ;
}
}
if ( flow ) {
if ( flow ) {
@ -618,7 +627,8 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now, bool reass
if ( reassign ) {
if ( reassign ) {
log ( " attempting to re-assign out-flow %04x previously on idx %d (%u / %zu flows) " , flow - > id , flow - > assignedPath , _paths [ _realIdxMap [ flow - > assignedPath ] ] . assignedFlowCount , _flows . size ( ) ) ;
log ( " attempting to re-assign out-flow %04x previously on idx %d (%u / %zu flows) " , flow - > id , flow - > assignedPath , _paths [ _realIdxMap [ flow - > assignedPath ] ] . assignedFlowCount , _flows . size ( ) ) ;
} else {
}
else {
debug ( " attempting to assign flow for the first time " ) ;
debug ( " attempting to assign flow for the first time " ) ;
}
}
@ -632,7 +642,8 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now, bool reass
if ( reassign ) {
if ( reassign ) {
bondedIdx = ( flow - > assignedPath + offset ) % ( _numBondedPaths ) ;
bondedIdx = ( flow - > assignedPath + offset ) % ( _numBondedPaths ) ;
} else {
}
else {
bondedIdx = abs ( ( int ) ( ( entropy + offset ) % ( _numBondedPaths ) ) ) ;
bondedIdx = abs ( ( int ) ( ( entropy + offset ) % ( _numBondedPaths ) ) ) ;
}
}
// debug("idx=%d, offset=%d, randomCap=%f, actualCap=%f", bondedIdx, offset, randomLinkCapacity, _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity);
// debug("idx=%d, offset=%d, randomCap=%f, actualCap=%f", bondedIdx, offset, randomLinkCapacity, _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity);
@ -655,7 +666,8 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now, bool reass
flow - > assignPath ( _realIdxMap [ bondedIdx ] , now ) ;
flow - > assignPath ( _realIdxMap [ bondedIdx ] , now ) ;
+ + ( _paths [ _realIdxMap [ bondedIdx ] ] . assignedFlowCount ) ;
+ + ( _paths [ _realIdxMap [ bondedIdx ] ] . assignedFlowCount ) ;
// debug(" ABLE to find optimal link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx);
// debug(" ABLE to find optimal link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx);
} else {
}
else {
// We were (unable) to find a path that didn't violate at least one quality requirement, will choose next best option
// We were (unable) to find a path that didn't violate at least one quality requirement, will choose next best option
flow - > assignPath ( _realIdxMap [ nextBestQualIdx ] , now ) ;
flow - > assignPath ( _realIdxMap [ nextBestQualIdx ] , now ) ;
+ + ( _paths [ _realIdxMap [ nextBestQualIdx ] ] . assignedFlowCount ) ;
+ + ( _paths [ _realIdxMap [ nextBestQualIdx ] ] . assignedFlowCount ) ;
@ -715,11 +727,13 @@ void Bond::forgetFlowsWhenNecessary(uint64_t age, bool oldest, int64_t now)
debug ( " forget flow %04x (age % " PRId64 " ) (%u / %zu) " , it - > first , it - > second - > age ( now ) , _paths [ it - > second - > assignedPath ] . assignedFlowCount , ( _flows . size ( ) - 1 ) ) ;
debug ( " forget flow %04x (age % " PRId64 " ) (%u / %zu) " , it - > first , it - > second - > age ( now ) , _paths [ it - > second - > assignedPath ] . assignedFlowCount , ( _flows . size ( ) - 1 ) ) ;
_paths [ it - > second - > assignedPath ] . assignedFlowCount - - ;
_paths [ it - > second - > assignedPath ] . assignedFlowCount - - ;
it = _flows . erase ( it ) ;
it = _flows . erase ( it ) ;
} else {
}
else {
+ + it ;
+ + it ;
}
}
}
}
} else if ( oldest ) { // Remove single oldest by natural expiration
}
else if ( oldest ) { // Remove single oldest by natural expiration
uint64_t maxAge = 0 ;
uint64_t maxAge = 0 ;
while ( it ! = _flows . end ( ) ) {
while ( it ! = _flows . end ( ) ) {
if ( it - > second - > age ( now ) > maxAge ) {
if ( it - > second - > age ( now ) > maxAge ) {
@ -766,7 +780,8 @@ void Bond::processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>&
if ( _peer - > _id . address ( ) . toInt ( ) > RR - > node - > identity ( ) . address ( ) . toInt ( ) ) {
if ( _peer - > _id . address ( ) . toInt ( ) > RR - > node - > identity ( ) . address ( ) . toInt ( ) ) {
debug ( " agree with peer to use alternate link %s/%s \n " , link - > ifname ( ) . c_str ( ) , pathStr ) ;
debug ( " agree with peer to use alternate link %s/%s \n " , link - > ifname ( ) . c_str ( ) , pathStr ) ;
_negotiatedPathIdx = pathIdx ;
_negotiatedPathIdx = pathIdx ;
} else {
}
else {
debug ( " ignore petition from peer to use alternate link %s/%s \n " , link - > ifname ( ) . c_str ( ) , pathStr ) ;
debug ( " ignore petition from peer to use alternate link %s/%s \n " , link - > ifname ( ) . c_str ( ) , pathStr ) ;
}
}
}
}
@ -881,7 +896,8 @@ void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, con
if ( atAddress ) {
if ( atAddress ) {
outp . armor ( _peer - > key ( ) , false , _peer - > aesKeysIfSupported ( ) ) ;
outp . armor ( _peer - > key ( ) , false , _peer - > aesKeysIfSupported ( ) ) ;
RR - > node - > putPacket ( tPtr , localSocket , atAddress , outp . data ( ) , outp . size ( ) ) ;
RR - > node - > putPacket ( tPtr , localSocket , atAddress , outp . data ( ) , outp . size ( ) ) ;
} else {
}
else {
RR - > sw - > send ( tPtr , outp , false ) ;
RR - > sw - > send ( tPtr , outp , false ) ;
}
}
Metrics : : pkt_qos_out + + ;
Metrics : : pkt_qos_out + + ;
@ -1222,7 +1238,8 @@ void Bond::estimatePathQuality(int64_t now)
if ( ( now - it - > second ) > = qosRecordTimeout ) {
if ( ( now - it - > second ) > = qosRecordTimeout ) {
it = _paths [ i ] . qosStatsOut . erase ( it ) ;
it = _paths [ i ] . qosStatsOut . erase ( it ) ;
+ + numDroppedQosOutRecords ;
+ + numDroppedQosOutRecords ;
} else {
}
else {
+ + it ;
+ + it ;
}
}
}
}
@ -1250,7 +1267,8 @@ void Bond::estimatePathQuality(int64_t now)
if ( ( now - it - > second ) > = qosRecordTimeout ) {
if ( ( now - it - > second ) > = qosRecordTimeout ) {
it = _paths [ i ] . qosStatsIn . erase ( it ) ;
it = _paths [ i ] . qosStatsIn . erase ( it ) ;
+ + numDroppedQosInRecords ;
+ + numDroppedQosInRecords ;
} else {
}
else {
+ + it ;
+ + it ;
}
}
}
}
@ -1327,10 +1345,10 @@ void Bond::estimatePathQuality(int64_t now)
continue ;
continue ;
}
}
// Compute/Smooth average of real-world observations
// Compute/Smooth average of real-world observations
if ( _paths [ i ] . latencySamples . count ( ) = = ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE ) {
if ( _paths [ i ] . latencySamples . count ( ) > = ZT_QOS_SHORTTERM_SAMPLE_WIN_MIN_REQ _SIZE ) {
_paths [ i ] . latency = _paths [ i ] . latencySamples . mean ( ) ;
_paths [ i ] . latency = _paths [ i ] . latencySamples . mean ( ) ;
}
}
if ( _paths [ i ] . latencySamples . count ( ) = = ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE ) {
if ( _paths [ i ] . latencySamples . count ( ) > = ZT_QOS_SHORTTERM_SAMPLE_WIN_MIN_REQ _SIZE ) {
_paths [ i ] . latencyVariance = _paths [ i ] . latencySamples . stddev ( ) ;
_paths [ i ] . latencyVariance = _paths [ i ] . latencySamples . stddev ( ) ;
}
}
@ -1344,6 +1362,7 @@ void Bond::estimatePathQuality(int64_t now)
//_paths[i].packetErrorRatio = 1.0 - (_paths[i].packetValiditySamples.count() ? _paths[i].packetValiditySamples.mean() : 1.0);
//_paths[i].packetErrorRatio = 1.0 - (_paths[i].packetValiditySamples.count() ? _paths[i].packetValiditySamples.mean() : 1.0);
// _valid is written elsewhere
// _valid is written elsewhere
_paths [ i ] . p - > _relativeQuality = _paths [ i ] . relativeQuality ;
_paths [ i ] . p - > _relativeQuality = _paths [ i ] . relativeQuality ;
_paths [ i ] . p - > _localPort = _paths [ i ] . localPort ;
}
}
// Flag links for avoidance
// Flag links for avoidance
@ -1370,7 +1389,8 @@ void Bond::estimatePathQuality(int64_t now)
shouldAvoid = true ;
shouldAvoid = true ;
}
}
_paths [ i ] . shouldAvoid = shouldAvoid ;
_paths [ i ] . shouldAvoid = shouldAvoid ;
} else {
}
else {
if ( ! shouldAvoid ) {
if ( ! shouldAvoid ) {
log ( " no longer avoiding link %s " , pathToStr ( _paths [ i ] . p ) . c_str ( ) ) ;
log ( " no longer avoiding link %s " , pathToStr ( _paths [ i ] . p ) . c_str ( ) ) ;
_paths [ i ] . shouldAvoid = false ;
_paths [ i ] . shouldAvoid = false ;
@ -1482,7 +1502,8 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
_lastBondStatusLog = now ;
_lastBondStatusLog = now ;
if ( _abPathIdx = = ZT_MAX_PEER_NETWORK_PATHS ) {
if ( _abPathIdx = = ZT_MAX_PEER_NETWORK_PATHS ) {
log ( " no active link " ) ;
log ( " no active link " ) ;
} else if ( _paths [ _abPathIdx ] . p ) {
}
else if ( _paths [ _abPathIdx ] . p ) {
log ( " active link is %s, failover queue size is %zu " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) , _abFailoverQueue . size ( ) ) ;
log ( " active link is %s, failover queue size is %zu " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) , _abFailoverQueue . size ( ) ) ;
}
}
if ( _abFailoverQueue . empty ( ) ) {
if ( _abFailoverQueue . empty ( ) ) {
@ -1590,7 +1611,8 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
log ( " link %s is ineligible, removing from failover queue (%zu links remain in queue) " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) , _abFailoverQueue . size ( ) ) ;
log ( " link %s is ineligible, removing from failover queue (%zu links remain in queue) " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) , _abFailoverQueue . size ( ) ) ;
}
}
continue ;
continue ;
} else {
}
else {
+ + it ;
+ + it ;
}
}
}
}
@ -1739,7 +1761,8 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
if ( ! _abFailoverQueue . empty ( ) ) {
if ( ! _abFailoverQueue . empty ( ) ) {
dequeueNextActiveBackupPath ( now ) ;
dequeueNextActiveBackupPath ( now ) ;
log ( " active link switched to %s " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) ) ;
log ( " active link switched to %s " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) ) ;
} else {
}
else {
log ( " failover queue is empty, no links to choose from " ) ;
log ( " failover queue is empty, no links to choose from " ) ;
}
}
}
}
@ -1785,7 +1808,8 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
dequeueNextActiveBackupPath ( now ) ;
dequeueNextActiveBackupPath ( now ) ;
_lastPathNegotiationCheck = now ;
_lastPathNegotiationCheck = now ;
log ( " switch negotiated link %s (select mode: optimize) " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) ) ;
log ( " switch negotiated link %s (select mode: optimize) " , pathToStr ( _paths [ _abPathIdx ] . p ) . c_str ( ) ) ;
} else {
}
else {
// Try to find a better path and automatically switch to it -- not too often, though.
// Try to find a better path and automatically switch to it -- not too often, though.
if ( ( now - _lastActiveBackupPathChange ) > ZT_BOND_OPTIMIZE_INTERVAL ) {
if ( ( now - _lastActiveBackupPathChange ) > ZT_BOND_OPTIMIZE_INTERVAL ) {
if ( ! _abFailoverQueue . empty ( ) ) {
if ( ! _abFailoverQueue . empty ( ) ) {
@ -1901,7 +1925,7 @@ void Bond::setBondParameters(int policy, SharedPtr<Bond> templateBond, bool useT
}
}
if ( ! _isLeaf ) {
if ( ! _isLeaf ) {
_policy = ZT_BOND_POLICY_ACTIVE_BACKUP ;
_policy = ZT_BOND_POLICY_NONE ;
}
}
// Timer geometry
// Timer geometry