blob: f07e72aa6c457cf92fefef8d35039850a24b8473 [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
117 static const Name PRODUCER_PREFIX;
118};
119
Saurab Dulal432be572021-01-26 12:09:29 -0600120const Name AsfGridFixture::PRODUCER_PREFIX("/hr/C");
121
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500122class AsfStrategyParametersGridFixture : public AsfGridFixture
123{
124protected:
125 AsfStrategyParametersGridFixture()
126 : AsfGridFixture(Name(AsfStrategy::getStrategyName())
127 .append("probing-interval~30000")
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400128 .append("max-timeouts~5"))
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500129 {
130 }
131};
132
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000133BOOST_FIXTURE_TEST_CASE(Basic, AsfGridFixture)
134{
135 // Both nodeB and nodeD have FIB entries to reach the producer
136 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
137 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
138
139 runConsumer();
140
141 // ASF should use the Face to nodeD because it has lower routing cost.
142 // After 5 seconds, a probe Interest should be sent to the Face to nodeB,
143 // and the probe should return Data quicker. ASF should then use the Face
144 // to nodeB to forward the remaining Interests.
145 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 30);
Alex Lane9cec6992020-03-05 19:10:09 -0600146 // Because of exploration, will forward to AB and AD simultaneously at least once
147 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 25);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000148 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 6);
149
150 // If the link from nodeA to nodeB fails, ASF should start using the Face
151 // to nodeD again.
152 linkAB->fail();
153
154 runConsumer();
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400155 // We experience 3 timeouts and marked AB as timed out
156 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 57);
Alex Lane9cec6992020-03-05 19:10:09 -0600157 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 36);
158 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 24);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000159
160 // If the link from nodeA to nodeB recovers, ASF should probe the Face
161 // to nodeB and start using it again.
162 linkAB->recover();
163
164 // Advance time to ensure probing is due
Davide Pesavento14e71f02019-03-28 17:35:25 -0400165 this->advanceClocks(10_ms, 10_s);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000166
167 runConsumer();
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400168 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 87);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000169 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 50);
170 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 40);
171
172 // If both links fail, nodeA should forward to the next hop with the lowest cost
173 linkAB->fail();
174 linkAD->fail();
175
176 runConsumer();
177
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400178 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 87);
Alex Lane9cec6992020-03-05 19:10:09 -0600179 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 65); // FIXME #3830
180 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 57); // FIXME #3830
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000181}
182
183BOOST_FIXTURE_TEST_CASE(Nack, AsfGridFixture)
184{
185 // nodeB has a FIB entry to reach the producer, but nodeD does not
186 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
187
188 // The strategy should first try to send to nodeD. But since nodeD does not have a route for
189 // the producer's prefix, it should return a NO_ROUTE Nack. The strategy should then start using the Face to
190 // nodeB.
191 runConsumer();
192
193 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nInNacks, 1);
194 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 29);
195 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 29);
196
197 // nodeD should receive 2 Interests: one for the very first Interest and
198 // another from a probe
199 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
200}
201
Saurab Dulala6dec222019-04-01 00:15:10 -0500202class AsfStrategyDelayedDataFixture : public AsfGridFixture
203{
204protected:
205 AsfStrategyDelayedDataFixture()
206 : AsfGridFixture(Name(AsfStrategy::getStrategyName()), 400_ms)
207 {
208 }
209};
210
211BOOST_FIXTURE_TEST_CASE(InterestForwarding, AsfStrategyDelayedDataFixture)
212{
Saurab Dulala6dec222019-04-01 00:15:10 -0500213 Name name(PRODUCER_PREFIX);
214 name.appendTimestamp();
Saurab Dulal432be572021-01-26 12:09:29 -0600215 auto interest = makeInterest(name);
Saurab Dulala6dec222019-04-01 00:15:10 -0500216
217 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
218 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
219
220 // The first interest should go via link AD
221 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
222 this->advanceClocks(10_ms, 100_ms);
223 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, 1);
224
225 // Second interest should go via link AB
226 interest->refreshNonce();
227 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
228 this->advanceClocks(10_ms, 100_ms);
229 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 1);
230
231 // The third interest should again go via AD, since both the face from A is already used
232 // and so asf should choose the earliest used face i.e. AD
233 interest->refreshNonce();
234 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
235 this->advanceClocks(10_ms, 100_ms);
236 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
237
238 this->advanceClocks(time::milliseconds(500), time::seconds(5));
239 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nInData, 1);
240 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nInData, 1);
241 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 1);
Saurab Dulala6dec222019-04-01 00:15:10 -0500242}
243
Saurab Dulal432be572021-01-26 12:09:29 -0600244BOOST_AUTO_TEST_CASE(Retransmission) // Bug #4874
Saurab Dulala6dec222019-04-01 00:15:10 -0500245{
Saurab Dulala6dec222019-04-01 00:15:10 -0500246 // Avoid clearing pit entry for those incoming interest that have pit entry but no next hops
Saurab Dulal432be572021-01-26 12:09:29 -0600247 /*
248 * +---------+ 10ms +---------+
249 * | nodeB | ------> | nodeC |
250 * +---------+ +---------+
251 */
Saurab Dulala6dec222019-04-01 00:15:10 -0500252
Saurab Dulal432be572021-01-26 12:09:29 -0600253 const Name PRODUCER_PREFIX = "/pnr/C";
Saurab Dulala6dec222019-04-01 00:15:10 -0500254 TopologyTester topo;
255
256 TopologyNode nodeB = topo.addForwarder("B"),
257 nodeC = topo.addForwarder("C");
258
Saurab Dulal432be572021-01-26 12:09:29 -0600259 for (auto node : {nodeB, nodeC}) {
260 topo.setStrategy<AsfStrategy>(node);
261 }
Saurab Dulala6dec222019-04-01 00:15:10 -0500262
Saurab Dulal432be572021-01-26 12:09:29 -0600263 auto linkBC = topo.addLink("BC", time::milliseconds(10), {nodeB, nodeC});
Saurab Dulala6dec222019-04-01 00:15:10 -0500264
Saurab Dulal432be572021-01-26 12:09:29 -0600265 auto consumer = topo.addAppFace("c", nodeB),
266 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
Saurab Dulala6dec222019-04-01 00:15:10 -0500267
268 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX, 100_ms);
269
270 Name name(PRODUCER_PREFIX);
271 name.appendTimestamp();
Saurab Dulal432be572021-01-26 12:09:29 -0600272 auto interest = makeInterest(name);
Saurab Dulala6dec222019-04-01 00:15:10 -0500273
Saurab Dulal432be572021-01-26 12:09:29 -0600274 auto& pit = topo.getForwarder(nodeB).getPit();
275 auto pitEntry = pit.insert(*interest).first;
Saurab Dulala6dec222019-04-01 00:15:10 -0500276
Davide Pesavento0498ce82021-06-14 02:02:21 -0400277 topo.getForwarder(nodeB).onOutgoingInterest(*interest, linkBC->getFace(nodeB), pitEntry);
Saurab Dulala6dec222019-04-01 00:15:10 -0500278 this->advanceClocks(time::milliseconds(100));
279
280 interest->refreshNonce();
281 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
282 this->advanceClocks(time::milliseconds(100));
283
Saurab Dulal432be572021-01-26 12:09:29 -0600284 auto outRecord = pitEntry->getOutRecord(linkBC->getFace(nodeB));
Saurab Dulala6dec222019-04-01 00:15:10 -0500285 BOOST_CHECK(outRecord != pitEntry->out_end());
286
287 this->advanceClocks(time::milliseconds(100));
288 BOOST_CHECK_EQUAL(linkBC->getFace(nodeC).getCounters().nOutData, 1);
289 BOOST_CHECK_EQUAL(linkBC->getFace(nodeB).getCounters().nInData, 1);
290}
291
Saurab Dulal432be572021-01-26 12:09:29 -0600292BOOST_AUTO_TEST_CASE(PerUpstreamSuppression)
293{
294 /*
295 * +---------+
296 * +----| nodeB |----+
297 * | +---------+ |
298 * 50ms | | 50ms
299 * | |
300 * +---------+ 50ms +---------+
301 * | nodeA | <-----> | nodeP |
302 * +---------+ +---------+
303 */
304
305 const Name PRODUCER_PREFIX = "/suppress/me";
306 TopologyTester topo;
307
308 TopologyNode nodeA = topo.addForwarder("A"),
309 nodeB = topo.addForwarder("B"),
310 nodeP = topo.addForwarder("P");
311
312 for (auto node : {nodeA, nodeB, nodeP}) {
313 topo.setStrategy<AsfStrategy>(node);
314 }
315
316 auto linkAB = topo.addLink("AB", 50_ms, {nodeA, nodeB});
317 auto linkAP = topo.addLink("AP", 50_ms, {nodeA, nodeP});
318 auto linkBP = topo.addLink("BP", 50_ms, {nodeB, nodeP});
319
320 auto consumer = topo.addAppFace("cons", nodeA),
321 producer = topo.addAppFace("prod", nodeP, PRODUCER_PREFIX);
322
323 topo.addEchoProducer(producer->getClientFace(), PRODUCER_PREFIX);
324
325 topo.registerPrefix(nodeA, linkAP->getFace(nodeA), PRODUCER_PREFIX, 10);
326 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 1);
327 topo.registerPrefix(nodeB, linkBP->getFace(nodeB), PRODUCER_PREFIX, 1);
328
329 auto& faceA2B = linkAB->getFace(nodeA);
330 auto& faceA2P = linkAP->getFace(nodeA);
331
332 Name name(PRODUCER_PREFIX);
333 name.appendTimestamp();
334 // very short lifetime to make it expire within the initial retx suppression period (10ms)
335 auto interest = makeInterest(name, false, 5_ms);
336
337 // 1st interest should be sent to B
338 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
339 this->advanceClocks(1_ms);
340 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
341 BOOST_TEST(faceA2P.getCounters().nOutInterests == 0);
342
343 // 2nd interest should be sent to P and NOT suppressed
344 interest->setInterestLifetime(100_ms);
345 interest->refreshNonce();
346 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
347 this->advanceClocks(1_ms);
348 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
349 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
350
351 this->advanceClocks(1_ms);
352
353 // 3rd interest should be suppressed
354 // without suppression, it would have been sent again to B as that's the earliest out-record
355 interest->refreshNonce();
356 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
357 this->advanceClocks(1_ms);
358 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
359 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
360
361 this->advanceClocks(2_ms); // 1st interest should expire now
362
363 // 4th interest should be suppressed
364 // without suppression, it would have been sent again to B because the out-record expired
365 interest->refreshNonce();
366 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
367 this->advanceClocks(1_ms);
368 BOOST_TEST(faceA2B.getCounters().nOutInterests == 1);
369 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
370
371 this->advanceClocks(5_ms); // suppression window ends
372
373 // 5th interest is sent to B and is outside the suppression window
374 interest->refreshNonce();
375 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
376 this->advanceClocks(1_ms);
377 BOOST_TEST(faceA2B.getCounters().nOutInterests == 2);
378 BOOST_TEST(faceA2P.getCounters().nOutInterests == 1);
379
380 this->advanceClocks(10_ms);
381
382 // 6th interest is sent to P and is outside the suppression window
383 interest->refreshNonce();
384 consumer->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
385 this->advanceClocks(1_ms);
386 BOOST_TEST(faceA2B.getCounters().nOutInterests == 2);
387 BOOST_TEST(faceA2P.getCounters().nOutInterests == 2);
388}
389
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000390BOOST_AUTO_TEST_CASE(NoPitOutRecordAndProbeInterestNewNonce)
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600391{
Saurab Dulal432be572021-01-26 12:09:29 -0600392 /* +---------+
393 * | nodeD |
394 * +---------+
395 * |
396 * | 80ms
397 * |
398 * |
399 * +---------+
400 * +----->| nodeB |<------+
401 * | +---------+ |
402 * 15ms | | 16ms
403 * v v
404 * +---------+ +---------+
405 * | nodeA |--------------| nodeC |
406 * +---------+ 14ms +---------+
407 */
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600408
409 const Name PRODUCER_PREFIX = "/ndn/edu/nodeD/ping";
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600410 TopologyTester topo;
Saurab Dulal432be572021-01-26 12:09:29 -0600411
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600412 TopologyNode nodeA = topo.addForwarder("A"),
413 nodeB = topo.addForwarder("B"),
414 nodeC = topo.addForwarder("C"),
415 nodeD = topo.addForwarder("D");
416
Saurab Dulal432be572021-01-26 12:09:29 -0600417 for (auto node : {nodeA, nodeB, nodeC, nodeD}) {
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500418 topo.setStrategy<AsfStrategy>(node);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600419 }
420
Saurab Dulal432be572021-01-26 12:09:29 -0600421 auto linkAB = topo.addLink("AB", 15_ms, {nodeA, nodeB}),
422 linkAC = topo.addLink("AC", 14_ms, {nodeA, nodeC}),
423 linkBC = topo.addLink("BC", 16_ms, {nodeB, nodeC}),
424 linkBD = topo.addLink("BD", 80_ms, {nodeB, nodeD});
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600425
Saurab Dulal432be572021-01-26 12:09:29 -0600426 auto ping = topo.addAppFace("c", nodeA);
427 auto pingServer = topo.addAppFace("p", nodeD, PRODUCER_PREFIX);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600428 topo.addEchoProducer(pingServer->getClientFace());
429
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600430 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 15);
431 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 14);
432 topo.registerPrefix(nodeC, linkBC->getFace(nodeC), PRODUCER_PREFIX, 16);
433 topo.registerPrefix(nodeB, linkBD->getFace(nodeB), PRODUCER_PREFIX, 80);
434
435 // Send 6 interest since probes can be scheduled b/w 0-5 seconds
436 for (int i = 1; i < 7; i++) {
437 // Send ping number i
438 Name name(PRODUCER_PREFIX);
439 name.appendTimestamp();
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400440 auto interest = makeInterest(name);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600441 ping->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400442 auto nonce = interest->getNonce();
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600443
444 // Don't know when the probe will be triggered since it is random between 0-5 seconds
445 // or whether it will be triggered for this interest
Davide Pesavento14e71f02019-03-28 17:35:25 -0400446 for (int j = 1; j <= 1000 && linkAB->getFace(nodeA).getCounters().nOutInterests != 1; ++j) {
447 this->advanceClocks(1_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600448 }
449
450 // Check if probe is sent to B else send another ping
451 if (linkAB->getFace(nodeA).getCounters().nOutInterests == 1) {
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000452 // Get pitEntry of node A
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400453 auto pitEntry = topo.getForwarder(nodeA).getPit().find(*interest);
454 // Get outRecord associated with face towards B
455 auto outRecord = pitEntry->getOutRecord(linkAB->getFace(nodeA));
456 BOOST_REQUIRE(outRecord != pitEntry->out_end());
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000457
Davide Pesavento51cf75c2020-03-11 22:21:13 -0400458 // Check that Nonce of interest is not equal to Nonce of Probe
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000459 BOOST_CHECK_NE(nonce, outRecord->getLastNonce());
460
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600461 // B should not have received the probe interest yet
462 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 0);
463
464 // i-1 interests through B when no probe
465 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i - 1);
466
467 // After 15ms, B should get the probe interest
Davide Pesavento14e71f02019-03-28 17:35:25 -0400468 this->advanceClocks(1_ms, 15_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600469 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 1);
470 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i);
471
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000472 pitEntry = topo.getForwarder(nodeB).getPit().find(*interest);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600473
474 // Get outRecord associated with face towards D.
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000475 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600476 BOOST_CHECK(outRecord != pitEntry->out_end());
477
478 // RTT between B and D
Davide Pesavento14e71f02019-03-28 17:35:25 -0400479 this->advanceClocks(5_ms, 160_ms);
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000480 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600481
482 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i);
483
484 BOOST_CHECK(outRecord == pitEntry->out_end());
485
486 // Data is returned for the ping after 15 ms - will result in false measurement
487 // 14+16-15 = 15ms
488 // Since outRecord == pitEntry->out_end()
Davide Pesavento14e71f02019-03-28 17:35:25 -0400489 this->advanceClocks(1_ms, 15_ms);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600490 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i+1);
491
492 break;
493 }
494 }
495}
496
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500497BOOST_FIXTURE_TEST_CASE(IgnoreTimeouts, AsfStrategyParametersGridFixture)
498{
499 // Both nodeB and nodeD have FIB entries to reach the producer
500 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
501 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
502
503 // Send 15 interests let it change to use the 10 ms link
504 runConsumer(15);
505
Saurab Dulal432be572021-01-26 12:09:29 -0600506 uint64_t outInterestsBeforeFailure = linkAD->getFace(nodeA).getCounters().nOutInterests;
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500507
508 // Bring down 10 ms link
509 linkAB->fail();
510
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400511 // Send 5 interests, after the last one it will record the timeout
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500512 // ready to switch for the next interest
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400513 runConsumer(5);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500514
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400515 // Check that link has not been switched to 100 ms because max-timeouts = 5
Saurab Dulal432be572021-01-26 12:09:29 -0600516 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, outInterestsBeforeFailure);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500517
518 // Send 5 interests, check that 100 ms link is used
519 runConsumer(5);
520
Saurab Dulal432be572021-01-26 12:09:29 -0600521 BOOST_CHECK_EQUAL(linkAD->getFace(nodeA).getCounters().nOutInterests, outInterestsBeforeFailure + 5);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500522}
523
524BOOST_FIXTURE_TEST_CASE(ProbingInterval, AsfStrategyParametersGridFixture)
525{
526 // Both nodeB and nodeD have FIB entries to reach the producer
527 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
528 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
529
530 // Send 6 interests let it change to use the 10 ms link
531 runConsumer(6);
532
Saurab Dulal432be572021-01-26 12:09:29 -0600533 auto linkAC = topo.addLink("AC", 5_ms, {nodeA, nodeD});
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500534 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 1);
535
536 BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 0);
537
538 // After 30 seconds a probe would be sent that would switch make ASF switch
539 runConsumer(30);
540
541 BOOST_CHECK_EQUAL(linkAC->getFace(nodeA).getCounters().nOutInterests, 1);
542}
543
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400544BOOST_AUTO_TEST_CASE(Parameters)
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500545{
Saurab Dulal432be572021-01-26 12:09:29 -0600546 FaceTable faceTable;
547 Forwarder forwarder{faceTable};
548
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400549 auto checkValidity = [&] (const std::string& parameters, bool isCorrect) {
550 Name strategyName(Name(AsfStrategy::getStrategyName()).append(parameters));
551 std::unique_ptr<AsfStrategy> strategy;
552 BOOST_TEST_CONTEXT(parameters) {
553 if (isCorrect) {
554 strategy = make_unique<AsfStrategy>(forwarder, strategyName);
555 BOOST_CHECK(strategy->m_retxSuppression != nullptr);
556 }
557 else {
558 BOOST_CHECK_THROW(make_unique<AsfStrategy>(forwarder, strategyName), std::invalid_argument);
559 }
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500560 }
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400561 return strategy;
Saurab Dulal432be572021-01-26 12:09:29 -0600562 };
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500563
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400564 auto strategy = checkValidity("", true);
565 BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
566 BOOST_TEST(strategy->m_nMaxTimeouts == 3);
567 strategy = checkValidity("/probing-interval~30000/max-timeouts~5", true);
568 BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
569 BOOST_TEST(strategy->m_nMaxTimeouts == 5);
570 strategy = checkValidity("/max-timeouts~5/probing-interval~30000", true);
571 BOOST_TEST(strategy->m_probing.getProbingInterval() == 30_s);
572 BOOST_TEST(strategy->m_nMaxTimeouts == 5);
573 strategy = checkValidity("/probing-interval~1000", true);
574 BOOST_TEST(strategy->m_probing.getProbingInterval() == 1_s);
575 BOOST_TEST(strategy->m_nMaxTimeouts == 3);
576 strategy = checkValidity("/max-timeouts~0", true);
577 BOOST_TEST(strategy->m_probing.getProbingInterval() == 60_s);
578 BOOST_TEST(strategy->m_nMaxTimeouts == 0);
579 BOOST_TEST(strategy->m_retxSuppression->m_initialInterval == RetxSuppressionExponential::DEFAULT_INITIAL_INTERVAL);
580 BOOST_TEST(strategy->m_retxSuppression->m_maxInterval == RetxSuppressionExponential::DEFAULT_MAX_INTERVAL);
581 BOOST_TEST(strategy->m_retxSuppression->m_multiplier == RetxSuppressionExponential::DEFAULT_MULTIPLIER);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500582
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400583 checkValidity("/probing-interval~500", false); // minimum is 1 second
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500584 checkValidity("/probing-interval~-5000", false);
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400585 checkValidity("/max-timeouts~-1", false);
586 checkValidity("/max-timeouts~ -1", false);
587 checkValidity("/max-timeouts~1-0", false);
588 checkValidity("/max-timeouts~1/probing-interval~-30000", false);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500589 checkValidity("/probing-interval~foo", false);
Saurab Dulalaf3ff5a2021-09-19 19:45:07 -0400590 checkValidity("/max-timeouts~1~2", false);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500591}
592
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000593BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
594BOOST_AUTO_TEST_SUITE_END() // Fw
595
596} // namespace tests
597} // namespace asf
598} // namespace fw
599} // namespace nfd