blob: 52643068251594a1542c525aecb56b8ab5451e62 [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 Pesavento2c9d2ca2024-01-27 16:36:51 -05003 * Copyright (c) 2014-2024, 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
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040027 * \brief Allows testing forwarding in a network topology.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070028 */
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
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -050041#include <unordered_map>
42
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040043namespace nfd::tests {
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070044
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040045/** \brief Identifies a node (forwarder) in the topology.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070046 */
47typedef size_t TopologyNode;
48
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040049/** \brief Represents a network link in the topology which connects two or more nodes.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070050 */
Junxiao Shi6535f1e2015-10-08 13:02:18 -070051class TopologyLink : noncopyable
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070052{
53public:
Junxiao Shi6535f1e2015-10-08 13:02:18 -070054 explicit
Teng Liangf995f382017-04-04 22:09:39 +000055 TopologyLink(time::nanoseconds delay);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070056
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040057 /** \brief Fail the link, cause packets to be dropped silently.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070058 */
59 void
60 fail()
61 {
62 m_isUp = false;
63 }
64
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040065 /** \brief Recover the link from a failure.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070066 */
67 void
68 recover()
69 {
70 m_isUp = true;
71 }
72
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040073 /** \brief Block transmission from i to j.
Teng Liangf995f382017-04-04 22:09:39 +000074 *
75 * Packets transmitted by i would not be delivered to j. Packets from j to i are unaffected.
76 * This can be used to simulate a wireless channel.
77 */
78 void
79 block(TopologyNode i, TopologyNode j);
80
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040081 /** \brief Unblock transmission from i to j.
Teng Liangf995f382017-04-04 22:09:39 +000082 */
83 void
84 unblock(TopologyNode i, TopologyNode j);
85
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040086 /** \brief Change the link delay.
Hila Ben Abraham39a79be2016-03-30 22:00:55 -070087 * \param delay link delay, must be positive
88 */
89 void
Teng Liangf995f382017-04-04 22:09:39 +000090 setDelay(time::nanoseconds delay);
Hila Ben Abraham39a79be2016-03-30 22:00:55 -070091
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040092 /** \brief Attach a face to the link.
Junxiao Shicde37ad2015-12-24 01:02:05 -070093 * \param i forwarder index
94 * \param face a Face with InternalForwarderTransport
95 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -070096 void
Junxiao Shicde37ad2015-12-24 01:02:05 -070097 addFace(TopologyNode i, shared_ptr<Face> face);
Junxiao Shi5e5e4452015-09-24 16:56:52 -070098
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070099 /** \return a face of forwarder \p i which is attached to this link
100 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700101 Face&
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700102 getFace(TopologyNode i)
103 {
Teng Liangf995f382017-04-04 22:09:39 +0000104 return *m_transports.at(i).face;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700105 }
106
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700107private:
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700108 void
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400109 transmit(TopologyNode i, const Block& packet);
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700110
111private:
Davide Pesavento284bd622019-03-31 02:10:02 -0400112 bool m_isUp = true;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700113 time::nanoseconds m_delay;
Teng Liangf995f382017-04-04 22:09:39 +0000114
Davide Pesavento0a05f7a2023-10-16 20:28:06 -0400115 class ReceiveProxy final : public face::InternalTransportBase
Teng Liangf995f382017-04-04 22:09:39 +0000116 {
Davide Pesavento284bd622019-03-31 02:10:02 -0400117 public:
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400118 using Callback = std::function<void(const Block&)>;
Davide Pesavento284bd622019-03-31 02:10:02 -0400119
120 explicit
121 ReceiveProxy(Callback cb)
122 : m_cb(std::move(cb))
123 {
124 }
125
126 void
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400127 receivePacket(const Block& packet) final
Davide Pesavento284bd622019-03-31 02:10:02 -0400128 {
Davide Pesaventob3a23ca2019-05-04 20:40:21 -0400129 m_cb(packet);
Davide Pesavento284bd622019-03-31 02:10:02 -0400130 }
131
132 private:
133 Callback m_cb;
134 };
135
136 class NodeTransport
137 {
138 public:
139 NodeTransport(shared_ptr<Face> face, ReceiveProxy::Callback receiveCallback);
140
141 public:
Teng Liangf995f382017-04-04 22:09:39 +0000142 shared_ptr<Face> face;
Davide Pesavento284bd622019-03-31 02:10:02 -0400143 face::InternalForwarderTransport* transport;
144 ReceiveProxy proxy;
Teng Liangf995f382017-04-04 22:09:39 +0000145 std::set<TopologyNode> blockedDestinations;
146 };
Davide Pesavento284bd622019-03-31 02:10:02 -0400147
Teng Liangf995f382017-04-04 22:09:39 +0000148 std::unordered_map<TopologyNode, NodeTransport> m_transports;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700149};
150
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400151/** \brief Represents a link on a single forwarder.
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600152 */
153class TopologySingleLink : noncopyable
154{
155public:
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400156 /** \brief Constructor.
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600157 * \param forwarderFace a Face with InternalForwarderTransport
158 */
159 explicit
160 TopologySingleLink(shared_ptr<Face> forwarderFace);
161
162 /** \return face on forwarder side
163 */
164 Face&
165 getForwarderFace()
166 {
167 return *m_face;
168 }
169
170protected:
171 shared_ptr<Face> m_face;
172 face::InternalForwarderTransport* m_forwarderTransport;
173};
174
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400175/** \brief Represents a link to a local application.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700176 */
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600177class TopologyAppLink : public TopologySingleLink
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700178{
179public:
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400180 /** \brief Constructor.
Junxiao Shicde37ad2015-12-24 01:02:05 -0700181 * \param forwarderFace a Face with InternalForwarderTransport
182 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700183 explicit
Junxiao Shicde37ad2015-12-24 01:02:05 -0700184 TopologyAppLink(shared_ptr<Face> forwarderFace);
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700185
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400186 /** \brief Fail the link, cause packets to be dropped silently.
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700187 */
188 void
189 fail();
190
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400191 /** \brief Recover the link from a failure.
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700192 */
193 void
194 recover();
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700195
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700196 /** \return face on application side
197 */
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700198 ndn::Face&
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700199 getClientFace()
200 {
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700201 return *m_client;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700202 }
203
204private:
Junxiao Shi6535f1e2015-10-08 13:02:18 -0700205 shared_ptr<face::InternalClientTransport> m_clientTransport;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700206 shared_ptr<ndn::Face> m_client;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700207};
208
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400209/** \brief Allows the test case to inject and observe L2 packets on a link.
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600210 */
211class TopologyBareLink : public TopologySingleLink
212{
213public:
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400214 /** \brief Constructor.
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600215 * \param forwarderFace a Face with InternalForwarderTransport
216 */
217 explicit
218 TopologyBareLink(shared_ptr<Face> forwarderFace);
219
220 void
221 receivePacket(const Block& packet);
222
223public:
224 std::vector<Block> sentPackets;
225
226private:
227 class Observer;
228 unique_ptr<Observer> m_observer;
229};
230
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400231/** \brief Captured packets on a face.
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000232 */
233class TopologyPcap : noncopyable
234{
235public:
236 std::vector<Interest> sentInterests;
237 std::vector<Data> sentData;
238 std::vector<lp::Nack> sentNacks;
239};
240
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400241/** \brief Captured packet timestamp tag.
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000242 */
Davide Pesavento412c9822021-07-02 00:21:05 -0400243using TopologyPcapTimestamp = ndn::SimpleTag<time::steady_clock::time_point, 0>;
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000244
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400245/** \brief Builds a topology for forwarding tests.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700246 */
247class TopologyTester : noncopyable
248{
249public:
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400250 /** \brief Creates a forwarder.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700251 * \return index of new forwarder
252 */
253 TopologyNode
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700254 addForwarder(const std::string& label);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700255
256 /** \return forwarder instance \p i
257 */
258 Forwarder&
259 getForwarder(TopologyNode i)
260 {
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400261 return m_forwarders.at(i)->forwarder;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700262 }
263
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400264 /** \brief Sets strategy on forwarder \p i.
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000265 * \tparam S the strategy type
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700266 * \note Test scenario can also access StrategyChoice table directly.
267 */
268 template<typename S>
269 void
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500270 setStrategy(TopologyNode i, Name prefix = Name("ndn:/"),
271 Name instanceName = S::getStrategyName())
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700272 {
273 Forwarder& forwarder = this->getForwarder(i);
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500274 choose<S>(forwarder, prefix, instanceName);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700275 }
276
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400277 /** \brief Makes a link that interconnects two or more forwarders.
278 * \param linkType Desired link type; LINK_TYPE_NONE to use point-to-point for two forwarders
Teng Liangf995f382017-04-04 22:09:39 +0000279 * and multi-access for more than two forwarders; it's an error to specify
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400280 * point-to-point when there are more than two forwarders.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700281 *
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400282 * A face is created on each of \p forwarders.
283 * When a packet is sent onto one of the faces on this link, the packet will be
284 * received by all other faces on this link after the specified delay.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700285 */
286 shared_ptr<TopologyLink>
Teng Liangf995f382017-04-04 22:09:39 +0000287 addLink(const std::string& label, time::nanoseconds delay,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700288 std::initializer_list<TopologyNode> forwarders,
Teng Liangf995f382017-04-04 22:09:39 +0000289 ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_NONE);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700290
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400291 /** \brief Makes a link to a local application.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700292 */
293 shared_ptr<TopologyAppLink>
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700294 addAppFace(const std::string& label, TopologyNode i);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700295
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400296 /** \brief Makes a link to a local application and registers a prefix.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700297 */
298 shared_ptr<TopologyAppLink>
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700299 addAppFace(const std::string& label, TopologyNode i, const Name& prefix, uint64_t cost = 0);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700300
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400301 /** \brief Makes a link that allows the test case to inject and observe layer-2 packets.
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600302 */
303 shared_ptr<TopologyBareLink>
304 addBareLink(const std::string& label, TopologyNode i,
305 ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_LOCAL,
306 ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
307
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400308 /** \brief Enables packet capture on every forwarder face.
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000309 */
310 void
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400311 enablePcap(bool isEnabled = true)
312 {
313 m_wantPcap = isEnabled;
314 }
Junxiao Shifab9e0d2017-02-02 06:04:59 +0000315
316 /** \return captured packets on a forwarder face
317 * \pre enablePcap(true) is in effect when the face was created
318 */
319 TopologyPcap&
320 getPcap(const Face& face);
321
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400322 /** \brief Registers a prefix on a forwarder face.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700323 */
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700324 void
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700325 registerPrefix(TopologyNode i, const Face& face, const Name& prefix, uint64_t cost = 0);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700326
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400327 /** \brief Creates a producer application that answers every Interest with Data of same Name.
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700328 */
329 void
Saurab Dulala6dec222019-04-01 00:15:10 -0500330 addEchoProducer(ndn::Face& face, const Name& prefix = "/", time::nanoseconds replyDelay = 0_ns);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700331
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400332 /** \brief Creates a consumer application that sends \p n Interests under \p prefix
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700333 * at \p interval fixed rate.
Teng Liangf995f382017-04-04 22:09:39 +0000334 * \param seq if non-negative, append sequence number instead of timestamp
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700335 */
336 void
Teng Liangf995f382017-04-04 22:09:39 +0000337 addIntervalConsumer(ndn::Face& face, const Name& prefix, time::nanoseconds interval,
338 size_t n, int seq = -1);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700339
340private:
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600341 shared_ptr<Face>
342 makeFace(TopologyNode i, const FaceUri& localUri, const FaceUri& remoteUri,
343 ndn::nfd::FaceScope scope, ndn::nfd::LinkType linkType);
344
345private:
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400346 class TopologyForwarder
347 {
348 public:
349 explicit
350 TopologyForwarder(const std::string& label)
351 : label(label)
352 {
353 }
354
355 public:
356 std::string label;
357 FaceTable faceTable;
358 Forwarder forwarder{faceTable};
359 };
360
361 std::vector<unique_ptr<TopologyForwarder>> m_forwarders;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700362 std::vector<shared_ptr<TopologyLink>> m_links;
363 std::vector<shared_ptr<TopologyAppLink>> m_appLinks;
Junxiao Shi606d5dd2019-09-23 12:47:44 -0600364 std::vector<shared_ptr<TopologyBareLink>> m_bareLinks;
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400365 bool m_wantPcap = false;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700366};
367
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400368} // namespace nfd::tests
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700369
Davide Pesavento97210d52016-10-14 15:45:48 +0200370#endif // NFD_TESTS_DAEMON_FW_TOPOLOGY_TESTER_HPP