blob: ff8ed50d219dd4e9baf3a604e1b6b1691350d6a4 [file] [log] [blame]
Vince Lehman8a4c29e2016-07-11 08:49:35 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -05002/*
Davide Pesaventod7083a52023-10-19 17:51:16 -04003 * Copyright (c) 2014-2023, Regents of the University of California,
Vince Lehman8a4c29e2016-07-11 08:49:35 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "fw/asf-strategy.hpp"
27
Junxiao Shi890afe92016-12-15 14:34:34 +000028#include "strategy-tester.hpp"
Vince Lehman8a4c29e2016-07-11 08:49:35 +000029#include "topology-tester.hpp"
30
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040031namespace nfd::tests {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000032
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040033using fw::AsfStrategy;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000034
Junxiao Shi890afe92016-12-15 14:34:34 +000035// The tester is unused in this file, but it's used in various templated test suites.
Davide Pesavento14e71f02019-03-28 17:35:25 -040036using AsfStrategyTester = StrategyTester<AsfStrategy>;
Junxiao Shi890afe92016-12-15 14:34:34 +000037NFD_REGISTER_STRATEGY(AsfStrategyTester);
38
Vince Lehman8a4c29e2016-07-11 08:49:35 +000039BOOST_AUTO_TEST_SUITE(Fw)
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040040BOOST_FIXTURE_TEST_SUITE(TestAsfStrategy, GlobalIoTimeFixture)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000041
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040042class AsfGridFixture : public GlobalIoTimeFixture
Vince Lehman8a4c29e2016-07-11 08:49:35 +000043{
44protected:
Davide Pesavento14e71f02019-03-28 17:35:25 -040045 explicit
Saurab Dulal432be572021-01-26 12:09:29 -060046 AsfGridFixture(const Name& params = AsfStrategy::getStrategyName(),
47 time::nanoseconds replyDelay = 0_ns)
Davide Pesavento14e71f02019-03-28 17:35:25 -040048 : parameters(params)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000049 {
50 /*
51 * +---------+
52 * +----->| nodeB |<------+
53 * | +---------+ |
54 * 10ms | | 10ms
55 * v v
56 * +---------+ +---------+
57 * | nodeA | | nodeC |
58 * +---------+ +---------+
59 * ^ ^
60 * 100ms | | 100ms
61 * | +---------+ |
62 * +----->| nodeD |<------+
63 * +---------+
64 */
65
66 nodeA = topo.addForwarder("A");
67 nodeB = topo.addForwarder("B");
68 nodeC = topo.addForwarder("C");
69 nodeD = topo.addForwarder("D");
70
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -040071 for (auto node : {nodeA, nodeB, nodeC, nodeD}) {
72 topo.setStrategy<AsfStrategy>(node, Name("/"), parameters);
73 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +000074
Davide Pesavento14e71f02019-03-28 17:35:25 -040075 linkAB = topo.addLink("AB", 10_ms, {nodeA, nodeB});
76 linkAD = topo.addLink("AD", 100_ms, {nodeA, nodeD});
77 linkBC = topo.addLink("BC", 10_ms, {nodeB, nodeC});
78 linkCD = topo.addLink("CD", 100_ms, {nodeC, nodeD});
Vince Lehman8a4c29e2016-07-11 08:49:35 +000079
80 consumer = topo.addAppFace("c", nodeA);
81 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
Saurab Dulala6dec222019-04-01 00:15:10 -050082
83 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX, replyDelay);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000084
85 // Register producer prefix on consumer node
86 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 10);
87 topo.registerPrefix(nodeA, linkAD->getFace(nodeA), PRODUCER_PREFIX, 5);
88 }
89
90 void
Saurab Dulal432be572021-01-26 12:09:29 -060091 runConsumer(size_t numInterests = 30)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000092 {
Davide Pesavento14e71f02019-03-28 17:35:25 -040093 topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, 1_s, numInterests);
94 this->advanceClocks(10_ms, time::seconds(numInterests));
Vince Lehman8a4c29e2016-07-11 08:49:35 +000095 }
96
97protected:
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -050098 Name parameters;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000099 TopologyTester topo;
100
101 TopologyNode nodeA;
102 TopologyNode nodeB;
103 TopologyNode nodeC;
104 TopologyNode nodeD;
105
106 shared_ptr<TopologyLink> linkAB;
107 shared_ptr<TopologyLink> linkAD;
108 shared_ptr<TopologyLink> linkBC;
109 shared_ptr<TopologyLink> linkCD;
110
111 shared_ptr<TopologyAppLink> consumer;
112 shared_ptr<TopologyAppLink> producer;
113
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400114 static inline const Name PRODUCER_PREFIX{"/hr/C"};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000115};
116
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500117class AsfStrategyParametersGridFixture : public AsfGridFixture
118{
119protected:
120 AsfStrategyParametersGridFixture()
121 : AsfGridFixture(Name(AsfStrategy::getStrategyName())
122 .append("probing-interval~30000")
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400123 .append("max-timeouts~5"))
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500124 {
125 }
126};
127
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000128BOOST_FIXTURE_TEST_CASE(Basic, AsfGridFixture)
129{
130 // Both nodeB and nodeD have FIB entries to reach the producer
131 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
132 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
133
134 runConsumer();
135
136 // ASF should use the Face to nodeD because it has lower routing cost.
137 // After 5 seconds, a probe Interest should be sent to the Face to nodeB,
138 // and the probe should return Data quicker. ASF should then use the Face
139 // to nodeB to forward the remaining Interests.
140 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 30);
Alex Lane9cec6992020-03-05 19:10:09 -0600141 // Because of exploration, will forward to AB and AD simultaneously at least once
142 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 25);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000143 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 6);
144
145 // If the link from nodeA to nodeB fails, ASF should start using the Face
146 // to nodeD again.
147 linkAB->fail();
148
149 runConsumer();
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400150 // We experience 3 timeouts and marked AB as timed out
151 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 57);
Alex Lane9cec6992020-03-05 19:10:09 -0600152 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 36);
153 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 24);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000154
155 // If the link from nodeA to nodeB recovers, ASF should probe the Face
156 // to nodeB and start using it again.
157 linkAB->recover();
158
159 // Advance time to ensure probing is due
Davide Pesavento14e71f02019-03-28 17:35:25 -0400160 this->advanceClocks(10_ms, 10_s);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000161
162 runConsumer();
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400163 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 87);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000164 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 50);
165 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 40);
166
167 // If both links fail, nodeA should forward to the next hop with the lowest cost
168 linkAB->fail();
169 linkAD->fail();
170
171 runConsumer();
172
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400173 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 87);
Alex Lane9cec6992020-03-05 19:10:09 -0600174 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 65); // FIXME #3830
175 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 57); // FIXME #3830
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000176}
177
178BOOST_FIXTURE_TEST_CASE(Nack, AsfGridFixture)
179{
180 // nodeB has a FIB entry to reach the producer, but nodeD does not
181 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
182
183 // The strategy should first try to send to nodeD. But since nodeD does not have a route for
184 // the producer's prefix, it should return a NO_ROUTE Nack. The strategy should then start using the Face to
185 // nodeB.
186 runConsumer();
187
188 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nInNacks, 1);
189 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 29);
190 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 29);
191
192 // nodeD should receive 2 Interests: one for the very first Interest and
193 // another from a probe
194 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
195}
196
Saurab Dulala6dec222019-04-01 00:15:10 -0500197class AsfStrategyDelayedDataFixture : public AsfGridFixture
198{
199protected:
200 AsfStrategyDelayedDataFixture()
201 : AsfGridFixture(Name(AsfStrategy::getStrategyName()), 400_ms)
202 {
203 }
204};
205
206BOOST_FIXTURE_TEST_CASE(InterestForwarding, AsfStrategyDelayedDataFixture)
207{
Saurab Dulala6dec222019-04-01 00:15:10 -0500208 Name name(PRODUCER_PREFIX);
209 name.appendTimestamp();
Saurab Dulal432be572021-01-26 12:09:29 -0600210 auto interest = makeInterest(name);
Saurab Dulala6dec222019-04-01 00:15:10 -0500211
212 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
213 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
214
215 // The first interest should go via link AD
216 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
217 this->advanceClocks(10_ms, 100_ms);
218 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, 1);
219
220 // Second interest should go via link AB
221 interest->refreshNonce();
222 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
223 this->advanceClocks(10_ms, 100_ms);
224 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 1);
225
226 // The third interest should again go via AD, since both the face from A is already used
227 // and so asf should choose the earliest used face i.e. AD
228 interest->refreshNonce();
229 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
230 this->advanceClocks(10_ms, 100_ms);
231 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
232
233 this->advanceClocks(time::milliseconds(500), time::seconds(5));
234 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nInData, 1);
235 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nInData, 1);
236 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 1);
Saurab Dulala6dec222019-04-01 00:15:10 -0500237}
238
Saurab Dulal432be572021-01-26 12:09:29 -0600239BOOST_AUTO_TEST_CASE(Retransmission) // Bug #4874
Saurab Dulala6dec222019-04-01 00:15:10 -0500240{
Saurab Dulala6dec222019-04-01 00:15:10 -0500241 // Avoid clearing pit entry for those incoming interest that have pit entry but no next hops
Saurab Dulal432be572021-01-26 12:09:29 -0600242 /*
243 * +---------+ 10ms +---------+
244 * | nodeB | ------> | nodeC |
245 * +---------+ +---------+
246 */
Saurab Dulala6dec222019-04-01 00:15:10 -0500247
Saurab Dulal432be572021-01-26 12:09:29 -0600248 const Name PRODUCER_PREFIX = "/pnr/C";
Saurab Dulala6dec222019-04-01 00:15:10 -0500249 TopologyTester topo;
250
251 TopologyNode nodeB = topo.addForwarder("B"),
252 nodeC = topo.addForwarder("C");
253
Saurab Dulal432be572021-01-26 12:09:29 -0600254 for (auto node : {nodeB, nodeC}) {
255 topo.setStrategy<AsfStrategy>(node);
256 }
Saurab Dulala6dec222019-04-01 00:15:10 -0500257
Saurab Dulal432be572021-01-26 12:09:29 -0600258 auto linkBC = topo.addLink("BC", time::milliseconds(10), {nodeB, nodeC});
Saurab Dulala6dec222019-04-01 00:15:10 -0500259
Saurab Dulal432be572021-01-26 12:09:29 -0600260 auto consumer = topo.addAppFace("c", nodeB),
261 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
Saurab Dulala6dec222019-04-01 00:15:10 -0500262
263 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX, 100_ms);
264
265 Name name(PRODUCER_PREFIX);
266 name.appendTimestamp();
Saurab Dulal432be572021-01-26 12:09:29 -0600267 auto interest = makeInterest(name);
Saurab Dulala6dec222019-04-01 00:15:10 -0500268
Saurab Dulal432be572021-01-26 12:09:29 -0600269 auto& pit = topo.getForwarder(nodeB).getPit();
270 auto pitEntry = pit.insert(*interest).first;
Saurab Dulala6dec222019-04-01 00:15:10 -0500271
Davide Pesavento0498ce82021-06-14 02:02:21 -0400272 topo.getForwarder(nodeB).onOutgoingInterest(*interest, linkBC->getFace(nodeB), pitEntry);
Saurab Dulala6dec222019-04-01 00:15:10 -0500273 this->advanceClocks(time::milliseconds(100));
274
275 interest->refreshNonce();
276 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
277 this->advanceClocks(time::milliseconds(100));
278
Saurab Dulal432be572021-01-26 12:09:29 -0600279 auto outRecord = pitEntry->getOutRecord(linkBC->getFace(nodeB));
Saurab Dulala6dec222019-04-01 00:15:10 -0500280 BOOST_CHECK(outRecord != pitEntry->out_end());
281
282 this->advanceClocks(time::milliseconds(100));
283 BOOST_CHECK_EQUAL(linkBC->getFace(nodeC).getCounters().nOutData, 1);
284 BOOST_CHECK_EQUAL(linkBC->getFace(nodeB).getCounters().nInData, 1);
285}
286
Saurab Dulal432be572021-01-26 12:09:29 -0600287BOOST_AUTO_TEST_CASE(PerUpstreamSuppression)
288{
289 /*
290 * +---------+
291 * +----| nodeB |----+
292 * | +---------+ |
293 * 50ms | | 50ms
294 * | |
295 * +---------+ 50ms +---------+
296 * | nodeA | <-----> | nodeP |
297 * +---------+ +---------+
298 */
299
300 const Name PRODUCER_PREFIX = "/suppress/me";
301 TopologyTester topo;
302
303 TopologyNode nodeA = topo.addForwarder("A"),
304 nodeB = topo.addForwarder("B"),
305 nodeP = topo.addForwarder("P");
306
307 for (auto node : {nodeA, nodeB, nodeP}) {
308 topo.setStrategy<AsfStrategy>(node);
309 }
310
311 auto linkAB = topo.addLink("AB", 50_ms, {nodeA, nodeB});
312 auto linkAP = topo.addLink("AP", 50_ms, {nodeA, nodeP});
313 auto linkBP = topo.addLink("BP", 50_ms, {nodeB, nodeP});
314
315 auto consumer = topo.addAppFace("cons", nodeA),
316 producer = topo.addAppFace("prod", nodeP, PRODUCER_PREFIX);
317
318 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX);
319
320 topo.registerPrefix(nodeA, linkAP->getFace(nodeA), PRODUCER_PREFIX, 10);
321 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 1);
322 topo.registerPrefix(nodeB, linkBP->getFace(nodeB), PRODUCER_PREFIX, 1);
323
324 auto& faceA2B = linkAB->getFace(nodeA);
325 auto& faceA2P = linkAP->getFace(nodeA);
326
327 Name name(PRODUCER_PREFIX);
328 name.appendTimestamp();
329 // very short lifetime to make it expire within the initial retx suppression period (10ms)
330 auto interest = makeInterest(name, false, 5_ms);
331
332 // 1st interest should be sent to B
333 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
334 this->advanceClocks(1_ms);
335 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
336 BOOST_TEST(faceA2P.getCounters().nOutInterests == 0);
337
338 // 2nd interest should be sent to P and NOT suppressed
339 interest->setInterestLifetime(100_ms);
340 interest->refreshNonce();
341 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
342 this->advanceClocks(1_ms);
343 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
344 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
345
346 this->advanceClocks(1_ms);
347
348 // 3rd interest should be suppressed
349 // without suppression, it would have been sent again to B as that's the earliest out-record
350 interest->refreshNonce();
351 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
352 this->advanceClocks(1_ms);
353 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
354 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
355
356 this->advanceClocks(2_ms); // 1st interest should expire now
357
358 // 4th interest should be suppressed
359 // without suppression, it would have been sent again to B because the out-record expired
360 interest->refreshNonce();
361 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
362 this->advanceClocks(1_ms);
363 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
364 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
365
366 this->advanceClocks(5_ms); // suppression window ends
367
368 // 5th interest is sent to B and is outside the suppression window
369 interest->refreshNonce();
370 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
371 this->advanceClocks(1_ms);
372 BOOST_TEST(faceA2B.getCounters().nOutInterests == 2);
373 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
374
375 this->advanceClocks(10_ms);
376
377 // 6th interest is sent to P and is outside the suppression window
378 interest->refreshNonce();
379 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
380 this->advanceClocks(1_ms);
381 BOOST_TEST(faceA2B.getCounters().nOutInterests == 2);
382 BOOST_TEST(faceA2P.getCounters().nOutInterests == 2);
383}
384
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000385BOOST_AUTO_TEST_CASE(NoPitOutRecordAndProbeInterestNewNonce)
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600386{
Saurab Dulal432be572021-01-26 12:09:29 -0600387 /* +---------+
388 * | nodeD |
389 * +---------+
390 * |
391 * | 80ms
392 * |
393 * |
394 * +---------+
395 * +----->| nodeB |<------+
396 * | +---------+ |
397 * 15ms | | 16ms
398 * v v
399 * +---------+ +---------+
400 * | nodeA |--------------| nodeC |
401 * +---------+ 14ms +---------+
402 */
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600403
404 const Name PRODUCER_PREFIX = "/ndn/edu/nodeD/ping";
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600405 TopologyTester topo;
Saurab Dulal432be572021-01-26 12:09:29 -0600406
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600407 TopologyNode nodeA = topo.addForwarder("A"),
408 nodeB = topo.addForwarder("B"),
409 nodeC = topo.addForwarder("C"),
410 nodeD = topo.addForwarder("D");
411
Saurab Dulal432be572021-01-26 12:09:29 -0600412 for (auto node : {nodeA, nodeB, nodeC, nodeD}) {
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500413 topo.setStrategy<AsfStrategy>(node);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600414 }
415
Saurab Dulal432be572021-01-26 12:09:29 -0600416 auto linkAB = topo.addLink("AB", 15_ms, {nodeA, nodeB}),
417 linkAC = topo.addLink("AC", 14_ms, {nodeA, nodeC}),
418 linkBC = topo.addLink("BC", 16_ms, {nodeB, nodeC}),
419 linkBD = topo.addLink("BD", 80_ms, {nodeB, nodeD});
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600420
Saurab Dulal432be572021-01-26 12:09:29 -0600421 auto ping = topo.addAppFace("c", nodeA);
422 auto pingServer = topo.addAppFace("p", nodeD, PRODUCER_PREFIX);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600423 topo.addEchoProducer(pingServer->getClientFace());
424
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600425 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 15);
426 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 14);
427 topo.registerPrefix(nodeC, linkBC->getFace(nodeC), PRODUCER_PREFIX, 16);
428 topo.registerPrefix(nodeB, linkBD->getFace(nodeB), PRODUCER_PREFIX, 80);
429
430 // Send 6 interest since probes can be scheduled b/w 0-5 seconds
431 for (int i = 1; i < 7; i++) {
432 // Send ping number i
433 Name name(PRODUCER_PREFIX);
434 name.appendTimestamp();
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400435 auto interest = makeInterest(name);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600436 ping->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400437 auto nonce = interest->getNonce();
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600438
439 // Don't know when the probe will be triggered since it is random between 0-5 seconds
440 // or whether it will be triggered for this interest
Davide Pesavento14e71f02019-03-28 17:35:25 -0400441 for (int j = 1; j <= 1000 && linkAB->getFace(nodeA).getCounters().nOutInterests != 1; ++j) {
442 this->advanceClocks(1_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600443 }
444
445 // Check if probe is sent to B else send another ping
446 if (linkAB->getFace(nodeA).getCounters().nOutInterests == 1) {
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000447 // Get pitEntry of node A
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400448 auto pitEntry = topo.getForwarder(nodeA).getPit().find(*interest);
449 // Get outRecord associated with face towards B
450 auto outRecord = pitEntry->getOutRecord(linkAB->getFace(nodeA));
451 BOOST_REQUIRE(outRecord != pitEntry->out_end());
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000452
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400453 // Check that Nonce of interest is not equal to Nonce of Probe
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000454 BOOST_CHECK_NE(nonce, outRecord->getLastNonce());
455
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600456 // B should not have received the probe interest yet
457 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 0);
458
459 // i-1 interests through B when no probe
460 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i - 1);
461
462 // After 15ms, B should get the probe interest
Davide Pesavento14e71f02019-03-28 17:35:25 -0400463 this->advanceClocks(1_ms, 15_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600464 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 1);
465 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i);
466
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000467 pitEntry = topo.getForwarder(nodeB).getPit().find(*interest);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600468
469 // Get outRecord associated with face towards D.
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000470 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600471 BOOST_CHECK(outRecord != pitEntry->out_end());
472
473 // RTT between B and D
Davide Pesavento14e71f02019-03-28 17:35:25 -0400474 this->advanceClocks(5_ms, 160_ms);
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000475 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600476
477 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i);
478
479 BOOST_CHECK(outRecord == pitEntry->out_end());
480
481 // Data is returned for the ping after 15 ms - will result in false measurement
482 // 14+16-15 = 15ms
483 // Since outRecord == pitEntry->out_end()
Davide Pesavento14e71f02019-03-28 17:35:25 -0400484 this->advanceClocks(1_ms, 15_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600485 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i+1);
486
487 break;
488 }
489 }
490}
491
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500492BOOST_FIXTURE_TEST_CASE(IgnoreTimeouts, AsfStrategyParametersGridFixture)
493{
494 // Both nodeB and nodeD have FIB entries to reach the producer
495 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
496 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
497
498 // Send 15 interests let it change to use the 10 ms link
499 runConsumer(15);
500
Saurab Dulal432be572021-01-26 12:09:29 -0600501 uint64_t outInterestsBeforeFailure = linkAD->getFace(nodeA).getCounters().nOutInterests;
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500502
503 // Bring down 10 ms link
504 linkAB->fail();
505
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400506 // Send 5 interests, after the last one it will record the timeout
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500507 // ready to switch for the next interest
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400508 runConsumer(5);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500509
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400510 // Check that link has not been switched to 100 ms because max-timeouts = 5
Saurab Dulal432be572021-01-26 12:09:29 -0600511 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, outInterestsBeforeFailure);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500512
513 // Send 5 interests, check that 100 ms link is used
514 runConsumer(5);
515
Saurab Dulal432be572021-01-26 12:09:29 -0600516 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, outInterestsBeforeFailure + 5);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500517}
518
519BOOST_FIXTURE_TEST_CASE(ProbingInterval, AsfStrategyParametersGridFixture)
520{
521 // Both nodeB and nodeD have FIB entries to reach the producer
522 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
523 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
524
525 // Send 6 interests let it change to use the 10 ms link
526 runConsumer(6);
527
Saurab Dulal432be572021-01-26 12:09:29 -0600528 auto linkAC = topo.addLink("AC", 5_ms, {nodeA, nodeD});
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500529 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 1);
530
531 BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 0);
532
533 // After 30 seconds a probe would be sent that would switch make ASF switch
534 runConsumer(30);
535
536 BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 1);
537}
538
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400539BOOST_AUTO_TEST_CASE(Parameters)
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500540{
Saurab Dulal432be572021-01-26 12:09:29 -0600541 FaceTable faceTable;
542 Forwarder forwarder{faceTable};
543
Davide Pesaventod7083a52023-10-19 17:51:16 -0400544 auto checkValidity = [&] (std::string_view parameters, bool isCorrect) {
545 BOOST_TEST_INFO_SCOPE(parameters);
546 Name strategyName(Name(AsfStrategy::getStrategyName()).append(Name(parameters)));
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400547 std::unique_ptr<AsfStrategy> strategy;
Davide Pesaventod7083a52023-10-19 17:51:16 -0400548 if (isCorrect) {
549 strategy = make_unique<AsfStrategy>(forwarder, strategyName);
550 BOOST_CHECK(strategy->m_retxSuppression != nullptr);
551 }
552 else {
553 BOOST_CHECK_THROW(make_unique<AsfStrategy>(forwarder, strategyName), std::invalid_argument);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500554 }
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400555 return strategy;
Saurab Dulal432be572021-01-26 12:09:29 -0600556 };
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500557
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400558 auto strategy = checkValidity("", true);
559 BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
560 BOOST_TEST(strategy->m_nMaxTimeouts == 3);
561 strategy = checkValidity("/probing-interval~30000/max-timeouts~5", true);
562 BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
563 BOOST_TEST(strategy->m_nMaxTimeouts == 5);
564 strategy = checkValidity("/max-timeouts~5/probing-interval~30000", true);
565 BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
566 BOOST_TEST(strategy->m_nMaxTimeouts == 5);
567 strategy = checkValidity("/probing-interval~1000", true);
568 BOOST_TEST(strategy->m_probing.getProbingInterval() == 1_s);
569 BOOST_TEST(strategy->m_nMaxTimeouts == 3);
570 strategy = checkValidity("/max-timeouts~0", true);
571 BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
572 BOOST_TEST(strategy->m_nMaxTimeouts == 0);
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400573 BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == fw::RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
574 BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == fw::RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
575 BOOST_TEST(strategy->m_retxSuppression->m_multiplier == fw::RetxSuppressionExponential::DEFAULT_MULTIPLIER);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500576
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400577 checkValidity("/probing-interval~500", false); // minimum is 1 second
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500578 checkValidity("/probing-interval~-5000", false);
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400579 checkValidity("/max-timeouts~-1", false);
580 checkValidity("/max-timeouts~ -1", false);
581 checkValidity("/max-timeouts~1-0", false);
582 checkValidity("/max-timeouts~1/probing-interval~-30000", false);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500583 checkValidity("/probing-interval~foo", false);
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400584 checkValidity("/max-timeouts~1~2", false);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500585}
586
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000587BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
588BOOST_AUTO_TEST_SUITE_END() // Fw
589
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400590} // namespace nfd::tests