summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/tests/option6_pdexclude_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/tests/option6_pdexclude_unittest.cc')
-rw-r--r--src/lib/dhcp/tests/option6_pdexclude_unittest.cc170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/lib/dhcp/tests/option6_pdexclude_unittest.cc b/src/lib/dhcp/tests/option6_pdexclude_unittest.cc
new file mode 100644
index 0000000..b119fc2
--- /dev/null
+++ b/src/lib/dhcp/tests/option6_pdexclude_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright (C) 2016-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// Author: Andrei Pavel <andrei.pavel@qualitance.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <exceptions/exceptions.h>
+#include <dhcp/option6_pdexclude.h>
+#include <util/buffer.h>
+#include <util/encode/hex.h>
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+using namespace asiolink;
+
+namespace {
+
+// Prefix constants used in unit tests.
+const IOAddress v4("192.0.2.0");
+const IOAddress bee0("2001:db8:dead:bee0::");
+const IOAddress beef("2001:db8:dead:beef::");
+const IOAddress cafe("2001:db8:dead:cafe::");
+const IOAddress beef01("2001:db8:dead:beef::01");
+
+// This test verifies that the constructor sets parameters appropriately.
+TEST(Option6PDExcludeTest, constructor) {
+ Option6PDExclude option = Option6PDExclude(beef, 56, beef01, 60);
+
+ EXPECT_EQ(bee0, option.getExcludedPrefix(beef, 56));
+ EXPECT_EQ(60, option.getExcludedPrefixLength());
+ EXPECT_EQ("E0", util::encode::encodeHex(option.getExcludedPrefixSubnetID()));
+
+ // Total length is a sum of option header length, excluded prefix
+ // length (always 1 byte) and delegated prefix length - excluded prefix
+ // length rounded to bytes.
+ EXPECT_EQ(Option::OPTION6_HDR_LEN + 1 + 1, option.len());
+
+ // v4 prefix is not accepted.
+ EXPECT_THROW(Option6PDExclude(v4, 56, beef01, 64), BadValue);
+ EXPECT_THROW(Option6PDExclude(beef, 56, v4, 64), BadValue);
+ // Length greater than 128 is not accepted.
+ EXPECT_THROW(Option6PDExclude(beef, 128, beef01, 129), BadValue);
+ // Excluded prefix length must be greater than delegated prefix length.
+ EXPECT_THROW(Option6PDExclude(beef, 56, beef01, 56), BadValue);
+ // Both prefixes shifted by 56 must be equal (see RFC6603, section 4.2).
+ EXPECT_THROW(Option6PDExclude(cafe, 56, beef01, 64), BadValue);
+}
+
+// This test verifies that on-wire format of the Prefix Exclude option is
+// created properly.
+TEST(Option6PDExcludeTest, pack) {
+ // Expected wire format of the option.
+ const uint8_t expected_data[] = {
+ 0x00, 0x43, // option code 67
+ 0x00, 0x02, // option length 2
+ 0x3F, 0x70 // excluded prefix length 63 + subnet id
+ };
+ std::vector<uint8_t> expected_vec(expected_data,
+ expected_data + sizeof(expected_data));
+ // Generate wire format of the option.
+ util::OutputBuffer buf(128);
+ Option6PDExcludePtr option;
+ ASSERT_NO_THROW(option.reset(new Option6PDExclude(IOAddress("2001:db8:dead:bee0::"),
+ 59,
+ IOAddress("2001:db8:dead:beef::"),
+ 63)));
+ ASSERT_NO_THROW(option->pack(buf));
+
+ // Check that size matches.
+ ASSERT_EQ(expected_vec.size(), buf.getLength());
+
+ // Check that the generated wire format is correct.
+ const uint8_t* data = static_cast<const uint8_t*>(buf.getData());
+ std::vector<uint8_t> vec(data, data + buf.getLength());
+ ASSERT_TRUE(std::equal(vec.begin(), vec.end(), expected_vec.begin()));
+}
+
+// This test verifies parsing option wire format with subnet id of
+// 1 byte.
+TEST(Option6PDExcludeTest, unpack1ByteSubnetId) {
+ const uint8_t data[] = {
+ 0x00, 0x43, // option code 67
+ 0x00, 0x02, // option length 2
+ 0x40, 0x78 // excluded prefix length 60 + subnet id
+ };
+ std::vector<uint8_t> vec(data, data + sizeof(data));
+
+ // Parse option.
+ Option6PDExcludePtr option;
+ ASSERT_NO_THROW(
+ option.reset(new Option6PDExclude(vec.begin() + 4, vec.end()))
+ );
+
+ // Make sure that the option has been parsed correctly.
+ EXPECT_EQ("2001:db8:dead:beef::",
+ option->getExcludedPrefix(IOAddress("2001:db8:dead:bee0::1"), 59).toText());
+ EXPECT_EQ(64, static_cast<int>(option->getExcludedPrefixLength()));
+}
+
+// This test verifies parsing option wire format with subnet id of
+// 2 bytes.
+TEST(Option6PDExcludeTest, unpack2ByteSubnetId) {
+ const uint8_t data[] = {
+ 0x00, 0x43, // option code 67
+ 0x00, 0x02, // option length
+ 0x40, 0xbe, 0xef // excluded prefix length 60 + subnet id
+ };
+ std::vector<uint8_t> vec(data, data + sizeof(data));
+
+ // Parse option.
+ Option6PDExcludePtr option;
+ ASSERT_NO_THROW(
+ option.reset(new Option6PDExclude(vec.begin() + 4, vec.end()))
+ );
+
+ // Make sure that the option has been parsed correctly.
+ EXPECT_EQ("2001:db8:dead:beef::",
+ option->getExcludedPrefix(IOAddress("2001:db8:dead::"), 48).toText());
+ EXPECT_EQ(64, static_cast<int>(option->getExcludedPrefixLength()));
+}
+
+// This test verifies that errors are reported when option buffer contains
+// invalid option data.
+TEST(Option6PDExcludeTest, unpackErrors) {
+ const uint8_t data[] = {
+ 0x00, 0x43,
+ 0x00, 0x02,
+ 0x40, 0x78
+ };
+ std::vector<uint8_t> vec(data, data + sizeof(data));
+
+ // Option has no IPv6 subnet id.
+ EXPECT_THROW(Option6PDExclude(vec.begin() + 4, vec.end() - 1),
+ BadValue);
+
+ // IPv6 subnet id is 0.
+ vec[4] = 0x00;
+ EXPECT_THROW(Option6PDExclude(vec.begin() + 4, vec.end()),
+ BadValue);
+}
+
+// This test verifies conversion of the Prefix Exclude option to the
+// textual format.
+TEST(Option6PDExcludeTest, toText) {
+ Option6PDExclude option(bee0, 59, beef, 64);
+ EXPECT_EQ("type=00067, len=00002: excluded-prefix-len=64, subnet-id=0x78",
+ option.toText());
+}
+
+// This test verifies calculation of the Prefix Exclude option length.
+TEST(Option6PDExcludeTest, len) {
+ Option6PDExcludePtr option;
+ // The IPv6 subnet id is 2 bytes long. Hence the total length is
+ // 2 bytes (option code) + 2 bytes (option length) + 1 byte
+ // (excluded prefix length) + 2 bytes (IPv6 subnet id) = 7 bytes.
+ ASSERT_NO_THROW(option.reset(new Option6PDExclude(bee0, 48, beef, 64)));
+ EXPECT_EQ(7, option->len());
+
+ // IPv6 subnet id is 1 byte long. The total length is 6.
+ ASSERT_NO_THROW(option.reset(new Option6PDExclude(bee0, 59, beef, 64)));
+ EXPECT_EQ(6, option->len());
+}
+
+} // anonymous namespace