aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/test
diff options
context:
space:
mode:
authorLuca Muscariello <lumuscar@cisco.com>2022-06-09 21:34:09 +0200
committerLuca Muscariello <muscariello@ieee.org>2022-06-30 10:47:50 +0200
commit6b94663b2455e212009a544ae23bb6a8c55407f8 (patch)
tree0af780ce5eeb1009fd24b8af8af08e8368eda3bd /libtransport/src/test
parenta1ac96f497719b897793ac14b287cb8d840651c1 (diff)
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 Co-authored-by: Mauro Sardara <msardara@cisco.com> Co-authored-by: Jordan Augé <jordan.auge+fdio@cisco.com> Co-authored-by: Michele Papalini <micpapal@cisco.com> Co-authored-by: Olivier Roques <oroques+fdio@cisco.com> Co-authored-by: Enrico Loparco <eloparco@cisco.com> Change-Id: Iaddebfe6aa5279ea8553433b0f519578f6b9ccd9 Signed-off-by: Luca Muscariello <muscariello@ieee.org>
Diffstat (limited to 'libtransport/src/test')
-rw-r--r--libtransport/src/test/CMakeLists.txt2
-rw-r--r--libtransport/src/test/test_core_manifest.cc227
-rw-r--r--libtransport/src/test/test_interest.cc39
-rw-r--r--libtransport/src/test/test_memif_connector.cc4
-rw-r--r--libtransport/src/test/test_packet_allocator.cc25
-rw-r--r--libtransport/src/test/test_prefix.cc334
-rw-r--r--libtransport/src/test/test_quadloop.cc176
7 files changed, 709 insertions, 98 deletions
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 <core/manifest.h>
#include <core/manifest_format_fixed.h>
-#include <core/manifest_inline.h>
#include <gtest/gtest.h>
#include <hicn/transport/auth/crypto_hash.h>
#include <hicn/transport/auth/signer.h>
@@ -33,10 +33,12 @@ namespace {
// The fixture for testing class Foo.
class ManifestTest : public ::testing::Test {
protected:
- using ContentObjectManifest = ManifestInline<ContentObject, Fixed>;
+ using ContentObjectManifest = Manifest<Fixed>;
- 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<uint8_t> manifest_payload = {
+ std::size_t signature_size_;
+ std::shared_ptr<ContentObjectManifest> manifest_;
+ std::vector<uint8_t> 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<ContentObject>(
+ 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::SymmetricSigner>(
auth::CryptoSuite::HMAC_SHA256, "hunter2");
auto verifier = std::make_shared<auth::SymmetricVerifier>("hunter2");
- std::shared_ptr<ContentObjectManifest> 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<ContentObjectManifest> 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<uint8_t>{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<ContentObject>(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_engine<std::default_random_engine, CHAR_BIT,
@@ -259,12 +293,13 @@ TEST_F(ManifestTest, SetSuffixList) {
entries[i] = std::make_pair(suffixes[i],
auth::CryptoHash(data[i].data(), data[i].size(),
auth::CryptoHashType::SHA256));
- manifest1_.addSuffixHash(entries[i].first, entries[i].second);
+ manifest_->addEntry(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<uint32_t> 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 <hicn/transport/core/global_object_pool.h>
#undef ALLOCATION_CHECKS
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <hicn/transport/utils/event_thread.h>
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<utils::MemBuf::Ptr, counter> 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 <glog/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/errors/invalid_ip_address_exception.h>
+#include <hicn/transport/portability/endianess.h>
+
+#include <cstring>
+#include <memory>
+#include <vector>
+
+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<sockaddr_in *>(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 <glog/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/portability/cache.h>
+
+#include <array>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+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<uint64_t, 8> data;
+};
+
+TEST_F(LoopTest, QuadLoopTest) {
+ // Create 2 arrays of 256 elements
+ std::vector<std::unique_ptr<Data>> _from;
+ std::vector<std::unique_ptr<Data>> _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<Data>());
+ _to_next.push_back(std::make_unique<Data>());
+
+ for (int j = 0; j < 8; j++) {
+ _from[i]->data[j] = j;
+ _to_next[i]->data[j] = 0;
+ }
+ }
+
+ const std::unique_ptr<Data> *from = &_from[0];
+ const std::unique_ptr<Data> *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<Data, READ>(d2, sizeof(Data));
+ prefetch<Data, READ>(d3, sizeof(Data));
+
+ d2 = to_next[2].get();
+ d3 = to_next[3].get();
+
+ prefetch<Data, WRITE>(d2, sizeof(Data));
+ prefetch<Data, WRITE>(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<std::unique_ptr<Data>> _from;
+ std::vector<std::unique_ptr<Data>> _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<Data>());
+ _to_next.push_back(std::make_unique<Data>());
+
+ for (int j = 0; j < 8; j++) {
+ _from[i]->data[j] = j;
+ _to_next[i]->data[j] = 0;
+ }
+ }
+
+ const std::unique_ptr<Data> *from = &_from[0];
+ const std::unique_ptr<Data> *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