From ab38321508d886f0acd535f0f5f07a3d44e29591 Mon Sep 17 00:00:00 2001 From: "Enrico Loparco (eloparco)" Date: Wed, 14 Sep 2022 08:58:55 +0000 Subject: feat(hicn-ping): allow usage of random prefixes/suffixes in hicn-ping Ref: HICN-783 Signed-off-by: Enrico Loparco (eloparco) Change-Id: I41c804dd639ee15aee9619732f55e39a3baf1385 --- apps/ping/src/ping_client.cc | 77 +++++++------ apps/ping/src/ping_server.cc | 90 ++++++++-------- hicn-light/src/hicn/core/forwarder.c | 3 +- lib/includes/hicn/name.h | 3 + lib/src/name.c | 6 ++ .../includes/hicn/transport/core/interest.h | 2 + libtransport/includes/hicn/transport/core/name.h | 2 + .../includes/hicn/transport/utils/CMakeLists.txt | 1 + .../hicn/transport/utils/traffic_generator.h | 72 +++++++++++++ libtransport/src/core/interest.cc | 10 +- libtransport/src/core/name.cc | 7 ++ libtransport/src/test/CMakeLists.txt | 1 + libtransport/src/test/test_traffic_generator.cc | 119 +++++++++++++++++++++ libtransport/src/utils/CMakeLists.txt | 1 + libtransport/src/utils/traffic_generator.cc | 87 +++++++++++++++ tests/1-node.yml | 1 - tests/Makefile | 13 ++- tests/config.sh | 95 ++++++++++++++++ tests/functional-tests/hicn-light-ping.robot | 26 +++++ 19 files changed, 530 insertions(+), 86 deletions(-) create mode 100644 libtransport/includes/hicn/transport/utils/traffic_generator.h create mode 100644 libtransport/src/test/test_traffic_generator.cc create mode 100644 libtransport/src/utils/traffic_generator.cc create mode 100644 tests/functional-tests/hicn-light-ping.robot diff --git a/apps/ping/src/ping_client.cc b/apps/ping/src/ping_client.cc index 3e95b8896..747f4bd1b 100644 --- a/apps/ping/src/ping_client.cc +++ b/apps/ping/src/ping_client.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,8 +41,11 @@ using Verifier = auth::AsymmetricVerifier; class Configuration { public: - uint64_t num_int_manifest_suffixes_ = - 0; // Number of suffixes in interest manifest + static constexpr char TRAFFIC_GENERATOR_RAND[] = "RANDOM"; + + uint32_t num_int_manifest_suffixes_ = + 0; // Number of suffixes in interest manifest (suffix in the header + // is not included in the count) uint64_t interestLifetime_ = 500; // ms uint64_t pingInterval_ = 1000000; // us uint32_t maxPing_ = 10; // number of interests @@ -49,6 +53,7 @@ class Configuration { std::string name_ = "b001::1"; std::string certificate_; std::string passphrase_; + std::string traffic_generator_type_; uint16_t srcPort_ = 9695; uint16_t dstPort_ = 8080; bool verbose_ = false; @@ -68,8 +73,7 @@ class Client : private interface::Portal::TransportCallback { : signals_(io_service_, SIGINT), config_(c), timer_(std::make_unique( - portal_.getThread().getIoService())), - sequence_number_(config_->first_suffix_) { + portal_.getThread().getIoService())) { // Let the main thread to catch SIGINT signals_.async_wait(std::bind(&Client::afterSignal, this)); @@ -83,6 +87,15 @@ class Client : private interface::Portal::TransportCallback { signer_ = std::make_unique( auth::CryptoSuite::HMAC_SHA256, c->passphrase_); } + + if (c->traffic_generator_type_ == + std::string(Configuration::TRAFFIC_GENERATOR_RAND)) { + traffic_generator_ = + std::make_unique(config_->maxPing_); + } else { + traffic_generator_ = std::make_unique( + config_->name_, config_->first_suffix_, config_->maxPing_); + } } virtual ~Client() = default; @@ -128,8 +141,8 @@ class Client : private interface::Portal::TransportCallback { if (config_->verbose_) { std::cout << "<<< recevied object. " << std::endl; - std::cout << "<<< interest name: " << interest.getName() - << " (n_suffixes=" << interest.numberOfSuffixes() << ")" + std::cout << "<<< interest name: " << interest.getName().getPrefix() + << " (n_suffixes=" << config_->num_int_manifest_suffixes_ << ")" << " src port: " << interest.getSrcPort() << " dst port: " << interest.getDstPort() << std::endl; std::cout << "<<< object name: " << object.getName() @@ -141,7 +154,8 @@ class Client : private interface::Portal::TransportCallback { } else if (!config_->quiet_) { std::cout << "<<< received object. " << std::endl; std::cout << "<<< round trip: " << rtt << " [us]" << std::endl; - std::cout << "<<< interest name: " << interest.getName() << std::endl; + std::cout << "<<< interest name: " << interest.getName().getPrefix() + << std::endl; std::cout << "<<< object name: " << object.getName() << std::endl; std::cout << "<<< content object size: " << object.payloadSize() + object.headerSize() << " [bytes]" @@ -197,7 +211,10 @@ class Client : private interface::Portal::TransportCallback { } void doPing() { - const Name interest_name(config_->name_, sequence_number_); + std::string name = traffic_generator_->getPrefix(); + uint32_t sequence_number = traffic_generator_->getSuffix(); + const Name interest_name(name, sequence_number); + hicn_packet_format_t format; if (interest_name.getAddressFamily() == AF_INET) { format = signer_ ? HICN_PACKET_FORMAT_IPV4_TCP_AH @@ -217,12 +234,6 @@ class Client : private interface::Portal::TransportCallback { interest->setSrcPort(config_->srcPort_); interest->setDstPort(config_->dstPort_); interest->setTTL(config_->ttl_); - uint32_t seq_offset = 1; - while (seq_offset <= config_->num_int_manifest_suffixes_ && - sequence_number_ + seq_offset < config_->maxPing_) { - interest->appendSuffix(sequence_number_ + seq_offset); - seq_offset++; - } if (config_->verbose_) { std::cout << ">>> send interest " << interest->getName() @@ -237,11 +248,15 @@ class Client : private interface::Portal::TransportCallback { if (!config_->quiet_) std::cout << std::endl; - send_timestamps_[sequence_number_] = utils::SteadyTime::now(); - for (uint64_t i = 1; i < seq_offset; i++) - send_timestamps_[sequence_number_ + i] = utils::SteadyTime::now(); + send_timestamps_[sequence_number] = utils::SteadyTime::now(); + for (int i = 0; i < config_->num_int_manifest_suffixes_ && + !traffic_generator_->hasFinished(); + i++) { + uint32_t sequence_number = traffic_generator_->getSuffix(); - if (signer_) signer_->signPacket(interest.get()); + interest->appendSuffix(sequence_number); + send_timestamps_[sequence_number] = utils::SteadyTime::now(); + } if (config_->dump_) { std::cout << "----- interest dump -----" << std::endl; @@ -250,13 +265,10 @@ class Client : private interface::Portal::TransportCallback { } interest->encodeSuffixes(); - + if (signer_) signer_->signPacket(interest.get()); portal_.sendInterest(interest, interest->getLifetime()); - sequence_number_ += seq_offset; - sent_ += seq_offset; - - if (sent_ < config_->maxPing_) { + if (!traffic_generator_->hasFinished()) { this->timer_->expires_from_now( std::chrono::microseconds(config_->pingInterval_)); this->timer_->async_wait([this](const std::error_code e) { @@ -269,18 +281,18 @@ class Client : private interface::Portal::TransportCallback { void afterSignal() { std::cout << "Stop ping" << std::endl; - std::cout << "Sent: " << sent_ << " Received: " << received_ - << " Timeouts: " << timedout_ << std::endl; + std::cout << "Sent: " << traffic_generator_->getSentCount() + << " Received: " << received_ << " Timeouts: " << timedout_ + << std::endl; io_service_.stop(); } void reset() { timer_.reset(new asio::steady_timer(portal_.getThread().getIoService())); - sequence_number_ = config_->first_suffix_; + traffic_generator_->reset(); last_jump_ = 0; processed_ = 0; state_ = SYN_STATE; - sent_ = 0; received_ = 0; timedout_ = 0; } @@ -292,15 +304,14 @@ class Client : private interface::Portal::TransportCallback { asio::signal_set signals_; Configuration *config_; std::unique_ptr timer_; - uint32_t sequence_number_; uint64_t last_jump_ = 0; uint64_t processed_ = 0; uint32_t state_ = SYN_STATE; - uint32_t sent_ = 0; uint32_t received_ = 0; uint32_t timedout_ = 0; Verifier verifier_; std::unique_ptr signer_; + std::unique_ptr traffic_generator_; }; void help() { @@ -339,6 +350,9 @@ void help() { std::cerr << "-F Path to optional configuration file for " "libtransport" << std::endl; + std::cout << "-b Traffic generator type. Use 'RANDOM' for " + "random prefixes and suffixes. Default: sequential suffixes." + << std::endl; std::cout << "-H prints this message" << std::endl; } @@ -358,13 +372,16 @@ int start(int argc, char *argv[]) { transport::interface::global_config::IoModuleConfiguration io_config; io_config.name = "hicnlight_module"; - while ((opt = getopt(argc, argv, "a:j::t:i:m:s:d:n:l:f:c:SAOqVDHz:F:")) != + while ((opt = getopt(argc, argv, "a:b:j::t:i:m:s:d:n:l:f:c:SAOqVDHz:F:")) != -1) { switch (opt) { case 'a': c->num_int_manifest_suffixes_ = std::stoi(optarg); c->passphrase_ = argv[optind]; break; + case 'b': + c->traffic_generator_type_ = optarg; + break; case 't': c->ttl_ = uint8_t(std::stoi(optarg)); break; diff --git a/apps/ping/src/ping_server.cc b/apps/ping/src/ping_server.cc index 876efd133..b91b2c612 100644 --- a/apps/ping/src/ping_server.cc +++ b/apps/ping/src/ping_server.cc @@ -40,6 +40,38 @@ using CryptoSuite = auth::CryptoSuite; class CallbackContainer { const std::size_t log2_content_object_buffer_size = 12; + private: + std::shared_ptr createContentObject(const Name &name, + uint32_t lifetime, + const Interest &interest) { + auto &content_object = content_objects_[content_objects_index_++ & mask_]; + + content_object->setName(name); + content_object->setLifetime(lifetime); + content_object->setLocator(interest.getLocator()); + content_object->setSrcPort(interest.getDstPort()); + content_object->setDstPort(interest.getSrcPort()); + content_object->setTTL(ttl_); + + if (verbose_) { + std::cout << ">>> send object " << content_object->getName() + << " src port: " << content_object->getSrcPort() + << " dst port: " << content_object->getDstPort() + << " TTL: " << (int)content_object->getTTL() << std::endl; + } else if (!quiet_) { + std::cout << ">>> send object " << content_object->getName() << std::endl; + } + + if (dump_) { + std::cout << "----- object dump -----" << std::endl; + content_object->dump(); + std::cout << "-----------------------" << std::endl; + } + + if (sign_ && signer_) signer_->signPacket(content_object.get()); + return content_object; + } + public: CallbackContainer(const Name &prefix, uint32_t object_size, bool verbose, bool dump, bool quiet, uint8_t ttl, auth::Signer *signer, @@ -109,58 +141,22 @@ class CallbackContainer { std::cout << "-------------------------" << std::endl; } - uint32_t *suffix = interest.firstSuffix(); - uint32_t n_suffixes_in_manifest = interest.numberOfSuffixes(); - hicn_uword *request_bitmap = interest.getRequestBitmap(); if (!interest.isValid()) throw std::runtime_error("Bad interest format"); - Name name = interest.getName(); - uint32_t pos = 0; // Position of current suffix in manifest - do { - // If suffix can be processed, i.e. no manifest with bitmap excluding it - if (!interest.hasManifest() || - bitmap_is_set_no_check(request_bitmap, pos)) { - auto &content_object = - content_objects_[content_objects_index_++ & mask_]; - - content_object->setName(interest.getName()); - content_object->setLifetime(lifetime); - content_object->setLocator(interest.getLocator()); - content_object->setSrcPort(interest.getDstPort()); - content_object->setDstPort(interest.getSrcPort()); - content_object->setTTL(ttl_); - - if (verbose_) { - std::cout << ">>> send object " << content_object->getName() - << " src port: " << content_object->getSrcPort() - << " dst port: " << content_object->getDstPort() - << " TTL: " << (int)content_object->getTTL() << std::endl; - } else if (!quiet_) { - std::cout << ">>> send object " << content_object->getName() - << std::endl; - } - - if (dump_) { - std::cout << "----- object dump -----" << std::endl; - content_object->dump(); - std::cout << "-----------------------" << std::endl; - } - - if (sign_ && signer_) { - signer_->signPacket(content_object.get()); - } - - p.produce(*content_object); - } - if (interest.hasManifest()) { - uint32_t seq = *suffix; - suffix++; + if (!interest.hasManifest()) { // Single interest + auto content_object = createContentObject(name, lifetime, interest); + p.produce(*content_object); + } else { // Interest manifest + uint32_t _, *suffix = NULL; + interest_manifest_foreach_suffix(interest.getIntManifestHeader(), suffix, + _) { + name.setSuffix(*suffix); - Name name = interest.getName(); - interest.setName(name.setSuffix(seq)); + auto content_object = createContentObject(name, lifetime, interest); + p.produce(*content_object); } - } while (pos++ < n_suffixes_in_manifest); + } if (!quiet_) std::cout << std::endl; } diff --git a/hicn-light/src/hicn/core/forwarder.c b/hicn-light/src/hicn/core/forwarder.c index 60493a9c5..fbf7040e3 100644 --- a/hicn-light/src/hicn/core/forwarder.c +++ b/hicn-light/src/hicn/core/forwarder.c @@ -1013,8 +1013,7 @@ static ssize_t forwarder_process_aggregated_interest( WITH_DEBUG({ char buf[MAXSZ_HICN_PREFIX]; - int rc = - hicn_name_snprintf(buf, MAXSZ_HICN_NAME, msgbuf_get_name(msgbuf)); + int rc = hicn_name_snprintf(buf, MAXSZ_HICN_NAME, &name_copy); if (rc < 0 || rc >= MAXSZ_HICN_PREFIX) snprintf(buf, MAXSZ_HICN_PREFIX, "(error)"); DEBUG("Next in manifest: %s", buf); diff --git a/lib/includes/hicn/name.h b/lib/includes/hicn/name.h index 895b86341..a1b8e1fc1 100644 --- a/lib/includes/hicn/name.h +++ b/lib/includes/hicn/name.h @@ -270,6 +270,9 @@ bool hicn_name_is_v4 (const hicn_name_t *name); int hicn_name_snprintf (char *s, size_t size, const hicn_name_t *name); +int hicn_name_no_suffix_snprintf (char *s, size_t size, + const hicn_name_t *name); + int hicn_name_cmp (const hicn_name_t *n1, const hicn_name_t *n2); bool hicn_name_equals (const hicn_name_t *n1, const hicn_name_t *n2); diff --git a/lib/src/name.c b/lib/src/name.c index 04c48cb4d..1c933d466 100644 --- a/lib/src/name.c +++ b/lib/src/name.c @@ -241,6 +241,12 @@ hicn_name_snprintf (char *s, size_t size, const hicn_name_t *name) return rc + n; } +int +hicn_name_no_suffix_snprintf (char *s, size_t size, const hicn_name_t *name) +{ + return hicn_ip_address_snprintf (s, size, &name->prefix); +} + int hicn_prefix_create_from_ip_prefix (const hicn_ip_prefix_t *hicn_ip_prefix, hicn_prefix_t *prefix) diff --git a/libtransport/includes/hicn/transport/core/interest.h b/libtransport/includes/hicn/transport/core/interest.h index 59da5b91f..270ea7027 100644 --- a/libtransport/includes/hicn/transport/core/interest.h +++ b/libtransport/includes/hicn/transport/core/interest.h @@ -104,6 +104,8 @@ class Interest hicn_uword *getRequestBitmap(); + interest_manifest_header_t *getIntManifestHeader(); + void setRequestBitmap(const uint32_t *request_bitmap); bool isValid(); diff --git a/libtransport/includes/hicn/transport/core/name.h b/libtransport/includes/hicn/transport/core/name.h index 90b665c15..14ea10898 100644 --- a/libtransport/includes/hicn/transport/core/name.h +++ b/libtransport/includes/hicn/transport/core/name.h @@ -98,6 +98,8 @@ class Name { hicn_ip_prefix_t toIpAddress() const; + std::string getPrefix() const; + void copyPrefixToDestination(uint8_t *destination) const; int getAddressFamily() const; diff --git a/libtransport/includes/hicn/transport/utils/CMakeLists.txt b/libtransport/includes/hicn/transport/utils/CMakeLists.txt index 1dba94451..060b83b63 100644 --- a/libtransport/includes/hicn/transport/utils/CMakeLists.txt +++ b/libtransport/includes/hicn/transport/utils/CMakeLists.txt @@ -34,6 +34,7 @@ list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/shared_ptr_utils.h ${CMAKE_CURRENT_SOURCE_DIR}/noncopyable.h ${CMAKE_CURRENT_SOURCE_DIR}/singleton.h + ${CMAKE_CURRENT_SOURCE_DIR}/traffic_generator.h ) if(NOT WIN32) diff --git a/libtransport/includes/hicn/transport/utils/traffic_generator.h b/libtransport/includes/hicn/transport/utils/traffic_generator.h new file mode 100644 index 000000000..abd84886d --- /dev/null +++ b/libtransport/includes/hicn/transport/utils/traffic_generator.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace transport { + +class TrafficGenerator { + public: + TrafficGenerator(uint32_t count); + virtual ~TrafficGenerator() = default; + bool hasFinished(); + uint32_t getSentCount(); + virtual std::pair getPrefixAndSuffix(); + + virtual std::string getPrefix() = 0; + virtual uint32_t getSuffix() = 0; + virtual void reset(); + + protected: + void onSuffixGenerated(); + + uint32_t count_; + uint32_t sent_; +}; + +/* Fixed prefix, incremental suffix */ +class IncrSuffixTrafficGenerator : public TrafficGenerator { + public: + explicit IncrSuffixTrafficGenerator(std::string prefix, uint32_t suffix, + uint32_t count); + std::string getPrefix() override; + uint32_t getSuffix() override; + void reset() override; + + private: + std::string prefix_; + uint32_t suffix_; + uint32_t initial_suffix_; +}; + +/* Random prefix, random suffix */ +class RandomTrafficGenerator : public TrafficGenerator { + public: + static constexpr char NET_PREFIX[] = "2001:db8:1::/64"; + + RandomTrafficGenerator(uint32_t count, std::string net_prefix = NET_PREFIX); + std::string getPrefix() override; + uint32_t getSuffix() override; + + private: + std::string net_prefix_; + std::default_random_engine rand_engine_; + std::uniform_int_distribution uniform_distribution_; +}; + +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/core/interest.cc b/libtransport/src/core/interest.cc index 6348a8d3e..c3eb7c379 100644 --- a/libtransport/src/core/interest.cc +++ b/libtransport/src/core/interest.cc @@ -170,9 +170,6 @@ void Interest::encodeSuffixes() { (interest_manifest_header_t *)(writableData() + headerSize()); interest_manifest_init(int_manifest_header, name_.getSuffix()); - memset(int_manifest_header->request_bitmap, 0xFFFFFFFF, - BITMAP_SIZE * sizeof(hicn_uword)); - for (auto it = suffix_set_.begin(); it != suffix_set_.end(); it++) { interest_manifest_add_suffix(int_manifest_header, *it); } @@ -237,6 +234,13 @@ hicn_uword *Interest::getRequestBitmap() { return header->request_bitmap; } +interest_manifest_header_t *Interest::getIntManifestHeader() { + if (!hasManifest()) return nullptr; + + auto header = (interest_manifest_header_t *)(writableData() + headerSize()); + return header; +}; + void Interest::setRequestBitmap(const uint32_t *request_bitmap) { if (!hasManifest()) return; diff --git a/libtransport/src/core/name.cc b/libtransport/src/core/name.cc index 02cc79be6..4f8ba7873 100644 --- a/libtransport/src/core/name.cc +++ b/libtransport/src/core/name.cc @@ -168,6 +168,13 @@ hicn_ip_prefix_t Name::toIpAddress() const { return ret; } +std::string Name::getPrefix() const { + char prefix[MAXSZ_HICN_NAME]; + hicn_name_no_suffix_snprintf(prefix, MAXSZ_HICN_NAME, &name_); + + return std::string(prefix); +} + int Name::getAddressFamily() const { int ret = 0; diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt index 356ee0067..864006e5d 100644 --- a/libtransport/src/test/CMakeLists.txt +++ b/libtransport/src/test/CMakeLists.txt @@ -33,6 +33,7 @@ list(APPEND TESTS_SRC test_thread_pool.cc test_quadloop.cc test_prefix.cc + test_traffic_generator.cc ) if (ENABLE_RELY) diff --git a/libtransport/src/test/test_traffic_generator.cc b/libtransport/src/test/test_traffic_generator.cc new file mode 100644 index 000000000..88cb2de75 --- /dev/null +++ b/libtransport/src/test/test_traffic_generator.cc @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +static constexpr int NUM_PINGS = 10; +static constexpr char PREFIX[] = "b001:1:2:3::"; +static constexpr uint32_t FIRST_SUFFIX = 5; + +namespace utils { + +using transport::IncrSuffixTrafficGenerator; +using transport::RandomTrafficGenerator; + +class TrafficGeneratorTest : public ::testing::Test { + protected: + TrafficGeneratorTest() {} + virtual ~TrafficGeneratorTest() {} +}; + +TEST_F(TrafficGeneratorTest, IncrSuffixGetPrefixAndSuffix) { + auto traffic_generator_ = std::make_unique( + PREFIX, FIRST_SUFFIX, NUM_PINGS); + + std::string prefix = traffic_generator_->getPrefix(); + EXPECT_EQ(prefix, PREFIX); + uint32_t suffix = traffic_generator_->getSuffix(); + EXPECT_EQ(suffix, FIRST_SUFFIX); +} + +TEST_F(TrafficGeneratorTest, IncrSuffixGetMultipleSuffixes) { + auto traffic_generator_ = std::make_unique( + PREFIX, FIRST_SUFFIX, NUM_PINGS); + + std::string prefix = traffic_generator_->getPrefix(); + EXPECT_EQ(prefix, PREFIX); + EXPECT_EQ(prefix, traffic_generator_->getPrefix()); + + for (int i = 0; i < NUM_PINGS; i++) + EXPECT_EQ(traffic_generator_->getSuffix(), FIRST_SUFFIX + i); +} + +TEST_F(TrafficGeneratorTest, IncrSuffixReset) { + auto traffic_generator_ = std::make_unique( + PREFIX, FIRST_SUFFIX, NUM_PINGS); + + for (int i = 0; i < NUM_PINGS; i++) traffic_generator_->getSuffix(); + + traffic_generator_->reset(); + EXPECT_EQ(traffic_generator_->getPrefix(), PREFIX); + EXPECT_EQ(traffic_generator_->getSuffix(), FIRST_SUFFIX); + EXPECT_EQ(traffic_generator_->getSuffix(), FIRST_SUFFIX + 1); +} + +TEST_F(TrafficGeneratorTest, IncrSuffixRequestTooManySuffixes) { + auto traffic_generator_ = std::make_unique( + PREFIX, FIRST_SUFFIX, NUM_PINGS); + + for (int i = 0; i < NUM_PINGS; i++) traffic_generator_->getSuffix(); + EXPECT_THROW(traffic_generator_->getSuffix(), std::runtime_error); +} + +TEST_F(TrafficGeneratorTest, IncrSuffixGetPrefixAndSuffixTogether) { + auto traffic_generator_ = std::make_unique( + PREFIX, FIRST_SUFFIX, NUM_PINGS); + + auto [prefix, suffix] = traffic_generator_->getPrefixAndSuffix(); + EXPECT_EQ(prefix, PREFIX); + EXPECT_EQ(suffix, FIRST_SUFFIX); +} + +TEST_F(TrafficGeneratorTest, IncrSuffixCheckSentCount) { + auto traffic_generator_ = std::make_unique( + PREFIX, FIRST_SUFFIX, NUM_PINGS); + + for (int i = 0; i < NUM_PINGS; i++) { + EXPECT_EQ(traffic_generator_->getSentCount(), i); + EXPECT_FALSE(traffic_generator_->hasFinished()); + traffic_generator_->getSuffix(); + } + EXPECT_TRUE(traffic_generator_->hasFinished()); +} + +TEST_F(TrafficGeneratorTest, RandomGetPrefixAndSuffix) { + auto traffic_generator_ = std::make_unique(NUM_PINGS); + + std::string prefix1 = traffic_generator_->getPrefix(); + std::string prefix2 = traffic_generator_->getPrefix(); + EXPECT_NE(prefix1, prefix2); + + uint32_t suffix1 = traffic_generator_->getSuffix(); + uint32_t suffix2 = traffic_generator_->getSuffix(); + EXPECT_NE(suffix1, suffix2); +} + +TEST_F(TrafficGeneratorTest, RandomGetPrefixAndSuffixWithNetPrefix) { + auto traffic_generator_ = std::make_unique( + NUM_PINGS, std::string(PREFIX) + "/64"); + + for (int i = 0; i < NUM_PINGS; i++) + EXPECT_THAT(traffic_generator_->getPrefix(), + testing::StartsWith(std::string(PREFIX))); +} + +} // namespace utils \ No newline at end of file diff --git a/libtransport/src/utils/CMakeLists.txt b/libtransport/src/utils/CMakeLists.txt index 5bb76303a..e7c1c03ea 100644 --- a/libtransport/src/utils/CMakeLists.txt +++ b/libtransport/src/utils/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/log.cc ${CMAKE_CURRENT_SOURCE_DIR}/membuf.cc ${CMAKE_CURRENT_SOURCE_DIR}/content_store.cc + ${CMAKE_CURRENT_SOURCE_DIR}/traffic_generator.cc ) diff --git a/libtransport/src/utils/traffic_generator.cc b/libtransport/src/utils/traffic_generator.cc new file mode 100644 index 000000000..a617e3dc9 --- /dev/null +++ b/libtransport/src/utils/traffic_generator.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +namespace transport { + +/* TrafficGenerator */ + +TrafficGenerator::TrafficGenerator(uint32_t count) : count_(count), sent_(0) {} + +bool TrafficGenerator::hasFinished() { return sent_ >= count_; } + +uint32_t TrafficGenerator::getSentCount() { return sent_; } + +std::pair TrafficGenerator::getPrefixAndSuffix() { + return std::make_pair(getPrefix(), getSuffix()); +} + +void TrafficGenerator::reset() { sent_ = 0; }; + +void TrafficGenerator::onSuffixGenerated() { + if (hasFinished()) throw std::runtime_error("Too many pings"); + sent_++; +}; + +/* IncrSuffixTrafficGenerator */ + +IncrSuffixTrafficGenerator::IncrSuffixTrafficGenerator(std::string prefix, + uint32_t suffix, + uint32_t count) + : TrafficGenerator(count), + prefix_(prefix), + suffix_(suffix), + initial_suffix_(suffix) {} + +std::string IncrSuffixTrafficGenerator::getPrefix() { return prefix_; } + +uint32_t IncrSuffixTrafficGenerator::getSuffix() { + TrafficGenerator::onSuffixGenerated(); + return suffix_++; +} + +void IncrSuffixTrafficGenerator::reset() { + TrafficGenerator::reset(); + suffix_ = initial_suffix_; +}; + +/* RandomTrafficGenerator */ + +RandomTrafficGenerator::RandomTrafficGenerator(uint32_t count, + std::string net_prefix) + : TrafficGenerator(count), + net_prefix_(net_prefix), + rand_engine_((std::random_device())()), + uniform_distribution_(0, std::numeric_limits::max()) {} + +std::string RandomTrafficGenerator::getPrefix() { + // Generate random prefix + core::Prefix prefix(net_prefix_); + core::Name name = prefix.makeRandomName(); + return name.getPrefix(); +} + +uint32_t RandomTrafficGenerator::getSuffix() { + TrafficGenerator::onSuffixGenerated(); + + // Generate random suffix + return uniform_distribution_(rand_engine_); +} + +} // namespace transport \ No newline at end of file diff --git a/tests/1-node.yml b/tests/1-node.yml index eb8c19f34..859d1b838 100644 --- a/tests/1-node.yml +++ b/tests/1-node.yml @@ -16,7 +16,6 @@ services: command: - | if [ -d /workspace/build-dev ]; then - git config --global --add safe.directory \* sudo ninja -C /workspace/build-dev install fi diff --git a/tests/Makefile b/tests/Makefile index f9c166b8d..a31a6f1a6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -# Use when building for the fist time, +# Use when building for the first time, # then `make test` forces a rebuild if local changes build: DOCKERFILE=Dockerfile.dev BUILD_SOFTWARE=1 \ @@ -28,8 +28,15 @@ shell: down: docker-compose -f 1-node.yml down -functional: +functional-ctrl: sleep 1 # Wait for the forwarder to be ready bash config.sh ctrl listeners bash config.sh ctrl connections - bash config.sh ctrl routes \ No newline at end of file + bash config.sh ctrl routes + +functional-ping-manifest: + bash config.sh ping manifest +functional-ping-signature: + bash config.sh ping signature +functional-ping-timeout: + bash config.sh ping timeout \ No newline at end of file diff --git a/tests/config.sh b/tests/config.sh index a6bc6ad2d..16000bff6 100755 --- a/tests/config.sh +++ b/tests/config.sh @@ -465,6 +465,97 @@ function ctrl() { ${ctrl_tests[${type}]} } +################################################################ +# Test ping +################################################################ +function test_ping_manifest() { + docker exec forwarder bash -c 'hicn-ping-server -a intmanifest >/tmp/ping_server.log 2>&1 &' + sleep 1 + + # 2 interests w/ 3 suffixes each (1 in header + 2 in manifest) + docker exec forwarder bash -c 'hicn-ping-client -m 6 -a 2 intmanifest | grep "Sent" >>/tmp/ping_client.log' + sleep 1 + + # 2 interests w/ 3 suffixes each + 1 single interest + docker exec forwarder bash -c 'hicn-ping-client -m 7 -a 2 intmanifest | grep "Sent" >>/tmp/ping_client.log' + sleep 1 + + # 2 interests w/ 3 suffixes each + 1 interest w/ 2 suffixes + docker exec forwarder bash -c 'hicn-ping-client -m 8 -a 2 intmanifest | grep "Sent" >>/tmp/ping_client.log' + sleep 1 + + # 2 interests w/ 3 suffixes each + 1 single interest, + # using random prefix/suffix generation + docker exec forwarder bash -c 'hicn-ping-client -m 7 -a 2 intmanifest -b RANDOM | grep "Sent" >>/tmp/ping_client.log' + + # No 'failed' expected + ping_server_logs=$(docker exec forwarder cat /tmp/ping_server.log) + if [[ $(echo $ping_server_logs | grep failed | wc -l) -ne 0 ]]; then + echo "******** Server logs (ping) ********" + echo "$ping_server_logs" + exit 1 + fi + + # No 'Timeouts: 0' expected + ping_client_logs=$(docker exec forwarder cat /tmp/ping_client.log) + if [[ $(echo $ping_client_logs | grep -v "Timeouts: 0" | wc -l) -ne 0 ]]; then + echo "******** Client logs (ping) ********" + echo "$ping_client_logs" + exit 1 + fi +} + +function test_ping_wrong_signature() { + docker exec forwarder bash -c 'hicn-ping-server -a intmanifest >/tmp/ping_server.log 2>&1 &' + sleep 1 + + # Signature mismatch ('intmamifest' on server vs 'wrong_sign' on client) + docker exec forwarder bash -c 'hicn-ping-client -m 6 -a 2 wrong_sig | grep "Sent" >>/tmp/ping_client.log' + + # 'failed' expected + ping_server_logs=$(docker exec forwarder cat /tmp/ping_server.log) + if [[ $(echo $ping_server_logs | grep "failed" | wc -l) -eq 0 ]]; then + echo "******** Server logs (signature fail) ********" + echo "$ping_server_logs" + exit 1 + fi +} + +function test_ping_no_server() { + # Server not started to check for ping client timeout + docker exec forwarder bash -c 'hicn-ping-client -m 6 | grep "Sent" >>/tmp/ping_client.log' + + # 'Timeouts: 6' expected + ping_client_logs=$(docker exec forwarder cat /tmp/ping_client.log) + if [[ $(echo $ping_client_logs | grep "Timeouts: 6" | wc -l) -eq 0 ]]; then + echo "******** Client logs (timeout) ********" + echo "$ping_client_logs" + exit 1 + fi +} + +declare -A ping_tests=( + ["manifest"]="test_ping_manifest" + ["signature"]="test_ping_wrong_signature" + ["timeout"]="test_ping_no_server" +) + +function ping_test_exists() { + [[ "${!ping_tests[*]}" =~ ${1} ]] && return 0 || return 1 +} + +function ping() { + type=$1 + if ! ping_test_exists "${type}"; then + error "Error: hicn-ping test does not exist." + exit 1 + fi + + ${ping_tests[${type}]} +} + +#--------------------------------------------------------------# + while (("${#}")); do case "$1" in 'build') @@ -510,6 +601,10 @@ while (("${#}")); do ctrl "${2}" break ;; + 'ping') + ping "${2}" + break + ;; *) exit 1 ;; diff --git a/tests/functional-tests/hicn-light-ping.robot b/tests/functional-tests/hicn-light-ping.robot new file mode 100644 index 000000000..238f49e0e --- /dev/null +++ b/tests/functional-tests/hicn-light-ping.robot @@ -0,0 +1,26 @@ +*** Settings *** +Resource resources/libraries/robot/common.robot +Test Setup Run Keywords +... Build Topology 1-node AND +... Check Environment +Test Teardown Run Keywords +... Destroy Topology + +*** Test Cases *** +Ping with manifest + Log to console Test ping with manifest + ${result} = Run Process ${EXECDIR}/config.sh ping manifest + Log Many stdout: ${result.stdout} + Should Be Equal As Integers ${result.rc} 0 + +Ping wrong signature + Log to console Test ping with wrong signature + ${result} = Run Process ${EXECDIR}/config.sh ping signature + Log Many stdout: ${result.stdout} + Should Be Equal As Integers ${result.rc} 0 + +Ping timeout + Log to console Test ping timeout + ${result} = Run Process ${EXECDIR}/config.sh ping timeout + Log Many stdout: ${result.stdout} + Should Be Equal As Integers ${result.rc} 0 -- cgit 1.2.3-korg