blob: 97f7da79b6795497b7de8e23b8408cb7b8a573a8 [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
Vince Lehman8a4c29e2016-07-11 08:49:35 +000051class AsfGridFixture : public UnitTestTimeFixture
52{
53protected:
54 AsfGridFixture()
55 {
56 /*
57 * +---------+
58 * +----->| nodeB |<------+
59 * | +---------+ |
60 * 10ms | | 10ms
61 * v v
62 * +---------+ +---------+
63 * | nodeA | | nodeC |
64 * +---------+ +---------+
65 * ^ ^
66 * 100ms | | 100ms
67 * | +---------+ |
68 * +----->| nodeD |<------+
69 * +---------+
70 */
71
72 nodeA = topo.addForwarder("A");
73 nodeB = topo.addForwarder("B");
74 nodeC = topo.addForwarder("C");
75 nodeD = topo.addForwarder("D");
76
77 topo.setStrategy<fw::AsfStrategy>(nodeA);
78 topo.setStrategy<fw::AsfStrategy>(nodeB);
79 topo.setStrategy<fw::AsfStrategy>(nodeC);
80 topo.setStrategy<fw::AsfStrategy>(nodeD);
81
82 linkAB = topo.addLink("AB", time::milliseconds(10), {nodeA, nodeB});
83 linkAD = topo.addLink("AD", time::milliseconds(100), {nodeA, nodeD});
84 linkBC = topo.addLink("BC", time::milliseconds(10), {nodeB, nodeC});
85 linkCD = topo.addLink("CD", time::milliseconds(100), {nodeC, nodeD});
86
87 consumer = topo.addAppFace("c", nodeA);
88 producer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
89 topo.addEchoProducer(producer->getClientFace());
90
91 // Register producer prefix on consumer node
92 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 10);
93 topo.registerPrefix(nodeA, linkAD->getFace(nodeA), PRODUCER_PREFIX, 5);
94 }
95
96 void
97 runConsumer()
98 {
99 topo.addIntervalConsumer(consumer->getClientFace(), PRODUCER_PREFIX, time::seconds(1), 30);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000100 this->advanceClocks(time::milliseconds(10), time::seconds(30));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000101 }
102
103protected:
104 TopologyTester topo;
105
106 TopologyNode nodeA;
107 TopologyNode nodeB;
108 TopologyNode nodeC;
109 TopologyNode nodeD;
110
111 shared_ptr<TopologyLink> linkAB;
112 shared_ptr<TopologyLink> linkAD;
113 shared_ptr<TopologyLink> linkBC;
114 shared_ptr<TopologyLink> linkCD;
115
116 shared_ptr<TopologyAppLink> consumer;
117 shared_ptr<TopologyAppLink> producer;
118
119 static const Name PRODUCER_PREFIX;
120};
121
122const Name AsfGridFixture::PRODUCER_PREFIX = Name("ndn:/hr/C");
123
124BOOST_FIXTURE_TEST_CASE(Basic, AsfGridFixture)
125{
126 // Both nodeB and nodeD have FIB entries to reach the producer
127 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
128 topo.registerPrefix(nodeD, linkCD->getFace(nodeD), PRODUCER_PREFIX);
129
130 runConsumer();
131
132 // ASF should use the Face to nodeD because it has lower routing cost.
133 // After 5 seconds, a probe Interest should be sent to the Face to nodeB,
134 // and the probe should return Data quicker. ASF should then use the Face
135 // to nodeB to forward the remaining Interests.
136 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 30);
137 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 24);
138 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 6);
139
140 // If the link from nodeA to nodeB fails, ASF should start using the Face
141 // to nodeD again.
142 linkAB->fail();
143
144 runConsumer();
145
146 // Only 59 Data because the first Interest to nodeB after the failure should timeout
147 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 59);
148 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 30);
149 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 30);
150
151 // If the link from nodeA to nodeB recovers, ASF should probe the Face
152 // to nodeB and start using it again.
153 linkAB->recover();
154
155 // Advance time to ensure probing is due
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000156 this->advanceClocks(time::milliseconds(10), time::seconds(10));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000157
158 runConsumer();
159
160 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 89);
161 BOOST_CHECK_GE(linkAB->getFace(nodeA).getCounters().nOutInterests, 50);
162 BOOST_CHECK_LE(linkAD->getFace(nodeA).getCounters().nOutInterests, 40);
163
164 // If both links fail, nodeA should forward to the next hop with the lowest cost
165 linkAB->fail();
166 linkAD->fail();
167
168 runConsumer();
169
170 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 89);
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200171 BOOST_CHECK_LE(linkAB->getFace(nodeA).getCounters().nOutInterests, 61); // FIXME #3830
172 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 59); // FIXME #3830
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000173}
174
175BOOST_FIXTURE_TEST_CASE(Nack, AsfGridFixture)
176{
177 // nodeB has a FIB entry to reach the producer, but nodeD does not
178 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX);
179
180 // The strategy should first try to send to nodeD. But since nodeD does not have a route for
181 // the producer's prefix, it should return a NO_ROUTE Nack. The strategy should then start using the Face to
182 // nodeB.
183 runConsumer();
184
185 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nInNacks, 1);
186 BOOST_CHECK_EQUAL(consumer->getForwarderFace().getCounters().nOutData, 29);
187 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nOutInterests, 29);
188
189 // nodeD should receive 2 Interests: one for the very first Interest and
190 // another from a probe
191 BOOST_CHECK_GE(linkAD->getFace(nodeA).getCounters().nOutInterests, 2);
192}
193
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000194BOOST_AUTO_TEST_CASE(NoPitOutRecordAndProbeInterestNewNonce)
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600195{
196 /* +---------+
197 * | nodeD |
198 * +---------+
199 * |
200 * | 80ms
201 * |
202 * |
203 * +---------+
204 * +----->| nodeB |<------+
205 * | +---------+ |
206 * 15ms | | 16ms
207 * v v
208 * +---------+ +---------+
209 * | nodeA |--------------| nodeC |
210 * +---------+ 14ms +---------+
211 */
212
213 const Name PRODUCER_PREFIX = "/ndn/edu/nodeD/ping";
214
215 TopologyTester topo;
216 TopologyNode nodeA = topo.addForwarder("A"),
217 nodeB = topo.addForwarder("B"),
218 nodeC = topo.addForwarder("C"),
219 nodeD = topo.addForwarder("D");
220
221 for (TopologyNode node : {nodeA, nodeB, nodeC, nodeD}) {
222 topo.setStrategy<fw::AsfStrategy>(node);
223 }
224
225 shared_ptr<TopologyLink> linkAB = topo.addLink("AB", time::milliseconds(15), {nodeA, nodeB}),
226 linkAC = topo.addLink("AC", time::milliseconds(14), {nodeA, nodeC}),
227 linkBC = topo.addLink("BC", time::milliseconds(16), {nodeB, nodeC}),
228 linkBD = topo.addLink("BD", time::milliseconds(80), {nodeB, nodeD});
229
230 shared_ptr<TopologyAppLink> ping = topo.addAppFace("c", nodeA),
231 pingServer = topo.addAppFace("p", nodeD, PRODUCER_PREFIX);
232 topo.addEchoProducer(pingServer->getClientFace());
233
234 // Register prefixes
235 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 15);
236 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), PRODUCER_PREFIX, 14);
237 topo.registerPrefix(nodeC, linkBC->getFace(nodeC), PRODUCER_PREFIX, 16);
238 topo.registerPrefix(nodeB, linkBD->getFace(nodeB), PRODUCER_PREFIX, 80);
239
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000240 uint32_t nonce;
241
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600242 // Send 6 interest since probes can be scheduled b/w 0-5 seconds
243 for (int i = 1; i < 7; i++) {
244 // Send ping number i
245 Name name(PRODUCER_PREFIX);
246 name.appendTimestamp();
247 shared_ptr<Interest> interest = makeInterest(name);
248 ping->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000249 nonce = interest->getNonce();
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600250
251 // Don't know when the probe will be triggered since it is random between 0-5 seconds
252 // or whether it will be triggered for this interest
253 int j = 1;
254 while (linkAB->getFace(nodeA).getCounters().nOutInterests != 1) {
255 this->advanceClocks(time::milliseconds(1));
256 ++j;
257 // Probe was not scheduled with this ping interest
258 if (j > 1000) {
259 break;
260 }
261 }
262
263 // Check if probe is sent to B else send another ping
264 if (linkAB->getFace(nodeA).getCounters().nOutInterests == 1) {
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000265 // Get pitEntry of node A
266 shared_ptr<pit::Entry> pitEntry = topo.getForwarder(nodeA).getPit().find(*interest);
267 //get outRecord associated with face towards B
268 pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(linkAB->getFace(nodeA));
269
270 BOOST_CHECK(outRecord != pitEntry->out_end());
271
272 //Check that Nonce of interest is not equal to Nonce of Probe
273 BOOST_CHECK_NE(nonce, outRecord->getLastNonce());
274
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600275 // B should not have received the probe interest yet
276 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 0);
277
278 // i-1 interests through B when no probe
279 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i - 1);
280
281 // After 15ms, B should get the probe interest
282 this->advanceClocks(time::milliseconds(1), time::milliseconds(15));
283 BOOST_CHECK_EQUAL(linkAB->getFace(nodeB).getCounters().nInInterests, 1);
284 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nOutInterests, i);
285
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000286 pitEntry = topo.getForwarder(nodeB).getPit().find(*interest);
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600287
288 // Get outRecord associated with face towards D.
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000289 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
Ashlesh Gawanded3ac7772016-11-06 00:53:05 -0600290
291 BOOST_CHECK(outRecord != pitEntry->out_end());
292
293 // RTT between B and D
294 this->advanceClocks(time::milliseconds(5), time::milliseconds(160));
295 outRecord = pitEntry->getOutRecord(linkBD->getFace(nodeB));
296
297 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i);
298
299 BOOST_CHECK(outRecord == pitEntry->out_end());
300
301 // Data is returned for the ping after 15 ms - will result in false measurement
302 // 14+16-15 = 15ms
303 // Since outRecord == pitEntry->out_end()
304 this->advanceClocks(time::milliseconds(1), time::milliseconds(15));
305 BOOST_CHECK_EQUAL(linkBD->getFace(nodeB).getCounters().nInData, i+1);
306
307 break;
308 }
309 }
310}
311
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000312BOOST_AUTO_TEST_SUITE_END() // TestAsfStrategy
313BOOST_AUTO_TEST_SUITE_END() // Fw
314
315} // namespace tests
316} // namespace asf
317} // namespace fw
318} // namespace nfd