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