blob: d9a749c4f1e4af5899838aa085813947210da6fa [file] [log] [blame]
Junxiao Shi67ba8d22015-08-21 21:21:28 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento87fc0f82018-04-11 23:43:51 -04002/*
Alexander Afanasyev4400e422021-02-17 11:17:33 -05003 * Copyright (c) 2014-2021, Regents of the University of California,
Junxiao Shi67ba8d22015-08-21 21:21:28 -07004 * 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/multicast-strategy.hpp"
Davide Pesavento2cae8ca2019-04-18 20:48:05 -040027#include "common/global.hpp"
Junxiao Shi67ba8d22015-08-21 21:21:28 -070028
29#include "tests/test-common.hpp"
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040030#include "tests/daemon/face/dummy-face.hpp"
Davide Pesavento3dade002019-03-19 11:29:56 -060031#include "strategy-tester.hpp"
Ashlesh Gawandec1d48372020-08-02 22:30:11 -070032#include "topology-tester.hpp"
Junxiao Shi67ba8d22015-08-21 21:21:28 -070033
34namespace nfd {
35namespace fw {
36namespace tests {
37
Davide Pesavento14e71f02019-03-28 17:35:25 -040038using MulticastStrategyTester = StrategyTester<MulticastStrategy>;
Junxiao Shi890afe92016-12-15 14:34:34 +000039NFD_REGISTER_STRATEGY(MulticastStrategyTester);
40
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040041class MulticastStrategyFixture : public GlobalIoTimeFixture
Junxiao Shi890afe92016-12-15 14:34:34 +000042{
43protected:
44 MulticastStrategyFixture()
Davide Pesaventoa4abfb02019-10-06 16:02:56 -040045 : face1(make_shared<DummyFace>())
Junxiao Shi890afe92016-12-15 14:34:34 +000046 , face2(make_shared<DummyFace>())
47 , face3(make_shared<DummyFace>())
48 {
Davide Pesaventoa4abfb02019-10-06 16:02:56 -040049 faceTable.add(face1);
50 faceTable.add(face2);
51 faceTable.add(face3);
Junxiao Shi890afe92016-12-15 14:34:34 +000052 }
53
54protected:
Davide Pesaventoa4abfb02019-10-06 16:02:56 -040055 FaceTable faceTable;
56 Forwarder forwarder{faceTable};
57 MulticastStrategyTester strategy{forwarder};
58 Fib& fib{forwarder.getFib()};
59 Pit& pit{forwarder.getPit()};
60
Junxiao Shi890afe92016-12-15 14:34:34 +000061 shared_ptr<DummyFace> face1;
62 shared_ptr<DummyFace> face2;
63 shared_ptr<DummyFace> face3;
64};
65
Junxiao Shi5e5e4452015-09-24 16:56:52 -070066BOOST_AUTO_TEST_SUITE(Fw)
Junxiao Shi890afe92016-12-15 14:34:34 +000067BOOST_FIXTURE_TEST_SUITE(TestMulticastStrategy, MulticastStrategyFixture)
Junxiao Shi67ba8d22015-08-21 21:21:28 -070068
Ashlesh Gawandec1d48372020-08-02 22:30:11 -070069BOOST_AUTO_TEST_CASE(Bug5123)
70{
71 fib::Entry& fibEntry = *fib.insert(Name()).first;
72 fib.addOrUpdateNextHop(fibEntry, *face2, 0);
73
74 // Send an Interest from face 1 to face 2
75 shared_ptr<Interest> interest = makeInterest("ndn:/H0D6i5fc");
76 shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
77 pitEntry->insertOrUpdateInRecord(*face1, *interest);
78
79 strategy.afterReceiveInterest(FaceEndpoint(*face1, 0), *interest, pitEntry);
80 BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
81
82 // Advance more than default suppression
83 this->advanceClocks(15_ms);
84
85 // Get same interest from face 2 which does not have anywhere to go
86 pitEntry = pit.insert(*interest).first;
87 pitEntry->insertOrUpdateInRecord(*face2, *interest);
88
89 strategy.afterReceiveInterest(FaceEndpoint(*face2, 0), *interest, pitEntry);
90 // Since the interest is same as the one sent out by face 1 pit should not be rejected
91 // as any data coming back should be able to satisfy original interest from face 1
92 BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
93
94 /*
95 * +---------+ +---------+ +---------+
96 * | nodeA |------------| nodeB |----------| nodeC |
97 * +---------+ 10ms +---------+ 100ms +---------+
98 */
99
100 const Name PRODUCER_PREFIX = "/ndn/edu/nodeC/ping";
101
102 TopologyTester topo;
103 TopologyNode nodeA = topo.addForwarder("A"),
104 nodeB = topo.addForwarder("B"),
105 nodeC = topo.addForwarder("C");
106
107 for (TopologyNode node : {nodeA, nodeB, nodeC}) {
108 topo.setStrategy<MulticastStrategy>(node);
109 }
110
111 shared_ptr<TopologyLink> linkAB = topo.addLink("AB", 10_ms, {nodeA, nodeB}),
112 linkBC = topo.addLink("BC", 100_ms, {nodeB, nodeC});
113
114 shared_ptr<TopologyAppLink> appA = topo.addAppFace("cA", nodeA),
115 appB = topo.addAppFace("cB", nodeB),
116 pingServer = topo.addAppFace("p", nodeC, PRODUCER_PREFIX);
117 topo.addEchoProducer(pingServer->getClientFace());
118 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), PRODUCER_PREFIX, 10);
119 topo.registerPrefix(nodeB, linkAB->getFace(nodeB), PRODUCER_PREFIX, 10);
120 topo.registerPrefix(nodeB, linkBC->getFace(nodeB), PRODUCER_PREFIX, 100);
121
122 Name name(PRODUCER_PREFIX);
123 name.appendTimestamp();
124 interest = makeInterest(name);
125 appA->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
126
127 this->advanceClocks(10_ms, 20_ms);
128
129 // AppB expresses the same interest
130 interest->refreshNonce();
131 appB->getClientFace().expressInterest(*interest, nullptr, nullptr, nullptr);
132 this->advanceClocks(10_ms, 200_ms);
133
134 // Data should have made to appB
135 BOOST_CHECK_EQUAL(linkBC->getFace(nodeB).getCounters().nInData, 1);
136 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nInData, 0);
137
138 this->advanceClocks(10_ms, 10_ms);
139 // nodeA should have gotten the data successfully
140 BOOST_CHECK_EQUAL(linkAB->getFace(nodeA).getCounters().nInData, 1);
141 BOOST_CHECK_EQUAL(topo.getForwarder(nodeA).getCounters().nUnsolicitedData, 0);
142}
143
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700144BOOST_AUTO_TEST_CASE(Forward2)
145{
Junxiao Shia6de4292016-07-12 02:08:10 +0000146 fib::Entry& fibEntry = *fib.insert(Name()).first;
Ju Pand8315bf2019-07-31 06:59:07 +0000147 fib.addOrUpdateNextHop(fibEntry, *face1, 0);
148 fib.addOrUpdateNextHop(fibEntry, *face2, 0);
149 fib.addOrUpdateNextHop(fibEntry, *face3, 0);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700150
151 shared_ptr<Interest> interest = makeInterest("ndn:/H0D6i5fc");
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700152 shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000153 pitEntry->insertOrUpdateInRecord(*face3, *interest);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700154
ashiqopuc7079482019-02-20 05:34:37 +0000155 strategy.afterReceiveInterest(FaceEndpoint(*face3, 0), *interest, pitEntry);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700156 BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
157 BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 2);
158 std::set<FaceId> sentInterestFaceIds;
159 std::transform(strategy.sendInterestHistory.begin(), strategy.sendInterestHistory.end(),
160 std::inserter(sentInterestFaceIds, sentInterestFaceIds.end()),
161 [] (const MulticastStrategyTester::SendInterestArgs& args) {
162 return args.outFaceId;
163 });
164 std::set<FaceId> expectedInterestFaceIds{face1->getId(), face2->getId()};
165 BOOST_CHECK_EQUAL_COLLECTIONS(sentInterestFaceIds.begin(), sentInterestFaceIds.end(),
166 expectedInterestFaceIds.begin(), expectedInterestFaceIds.end());
Ashlesh Gawandee38e2612017-02-25 07:23:41 +0000167
Ashlesh Gawandeecdbe5f2017-03-04 03:08:24 +0000168 const time::nanoseconds TICK = time::duration_cast<time::nanoseconds>(
169 MulticastStrategy::RETX_SUPPRESSION_INITIAL * 0.1);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700170
Ashlesh Gawandeecdbe5f2017-03-04 03:08:24 +0000171 // downstream retransmits frequently, but the strategy should not send Interests
172 // more often than DEFAULT_MIN_RETX_INTERVAL
173 scheduler::EventId retxFrom4Evt;
174 size_t nSentLast = strategy.sendInterestHistory.size();
175 time::steady_clock::TimePoint timeSentLast = time::steady_clock::now();
Davide Pesavento87fc0f82018-04-11 23:43:51 -0400176 std::function<void()> periodicalRetxFrom4; // let periodicalRetxFrom4 lambda capture itself
Ashlesh Gawandeecdbe5f2017-03-04 03:08:24 +0000177 periodicalRetxFrom4 = [&] {
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000178 pitEntry->insertOrUpdateInRecord(*face3, *interest);
ashiqopuc7079482019-02-20 05:34:37 +0000179 strategy.afterReceiveInterest(FaceEndpoint(*face3, 0), *interest, pitEntry);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700180
Ashlesh Gawandeecdbe5f2017-03-04 03:08:24 +0000181 size_t nSent = strategy.sendInterestHistory.size();
182 if (nSent > nSentLast) {
183 // Multicast strategy should multicast the interest to other two faces
184 BOOST_CHECK_EQUAL(nSent - nSentLast, 2);
Davide Pesavento3dade002019-03-19 11:29:56 -0600185 auto timeSent = time::steady_clock::now();
Ashlesh Gawandeecdbe5f2017-03-04 03:08:24 +0000186 BOOST_CHECK_GE(timeSent - timeSentLast, TICK * 8);
187 nSentLast = nSent;
188 timeSentLast = timeSent;
189 }
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700190
Davide Pesavento3dade002019-03-19 11:29:56 -0600191 retxFrom4Evt = getScheduler().schedule(TICK * 5, periodicalRetxFrom4);
Ashlesh Gawandeecdbe5f2017-03-04 03:08:24 +0000192 };
193 periodicalRetxFrom4();
194 this->advanceClocks(TICK, MulticastStrategy::RETX_SUPPRESSION_MAX * 16);
Davide Pesavento3dade002019-03-19 11:29:56 -0600195 retxFrom4Evt.cancel();
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700196}
197
Alexander Afanasyev4400e422021-02-17 11:17:33 -0500198BOOST_AUTO_TEST_CASE(LoopingInterest)
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700199{
Junxiao Shia6de4292016-07-12 02:08:10 +0000200 fib::Entry& fibEntry = *fib.insert(Name()).first;
Ju Pand8315bf2019-07-31 06:59:07 +0000201 fib.addOrUpdateNextHop(fibEntry, *face1, 0);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700202
203 shared_ptr<Interest> interest = makeInterest("ndn:/H0D6i5fc");
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700204 shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
Md Ashiqur Rahmanc88d2d42019-08-28 20:19:47 +0000205 pitEntry->insertOrUpdateInRecord(*face1, *interest);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700206
ashiqopuc7079482019-02-20 05:34:37 +0000207 strategy.afterReceiveInterest(FaceEndpoint(*face1, 0), *interest, pitEntry);
Alexander Afanasyev4400e422021-02-17 11:17:33 -0500208 BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700209 BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 0);
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700210}
211
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700212BOOST_AUTO_TEST_SUITE_END() // TestMulticastStrategy
213BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi67ba8d22015-08-21 21:21:28 -0700214
215} // namespace tests
216} // namespace fw
217} // namespace nfd