blob: e80a28769d9b0953bb467894fc76ef11ab8c1008 [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/*
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -04003 * Copyright (c) 2014-2022, 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
31namespace nfd {
32namespace fw {
33namespace asf {
34namespace tests {
35
36using namespace nfd::fw::tests;
37
Junxiao Shi890afe92016-12-15 14:34:34 +000038// The tester is unused in this file, but it's used in various templated test suites.
Davide Pesavento14e71f02019-03-28 17:35:25 -040039using AsfStrategyTester = StrategyTester<AsfStrategy>;
Junxiao Shi890afe92016-12-15 14:34:34 +000040NFD_REGISTER_STRATEGY(AsfStrategyTester);
41
Vince Lehman8a4c29e2016-07-11 08:49:35 +000042BOOST_AUTO_TEST_SUITE(Fw)
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040043BOOST_FIXTURE_TEST_SUITE(TestAsfStrategy, GlobalIoTimeFixture)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000044
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040045class AsfGridFixture : public GlobalIoTimeFixture
Vince Lehman8a4c29e2016-07-11 08:49:35 +000046{
47protected:
Davide Pesavento14e71f02019-03-28 17:35:25 -040048 explicit
Saurab Dulal432be572021-01-26 12:09:29 -060049 AsfGridFixture(const Name& params = AsfStrategy::getStrategyName(),
50 time::nanoseconds replyDelay = 0_ns)
Davide Pesavento14e71f02019-03-28 17:35:25 -040051 : parameters(params)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000052 {
53 /*
54 * +---------+
55 * +----->| nodeB |<------+
56 * | +---------+ |
57 * 10ms | | 10ms
58 * v v
59 * +---------+ +---------+
60 * | nodeA | | nodeC |
61 * +---------+ +---------+
62 * ^ ^
63 * 100ms | | 100ms
64 * | +---------+ |
65 * +----->| nodeD |<------+
66 * +---------+
67 */
68
69 nodeA = topo.addForwarder("A");
70 nodeB = topo.addForwarder("B");
71 nodeC = topo.addForwarder("C");
72 nodeD = topo.addForwarder("D");
73
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -040074 for (auto node : {nodeA, nodeB, nodeC, nodeD}) {
75 topo.setStrategy<AsfStrategy>(node, Name("/"), parameters);
76 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +000077
Davide Pesavento14e71f02019-03-28 17:35:25 -040078 linkAB = topo.addLink("AB", 10_ms, {nodeA, nodeB});
79 linkAD = topo.addLink("AD", 100_ms, {nodeA, nodeD});
80 linkBC = topo.addLink("BC", 10_ms, {nodeB, nodeC});
81 linkCD = topo.addLink("CD", 100_ms, {nodeC, nodeD});
Vince Lehman8a4c29e2016-07-11 08:49:35 +000082
83 consumer = topo.addAppFace("c", nodeA);
84 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
Saurab Dulala6dec222019-04-01 00:15:10 -050085
86 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX, replyDelay);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000087
88 // Register producer prefix on consumer node
89 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 10);
90 topo.registerPrefix(nodeA, linkAD->getFace(nodeA), PRODUCER_PREFIX, 5);
91 }
92
93 void
Saurab Dulal432be572021-01-26 12:09:29 -060094 runConsumer(size_t numInterests = 30)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000095 {
Davide Pesavento14e71f02019-03-28 17:35:25 -040096 topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, 1_s, numInterests);
97 this->advanceClocks(10_ms, time::seconds(numInterests));
Vince Lehman8a4c29e2016-07-11 08:49:35 +000098 }
99
100protected:
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500101 Name parameters;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000102 TopologyTester topo;
103
104 TopologyNode nodeA;
105 TopologyNode nodeB;
106 TopologyNode nodeC;
107 TopologyNode nodeD;
108
109 shared_ptr<TopologyLink> linkAB;
110 shared_ptr<TopologyLink> linkAD;
111 shared_ptr<TopologyLink> linkBC;
112 shared_ptr<TopologyLink> linkCD;
113
114 shared_ptr<TopologyAppLink> consumer;
115 shared_ptr<TopologyAppLink> producer;
116
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400117 static inline const Name PRODUCER_PREFIX{"/hr/C"};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000118};
119
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500120class AsfStrategyParametersGridFixture : public AsfGridFixture
121{
122protected:
123 AsfStrategyParametersGridFixture()
124 : AsfGridFixture(Name(AsfStrategy::getStrategyName())
125 .append("probing-interval~30000")
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400126 .append("max-timeouts~5"))
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500127 {
128 }
129};
130
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000131BOOST_FIXTURE_TEST_CASE(Basic, AsfGridFixture)
132{
133 // Both nodeB and nodeD have FIB entries to reach the producer
134 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
135 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
136
137 runConsumer();
138
139 // ASF should use the Face to nodeD because it has lower routing cost.
140 // After 5 seconds, a probe Interest should be sent to the Face to nodeB,
141 // and the probe should return Data quicker. ASF should then use the Face
142 // to nodeB to forward the remaining Interests.
143 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 30);
Alex Lane9cec6992020-03-05 19:10:09 -0600144 // Because of exploration, will forward to AB and AD simultaneously at least once
145 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 25);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000146 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 6);
147
148 // If the link from nodeA to nodeB fails, ASF should start using the Face
149 // to nodeD again.
150 linkAB->fail();
151
152 runConsumer();
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400153 // We experience 3 timeouts and marked AB as timed out
154 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 57);
Alex Lane9cec6992020-03-05 19:10:09 -0600155 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 36);
156 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 24);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000157
158 // If the link from nodeA to nodeB recovers, ASF should probe the Face
159 // to nodeB and start using it again.
160 linkAB->recover();
161
162 // Advance time to ensure probing is due
Davide Pesavento14e71f02019-03-28 17:35:25 -0400163 this->advanceClocks(10_ms, 10_s);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000164
165 runConsumer();
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400166 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 87);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000167 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 50);
168 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 40);
169
170 // If both links fail, nodeA should forward to the next hop with the lowest cost
171 linkAB->fail();
172 linkAD->fail();
173
174 runConsumer();
175
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400176 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 87);
Alex Lane9cec6992020-03-05 19:10:09 -0600177 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 65); // FIXME #3830
178 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 57); // FIXME #3830
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000179}
180
181BOOST_FIXTURE_TEST_CASE(Nack, AsfGridFixture)
182{
183 // nodeB has a FIB entry to reach the producer, but nodeD does not
184 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
185
186 // The strategy should first try to send to nodeD. But since nodeD does not have a route for
187 // the producer's prefix, it should return a NO_ROUTE Nack. The strategy should then start using the Face to
188 // nodeB.
189 runConsumer();
190
191 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nInNacks, 1);
192 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 29);
193 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 29);
194
195 // nodeD should receive 2 Interests: one for the very first Interest and
196 // another from a probe
197 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
198}
199
Saurab Dulala6dec222019-04-01 00:15:10 -0500200class AsfStrategyDelayedDataFixture : public AsfGridFixture
201{
202protected:
203 AsfStrategyDelayedDataFixture()
204 : AsfGridFixture(Name(AsfStrategy::getStrategyName()), 400_ms)
205 {
206 }
207};
208
209BOOST_FIXTURE_TEST_CASE(InterestForwarding, AsfStrategyDelayedDataFixture)
210{
Saurab Dulala6dec222019-04-01 00:15:10 -0500211 Name name(PRODUCER_PREFIX);
212 name.appendTimestamp();
Saurab Dulal432be572021-01-26 12:09:29 -0600213 auto interest = makeInterest(name);
Saurab Dulala6dec222019-04-01 00:15:10 -0500214
215 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
216 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
217
218 // The first interest should go via link AD
219 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
220 this->advanceClocks(10_ms, 100_ms);
221 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, 1);
222
223 // Second interest should go via link AB
224 interest->refreshNonce();
225 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
226 this->advanceClocks(10_ms, 100_ms);
227 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 1);
228
229 // The third interest should again go via AD, since both the face from A is already used
230 // and so asf should choose the earliest used face i.e. AD
231 interest->refreshNonce();
232 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
233 this->advanceClocks(10_ms, 100_ms);
234 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
235
236 this->advanceClocks(time::milliseconds(500), time::seconds(5));
237 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nInData, 1);
238 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nInData, 1);
239 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 1);
Saurab Dulala6dec222019-04-01 00:15:10 -0500240}
241
Saurab Dulal432be572021-01-26 12:09:29 -0600242BOOST_AUTO_TEST_CASE(Retransmission) // Bug #4874
Saurab Dulala6dec222019-04-01 00:15:10 -0500243{
Saurab Dulala6dec222019-04-01 00:15:10 -0500244 // Avoid clearing pit entry for those incoming interest that have pit entry but no next hops
Saurab Dulal432be572021-01-26 12:09:29 -0600245 /*
246 * +---------+ 10ms +---------+
247 * | nodeB | ------> | nodeC |
248 * +---------+ +---------+
249 */
Saurab Dulala6dec222019-04-01 00:15:10 -0500250
Saurab Dulal432be572021-01-26 12:09:29 -0600251 const Name PRODUCER_PREFIX = "/pnr/C";
Saurab Dulala6dec222019-04-01 00:15:10 -0500252 TopologyTester topo;
253
254 TopologyNode nodeB = topo.addForwarder("B"),
255 nodeC = topo.addForwarder("C");
256
Saurab Dulal432be572021-01-26 12:09:29 -0600257 for (auto node : {nodeB, nodeC}) {
258 topo.setStrategy<AsfStrategy>(node);
259 }
Saurab Dulala6dec222019-04-01 00:15:10 -0500260
Saurab Dulal432be572021-01-26 12:09:29 -0600261 auto linkBC = topo.addLink("BC", time::milliseconds(10), {nodeB, nodeC});
Saurab Dulala6dec222019-04-01 00:15:10 -0500262
Saurab Dulal432be572021-01-26 12:09:29 -0600263 auto consumer = topo.addAppFace("c", nodeB),
264 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
Saurab Dulala6dec222019-04-01 00:15:10 -0500265
266 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX, 100_ms);
267
268 Name name(PRODUCER_PREFIX);
269 name.appendTimestamp();
Saurab Dulal432be572021-01-26 12:09:29 -0600270 auto interest = makeInterest(name);
Saurab Dulala6dec222019-04-01 00:15:10 -0500271
Saurab Dulal432be572021-01-26 12:09:29 -0600272 auto& pit = topo.getForwarder(nodeB).getPit();
273 auto pitEntry = pit.insert(*interest).first;
Saurab Dulala6dec222019-04-01 00:15:10 -0500274
Davide Pesavento0498ce82021-06-14 02:02:21 -0400275 topo.getForwarder(nodeB).onOutgoingInterest(*interest, linkBC->getFace(nodeB), pitEntry);
Saurab Dulala6dec222019-04-01 00:15:10 -0500276 this->advanceClocks(time::milliseconds(100));
277
278 interest->refreshNonce();
279 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
280 this->advanceClocks(time::milliseconds(100));
281
Saurab Dulal432be572021-01-26 12:09:29 -0600282 auto outRecord = pitEntry->getOutRecord(linkBC->getFace(nodeB));
Saurab Dulala6dec222019-04-01 00:15:10 -0500283 BOOST_CHECK(outRecord != pitEntry->out_end());
284
285 this->advanceClocks(time::milliseconds(100));
286 BOOST_CHECK_EQUAL(linkBC->getFace(nodeC).getCounters().nOutData, 1);
287 BOOST_CHECK_EQUAL(linkBC->getFace(nodeB).getCounters().nInData, 1);
288}
289
Saurab Dulal432be572021-01-26 12:09:29 -0600290BOOST_AUTO_TEST_CASE(PerUpstreamSuppression)
291{
292 /*
293 * +---------+
294 * +----| nodeB |----+
295 * | +---------+ |
296 * 50ms | | 50ms
297 * | |
298 * +---------+ 50ms +---------+
299 * | nodeA | <-----> | nodeP |
300 * +---------+ +---------+
301 */
302
303 const Name PRODUCER_PREFIX = "/suppress/me";
304 TopologyTester topo;
305
306 TopologyNode nodeA = topo.addForwarder("A"),
307 nodeB = topo.addForwarder("B"),
308 nodeP = topo.addForwarder("P");
309
310 for (auto node : {nodeA, nodeB, nodeP}) {
311 topo.setStrategy<AsfStrategy>(node);
312 }
313
314 auto linkAB = topo.addLink("AB", 50_ms, {nodeA, nodeB});
315 auto linkAP = topo.addLink("AP", 50_ms, {nodeA, nodeP});
316 auto linkBP = topo.addLink("BP", 50_ms, {nodeB, nodeP});
317
318 auto consumer = topo.addAppFace("cons", nodeA),
319 producer = topo.addAppFace("prod", nodeP, PRODUCER_PREFIX);
320
321 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX);
322
323 topo.registerPrefix(nodeA, linkAP->getFace(nodeA), PRODUCER_PREFIX, 10);
324 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 1);
325 topo.registerPrefix(nodeB, linkBP->getFace(nodeB), PRODUCER_PREFIX, 1);
326
327 auto& faceA2B = linkAB->getFace(nodeA);
328 auto& faceA2P = linkAP->getFace(nodeA);
329
330 Name name(PRODUCER_PREFIX);
331 name.appendTimestamp();
332 // very short lifetime to make it expire within the initial retx suppression period (10ms)
333 auto interest = makeInterest(name, false, 5_ms);
334
335 // 1st interest should be sent to B
336 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
337 this->advanceClocks(1_ms);
338 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
339 BOOST_TEST(faceA2P.getCounters().nOutInterests == 0);
340
341 // 2nd interest should be sent to P and NOT suppressed
342 interest->setInterestLifetime(100_ms);
343 interest->refreshNonce();
344 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
345 this->advanceClocks(1_ms);
346 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
347 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
348
349 this->advanceClocks(1_ms);
350
351 // 3rd interest should be suppressed
352 // without suppression, it would have been sent again to B as that's the earliest out-record
353 interest->refreshNonce();
354 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
355 this->advanceClocks(1_ms);
356 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
357 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
358
359 this->advanceClocks(2_ms); // 1st interest should expire now
360
361 // 4th interest should be suppressed
362 // without suppression, it would have been sent again to B because the out-record expired
363 interest->refreshNonce();
364 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
365 this->advanceClocks(1_ms);
366 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
367 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
368
369 this->advanceClocks(5_ms); // suppression window ends
370
371 // 5th interest is sent to B and is outside the suppression window
372 interest->refreshNonce();
373 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
374 this->advanceClocks(1_ms);
375 BOOST_TEST(faceA2B.getCounters().nOutInterests == 2);
376 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
377
378 this->advanceClocks(10_ms);
379
380 // 6th interest is sent to P and is outside the suppression window
381 interest->refreshNonce();
382 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
383 this->advanceClocks(1_ms);
384 BOOST_TEST(faceA2B.getCounters().nOutInterests == 2);
385 BOOST_TEST(faceA2P.getCounters().nOutInterests == 2);
386}
387
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000388BOOST_AUTO_TEST_CASE(NoPitOutRecordAndProbeInterestNewNonce)
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600389{
Saurab Dulal432be572021-01-26 12:09:29 -0600390 /* +---------+
391 * | nodeD |
392 * +---------+
393 * |
394 * | 80ms
395 * |
396 * |
397 * +---------+
398 * +----->| nodeB |<------+
399 * | +---------+ |
400 * 15ms | | 16ms
401 * v v
402 * +---------+ +---------+
403 * | nodeA |--------------| nodeC |
404 * +---------+ 14ms +---------+
405 */
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600406
407 const Name PRODUCER_PREFIX = "/ndn/edu/nodeD/ping";
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600408 TopologyTester topo;
Saurab Dulal432be572021-01-26 12:09:29 -0600409
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600410 TopologyNode nodeA = topo.addForwarder("A"),
411 nodeB = topo.addForwarder("B"),
412 nodeC = topo.addForwarder("C"),
413 nodeD = topo.addForwarder("D");
414
Saurab Dulal432be572021-01-26 12:09:29 -0600415 for (auto node : {nodeA, nodeB, nodeC, nodeD}) {
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500416 topo.setStrategy<AsfStrategy>(node);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600417 }
418
Saurab Dulal432be572021-01-26 12:09:29 -0600419 auto linkAB = topo.addLink("AB", 15_ms, {nodeA, nodeB}),
420 linkAC = topo.addLink("AC", 14_ms, {nodeA, nodeC}),
421 linkBC = topo.addLink("BC", 16_ms, {nodeB, nodeC}),
422 linkBD = topo.addLink("BD", 80_ms, {nodeB, nodeD});
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600423
Saurab Dulal432be572021-01-26 12:09:29 -0600424 auto ping = topo.addAppFace("c", nodeA);
425 auto pingServer = topo.addAppFace("p", nodeD, PRODUCER_PREFIX);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600426 topo.addEchoProducer(pingServer->getClientFace());
427
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600428 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 15);
429 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 14);
430 topo.registerPrefix(nodeC, linkBC->getFace(nodeC), PRODUCER_PREFIX, 16);
431 topo.registerPrefix(nodeB, linkBD->getFace(nodeB), PRODUCER_PREFIX, 80);
432
433 // Send 6 interest since probes can be scheduled b/w 0-5 seconds
434 for (int i = 1; i < 7; i++) {
435 // Send ping number i
436 Name name(PRODUCER_PREFIX);
437 name.appendTimestamp();
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400438 auto interest = makeInterest(name);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600439 ping->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400440 auto nonce = interest->getNonce();
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600441
442 // Don't know when the probe will be triggered since it is random between 0-5 seconds
443 // or whether it will be triggered for this interest
Davide Pesavento14e71f02019-03-28 17:35:25 -0400444 for (int j = 1; j <= 1000 && linkAB->getFace(nodeA).getCounters().nOutInterests != 1; ++j) {
445 this->advanceClocks(1_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600446 }
447
448 // Check if probe is sent to B else send another ping
449 if (linkAB->getFace(nodeA).getCounters().nOutInterests == 1) {
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000450 // Get pitEntry of node A
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400451 auto pitEntry = topo.getForwarder(nodeA).getPit().find(*interest);
452 // Get outRecord associated with face towards B
453 auto outRecord = pitEntry->getOutRecord(linkAB->getFace(nodeA));
454 BOOST_REQUIRE(outRecord != pitEntry->out_end());
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000455
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400456 // Check that Nonce of interest is not equal to Nonce of Probe
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000457 BOOST_CHECK_NE(nonce, outRecord->getLastNonce());
458
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600459 // B should not have received the probe interest yet
460 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 0);
461
462 // i-1 interests through B when no probe
463 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i - 1);
464
465 // After 15ms, B should get the probe interest
Davide Pesavento14e71f02019-03-28 17:35:25 -0400466 this->advanceClocks(1_ms, 15_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600467 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 1);
468 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i);
469
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000470 pitEntry = topo.getForwarder(nodeB).getPit().find(*interest);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600471
472 // Get outRecord associated with face towards D.
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000473 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600474 BOOST_CHECK(outRecord != pitEntry->out_end());
475
476 // RTT between B and D
Davide Pesavento14e71f02019-03-28 17:35:25 -0400477 this->advanceClocks(5_ms, 160_ms);
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000478 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600479
480 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i);
481
482 BOOST_CHECK(outRecord == pitEntry->out_end());
483
484 // Data is returned for the ping after 15 ms - will result in false measurement
485 // 14+16-15 = 15ms
486 // Since outRecord == pitEntry->out_end()
Davide Pesavento14e71f02019-03-28 17:35:25 -0400487 this->advanceClocks(1_ms, 15_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600488 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i+1);
489
490 break;
491 }
492 }
493}
494
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500495BOOST_FIXTURE_TEST_CASE(IgnoreTimeouts, AsfStrategyParametersGridFixture)
496{
497 // Both nodeB and nodeD have FIB entries to reach the producer
498 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
499 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
500
501 // Send 15 interests let it change to use the 10 ms link
502 runConsumer(15);
503
Saurab Dulal432be572021-01-26 12:09:29 -0600504 uint64_t outInterestsBeforeFailure = linkAD->getFace(nodeA).getCounters().nOutInterests;
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500505
506 // Bring down 10 ms link
507 linkAB->fail();
508
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400509 // Send 5 interests, after the last one it will record the timeout
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500510 // ready to switch for the next interest
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400511 runConsumer(5);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500512
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400513 // Check that link has not been switched to 100 ms because max-timeouts = 5
Saurab Dulal432be572021-01-26 12:09:29 -0600514 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, outInterestsBeforeFailure);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500515
516 // Send 5 interests, check that 100 ms link is used
517 runConsumer(5);
518
Saurab Dulal432be572021-01-26 12:09:29 -0600519 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, outInterestsBeforeFailure + 5);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500520}
521
522BOOST_FIXTURE_TEST_CASE(ProbingInterval, AsfStrategyParametersGridFixture)
523{
524 // Both nodeB and nodeD have FIB entries to reach the producer
525 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
526 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
527
528 // Send 6 interests let it change to use the 10 ms link
529 runConsumer(6);
530
Saurab Dulal432be572021-01-26 12:09:29 -0600531 auto linkAC = topo.addLink("AC", 5_ms, {nodeA, nodeD});
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500532 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 1);
533
534 BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 0);
535
536 // After 30 seconds a probe would be sent that would switch make ASF switch
537 runConsumer(30);
538
539 BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 1);
540}
541
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400542BOOST_AUTO_TEST_CASE(Parameters)
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500543{
Saurab Dulal432be572021-01-26 12:09:29 -0600544 FaceTable faceTable;
545 Forwarder forwarder{faceTable};
546
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400547 auto checkValidity = [&] (const std::string& parameters, bool isCorrect) {
548 Name strategyName(Name(AsfStrategy::getStrategyName()).append(parameters));
549 std::unique_ptr<AsfStrategy> strategy;
550 BOOST_TEST_CONTEXT(parameters) {
551 if (isCorrect) {
552 strategy = make_unique<AsfStrategy>(forwarder, strategyName);
553 BOOST_CHECK(strategy->m_retxSuppression != nullptr);
554 }
555 else {
556 BOOST_CHECK_THROW(make_unique<AsfStrategy>(forwarder, strategyName), std::invalid_argument);
557 }
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500558 }
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400559 return strategy;
Saurab Dulal432be572021-01-26 12:09:29 -0600560 };
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500561
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400562 auto strategy = checkValidity("", true);
563 BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
564 BOOST_TEST(strategy->m_nMaxTimeouts == 3);
565 strategy = checkValidity("/probing-interval~30000/max-timeouts~5", true);
566 BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
567 BOOST_TEST(strategy->m_nMaxTimeouts == 5);
568 strategy = checkValidity("/max-timeouts~5/probing-interval~30000", true);
569 BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
570 BOOST_TEST(strategy->m_nMaxTimeouts == 5);
571 strategy = checkValidity("/probing-interval~1000", true);
572 BOOST_TEST(strategy->m_probing.getProbingInterval() == 1_s);
573 BOOST_TEST(strategy->m_nMaxTimeouts == 3);
574 strategy = checkValidity("/max-timeouts~0", true);
575 BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
576 BOOST_TEST(strategy->m_nMaxTimeouts == 0);
577 BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
578 BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
579 BOOST_TEST(strategy->m_retxSuppression->m_multiplier == RetxSuppressionExponential::DEFAULT_MULTIPLIER);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500580
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400581 checkValidity("/probing-interval~500", false); // minimum is 1 second
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500582 checkValidity("/probing-interval~-5000", false);
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400583 checkValidity("/max-timeouts~-1", false);
584 checkValidity("/max-timeouts~ -1", false);
585 checkValidity("/max-timeouts~1-0", false);
586 checkValidity("/max-timeouts~1/probing-interval~-30000", false);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500587 checkValidity("/probing-interval~foo", false);
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400588 checkValidity("/max-timeouts~1~2", false);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500589}
590
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000591BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
592BOOST_AUTO_TEST_SUITE_END() // Fw
593
594} // namespace tests
595} // namespace asf
596} // namespace fw
597} // namespace nfd