blob: c370cbd2314e551c75a50b86806eb519ccb51f81 [file] [log] [blame]
Vince Lehman8a4c29e2016-07-11 08:49:35 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2016, Regents of the University of California,
4 * 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
28#include "tests/test-common.hpp"
Junxiao Shi890afe92016-12-15 14:34:34 +000029#include "strategy-tester.hpp"
Vince Lehman8a4c29e2016-07-11 08:49:35 +000030#include "topology-tester.hpp"
31
32namespace nfd {
33namespace fw {
34namespace asf {
35namespace tests {
36
37using namespace nfd::fw::tests;
38
Junxiao Shi890afe92016-12-15 14:34:34 +000039// The tester is unused in this file, but it's used in various templated test suites.
40typedef StrategyTester<AsfStrategy> AsfStrategyTester;
41NFD_REGISTER_STRATEGY(AsfStrategyTester);
42
Vince Lehman8a4c29e2016-07-11 08:49:35 +000043BOOST_AUTO_TEST_SUITE(Fw)
44BOOST_FIXTURE_TEST_SUITE(TestAsfStrategy, UnitTestTimeFixture)
45
Junxiao Shic34d1672016-12-09 15:57:59 +000046BOOST_AUTO_TEST_CASE(Registration)
47{
Junxiao Shi037f4ab2016-12-13 04:27:06 +000048 BOOST_CHECK_EQUAL(Strategy::listRegistered().count(AsfStrategy::getStrategyName()), 1);
Junxiao Shic34d1672016-12-09 15:57:59 +000049}
50
Junxiao Shi18739c42016-12-22 08:03:00 +000051BOOST_AUTO_TEST_CASE(InstanceName)
52{
53 Forwarder forwarder;
54 BOOST_REQUIRE(AsfStrategy::getStrategyName().at(-1).isVersion());
55 BOOST_CHECK_EQUAL(
56 AsfStrategy(forwarder, AsfStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
57 AsfStrategy::getStrategyName());
58 BOOST_CHECK_THROW(
59 AsfStrategy(forwarder, Name(AsfStrategy::getStrategyName()).append("param")),
60 std::invalid_argument);
61}
62
Vince Lehman8a4c29e2016-07-11 08:49:35 +000063class AsfGridFixture : public UnitTestTimeFixture
64{
65protected:
66 AsfGridFixture()
67 {
68 /*
69 * +---------+
70 * +----->| nodeB |<------+
71 * | +---------+ |
72 * 10ms | | 10ms
73 * v v
74 * +---------+ +---------+
75 * | nodeA | | nodeC |
76 * +---------+ +---------+
77 * ^ ^
78 * 100ms | | 100ms
79 * | +---------+ |
80 * +----->| nodeD |<------+
81 * +---------+
82 */
83
84 nodeA = topo.addForwarder("A");
85 nodeB = topo.addForwarder("B");
86 nodeC = topo.addForwarder("C");
87 nodeD = topo.addForwarder("D");
88
89 topo.setStrategy<fw::AsfStrategy>(nodeA);
90 topo.setStrategy<fw::AsfStrategy>(nodeB);
91 topo.setStrategy<fw::AsfStrategy>(nodeC);
92 topo.setStrategy<fw::AsfStrategy>(nodeD);
93
94 linkAB = topo.addLink("AB", time::milliseconds(10), {nodeA, nodeB});
95 linkAD = topo.addLink("AD", time::milliseconds(100), {nodeA, nodeD});
96 linkBC = topo.addLink("BC", time::milliseconds(10), {nodeB, nodeC});
97 linkCD = topo.addLink("CD", time::milliseconds(100), {nodeC, nodeD});
98
99 consumer = topo.addAppFace("c", nodeA);
100 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
101 topo.addEchoProducer(producer->getClientFace());
102
103 // Register producer prefix on consumer node
104 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 10);
105 topo.registerPrefix(nodeA, linkAD->getFace(nodeA), PRODUCER_PREFIX, 5);
106 }
107
108 void
109 runConsumer()
110 {
111 topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, time::seconds(1), 30);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000112 this->advanceClocks(time::milliseconds(10), time::seconds(30));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000113 }
114
115protected:
116 TopologyTester topo;
117
118 TopologyNode nodeA;
119 TopologyNode nodeB;
120 TopologyNode nodeC;
121 TopologyNode nodeD;
122
123 shared_ptr<TopologyLink> linkAB;
124 shared_ptr<TopologyLink> linkAD;
125 shared_ptr<TopologyLink> linkBC;
126 shared_ptr<TopologyLink> linkCD;
127
128 shared_ptr<TopologyAppLink> consumer;
129 shared_ptr<TopologyAppLink> producer;
130
131 static const Name PRODUCER_PREFIX;
132};
133
134const Name AsfGridFixture::PRODUCER_PREFIX = Name("ndn:/hr/C");
135
136BOOST_FIXTURE_TEST_CASE(Basic, AsfGridFixture)
137{
138 // Both nodeB and nodeD have FIB entries to reach the producer
139 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
140 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
141
142 runConsumer();
143
144 // ASF should use the Face to nodeD because it has lower routing cost.
145 // After 5 seconds, a probe Interest should be sent to the Face to nodeB,
146 // and the probe should return Data quicker. ASF should then use the Face
147 // to nodeB to forward the remaining Interests.
148 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 30);
149 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 24);
150 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 6);
151
152 // If the link from nodeA to nodeB fails, ASF should start using the Face
153 // to nodeD again.
154 linkAB->fail();
155
156 runConsumer();
157
158 // Only 59 Data because the first Interest to nodeB after the failure should timeout
159 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 59);
160 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 30);
161 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 30);
162
163 // If the link from nodeA to nodeB recovers, ASF should probe the Face
164 // to nodeB and start using it again.
165 linkAB->recover();
166
167 // Advance time to ensure probing is due
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000168 this->advanceClocks(time::milliseconds(10), time::seconds(10));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000169
170 runConsumer();
171
172 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 89);
173 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 50);
174 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 40);
175
176 // If both links fail, nodeA should forward to the next hop with the lowest cost
177 linkAB->fail();
178 linkAD->fail();
179
180 runConsumer();
181
182 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 89);
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200183 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 61); // FIXME #3830
184 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 59); // FIXME #3830
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000185}
186
187BOOST_FIXTURE_TEST_CASE(Nack, AsfGridFixture)
188{
189 // nodeB has a FIB entry to reach the producer, but nodeD does not
190 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
191
192 // The strategy should first try to send to nodeD. But since nodeD does not have a route for
193 // the producer's prefix, it should return a NO_ROUTE Nack. The strategy should then start using the Face to
194 // nodeB.
195 runConsumer();
196
197 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nInNacks, 1);
198 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 29);
199 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 29);
200
201 // nodeD should receive 2 Interests: one for the very first Interest and
202 // another from a probe
203 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
204}
205
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000206BOOST_AUTO_TEST_CASE(NoPitOutRecordAndProbeInterestNewNonce)
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600207{
208 /* +---------+
209 * | nodeD |
210 * +---------+
211 * |
212 * | 80ms
213 * |
214 * |
215 * +---------+
216 * +----->| nodeB |<------+
217 * | +---------+ |
218 * 15ms | | 16ms
219 * v v
220 * +---------+ +---------+
221 * | nodeA |--------------| nodeC |
222 * +---------+ 14ms +---------+
223 */
224
225 const Name PRODUCER_PREFIX = "/ndn/edu/nodeD/ping";
226
227 TopologyTester topo;
228 TopologyNode nodeA = topo.addForwarder("A"),
229 nodeB = topo.addForwarder("B"),
230 nodeC = topo.addForwarder("C"),
231 nodeD = topo.addForwarder("D");
232
233 for (TopologyNode node : {nodeA, nodeB, nodeC, nodeD}) {
234 topo.setStrategy<fw::AsfStrategy>(node);
235 }
236
237 shared_ptr<TopologyLink> linkAB = topo.addLink("AB", time::milliseconds(15), {nodeA, nodeB}),
238 linkAC = topo.addLink("AC", time::milliseconds(14), {nodeA, nodeC}),
239 linkBC = topo.addLink("BC", time::milliseconds(16), {nodeB, nodeC}),
240 linkBD = topo.addLink("BD", time::milliseconds(80), {nodeB, nodeD});
241
242 shared_ptr<TopologyAppLink> ping = topo.addAppFace("c", nodeA),
243 pingServer = topo.addAppFace("p", nodeD, PRODUCER_PREFIX);
244 topo.addEchoProducer(pingServer->getClientFace());
245
246 // Register prefixes
247 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 15);
248 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 14);
249 topo.registerPrefix(nodeC, linkBC->getFace(nodeC), PRODUCER_PREFIX, 16);
250 topo.registerPrefix(nodeB, linkBD->getFace(nodeB), PRODUCER_PREFIX, 80);
251
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000252 uint32_t nonce;
253
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600254 // Send 6 interest since probes can be scheduled b/w 0-5 seconds
255 for (int i = 1; i < 7; i++) {
256 // Send ping number i
257 Name name(PRODUCER_PREFIX);
258 name.appendTimestamp();
259 shared_ptr<Interest> interest = makeInterest(name);
260 ping->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000261 nonce = interest->getNonce();
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600262
263 // Don't know when the probe will be triggered since it is random between 0-5 seconds
264 // or whether it will be triggered for this interest
265 int j = 1;
266 while (linkAB->getFace(nodeA).getCounters().nOutInterests != 1) {
267 this->advanceClocks(time::milliseconds(1));
268 ++j;
269 // Probe was not scheduled with this ping interest
270 if (j > 1000) {
271 break;
272 }
273 }
274
275 // Check if probe is sent to B else send another ping
276 if (linkAB->getFace(nodeA).getCounters().nOutInterests == 1) {
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000277 // Get pitEntry of node A
278 shared_ptr<pit::Entry> pitEntry = topo.getForwarder(nodeA).getPit().find(*interest);
279 //get outRecord associated with face towards B
280 pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(linkAB->getFace(nodeA));
281
282 BOOST_CHECK(outRecord != pitEntry->out_end());
283
284 //Check that Nonce of interest is not equal to Nonce of Probe
285 BOOST_CHECK_NE(nonce, outRecord->getLastNonce());
286
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600287 // B should not have received the probe interest yet
288 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 0);
289
290 // i-1 interests through B when no probe
291 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i - 1);
292
293 // After 15ms, B should get the probe interest
294 this->advanceClocks(time::milliseconds(1), time::milliseconds(15));
295 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 1);
296 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i);
297
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000298 pitEntry = topo.getForwarder(nodeB).getPit().find(*interest);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600299
300 // Get outRecord associated with face towards D.
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000301 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600302
303 BOOST_CHECK(outRecord != pitEntry->out_end());
304
305 // RTT between B and D
306 this->advanceClocks(time::milliseconds(5), time::milliseconds(160));
307 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
308
309 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i);
310
311 BOOST_CHECK(outRecord == pitEntry->out_end());
312
313 // Data is returned for the ping after 15 ms - will result in false measurement
314 // 14+16-15 = 15ms
315 // Since outRecord == pitEntry->out_end()
316 this->advanceClocks(time::milliseconds(1), time::milliseconds(15));
317 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i+1);
318
319 break;
320 }
321 }
322}
323
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000324BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
325BOOST_AUTO_TEST_SUITE_END() // Fw
326
327} // namespace tests
328} // namespace asf
329} // namespace fw
330} // namespace nfd