blob: 2761e04f63455e5f6c947c2b6cdaf000b50e5ac9 [file] [log] [blame]
Davide Pesavento912d2e82019-01-10 17:04:31 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesavento92669062022-03-10 19:09:44 -05003 * Copyright (c) 2014-2022, Arizona Board of Regents.
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -08004 *
Davide Pesaventod0b59982015-02-27 19:15:15 +01005 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080017 *
18 * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
19 */
20
Davide Pesavento35185332019-01-14 04:00:15 -050021#include "util.hpp"
22
Davide Pesaventoef064892022-04-05 02:26:03 -040023#include <ndn-cxx/data.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050024#include <ndn-cxx/face.hpp>
Davide Pesaventoef064892022-04-05 02:26:03 -040025#include <ndn-cxx/interest.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050026#include <ndn-cxx/lp/tags.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050027#include <ndn-cxx/util/random.hpp>
Davide Pesaventoef064892022-04-05 02:26:03 -040028#include <ndn-cxx/util/time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050029
Davide Pesavento35185332019-01-14 04:00:15 -050030#include <limits>
Davide Pesaventoef064892022-04-05 02:26:03 -040031#include <optional>
Davide Pesavento56f79d62019-01-26 17:30:32 -050032#include <sstream>
Davide Pesaventoef064892022-04-05 02:26:03 -040033#include <string_view>
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080034#include <vector>
35
Davide Pesavento912d2e82019-01-10 17:04:31 -050036#include <boost/asio/deadline_timer.hpp>
37#include <boost/asio/io_service.hpp>
38#include <boost/asio/signal_set.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070039#include <boost/date_time/posix_time/posix_time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050040#include <boost/lexical_cast.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070041#include <boost/noncopyable.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050042#include <boost/program_options/options_description.hpp>
43#include <boost/program_options/parsers.hpp>
44#include <boost/program_options/variables_map.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070045
Davide Pesavento35185332019-01-14 04:00:15 -050046namespace po = boost::program_options;
Davide Pesaventoef064892022-04-05 02:26:03 -040047using namespace ndn::time_literals;
48using namespace std::string_literals;
jeraldabraham420dbf02014-04-25 22:58:31 -070049
Davide Pesaventoef064892022-04-05 02:26:03 -040050namespace ndntg {
51
52namespace time = ndn::time;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080053
jeraldabraham420dbf02014-04-25 22:58:31 -070054class NdnTrafficClient : boost::noncopyable
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080055{
56public:
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070057 explicit
Davide Pesavento35185332019-01-14 04:00:15 -050058 NdnTrafficClient(const std::string& configFile)
59 : m_signalSet(m_ioService, SIGINT, SIGTERM)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070060 , m_logger("NdnTrafficClient")
Alexander Afanasyev740812e2014-10-30 15:37:45 -070061 , m_face(m_ioService)
Davide Pesavento35185332019-01-14 04:00:15 -050062 , m_configurationFile(configFile)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080063 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080064 }
65
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080066 void
Davide Pesavento35185332019-01-14 04:00:15 -050067 setMaximumInterests(uint64_t maxInterests)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080068 {
Davide Pesavento35185332019-01-14 04:00:15 -050069 m_nMaximumInterests = maxInterests;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080070 }
71
72 void
Davide Pesavento35185332019-01-14 04:00:15 -050073 setInterestInterval(time::milliseconds interval)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080074 {
Davide Pesavento35185332019-01-14 04:00:15 -050075 BOOST_ASSERT(interval > 0_ms);
76 m_interestInterval = interval;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080077 }
78
79 void
jeraldabraham420dbf02014-04-25 22:58:31 -070080 setQuietLogging()
81 {
Davide Pesavento35185332019-01-14 04:00:15 -050082 m_wantQuiet = true;
jeraldabraham420dbf02014-04-25 22:58:31 -070083 }
84
Davide Pesavento306e5bc2019-01-26 16:20:34 -050085 int
Davide Pesavento35185332019-01-14 04:00:15 -050086 run()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080087 {
Davide Pesaventoef064892022-04-05 02:26:03 -040088 m_logger.initializeLog(std::to_string(ndn::random::generateWord32()));
Davide Pesavento306e5bc2019-01-26 16:20:34 -050089
90 if (!readConfigurationFile(m_configurationFile, m_trafficPatterns, m_logger)) {
91 return 2;
92 }
93
94 if (!checkTrafficPatternCorrectness()) {
95 m_logger.log("ERROR: Traffic configuration provided is not proper", false, true);
96 return 2;
97 }
98
99 m_logger.log("Traffic configuration file processing completed.\n", true, false);
100 for (std::size_t i = 0; i < m_trafficPatterns.size(); i++) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400101 m_logger.log("Traffic Pattern Type #" + std::to_string(i + 1), false, false);
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500102 m_trafficPatterns[i].printTrafficConfiguration(m_logger);
103 m_logger.log("", false, false);
104 }
Davide Pesaventod0b59982015-02-27 19:15:15 +0100105
Davide Pesavento35185332019-01-14 04:00:15 -0500106 if (m_nMaximumInterests == 0) {
107 logStatistics();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500108 return 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500109 }
Davide Pesaventod0b59982015-02-27 19:15:15 +0100110
Davide Pesaventoef064892022-04-05 02:26:03 -0400111 m_signalSet.async_wait([this] (auto&&...) { stop(); });
Davide Pesavento35185332019-01-14 04:00:15 -0500112
113 boost::asio::deadline_timer timer(m_ioService,
114 boost::posix_time::millisec(m_interestInterval.count()));
Davide Pesaventoef064892022-04-05 02:26:03 -0400115 timer.async_wait([this, &timer] (auto&&...) { generateTraffic(timer); });
Davide Pesavento35185332019-01-14 04:00:15 -0500116
117 try {
118 m_face.processEvents();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500119 return m_hasError ? 1 : 0;
Davide Pesavento35185332019-01-14 04:00:15 -0500120 }
121 catch (const std::exception& e) {
122 m_logger.log("ERROR: "s + e.what(), true, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500123 m_ioService.stop();
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500124 return 1;
Davide Pesavento35185332019-01-14 04:00:15 -0500125 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800126 }
127
Davide Pesavento35185332019-01-14 04:00:15 -0500128private:
129 class InterestTrafficConfiguration
130 {
131 public:
132 void
133 printTrafficConfiguration(Logger& logger) const
134 {
Davide Pesavento56f79d62019-01-26 17:30:32 -0500135 std::ostringstream os;
Davide Pesavento35185332019-01-14 04:00:15 -0500136
Davide Pesavento56f79d62019-01-26 17:30:32 -0500137 os << "TrafficPercentage=" << m_trafficPercentage << ", ";
138 os << "Name=" << m_name << ", ";
139 if (m_nameAppendBytes) {
140 os << "NameAppendBytes=" << *m_nameAppendBytes << ", ";
141 }
142 if (m_nameAppendSeqNum) {
143 os << "NameAppendSequenceNumber=" << *m_nameAppendSeqNum << ", ";
144 }
145 if (m_canBePrefix) {
146 os << "CanBePrefix=" << m_canBePrefix << ", ";
147 }
148 if (m_mustBeFresh) {
149 os << "MustBeFresh=" << m_mustBeFresh << ", ";
150 }
151 if (m_nonceDuplicationPercentage > 0) {
152 os << "NonceDuplicationPercentage=" << m_nonceDuplicationPercentage << ", ";
153 }
154 if (m_interestLifetime >= 0_ms) {
155 os << "InterestLifetime=" << m_interestLifetime.count() << ", ";
156 }
157 if (m_nextHopFaceId > 0) {
158 os << "NextHopFaceId=" << m_nextHopFaceId << ", ";
159 }
160 if (m_expectedContent) {
161 os << "ExpectedContent=" << *m_expectedContent << ", ";
162 }
Davide Pesavento35185332019-01-14 04:00:15 -0500163
Davide Pesavento56f79d62019-01-26 17:30:32 -0500164 auto str = os.str();
165 str = str.substr(0, str.length() - 2); // remove suffix ", "
166 logger.log(str, false, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500167 }
168
169 bool
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500170 parseConfigurationLine(const std::string& line, Logger& logger, int lineNumber)
Davide Pesavento35185332019-01-14 04:00:15 -0500171 {
172 std::string parameter, value;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500173 if (!extractParameterAndValue(line, parameter, value)) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400174 logger.log("Line " + std::to_string(lineNumber) + " - Invalid syntax: " + line,
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500175 false, true);
176 return false;
177 }
178
179 if (parameter == "TrafficPercentage") {
180 m_trafficPercentage = std::stoul(value);
181 }
182 else if (parameter == "Name") {
183 m_name = value;
184 }
185 else if (parameter == "NameAppendBytes") {
186 m_nameAppendBytes = std::stoul(value);
187 }
188 else if (parameter == "NameAppendSequenceNumber") {
189 m_nameAppendSeqNum = std::stoull(value);
190 }
Davide Pesavento56f79d62019-01-26 17:30:32 -0500191 else if (parameter == "CanBePrefix") {
192 m_canBePrefix = parseBoolean(value);
193 }
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500194 else if (parameter == "MustBeFresh") {
195 m_mustBeFresh = parseBoolean(value);
196 }
197 else if (parameter == "NonceDuplicationPercentage") {
198 m_nonceDuplicationPercentage = std::stoul(value);
199 }
200 else if (parameter == "InterestLifetime") {
201 m_interestLifetime = time::milliseconds(std::stoul(value));
202 }
203 else if (parameter == "NextHopFaceId") {
204 m_nextHopFaceId = std::stoull(value);
205 }
206 else if (parameter == "ExpectedContent") {
207 m_expectedContent = value;
Davide Pesavento35185332019-01-14 04:00:15 -0500208 }
209 else {
Davide Pesaventoef064892022-04-05 02:26:03 -0400210 logger.log("Line " + std::to_string(lineNumber) + " - Ignoring unknown parameter: " + parameter,
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500211 false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500212 }
213 return true;
214 }
215
216 bool
217 checkTrafficDetailCorrectness() const
218 {
219 return true;
220 }
221
222 public:
223 uint8_t m_trafficPercentage = 0;
224 std::string m_name;
Davide Pesaventoef064892022-04-05 02:26:03 -0400225 std::optional<std::size_t> m_nameAppendBytes;
226 std::optional<uint64_t> m_nameAppendSeqNum;
Davide Pesavento56f79d62019-01-26 17:30:32 -0500227 bool m_canBePrefix = false;
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500228 bool m_mustBeFresh = false;
Davide Pesavento35185332019-01-14 04:00:15 -0500229 uint8_t m_nonceDuplicationPercentage = 0;
230 time::milliseconds m_interestLifetime = -1_ms;
231 uint64_t m_nextHopFaceId = 0;
Davide Pesaventoef064892022-04-05 02:26:03 -0400232 std::optional<std::string> m_expectedContent;
Davide Pesavento35185332019-01-14 04:00:15 -0500233
234 uint64_t m_nInterestsSent = 0;
235 uint64_t m_nInterestsReceived = 0;
236 uint64_t m_nNacks = 0;
237 uint64_t m_nContentInconsistencies = 0;
238
239 // RTT is stored as milliseconds with fractional sub-milliseconds precision
240 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
241 double m_maximumInterestRoundTripTime = 0;
242 double m_totalInterestRoundTripTime = 0;
243 };
244
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800245 void
246 logStatistics()
247 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800248 m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700249 m_logger.log("Total Traffic Pattern Types = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400250 std::to_string(m_trafficPatterns.size()), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700251 m_logger.log("Total Interests Sent = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400252 std::to_string(m_nInterestsSent), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700253 m_logger.log("Total Responses Received = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400254 std::to_string(m_nInterestsReceived), false, true);
Eric Newberry976c2042016-06-19 23:37:35 -0700255 m_logger.log("Total Nacks Received = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400256 std::to_string(m_nNacks), false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100257
Davide Pesavento35185332019-01-14 04:00:15 -0500258 double loss = 0.0;
259 if (m_nInterestsSent > 0) {
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700260 loss = (m_nInterestsSent - m_nInterestsReceived) * 100.0 / m_nInterestsSent;
Davide Pesavento35185332019-01-14 04:00:15 -0500261 }
Davide Pesaventoef064892022-04-05 02:26:03 -0400262 m_logger.log("Total Interest Loss = " + std::to_string(loss) + "%", false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100263
Davide Pesavento35185332019-01-14 04:00:15 -0500264 double average = 0.0;
265 double inconsistency = 0.0;
266 if (m_nInterestsReceived > 0) {
267 average = m_totalInterestRoundTripTime / m_nInterestsReceived;
268 inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
269 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700270 m_logger.log("Total Data Inconsistency = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400271 std::to_string(inconsistency) + "%", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700272 m_logger.log("Total Round Trip Time = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400273 std::to_string(m_totalInterestRoundTripTime) + "ms", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700274 m_logger.log("Average Round Trip Time = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400275 std::to_string(average) + "ms\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700276
Davide Pesavento35185332019-01-14 04:00:15 -0500277 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400278 m_logger.log("Traffic Pattern Type #" + std::to_string(patternId + 1), false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500279 m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
280 m_logger.log("Total Interests Sent = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400281 std::to_string(m_trafficPatterns[patternId].m_nInterestsSent), false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500282 m_logger.log("Total Responses Received = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400283 std::to_string(m_trafficPatterns[patternId].m_nInterestsReceived), false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500284 m_logger.log("Total Nacks Received = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400285 std::to_string(m_trafficPatterns[patternId].m_nNacks), false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500286 loss = 0;
287 if (m_trafficPatterns[patternId].m_nInterestsSent > 0) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400288 loss = m_trafficPatterns[patternId].m_nInterestsSent - m_trafficPatterns[patternId].m_nInterestsReceived;
Davide Pesavento35185332019-01-14 04:00:15 -0500289 loss *= 100.0;
290 loss /= m_trafficPatterns[patternId].m_nInterestsSent;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800291 }
Davide Pesaventoef064892022-04-05 02:26:03 -0400292 m_logger.log("Total Interest Loss = " + std::to_string(loss) + "%", false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500293 average = 0;
294 inconsistency = 0;
295 if (m_trafficPatterns[patternId].m_nInterestsReceived > 0) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400296 average = m_trafficPatterns[patternId].m_totalInterestRoundTripTime /
297 m_trafficPatterns[patternId].m_nInterestsReceived;
Davide Pesavento35185332019-01-14 04:00:15 -0500298 inconsistency = m_trafficPatterns[patternId].m_nContentInconsistencies;
299 inconsistency *= 100.0 / m_trafficPatterns[patternId].m_nInterestsReceived;
300 }
Davide Pesaventoef064892022-04-05 02:26:03 -0400301 m_logger.log("Total Data Inconsistency = " + std::to_string(inconsistency) + "%", false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500302 m_logger.log("Total Round Trip Time = " +
Davide Pesaventoef064892022-04-05 02:26:03 -0400303 std::to_string(m_trafficPatterns[patternId].m_totalInterestRoundTripTime) + "ms", false, true);
304 m_logger.log("Average Round Trip Time = " + std::to_string(average) + "ms\n", false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500305 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800306 }
307
308 bool
Davide Pesavento35185332019-01-14 04:00:15 -0500309 checkTrafficPatternCorrectness() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800310 {
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500311 // TODO
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800312 return true;
313 }
314
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700315 uint32_t
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800316 getNewNonce()
317 {
Davide Pesavento35185332019-01-14 04:00:15 -0500318 if (m_nonces.size() >= 1000)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700319 m_nonces.clear();
jeraldabraham473ef3d2014-03-06 12:40:35 -0700320
Davide Pesaventoef064892022-04-05 02:26:03 -0400321 auto randomNonce = ndn::random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700322 while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end())
Davide Pesaventoef064892022-04-05 02:26:03 -0400323 randomNonce = ndn::random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700324
325 m_nonces.push_back(randomNonce);
326 return randomNonce;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800327 }
328
Davide Pesavento35185332019-01-14 04:00:15 -0500329 uint32_t
330 getOldNonce()
331 {
332 if (m_nonces.empty())
333 return getNewNonce();
334
335 std::uniform_int_distribution<std::size_t> dist(0, m_nonces.size() - 1);
Davide Pesaventoef064892022-04-05 02:26:03 -0400336 return m_nonces[dist(ndn::random::getRandomNumberEngine())];
Davide Pesavento35185332019-01-14 04:00:15 -0500337 }
338
Davide Pesaventoef064892022-04-05 02:26:03 -0400339 static auto
Davide Pesavento912d2e82019-01-10 17:04:31 -0500340 generateRandomNameComponent(std::size_t length)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800341 {
Davide Pesavento35185332019-01-14 04:00:15 -0500342 // per ISO C++ std, cannot instantiate uniform_int_distribution with uint8_t
343 static std::uniform_int_distribution<unsigned short> dist(std::numeric_limits<uint8_t>::min(),
344 std::numeric_limits<uint8_t>::max());
345
Davide Pesaventoef064892022-04-05 02:26:03 -0400346 ndn::Buffer buf(length);
Davide Pesavento912d2e82019-01-10 17:04:31 -0500347 for (std::size_t i = 0; i < length; i++) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400348 buf[i] = static_cast<uint8_t>(dist(ndn::random::getRandomNumberEngine()));
Eric Newberry3b284192015-07-06 21:44:46 -0700349 }
Davide Pesaventoef064892022-04-05 02:26:03 -0400350 return ndn::name::Component(buf);
Davide Pesavento35185332019-01-14 04:00:15 -0500351 }
352
Davide Pesaventoef064892022-04-05 02:26:03 -0400353 auto
Davide Pesavento35185332019-01-14 04:00:15 -0500354 prepareInterest(std::size_t patternId)
355 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400356 ndn::Interest interest;
Davide Pesavento35185332019-01-14 04:00:15 -0500357 auto& pattern = m_trafficPatterns[patternId];
358
Davide Pesaventoef064892022-04-05 02:26:03 -0400359 ndn::Name name(pattern.m_name);
Davide Pesavento35185332019-01-14 04:00:15 -0500360 if (pattern.m_nameAppendBytes > 0) {
361 name.append(generateRandomNameComponent(*pattern.m_nameAppendBytes));
362 }
363 if (pattern.m_nameAppendSeqNum) {
364 auto seqNum = *pattern.m_nameAppendSeqNum;
365 name.appendSequenceNumber(seqNum);
366 pattern.m_nameAppendSeqNum = seqNum + 1;
367 }
368 interest.setName(name);
369
Davide Pesavento56f79d62019-01-26 17:30:32 -0500370 interest.setCanBePrefix(pattern.m_canBePrefix);
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500371 interest.setMustBeFresh(pattern.m_mustBeFresh);
Davide Pesavento35185332019-01-14 04:00:15 -0500372
373 static std::uniform_int_distribution<> duplicateNonceDist(1, 100);
Davide Pesaventoef064892022-04-05 02:26:03 -0400374 if (duplicateNonceDist(ndn::random::getRandomNumberEngine()) <= pattern.m_nonceDuplicationPercentage)
Davide Pesavento35185332019-01-14 04:00:15 -0500375 interest.setNonce(getOldNonce());
376 else
377 interest.setNonce(getNewNonce());
378
379 if (pattern.m_interestLifetime >= 0_ms)
380 interest.setInterestLifetime(pattern.m_interestLifetime);
381
382 if (pattern.m_nextHopFaceId > 0)
Davide Pesaventoef064892022-04-05 02:26:03 -0400383 interest.setTag(std::make_shared<ndn::lp::NextHopFaceIdTag>(pattern.m_nextHopFaceId));
Davide Pesavento35185332019-01-14 04:00:15 -0500384
385 return interest;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800386 }
387
388 void
Davide Pesaventoef064892022-04-05 02:26:03 -0400389 onData(const ndn::Data& data, int globalRef, int localRef, std::size_t patternId,
390 const time::steady_clock::time_point& sentTime)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800391 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400392 auto logLine = "Data Received - PatternType=" + std::to_string(patternId + 1) +
393 ", GlobalID=" + std::to_string(globalRef) +
394 ", LocalID=" + std::to_string(localRef) +
Davide Pesavento35185332019-01-14 04:00:15 -0500395 ", Name=" + data.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700396
397 m_nInterestsReceived++;
398 m_trafficPatterns[patternId].m_nInterestsReceived++;
Davide Pesavento35185332019-01-14 04:00:15 -0500399
400 if (m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento92669062022-03-10 19:09:44 -0500401 std::string receivedContent = readString(data.getContent());
Davide Pesavento35185332019-01-14 04:00:15 -0500402 if (receivedContent != *m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500403 m_nContentInconsistencies++;
404 m_trafficPatterns[patternId].m_nContentInconsistencies++;
405 logLine += ", IsConsistent=No";
jeraldabraham473ef3d2014-03-06 12:40:35 -0700406 }
Davide Pesavento35185332019-01-14 04:00:15 -0500407 else {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500408 logLine += ", IsConsistent=Yes";
Davide Pesavento35185332019-01-14 04:00:15 -0500409 }
Davide Pesavento912d2e82019-01-10 17:04:31 -0500410 }
Davide Pesavento35185332019-01-14 04:00:15 -0500411 else {
jeraldabraham473ef3d2014-03-06 12:40:35 -0700412 logLine += ", IsConsistent=NotChecked";
Davide Pesavento35185332019-01-14 04:00:15 -0500413 }
414 if (!m_wantQuiet) {
jeraldabraham420dbf02014-04-25 22:58:31 -0700415 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500416 }
417
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700418 double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0;
419 if (m_minimumInterestRoundTripTime > roundTripTime)
420 m_minimumInterestRoundTripTime = roundTripTime;
421 if (m_maximumInterestRoundTripTime < roundTripTime)
422 m_maximumInterestRoundTripTime = roundTripTime;
423 if (m_trafficPatterns[patternId].m_minimumInterestRoundTripTime > roundTripTime)
424 m_trafficPatterns[patternId].m_minimumInterestRoundTripTime = roundTripTime;
425 if (m_trafficPatterns[patternId].m_maximumInterestRoundTripTime < roundTripTime)
426 m_trafficPatterns[patternId].m_maximumInterestRoundTripTime = roundTripTime;
427 m_totalInterestRoundTripTime += roundTripTime;
428 m_trafficPatterns[patternId].m_totalInterestRoundTripTime += roundTripTime;
Davide Pesavento35185332019-01-14 04:00:15 -0500429
430 if (m_nMaximumInterests == globalRef) {
431 stop();
Davide Pesavento912d2e82019-01-10 17:04:31 -0500432 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700433 }
434
435 void
Davide Pesaventoef064892022-04-05 02:26:03 -0400436 onNack(const ndn::Interest& interest, const ndn::lp::Nack& nack,
Davide Pesavento35185332019-01-14 04:00:15 -0500437 int globalRef, int localRef, std::size_t patternId)
Eric Newberry976c2042016-06-19 23:37:35 -0700438 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400439 auto logLine = "Interest Nack'd - PatternType=" + std::to_string(patternId + 1) +
440 ", GlobalID=" + std::to_string(globalRef) +
441 ", LocalID=" + std::to_string(localRef) +
Davide Pesavento35185332019-01-14 04:00:15 -0500442 ", Name=" + interest.getName().toUri() +
443 ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
Eric Newberry976c2042016-06-19 23:37:35 -0700444 m_logger.log(logLine, true, false);
445
446 m_nNacks++;
447 m_trafficPatterns[patternId].m_nNacks++;
448
Davide Pesavento35185332019-01-14 04:00:15 -0500449 if (m_nMaximumInterests == globalRef) {
450 stop();
Eric Newberry976c2042016-06-19 23:37:35 -0700451 }
452 }
453
454 void
Davide Pesaventoef064892022-04-05 02:26:03 -0400455 onTimeout(const ndn::Interest& interest, int globalRef, int localRef, int patternId)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700456 {
Davide Pesaventoef064892022-04-05 02:26:03 -0400457 auto logLine = "Interest Timed Out - PatternType=" + std::to_string(patternId + 1) +
458 ", GlobalID=" + std::to_string(globalRef) +
459 ", LocalID=" + std::to_string(localRef) +
Davide Pesavento35185332019-01-14 04:00:15 -0500460 ", Name=" + interest.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700461 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500462
463 if (m_nMaximumInterests == globalRef) {
464 stop();
465 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700466 }
467
468 void
Davide Pesavento35185332019-01-14 04:00:15 -0500469 generateTraffic(boost::asio::deadline_timer& timer)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700470 {
Davide Pesavento35185332019-01-14 04:00:15 -0500471 if (m_nMaximumInterests && m_nInterestsSent >= *m_nMaximumInterests) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500472 return;
473 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700474
Davide Pesavento35185332019-01-14 04:00:15 -0500475 static std::uniform_int_distribution<> trafficDist(1, 100);
Davide Pesaventoef064892022-04-05 02:26:03 -0400476 int trafficKey = trafficDist(ndn::random::getRandomNumberEngine());
Davide Pesaventod0b59982015-02-27 19:15:15 +0100477
Davide Pesavento35185332019-01-14 04:00:15 -0500478 int cumulativePercentage = 0;
479 std::size_t patternId = 0;
480 for (; patternId < m_trafficPatterns.size(); patternId++) {
481 cumulativePercentage += m_trafficPatterns[patternId].m_trafficPercentage;
482 if (trafficKey <= cumulativePercentage) {
483 auto interest = prepareInterest(patternId);
484 try {
485 m_nInterestsSent++;
486 m_trafficPatterns[patternId].m_nInterestsSent++;
487 auto sentTime = time::steady_clock::now();
488 m_face.expressInterest(interest,
489 bind(&NdnTrafficClient::onData, this, _2, m_nInterestsSent,
490 m_trafficPatterns[patternId].m_nInterestsSent, patternId, sentTime),
491 bind(&NdnTrafficClient::onNack, this, _1, _2, m_nInterestsSent,
492 m_trafficPatterns[patternId].m_nInterestsSent, patternId),
493 bind(&NdnTrafficClient::onTimeout, this, _1, m_nInterestsSent,
494 m_trafficPatterns[patternId].m_nInterestsSent, patternId));
495
496 if (!m_wantQuiet) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400497 auto logLine = "Sending Interest - PatternType=" + std::to_string(patternId + 1) +
498 ", GlobalID=" + std::to_string(m_nInterestsSent) +
499 ", LocalID=" + std::to_string(m_trafficPatterns[patternId].m_nInterestsSent) +
Davide Pesavento35185332019-01-14 04:00:15 -0500500 ", Name=" + interest.getName().toUri();
501 m_logger.log(logLine, true, false);
502 }
503
Davide Pesaventoef064892022-04-05 02:26:03 -0400504 timer.expires_at(timer.expires_at() + boost::posix_time::millisec(m_interestInterval.count()));
505 timer.async_wait([this, &timer] (auto&&...) { generateTraffic(timer); });
Davide Pesavento35185332019-01-14 04:00:15 -0500506 }
507 catch (const std::exception& e) {
508 m_logger.log("ERROR: "s + e.what(), true, true);
509 }
510 break;
511 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800512 }
Davide Pesavento35185332019-01-14 04:00:15 -0500513 if (patternId == m_trafficPatterns.size()) {
Davide Pesaventoef064892022-04-05 02:26:03 -0400514 timer.expires_at(timer.expires_at() + boost::posix_time::millisec(m_interestInterval.count()));
515 timer.async_wait([this, &timer] (auto&&...) { generateTraffic(timer); });
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800516 }
517 }
518
Davide Pesavento35185332019-01-14 04:00:15 -0500519 void
520 stop()
521 {
522 if (m_nContentInconsistencies > 0 || m_nInterestsSent != m_nInterestsReceived) {
523 m_hasError = true;
524 }
525
526 logStatistics();
527 m_face.shutdown();
528 m_ioService.stop();
529 }
530
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800531private:
Alexander Afanasyev976c3972014-05-26 17:03:40 +0300532 boost::asio::io_service m_ioService;
Davide Pesavento35185332019-01-14 04:00:15 -0500533 boost::asio::signal_set m_signalSet;
534 Logger m_logger;
Davide Pesaventoef064892022-04-05 02:26:03 -0400535 ndn::Face m_face;
Davide Pesavento35185332019-01-14 04:00:15 -0500536
537 std::string m_configurationFile;
Davide Pesaventoef064892022-04-05 02:26:03 -0400538 std::optional<uint64_t> m_nMaximumInterests;
Davide Pesavento35185332019-01-14 04:00:15 -0500539 time::milliseconds m_interestInterval = 1_s;
Davide Pesavento35185332019-01-14 04:00:15 -0500540
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700541 std::vector<InterestTrafficConfiguration> m_trafficPatterns;
542 std::vector<uint32_t> m_nonces;
Davide Pesavento35185332019-01-14 04:00:15 -0500543 uint64_t m_nInterestsSent = 0;
544 uint64_t m_nInterestsReceived = 0;
545 uint64_t m_nNacks = 0;
546 uint64_t m_nContentInconsistencies = 0;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700547
Davide Pesavento912d2e82019-01-10 17:04:31 -0500548 // RTT is stored as milliseconds with fractional sub-milliseconds precision
Davide Pesavento35185332019-01-14 04:00:15 -0500549 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
550 double m_maximumInterestRoundTripTime = 0;
551 double m_totalInterestRoundTripTime = 0;
552
Davide Pesaventoef064892022-04-05 02:26:03 -0400553 bool m_wantQuiet = false;
Davide Pesavento35185332019-01-14 04:00:15 -0500554 bool m_hasError = false;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800555};
556
Davide Pesaventoef064892022-04-05 02:26:03 -0400557} // namespace ndntg
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800558
Davide Pesavento35185332019-01-14 04:00:15 -0500559static void
Davide Pesaventoef064892022-04-05 02:26:03 -0400560usage(std::ostream& os, std::string_view programName, const po::options_description& desc)
Davide Pesavento35185332019-01-14 04:00:15 -0500561{
562 os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
563 << "\n"
564 << "Generate Interest traffic as per provided Traffic_Configuration_File.\n"
565 << "Interests are continuously generated unless a total number is specified.\n"
566 << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
567 << "\n"
568 << desc;
569}
570
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700571int
572main(int argc, char* argv[])
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800573{
Davide Pesavento35185332019-01-14 04:00:15 -0500574 std::string configFile;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100575
Davide Pesavento35185332019-01-14 04:00:15 -0500576 po::options_description visibleOptions("Options");
577 visibleOptions.add_options()
578 ("help,h", "print this help message and exit")
579 ("count,c", po::value<int>(), "total number of Interests to be generated")
580 ("interval,i", po::value<ndn::time::milliseconds::rep>()->default_value(1000),
581 "Interest generation interval in milliseconds")
582 ("quiet,q", po::bool_switch(), "turn off logging of Interest generation/Data reception")
583 ;
584
585 po::options_description hiddenOptions;
586 hiddenOptions.add_options()
587 ("config-file", po::value<std::string>(&configFile))
588 ;
589
590 po::positional_options_description posOptions;
591 posOptions.add("config-file", -1);
592
593 po::options_description allOptions;
594 allOptions.add(visibleOptions).add(hiddenOptions);
595
596 po::variables_map vm;
597 try {
598 po::store(po::command_line_parser(argc, argv).options(allOptions).positional(posOptions).run(), vm);
599 po::notify(vm);
600 }
601 catch (const po::error& e) {
602 std::cerr << "ERROR: " << e.what() << std::endl;
603 return 2;
604 }
605 catch (const boost::bad_any_cast& e) {
606 std::cerr << "ERROR: " << e.what() << std::endl;
607 return 2;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800608 }
609
Davide Pesavento35185332019-01-14 04:00:15 -0500610 if (vm.count("help") > 0) {
611 usage(std::cout, argv[0], visibleOptions);
612 return 0;
613 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800614
Davide Pesavento35185332019-01-14 04:00:15 -0500615 if (configFile.empty()) {
616 usage(std::cerr, argv[0], visibleOptions);
617 return 2;
618 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800619
Davide Pesaventoef064892022-04-05 02:26:03 -0400620 ndntg::NdnTrafficClient client(configFile);
Davide Pesavento35185332019-01-14 04:00:15 -0500621
622 if (vm.count("count") > 0) {
623 int count = vm["count"].as<int>();
624 if (count < 0) {
625 std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
626 return 2;
627 }
628 client.setMaximumInterests(static_cast<uint64_t>(count));
629 }
630
631 if (vm.count("interval") > 0) {
632 ndn::time::milliseconds interval(vm["interval"].as<ndn::time::milliseconds::rep>());
Davide Pesaventoef064892022-04-05 02:26:03 -0400633 if (interval <= 0_ms) {
Davide Pesavento35185332019-01-14 04:00:15 -0500634 std::cerr << "ERROR: the argument for option '--interval' must be positive" << std::endl;
635 return 2;
636 }
637 client.setInterestInterval(interval);
638 }
639
640 if (vm["quiet"].as<bool>()) {
641 client.setQuietLogging();
642 }
643
Davide Pesavento306e5bc2019-01-26 16:20:34 -0500644 return client.run();
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800645}