@@ -109,76 +109,51 @@ void Peer::received(
109
109
havePath = true ;
110
110
break ;
111
111
}
112
+ // If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop)
113
+ if (_paths[i].p ->address ().ipsEqual (path->address ()) && _paths[i].p ->localSocket () == path->localSocket ()) {
114
+ if (_paths[i].p ->alive (now) && !_bond) {
115
+ havePath = true ;
116
+ break ;
117
+ }
118
+ }
112
119
} else {
113
120
break ;
114
121
}
115
122
}
116
123
}
117
124
118
125
if ( (!havePath) && RR->node ->shouldUsePathForZeroTierTraffic (tPtr,_id.address (),path->localSocket (),path->address ()) ) {
119
-
120
- /* *
121
- * First, fill all free slots before attempting to replace a path
122
- * - If the above fails, attempt to replace the path that has been dead the longest
123
- * - If there are no free slots, and no dead paths (unlikely), then replace old path most similar to new path
124
- * - If all of the above fails to yield a suitable replacement. Replace first path found to have lower `(quality / priority)`
125
- */
126
-
127
126
if (verb == Packet::VERB_OK) {
128
127
Mutex::Lock _l (_paths_m);
128
+ unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
129
+ unsigned int oldestPathAge = 0 ;
129
130
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS;
130
- uint64_t maxScore = 0 ;
131
- uint64_t currScore;
132
- long replacePathQuality = 0 ;
133
- bool foundFreeSlot = false ;
134
131
135
132
for (unsigned int i=0 ;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
136
- currScore = 0 ;
137
133
if (_paths[i].p ) {
138
- // Reward dead paths
139
- if (!_paths[i].p ->alive (now)) {
140
- currScore = _paths[i].p ->age (now) / 1000 ;
134
+ // Keep track of oldest path as a last resort option
135
+ unsigned int currAge = _paths[i].p ->age (now);
136
+ if (currAge > oldestPathAge) {
137
+ oldestPathAge = currAge;
138
+ oldestPathIdx = i;
141
139
}
142
- // Reward as similarity increases
143
140
if (_paths[i].p ->address ().ipsEqual (path->address ())) {
144
- currScore++;
145
- if (_paths[i].p ->address ().port () == path->address ().port ()) {
146
- currScore++;
147
- if (_paths[i].p ->localSocket () == path->localSocket ()) {
148
- currScore++; // max score (3)
141
+ if (_paths[i].p ->localSocket () == path->localSocket ()) {
142
+ if (!_paths[i].p ->alive (now)) {
143
+ replacePath = i;
144
+ break ;
149
145
}
150
146
}
151
147
}
152
- // If best so far, mark for replacement
153
- if (currScore > maxScore) {
154
- maxScore = currScore;
155
- replacePath = i;
156
- }
157
148
}
158
149
else {
159
- foundFreeSlot = true ;
160
150
replacePath = i;
161
151
break ;
162
152
}
163
153
}
164
- if (!foundFreeSlot) {
165
- if (maxScore > 3 ) {
166
- // Do nothing. We found a dead path and have already marked it as a candidate
167
- }
168
- // If we couldn't find a replacement by matching, replacing a dead path, or taking a free slot, then replace by quality
169
- else if (maxScore == 0 ) {
170
- for (unsigned int i=0 ;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
171
- if (_paths[i].p ) {
172
- const long q = _paths[i].p ->quality (now) / _paths[i].priority ;
173
- if (q > replacePathQuality) {
174
- replacePathQuality = q;
175
- replacePath = i;
176
- }
177
- }
178
- }
179
- }
180
- }
181
154
155
+ // If we didn't find a good candidate then resort to replacing oldest path
156
+ replacePath = (replacePath == ZT_MAX_PEER_NETWORK_PATHS) ? oldestPathIdx : replacePath;
182
157
if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) {
183
158
RR->t ->peerLearnedNewPath (tPtr, networkId, *this , path, packetId);
184
159
_paths[replacePath].lr = now;
@@ -540,11 +515,15 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
540
515
// let those old links expire.
541
516
long maxPriority = 0 ;
542
517
for (unsigned int i=0 ;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
543
- if (_paths[i].p )
518
+ if (_paths[i].p ) {
544
519
maxPriority = std::max (_paths[i].priority ,maxPriority);
545
- else break ;
520
+ }
521
+ else {
522
+ break ;
523
+ }
546
524
}
547
525
526
+ bool deletionOccurred = false ;
548
527
for (unsigned int i=0 ;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
549
528
if (_paths[i].p ) {
550
529
// Clean expired and reduced priority paths
@@ -554,10 +533,22 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
554
533
_paths[i].p ->sent (now);
555
534
sent |= (_paths[i].p ->address ().ss_family == AF_INET) ? 0x1 : 0x2 ;
556
535
}
557
- } else {
536
+ }
537
+ else {
558
538
_paths[i] = _PeerPath ();
539
+ deletionOccurred = true ;
559
540
}
560
- } else break ;
541
+ }
542
+ if (!_paths[i].p || deletionOccurred) {
543
+ for (unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) {
544
+ if (_paths[j].p && i != j) {
545
+ _paths[i] = _paths[j];
546
+ _paths[j] = _PeerPath ();
547
+ break ;
548
+ }
549
+ }
550
+ deletionOccurred = false ;
551
+ }
561
552
}
562
553
return sent;
563
554
}
0 commit comments