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