From 6b94663b2455e212009a544ae23bb6a8c55407f8 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Thu, 9 Jun 2022 21:34:09 +0200 Subject: refactor(lib, hicn-light, vpp, hiperf): HICN-723 - move infra data structure into the shared lib - new packet cache using double hashing and lookup on prefix suffix - testing updates - authenticated requests using interest manifests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mauro Sardara Co-authored-by: Jordan Augé Co-authored-by: Michele Papalini Co-authored-by: Olivier Roques Co-authored-by: Enrico Loparco Change-Id: Iaddebfe6aa5279ea8553433b0f519578f6b9ccd9 Signed-off-by: Luca Muscariello --- libtransport/src/test/CMakeLists.txt | 2 + libtransport/src/test/test_core_manifest.cc | 227 ++++++++++------- libtransport/src/test/test_interest.cc | 39 +++ libtransport/src/test/test_memif_connector.cc | 4 +- libtransport/src/test/test_packet_allocator.cc | 25 ++ libtransport/src/test/test_prefix.cc | 334 +++++++++++++++++++++++++ libtransport/src/test/test_quadloop.cc | 176 +++++++++++++ 7 files changed, 709 insertions(+), 98 deletions(-) create mode 100644 libtransport/src/test/test_prefix.cc create mode 100644 libtransport/src/test/test_quadloop.cc (limited to 'libtransport/src/test') diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt index e7018ceed..b7f14766e 100644 --- a/libtransport/src/test/CMakeLists.txt +++ b/libtransport/src/test/CMakeLists.txt @@ -31,6 +31,8 @@ list(APPEND TESTS_SRC test_quality_score.cc test_sessions.cc test_thread_pool.cc + test_quadloop.cc + test_prefix.cc ) if (ENABLE_RELY) diff --git a/libtransport/src/test/test_core_manifest.cc b/libtransport/src/test/test_core_manifest.cc index b998ce96b..e3d66c1cd 100644 --- a/libtransport/src/test/test_core_manifest.cc +++ b/libtransport/src/test/test_core_manifest.cc @@ -13,8 +13,8 @@ * limitations under the License. */ +#include #include -#include #include #include #include @@ -33,10 +33,12 @@ namespace { // The fixture for testing class Foo. class ManifestTest : public ::testing::Test { protected: - using ContentObjectManifest = ManifestInline; + using ContentObjectManifest = Manifest; - ManifestTest() : name_("b001::123|321"), manifest1_(HF_INET6_TCP_AH, name_) { - // You can do set-up work for each test here. + ManifestTest() + : format_(HF_INET6_TCP_AH), name_("b001::123|321"), signature_size_(0) { + manifest_ = ContentObjectManifest::createContentManifest(format_, name_, + signature_size_); } virtual ~ManifestTest() { @@ -56,10 +58,11 @@ class ManifestTest : public ::testing::Test { // before the destructor). } + Packet::Format format_; Name name_; - ContentObjectManifest manifest1_; - - std::vector manifest_payload = { + std::size_t signature_size_; + std::shared_ptr manifest_; + std::vector manifest_payload_ = { 0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad // , 0x00, 0x00, // 0x00, 0x45, 0xa3, @@ -75,169 +78,200 @@ class ManifestTest : public ::testing::Test { } // namespace -TEST_F(ManifestTest, MoveConstructor) { +TEST_F(ManifestTest, ManifestConstructor) { // Create content object with manifest in payload - ContentObject co(HF_INET6_TCP_AH, 128); - co.appendPayload(&manifest_payload[0], manifest_payload.size()); - uint8_t buffer[256]; - co.appendPayload(buffer, 256); + ContentObject::Ptr co = + core::PacketManager<>::getInstance().getPacket( + format_, signature_size_); + co->setName(name_); + co->appendPayload(manifest_payload_.data(), manifest_payload_.size()); + + uint8_t buffer[256] = {0}; + co->appendPayload(buffer, 256); // Copy packet payload uint8_t packet[1500]; - auto length = co.getPayload()->length(); - std::memcpy(packet, co.getPayload()->data(), length); + auto length = co->getPayload()->length(); + std::memcpy(packet, co->getPayload()->data(), length); // Create manifest - ContentObjectManifest m(std::move(co)); + ContentObjectManifest manifest(co); // Check manifest payload is exactly the same of content object - ASSERT_EQ(length, m.getPayload()->length()); - auto ret = std::memcmp(packet, m.getPayload()->data(), length); + ASSERT_EQ(length, manifest.getPacket()->getPayload()->length()); + auto ret = + std::memcmp(packet, manifest.getPacket()->getPayload()->data(), length); ASSERT_EQ(ret, 0); } -TEST_F(ManifestTest, SetLastManifest) { - manifest1_.clear(); - - manifest1_.setIsLast(true); - bool fcn = manifest1_.getIsLast(); - - ASSERT_TRUE(fcn == true); -} - TEST_F(ManifestTest, SetManifestType) { - manifest1_.clear(); + manifest_->Encoder::clear(); ManifestType type1 = ManifestType::INLINE_MANIFEST; ManifestType type2 = ManifestType::FLIC_MANIFEST; - manifest1_.setType(type1); - ManifestType type_returned1 = manifest1_.getType(); + manifest_->setType(type1); + ManifestType type_returned1 = manifest_->getType(); - manifest1_.clear(); + manifest_->Encoder::clear(); - manifest1_.setType(type2); - ManifestType type_returned2 = manifest1_.getType(); + manifest_->setType(type2); + ManifestType type_returned2 = manifest_->getType(); ASSERT_EQ(type1, type_returned1); ASSERT_EQ(type2, type_returned2); } +TEST_F(ManifestTest, SetMaxCapacity) { + manifest_->Encoder::clear(); + + uint8_t max_capacity1 = 0; + uint8_t max_capacity2 = 20; + + manifest_->setMaxCapacity(max_capacity1); + uint8_t max_capacity_returned1 = manifest_->getMaxCapacity(); + + manifest_->Encoder::clear(); + + manifest_->setMaxCapacity(max_capacity2); + uint8_t max_capacity_returned2 = manifest_->getMaxCapacity(); + + ASSERT_EQ(max_capacity1, max_capacity_returned1); + ASSERT_EQ(max_capacity2, max_capacity_returned2); +} + TEST_F(ManifestTest, SetHashAlgorithm) { - manifest1_.clear(); + manifest_->Encoder::clear(); - auth::CryptoHashType hash1 = auth::CryptoHashType::SHA512; - auth::CryptoHashType hash2 = auth::CryptoHashType::BLAKE2B512; - auth::CryptoHashType hash3 = auth::CryptoHashType::SHA256; + auth::CryptoHashType hash1 = auth::CryptoHashType::SHA256; + auth::CryptoHashType hash2 = auth::CryptoHashType::SHA512; + auth::CryptoHashType hash3 = auth::CryptoHashType::BLAKE2B512; - manifest1_.setHashAlgorithm(hash1); - auto type_returned1 = manifest1_.getHashAlgorithm(); + manifest_->setHashAlgorithm(hash1); + auto type_returned1 = manifest_->getHashAlgorithm(); - manifest1_.clear(); + manifest_->Encoder::clear(); - manifest1_.setHashAlgorithm(hash2); - auto type_returned2 = manifest1_.getHashAlgorithm(); + manifest_->setHashAlgorithm(hash2); + auto type_returned2 = manifest_->getHashAlgorithm(); - manifest1_.clear(); + manifest_->Encoder::clear(); - manifest1_.setHashAlgorithm(hash3); - auto type_returned3 = manifest1_.getHashAlgorithm(); + manifest_->setHashAlgorithm(hash3); + auto type_returned3 = manifest_->getHashAlgorithm(); ASSERT_EQ(hash1, type_returned1); ASSERT_EQ(hash2, type_returned2); ASSERT_EQ(hash3, type_returned3); } +TEST_F(ManifestTest, SetLastManifest) { + manifest_->Encoder::clear(); + + manifest_->setIsLast(true); + bool is_last = manifest_->getIsLast(); + + ASSERT_TRUE(is_last); +} + +TEST_F(ManifestTest, SetBaseName) { + manifest_->Encoder::clear(); + + core::Name base_name("b001::dead"); + + manifest_->setBaseName(base_name); + core::Name ret_name = manifest_->getBaseName(); + + ASSERT_EQ(base_name, ret_name); +} + TEST_F(ManifestTest, setParamsBytestream) { - manifest1_.clear(); + manifest_->Encoder::clear(); ParamsBytestream params{ - .final_segment = 1, + .final_segment = 0x0a, }; - manifest1_.setParamsBytestream(params); - manifest1_.encode(); + manifest_->setParamsBytestream(params); + auth::CryptoHash hash(auth::CryptoHashType::SHA256); + hash.computeDigest({0x01, 0x02, 0x03, 0x04}); + manifest_->addEntry(1, hash); + + manifest_->encode(); + manifest_->decode(); - ContentObjectManifest manifest(manifest1_); - manifest.decode(); + auto transport_type_returned = manifest_->getTransportType(); + auto params_returned = manifest_->getParamsBytestream(); ASSERT_EQ(interface::ProductionProtocolAlgorithms::BYTE_STREAM, - manifest.getTransportType()); - ASSERT_EQ(params, manifest.getParamsBytestream()); + transport_type_returned); + ASSERT_EQ(params, params_returned); } TEST_F(ManifestTest, SetParamsRTC) { - manifest1_.clear(); + manifest_->Encoder::clear(); ParamsRTC params{ - .timestamp = 1, - .prod_rate = 2, - .prod_seg = 3, + .timestamp = 0x0a, + .prod_rate = 0x0b, + .prod_seg = 0x0c, .fec_type = protocol::fec::FECType::UNKNOWN, }; - manifest1_.setParamsRTC(params); - manifest1_.encode(); + manifest_->setParamsRTC(params); + auth::CryptoHash hash(auth::CryptoHashType::SHA256); + hash.computeDigest({0x01, 0x02, 0x03, 0x04}); + manifest_->addEntry(1, hash); - ContentObjectManifest manifest(manifest1_); - manifest.decode(); + manifest_->encode(); + manifest_->decode(); + + auto transport_type_returned = manifest_->getTransportType(); + auto params_returned = manifest_->getParamsRTC(); ASSERT_EQ(interface::ProductionProtocolAlgorithms::RTC_PROD, - manifest.getTransportType()); - ASSERT_EQ(params, manifest.getParamsRTC()); + transport_type_returned); + ASSERT_EQ(params, params_returned); } TEST_F(ManifestTest, SignManifest) { - Name name("b001::", 0); auto signer = std::make_shared( auth::CryptoSuite::HMAC_SHA256, "hunter2"); auto verifier = std::make_shared("hunter2"); - std::shared_ptr manifest; - // Instantiate Manifest - manifest.reset(ContentObjectManifest::createManifest( - HF_INET6_TCP_AH, name, ManifestVersion::VERSION_1, - ManifestType::INLINE_MANIFEST, false, name, signer->getHashType(), - signer->getSignatureFieldSize())); + // Instantiate manifest + uint8_t max_capacity = 30; + std::shared_ptr manifest = + ContentObjectManifest::createContentManifest( + format_, name_, signer->getSignatureFieldSize()); + manifest->setHeaders(ManifestType::INLINE_MANIFEST, max_capacity, + signer->getHashType(), false /* is_last */, name_); - // Add Manifest entry + // Add manifest entry auth::CryptoHash hash(signer->getHashType()); - hash.computeDigest(std::vector{0x01, 0x02, 0x03, 0x04}); - manifest->addSuffixHash(1, hash); + hash.computeDigest({0x01, 0x02, 0x03, 0x04}); + manifest->addEntry(1, hash); // Encode manifest manifest->encode(); + auto manifest_co = + std::dynamic_pointer_cast(manifest->getPacket()); // Sign manifest - signer->signPacket(manifest.get()); + signer->signPacket(manifest_co.get()); // Check size - ASSERT_EQ(manifest->payloadSize(), manifest->estimateManifestSize()); - ASSERT_EQ(manifest->length(), - manifest->headerSize() + manifest->payloadSize()); - ASSERT_EQ(ContentObjectManifest::manifestHeaderSize( - interface::ProductionProtocolAlgorithms::UNKNOWN), - manifest->manifestHeaderSize()); + ASSERT_EQ(manifest_co->payloadSize(), manifest->Encoder::manifestSize()); + ASSERT_EQ(manifest_co->length(), + manifest_co->headerSize() + manifest_co->payloadSize()); // Verify manifest - auth::VerificationPolicy policy = verifier->verifyPackets(manifest.get()); + auth::VerificationPolicy policy = verifier->verifyPackets(manifest_co.get()); ASSERT_EQ(auth::VerificationPolicy::ACCEPT, policy); } -TEST_F(ManifestTest, SetBaseName) { - manifest1_.clear(); - - core::Name base_name("b001::dead"); - manifest1_.setBaseName(base_name); - core::Name ret_name = manifest1_.getBaseName(); - - ASSERT_EQ(base_name, ret_name); -} - TEST_F(ManifestTest, SetSuffixList) { - manifest1_.clear(); - - core::Name base_name("b001::dead"); + manifest_->Encoder::clear(); using random_bytes_engine = std::independent_bits_engineaddEntry(entries[i].first, entries[i].second); } - manifest1_.setBaseName(base_name); - core::Name ret_name = manifest1_.getBaseName(); + core::Name base_name("b001::dead"); + manifest_->setBaseName(base_name); + core::Name ret_name = manifest_->getBaseName(); ASSERT_EQ(base_name, ret_name); delete[] entries; diff --git a/libtransport/src/test/test_interest.cc b/libtransport/src/test/test_interest.cc index d9c535881..e36ca0f93 100644 --- a/libtransport/src/test/test_interest.cc +++ b/libtransport/src/test/test_interest.cc @@ -258,5 +258,44 @@ TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) { } } +TEST_F(InterestTest, AppendSuffixesWithGaps) { + // Create interest from buffer + Interest interest(HF_INET6_TCP); + + // Appenad some suffixes, out of order and with gaps + interest.appendSuffix(6); + interest.appendSuffix(2); + interest.appendSuffix(5); + interest.appendSuffix(1); + + // Encode them in wire format + interest.encodeSuffixes(); + EXPECT_TRUE(interest.hasManifest()); + + // Check first suffix correctness + auto suffix = interest.firstSuffix(); + EXPECT_NE(suffix, nullptr); + EXPECT_EQ(*suffix, 1U); + + // Iterate over them. They should be in order and without repetitions + std::vector expected = {1, 2, 5, 6}; + EXPECT_EQ(interest.numberOfSuffixes(), expected.size()); + + for (uint32_t seq : expected) { + EXPECT_EQ(*suffix, seq); + suffix++; + } +} + +TEST_F(InterestTest, InterestWithoutManifest) { + // Create interest without manifest + Interest interest(HF_INET6_TCP); + auto suffix = interest.firstSuffix(); + + EXPECT_FALSE(interest.hasManifest()); + EXPECT_EQ(interest.numberOfSuffixes(), 0U); + EXPECT_EQ(suffix, nullptr); +} + } // namespace core } // namespace transport diff --git a/libtransport/src/test/test_memif_connector.cc b/libtransport/src/test/test_memif_connector.cc index 562a12c88..40f4df927 100644 --- a/libtransport/src/test/test_memif_connector.cc +++ b/libtransport/src/test/test_memif_connector.cc @@ -83,8 +83,8 @@ class Memif { recv_counter_ += buffers.size(); if (recv_counter_ == total_packets) { auto t1 = utils::SteadyTime::now(); - auto delta = utils::SteadyTime::getDurationS(t0_, t1); - auto rate = recv_counter_ / delta.count(); + auto delta = utils::SteadyTime::getDurationUs(t0_, t1); + double rate = double(recv_counter_) * 1.0e6 / double(delta.count()); LOG(INFO) << "rate: " << rate << " packets/s"; io_service_.stop(); } diff --git a/libtransport/src/test/test_packet_allocator.cc b/libtransport/src/test/test_packet_allocator.cc index b63ddde8d..744f1bd24 100644 --- a/libtransport/src/test/test_packet_allocator.cc +++ b/libtransport/src/test/test_packet_allocator.cc @@ -21,6 +21,7 @@ #define ALLOCATION_CHECKS #include #undef ALLOCATION_CHECKS +#include #include namespace transport { @@ -30,6 +31,8 @@ class PacketAllocatorTest : public ::testing::Test { protected: static inline const std::size_t default_size = 2048; static inline const std::size_t default_n_buffer = 1024; + static inline const std::size_t counter = 1024; + static inline const std::size_t total_packets = 1024 * counter; // Get fixed block allocator_ of 1024 buffers of size 2048 bytes PacketAllocatorTest() : allocator_(PacketManager<>::getInstance()) { @@ -102,5 +105,27 @@ TEST_F(PacketAllocatorTest, CheckAllocationIsCorrect) { PacketManager<>::PacketStorage::packet_and_shared_ptr))); } +TEST_F(PacketAllocatorTest, CheckAllocationSpeed) { + // Check time needed to allocate 1 million packeauto &packet_manager = + auto &packet_manager = core::PacketManager<>::getInstance(); + + // Send 1 million packets + std::array packets; + auto t0 = utils::SteadyTime::now(); + std::size_t sum = 0; + for (std::size_t j = 0; j < counter; j++) { + for (std::size_t i = 0; i < counter; i++) { + packets[i] = packet_manager.getMemBuf(); + sum++; + } + } + auto t1 = utils::SteadyTime::now(); + + auto delta = utils::SteadyTime::getDurationUs(t0, t1); + auto rate = double(sum) * 1000000.0 / double(delta.count()); + + LOG(INFO) << "rate: " << rate << " packets/s"; +} + } // namespace core } // namespace transport \ No newline at end of file diff --git a/libtransport/src/test/test_prefix.cc b/libtransport/src/test/test_prefix.cc new file mode 100644 index 000000000..5de737566 --- /dev/null +++ b/libtransport/src/test/test_prefix.cc @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include + +#include +#include +#include + +namespace transport { +namespace core { + +namespace { +class PrefixTest : public ::testing::Test { + protected: + static inline const char prefix_str0[] = "2001:db8:1::/64"; + static inline const char prefix_str1[] = "10.11.12.0/24"; + static inline const char prefix_str2[] = "2001:db8:1::abcd/64"; + static inline const char prefix_str3[] = "10.11.12.245/27"; + static inline const char wrong_prefix_str0[] = "10.11.12.245/45"; + static inline const char wrong_prefix_str1[] = "10.400.12.13/8"; + static inline const char wrong_prefix_str2[] = "2001:db8:1::/640"; + static inline const char wrong_prefix_str3[] = "20011::db8:1::/16"; + static inline const char wrong_prefix_str4[] = "2001::db8:1::fffff/96"; + + PrefixTest() = default; + + ~PrefixTest() override = default; + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + void SetUp() override { + // Code here will be called immediately after the constructor (right + // before each test). + } + + void TearDown() override { + // Code here will be called immediately after each test (right + // before the destructor). + } +}; + +TEST_F(PrefixTest, ConstructorRightString) { + // Create empty prefix + Prefix p; + + // Create prefix from string + Prefix p0(prefix_str0); + // Reconstruct string and check it is equal to original address + std::string network = p0.getNetwork(); + std::uint16_t prefix_length = p0.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str0)); + + // Create prefix from string + Prefix p1(prefix_str1); + // Reconstruct string and check it is equal to original address + network = p1.getNetwork(); + prefix_length = p1.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str1)); + + // Create prefix from string + Prefix p2(prefix_str2); + // Reconstruct string and check it is equal to original address + network = p2.getNetwork(); + prefix_length = p2.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str2)); + + // Create prefix from string + Prefix p3(prefix_str3); + // Reconstruct string and check it is equal to original address + network = p3.getNetwork(); + prefix_length = p3.getPrefixLength(); + EXPECT_THAT(network + "/" + std::to_string(prefix_length), + ::testing::StrEq(prefix_str3)); + + // Create prefix from string and prefix length + Prefix p4("2001::1234", 66); + // Reconstruct string and check it is equal to original address + network = p4.getNetwork(); + prefix_length = p4.getPrefixLength(); + auto af = p4.getAddressFamily(); + EXPECT_THAT(network, ::testing::StrEq("2001::1234")); + EXPECT_THAT(prefix_length, ::testing::Eq(66)); + EXPECT_THAT(af, ::testing::Eq(AF_INET6)); +} + +TEST_F(PrefixTest, ConstructorWrongString) { + try { + Prefix p0(wrong_prefix_str0); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p1(wrong_prefix_str1); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p2(wrong_prefix_str2); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p3(wrong_prefix_str3); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } + + try { + Prefix p4(wrong_prefix_str4); + FAIL() << "Expected exception"; + } catch (const errors::InvalidIpAddressException &) { + // Expected exception + } +} + +TEST_F(PrefixTest, Comparison) { + Prefix p0(prefix_str0); + Prefix p1(prefix_str1); + + // Expect they are different + EXPECT_THAT(p0, ::testing::Ne(p1)); + + auto p2 = p1; + // Expect they are equal + EXPECT_THAT(p1, ::testing::Eq(p2)); +} + +TEST_F(PrefixTest, ToSockAddress) { + Prefix p0(prefix_str3); + + auto ret = p0.toSockaddr(); + auto sockaddr = reinterpret_cast(ret.get()); + + EXPECT_THAT(sockaddr->sin_family, ::testing::Eq(AF_INET)); + EXPECT_THAT(sockaddr->sin_addr.s_addr, portability::host_to_net(0x0a0b0cf5)); +} + +TEST_F(PrefixTest, GetPrefixLength) { + Prefix p0(prefix_str3); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(27)); +} + +TEST_F(PrefixTest, SetPrefixLength) { + Prefix p0(prefix_str3); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(27)); + p0.setPrefixLength(20); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(20)); + + try { + p0.setPrefixLength(33); + FAIL() << "Expected exception"; + } catch ([[maybe_unused]] const errors::InvalidIpAddressException &) { + // Expected exception + } +} + +TEST_F(PrefixTest, SetGetNetwork) { + Prefix p0(prefix_str0); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(64)); + p0.setNetwork("b001::1234"); + EXPECT_THAT(p0.getNetwork(), ::testing::StrEq("b001::1234")); + EXPECT_THAT(p0.getPrefixLength(), ::testing::Eq(64)); +} + +TEST_F(PrefixTest, Contains) { + // IPv6 prefix + Prefix p0(prefix_str0); + ip_address_t ip0, ip1; + + ip_address_pton("2001:db8:1::1234", &ip0); + ip_address_pton("2001:db9:1::1234", &ip1); + + EXPECT_TRUE(p0.contains(ip0)); + EXPECT_FALSE(p0.contains(ip1)); + + Prefix p1(prefix_str1); + ip_address_pton("10.11.12.12", &ip0); + ip_address_pton("10.12.12.13", &ip1); + + EXPECT_TRUE(p1.contains(ip0)); + EXPECT_FALSE(p1.contains(ip1)); + + Prefix p2(prefix_str2); + ip_address_pton("2001:db8:1::dbca", &ip0); + ip_address_pton("10.12.12.12", &ip1); + + EXPECT_TRUE(p2.contains(ip0)); + EXPECT_FALSE(p2.contains(ip1)); + + Prefix p3(prefix_str3); + ip_address_pton("10.11.12.245", &ip0); + ip_address_pton("10.11.12.1", &ip1); + + EXPECT_TRUE(p3.contains(ip0)); + EXPECT_FALSE(p3.contains(ip1)); + + // Corner cases + Prefix p4("::/0"); + ip_address_pton("7001:db8:1::1234", &ip0); + ip_address_pton("8001:db8:1::1234", &ip1); + + EXPECT_TRUE(p4.contains(ip0)); + EXPECT_TRUE(p4.contains(ip1)); + + // Corner cases + Prefix p5("b001:a:b:c:d:e:f:1/128"); + ip_address_pton("b001:a:b:c:d:e:f:1", &ip0); + ip_address_pton("b001:a:b:c:d:e:f:2", &ip1); + + EXPECT_TRUE(p5.contains(ip0)); + EXPECT_FALSE(p5.contains(ip1)); +} + +TEST_F(PrefixTest, GetAddressFamily) { + Prefix p0(prefix_str0); + auto af = p0.getAddressFamily(); + EXPECT_THAT(af, ::testing::Eq(AF_INET6)); + + Prefix p1(prefix_str1); + af = p1.getAddressFamily(); + EXPECT_THAT(af, ::testing::Eq(AF_INET)); +} + +TEST_F(PrefixTest, MakeName) { + Prefix p0(prefix_str0); + auto name0 = p0.makeName(); + EXPECT_THAT(name0.toString(), ::testing::StrEq("2001:db8:1::|0")); + + Prefix p1(prefix_str1); + auto name1 = p1.makeName(); + EXPECT_THAT(name1.toString(), ::testing::StrEq("10.11.12.0|0")); + + Prefix p2(prefix_str2); + auto name2 = p2.makeName(); + EXPECT_THAT(name2.toString(), ::testing::StrEq("2001:db8:1::|0")); + + Prefix p3(prefix_str3); + auto name3 = p3.makeName(); + EXPECT_THAT(name3.toString(), ::testing::StrEq("10.11.12.224|0")); + + Prefix p4("b001:a:b:c:d:e:f:1/128"); + auto name4 = p4.makeName(); + EXPECT_THAT(name4.toString(), ::testing::StrEq("b001:a:b:c:d:e:f:1|0")); +} + +TEST_F(PrefixTest, MakeRandomName) { + Prefix p0(prefix_str0); + auto name0 = p0.makeRandomName(); + auto name1 = p0.makeRandomName(); + auto name2 = p0.makeRandomName(); + auto name3 = p0.makeRandomName(); + + EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name1))); + EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name2))); + EXPECT_THAT(name0, ::testing::Not(::testing::Eq(name3))); + EXPECT_THAT(name1, ::testing::Not(::testing::Eq(name2))); + EXPECT_THAT(name1, ::testing::Not(::testing::Eq(name3))); + EXPECT_THAT(name2, ::testing::Not(::testing::Eq(name3))); + + // Corner case + Prefix p2("b001:a:b:c:d:e:f:1/128"); + name0 = p2.makeRandomName(); + name1 = p2.makeRandomName(); + name2 = p2.makeRandomName(); + name3 = p2.makeRandomName(); + + EXPECT_THAT(name0, ::testing::Eq(name1)); + EXPECT_THAT(name0, ::testing::Eq(name2)); + EXPECT_THAT(name0, ::testing::Eq(name3)); + EXPECT_THAT(name1, ::testing::Eq(name2)); + EXPECT_THAT(name1, ::testing::Eq(name3)); + EXPECT_THAT(name2, ::testing::Eq(name3)); +} + +TEST_F(PrefixTest, MakeNameWithIndex) { + Prefix p0(prefix_str0); + auto name0 = p0.makeNameWithIndex(0); + EXPECT_THAT(name0.toString(), ::testing::StrEq("2001:db8:1::|0")); + auto name1 = p0.makeNameWithIndex(1); + EXPECT_THAT(name1.toString(), ::testing::StrEq("2001:db8:1::1|0")); + auto name2 = p0.makeNameWithIndex(2); + EXPECT_THAT(name2.toString(), ::testing::StrEq("2001:db8:1::2|0")); + auto name3 = p0.makeNameWithIndex(3); + EXPECT_THAT(name3.toString(), ::testing::StrEq("2001:db8:1::3|0")); + + Prefix p1(prefix_str1); + name0 = p1.makeNameWithIndex(0); + EXPECT_THAT(name0.toString(), ::testing::StrEq("10.11.12.0|0")); + name1 = p1.makeNameWithIndex(1); + EXPECT_THAT(name1.toString(), ::testing::StrEq("10.11.12.1|0")); + name2 = p1.makeNameWithIndex(2); + EXPECT_THAT(name2.toString(), ::testing::StrEq("10.11.12.2|0")); + name3 = p1.makeNameWithIndex(3); + EXPECT_THAT(name3.toString(), ::testing::StrEq("10.11.12.3|0")); + + // Test truncation + Prefix p2("b001::/96"); + name0 = p2.makeNameWithIndex(0xffffffffffffffff); + EXPECT_THAT(name0.toString(), ::testing::StrEq("b001::ffff:ffff|0")); +} + +} // namespace + +} // namespace core +} // namespace transport \ No newline at end of file diff --git a/libtransport/src/test/test_quadloop.cc b/libtransport/src/test/test_quadloop.cc new file mode 100644 index 000000000..6a08033aa --- /dev/null +++ b/libtransport/src/test/test_quadloop.cc @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2021 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 +#include + +#include +#include +#include +#include + +namespace utils { + +class LoopTest : public ::testing::Test { + protected: + static inline const std::size_t size = 256; + + LoopTest() = default; + + ~LoopTest() override = default; + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + void SetUp() override { + // Code here will be called immediately after the constructor (right + // before each test). + } + + void TearDown() override { + // Code here will be called immediately after each test (right + // before the destructor). + } +}; + +// 1 cache line struct (64 bytes) +struct Data { + std::array data; +}; + +TEST_F(LoopTest, QuadLoopTest) { + // Create 2 arrays of 256 elements + std::vector> _from; + std::vector> _to_next; + _from.reserve(size); + _to_next.reserve(size); + + int n_left_from = size; + int n_left_to_next = size; + + // Initialize the arrays + for (std::size_t i = 0; i < size; i++) { + _from.push_back(std::make_unique()); + _to_next.push_back(std::make_unique()); + + for (int j = 0; j < 8; j++) { + _from[i]->data[j] = j; + _to_next[i]->data[j] = 0; + } + } + + const std::unique_ptr *from = &_from[0]; + const std::unique_ptr *to_next = &_to_next[0]; + + clock_t start; + clock_t end; + double clocks; + + start = clock(); + // Create a quad loop + while (n_left_from > 0) { + while (n_left_from >= 4 && n_left_to_next >= 4) { + { + using namespace transport::portability::cache; + Data *d2; + Data *d3; + + d2 = from[2].get(); + d3 = from[3].get(); + + prefetch(d2, sizeof(Data)); + prefetch(d3, sizeof(Data)); + + d2 = to_next[2].get(); + d3 = to_next[3].get(); + + prefetch(d2, sizeof(Data)); + prefetch(d3, sizeof(Data)); + } + + // Do 4 iterations + std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(), + sizeof(Data)); + std::memcpy(to_next[1].get()->data.data(), from[1].get()->data.data(), + sizeof(Data)); + n_left_from -= 2; + n_left_to_next -= 2; + from += 2; + to_next += 2; + } + + while (n_left_from > 0 && n_left_to_next > 0) { + std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(), + sizeof(Data)); + n_left_from -= 1; + n_left_to_next -= 1; + from += 1; + to_next += 1; + } + } + end = clock(); + clocks = (double)(end - start); + + LOG(INFO) << "Time with quad loop: " << clocks << std::endl; +} + +TEST_F(LoopTest, NormalLoopTest) { + // Create 2 arrays of 256 elements + std::vector> _from; + std::vector> _to_next; + _from.reserve(size); + _to_next.reserve(size); + + int n_left_from = size; + int n_left_to_next = size; + + // Initialize the arrays + for (std::size_t i = 0; i < size; i++) { + _from.push_back(std::make_unique()); + _to_next.push_back(std::make_unique()); + + for (int j = 0; j < 8; j++) { + _from[i]->data[j] = j; + _to_next[i]->data[j] = 0; + } + } + + const std::unique_ptr *from = &_from[0]; + const std::unique_ptr *to_next = &_to_next[0]; + + clock_t start; + clock_t end; + double clocks; + + start = clock(); + while (n_left_from > 0) { + while (n_left_from > 0 && n_left_to_next > 0) { + std::memcpy(to_next[0].get()->data.data(), from[0].get()->data.data(), + sizeof(Data)); + n_left_from -= 1; + n_left_to_next -= 1; + from += 1; + to_next += 1; + } + } + end = clock(); + clocks = ((double)(end - start)); + + LOG(INFO) << "Time with normal loop: " << clocks << std::endl; +} + +} // namespace utils \ No newline at end of file -- cgit 1.2.3-korg