blob: 6e5cb9599af08a05929b4bf2299b342786c24274 [file] [log] [blame]
Junxiao Shi80ee7cb2014-12-14 10:53:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -05002/*
Davide Pesavento284bd622019-03-31 02:10:02 -04003 * Copyright (c) 2014-2019, Regents of the University of California,
Junxiao Shi80ee7cb2014-12-14 10:53:05 -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/** \file
27 * \brief allows testing forwarding in a network topology
28 */
29
Davide Pesavento97210d52016-10-14 15:45:48 +020030#ifndef NFD_TESTS_DAEMON_FW_TOPOLOGY_TESTER_HPP
31#define NFD_TESTS_DAEMON_FW_TOPOLOGY_TESTER_HPP
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070032
Junxiao Shi6535f1e2015-10-08 13:02:18 -070033#include "face/internal-transport.hpp"
Junxiao Shicde37ad2015-12-24 01:02:05 -070034#include "face/face.hpp"
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070035#include "fw/strategy.hpp"
Junxiao Shi0e4a1f12016-12-24 02:39:01 +000036#include "choose-strategy.hpp"
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070037#include "tests/test-common.hpp"
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070038
Davide Pesavento97210d52016-10-14 15:45:48 +020039#include <ndn-cxx/face.hpp>
40
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070041namespace nfd {
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080042namespace fw {
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070043namespace tests {
44
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080045using namespace nfd::tests;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070046
47/** \brief identifies a node (forwarder) in the topology
48 */
49typedef size_t TopologyNode;
50
Junxiao Shi6535f1e2015-10-08 13:02:18 -070051/** \brief represents a network link in the topology which connects two or more nodes
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070052 */
Junxiao Shi6535f1e2015-10-08 13:02:18 -070053class TopologyLink : noncopyable
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070054{
55public:
Junxiao Shi6535f1e2015-10-08 13:02:18 -070056 explicit
Teng Liangf995f382017-04-04 22:09:39 +000057 TopologyLink(time::nanoseconds delay);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070058
59 /** \brief fail the link, cause packets to be dropped silently
60 */
61 void
62 fail()
63 {
64 m_isUp = false;
65 }
66
67 /** \brief recover the link from a failure
68 */
69 void
70 recover()
71 {
72 m_isUp = true;
73 }
74
Teng Liangf995f382017-04-04 22:09:39 +000075 /** \brief block transmission from i to j
76 *
77 * Packets transmitted by i would not be delivered to j. Packets from j to i are unaffected.
78 * This can be used to simulate a wireless channel.
79 */
80 void
81 block(TopologyNode i, TopologyNode j);
82
83 /** \brief unblock transmission from i to j
84 */
85 void
86 unblock(TopologyNode i, TopologyNode j);
87
Hila Ben Abraham39a79be2016-03-30 22:00:55 -070088 /** \brief change the link delay
89 * \param delay link delay, must be positive
90 */
91 void
Teng Liangf995f382017-04-04 22:09:39 +000092 setDelay(time::nanoseconds delay);
Hila Ben Abraham39a79be2016-03-30 22:00:55 -070093
Junxiao Shicde37ad2015-12-24 01:02:05 -070094 /** \brief attach a face to the link
95 * \param i forwarder index
96 * \param face a Face with InternalForwarderTransport
97 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -070098 void
Junxiao Shicde37ad2015-12-24 01:02:05 -070099 addFace(TopologyNode i, shared_ptr<Face> face);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700100
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700101 /** \return a face of forwarder \p i which is attached to this link
102 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700103 Face&
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700104 getFace(TopologyNode i)
105 {
Teng Liangf995f382017-04-04 22:09:39 +0000106 return *m_transports.at(i).face;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700107 }
108
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700109private:
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700110 void
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400111 transmit(TopologyNode i, const Block& packet);
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700112
113private:
Davide Pesavento284bd622019-03-31 02:10:02 -0400114 bool m_isUp = true;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700115 time::nanoseconds m_delay;
Teng Liangf995f382017-04-04 22:09:39 +0000116
Davide Pesavento284bd622019-03-31 02:10:02 -0400117 class ReceiveProxy : public face::InternalTransportBase
Teng Liangf995f382017-04-04 22:09:39 +0000118 {
Davide Pesavento284bd622019-03-31 02:10:02 -0400119 public:
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400120 using Callback = std::function<void(const Block&)>;
Davide Pesavento284bd622019-03-31 02:10:02 -0400121
122 explicit
123 ReceiveProxy(Callback cb)
124 : m_cb(std::move(cb))
125 {
126 }
127
128 void
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400129 receivePacket(const Block& packet) final
Davide Pesavento284bd622019-03-31 02:10:02 -0400130 {
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400131 m_cb(packet);
Davide Pesavento284bd622019-03-31 02:10:02 -0400132 }
133
134 private:
135 Callback m_cb;
136 };
137
138 class NodeTransport
139 {
140 public:
141 NodeTransport(shared_ptr<Face> face, ReceiveProxy::Callback receiveCallback);
142
143 public:
Teng Liangf995f382017-04-04 22:09:39 +0000144 shared_ptr<Face> face;
Davide Pesavento284bd622019-03-31 02:10:02 -0400145 face::InternalForwarderTransport* transport;
146 ReceiveProxy proxy;
Teng Liangf995f382017-04-04 22:09:39 +0000147 std::set<TopologyNode> blockedDestinations;
148 };
Davide Pesavento284bd622019-03-31 02:10:02 -0400149
Teng Liangf995f382017-04-04 22:09:39 +0000150 std::unordered_map<TopologyNode, NodeTransport> m_transports;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700151};
152
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600153/** \brief represents a link on a single forwarder
154 */
155class TopologySingleLink : noncopyable
156{
157public:
158 /** \brief constructor
159 * \param forwarderFace a Face with InternalForwarderTransport
160 */
161 explicit
162 TopologySingleLink(shared_ptr<Face> forwarderFace);
163
164 /** \return face on forwarder side
165 */
166 Face&
167 getForwarderFace()
168 {
169 return *m_face;
170 }
171
172protected:
173 shared_ptr<Face> m_face;
174 face::InternalForwarderTransport* m_forwarderTransport;
175};
176
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700177/** \brief represents a link to a local application
178 */
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600179class TopologyAppLink : public TopologySingleLink
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700180{
181public:
Junxiao Shicde37ad2015-12-24 01:02:05 -0700182 /** \brief constructor
183 * \param forwarderFace a Face with InternalForwarderTransport
184 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700185 explicit
Junxiao Shicde37ad2015-12-24 01:02:05 -0700186 TopologyAppLink(shared_ptr<Face> forwarderFace);
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700187
188 /** \brief fail the link, cause packets to be dropped silently
189 */
190 void
191 fail();
192
193 /** \brief recover the link from a failure
194 */
195 void
196 recover();
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700197
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700198 /** \return face on application side
199 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700200 ndn::Face&
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700201 getClientFace()
202 {
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700203 return *m_client;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700204 }
205
206private:
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700207 shared_ptr<face::InternalClientTransport> m_clientTransport;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700208 shared_ptr<ndn::Face> m_client;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700209};
210
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600211/** \brief allows the test case to inject and observe L2 packets on a link
212 */
213class TopologyBareLink : public TopologySingleLink
214{
215public:
216 /** \brief constructor
217 * \param forwarderFace a Face with InternalForwarderTransport
218 */
219 explicit
220 TopologyBareLink(shared_ptr<Face> forwarderFace);
221
222 void
223 receivePacket(const Block& packet);
224
225public:
226 std::vector<Block> sentPackets;
227
228private:
229 class Observer;
230 unique_ptr<Observer> m_observer;
231};
232
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000233/** \brief captured packets on a face
234 */
235class TopologyPcap : noncopyable
236{
237public:
238 std::vector<Interest> sentInterests;
239 std::vector<Data> sentData;
240 std::vector<lp::Nack> sentNacks;
241};
242
243/** \brief captured packet timestamp tag
244 */
245using TopologyPcapTimestamp = ndn::SimpleTag<time::steady_clock::TimePoint, 0>;
246
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700247/** \brief builds a topology for forwarding tests
248 */
249class TopologyTester : noncopyable
250{
251public:
252 /** \brief creates a forwarder
253 * \return index of new forwarder
254 */
255 TopologyNode
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700256 addForwarder(const std::string& label);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700257
258 /** \return forwarder instance \p i
259 */
260 Forwarder&
261 getForwarder(TopologyNode i)
262 {
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400263 return m_forwarders.at(i)->forwarder;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700264 }
265
266 /** \brief sets strategy on forwarder \p i
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000267 * \tparam S the strategy type
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700268 * \note Test scenario can also access StrategyChoice table directly.
269 */
270 template<typename S>
271 void
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500272 setStrategy(TopologyNode i, Name prefix = Name("ndn:/"),
273 Name instanceName = S::getStrategyName())
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700274 {
275 Forwarder& forwarder = this->getForwarder(i);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500276 choose<S>(forwarder, prefix, instanceName);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700277 }
278
279 /** \brief makes a link that interconnects two or more forwarders
Teng Liangf995f382017-04-04 22:09:39 +0000280 * \brief linkType desired link type; LINK_TYPE_NONE to use point-to-point for two forwarders
281 * and multi-access for more than two forwarders; it's an error to specify
282 * point-to-point when there are more than two forwarders
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700283 *
284 * A face is created on each of \p forwarders .
285 * When a packet is sent onto one of the faces on this link,
286 * this packet will be received by all other faces on this link after \p delay .
287 */
288 shared_ptr<TopologyLink>
Teng Liangf995f382017-04-04 22:09:39 +0000289 addLink(const std::string& label, time::nanoseconds delay,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700290 std::initializer_list<TopologyNode> forwarders,
Teng Liangf995f382017-04-04 22:09:39 +0000291 ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_NONE);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700292
293 /** \brief makes a link to local application
294 */
295 shared_ptr<TopologyAppLink>
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700296 addAppFace(const std::string& label, TopologyNode i);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700297
298 /** \brief makes a link to local application, and register a prefix
299 */
300 shared_ptr<TopologyAppLink>
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700301 addAppFace(const std::string& label, TopologyNode i, const Name& prefix, uint64_t cost = 0);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700302
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600303 /** \brief makes a link that allows the test case to inject and observe L2 packets
304 */
305 shared_ptr<TopologyBareLink>
306 addBareLink(const std::string& label, TopologyNode i,
307 ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_LOCAL,
308 ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
309
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000310 /** \brief enables packet capture on every forwarder face
311 */
312 void
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400313 enablePcap(bool isEnabled = true)
314 {
315 m_wantPcap = isEnabled;
316 }
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000317
318 /** \return captured packets on a forwarder face
319 * \pre enablePcap(true) is in effect when the face was created
320 */
321 TopologyPcap&
322 getPcap(const Face& face);
323
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700324 /** \brief registers a prefix on a forwarder face
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700325 */
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700326 void
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700327 registerPrefix(TopologyNode i, const Face& face, const Name& prefix, uint64_t cost = 0);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700328
329 /** \brief creates a producer application that answers every Interest with Data of same Name
330 */
331 void
Saurab Dulala6dec222019-04-01 00:15:10 -0500332 addEchoProducer(ndn::Face& face, const Name& prefix = "/", time::nanoseconds replyDelay = 0_ns);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700333
334 /** \brief creates a consumer application that sends \p n Interests under \p prefix
335 * at \p interval fixed rate.
Teng Liangf995f382017-04-04 22:09:39 +0000336 * \param seq if non-negative, append sequence number instead of timestamp
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700337 */
338 void
Teng Liangf995f382017-04-04 22:09:39 +0000339 addIntervalConsumer(ndn::Face& face, const Name& prefix, time::nanoseconds interval,
340 size_t n, int seq = -1);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700341
342private:
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600343 shared_ptr<Face>
344 makeFace(TopologyNode i, const FaceUri& localUri, const FaceUri& remoteUri,
345 ndn::nfd::FaceScope scope, ndn::nfd::LinkType linkType);
346
347private:
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400348 class TopologyForwarder
349 {
350 public:
351 explicit
352 TopologyForwarder(const std::string& label)
353 : label(label)
354 {
355 }
356
357 public:
358 std::string label;
359 FaceTable faceTable;
360 Forwarder forwarder{faceTable};
361 };
362
363 std::vector<unique_ptr<TopologyForwarder>> m_forwarders;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700364 std::vector<shared_ptr<TopologyLink>> m_links;
365 std::vector<shared_ptr<TopologyAppLink>> m_appLinks;
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600366 std::vector<shared_ptr<TopologyBareLink>> m_bareLinks;
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400367 bool m_wantPcap = false;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700368};
369
370} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800371} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700372} // namespace nfd
373
Davide Pesavento97210d52016-10-14 15:45:48 +0200374#endif // NFD_TESTS_DAEMON_FW_TOPOLOGY_TESTER_HPP