#include <config.h>
#include <asiolink/io_address.h>
+#include <exceptions/exceptions.h>
#include <dhcp/dhcp6.h>
#include <dhcp/option6_pdexclude.h>
#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
#include <boost/dynamic_bitset.hpp>
-
-#include <sstream>
-
-#include <arpa/inet.h>
+#include <iostream>
#include <stdint.h>
using namespace std;
namespace isc {
namespace dhcp {
-Option6PDExclude::Option6PDExclude(
- const isc::asiolink::IOAddress& delegated_address,
- uint8_t delegated_prefix_length,
- const isc::asiolink::IOAddress& excluded_address,
- uint8_t excluded_prefix_length) :
- Option(V6, D6O_PD_EXCLUDE), delegated_address_(delegated_address),
- delegated_prefix_length_(delegated_prefix_length),
- excluded_address_(excluded_address),
- excluded_prefix_length_(excluded_prefix_length) {
+Option6PDExclude::Option6PDExclude(const isc::asiolink::IOAddress& delegated_prefix,
+ const uint8_t delegated_prefix_length,
+ const isc::asiolink::IOAddress& excluded_prefix,
+ const uint8_t excluded_prefix_length)
+ : Option(V6, D6O_PD_EXCLUDE),
+ delegated_prefix_(delegated_prefix),
+ delegated_prefix_length_(delegated_prefix_length),
+ excluded_prefix_(excluded_prefix),
+ excluded_prefix_length_(excluded_prefix_length) {
+
+ // Expecting v6 prefixes of sane length.
+ if (!delegated_prefix_.isV6() || !excluded_prefix_.isV6() ||
+ (delegated_prefix_length_ > 128) || (excluded_prefix_length_ > 128)) {
+ isc_throw(BadValue, "invalid delegated or excluded prefix values specified: "
+ << delegated_prefix_ << "/"
+ << static_cast<int>(delegated_prefix_length_) << ", "
+ << excluded_prefix_ << "/"
+ << static_cast<int>(excluded_prefix_length_));
+ }
+
+ // Excluded prefix must be longer than the delegated prefix.
+ if (excluded_prefix_length_ <= delegated_prefix_length_) {
+ isc_throw(BadValue, "length of the excluded prefix "
+ << excluded_prefix_ << "/"
+ << static_cast<int>(excluded_prefix_length_)
+ << " must be greater than the length of the"
+ " delegated prefix " << delegated_prefix_ << "/"
+ << static_cast<int>(delegated_prefix_length_));
+ }
+
+ // Both prefixes must share common part with a length equal to the
+ // delegated prefix length.
+ std::vector<uint8_t> delegated_prefix_bytes = delegated_prefix_.toBytes();
+ boost::dynamic_bitset<uint8_t> delegated_prefix_bits(delegated_prefix_bytes.rbegin(),
+ delegated_prefix_bytes.rend());
+
+ std::vector<uint8_t> excluded_prefix_bytes = excluded_prefix_.toBytes();
+ boost::dynamic_bitset<uint8_t> excluded_prefix_bits(excluded_prefix_bytes.rbegin(),
+ excluded_prefix_bytes.rend());
+
+
+ // See RFC6603, section 4.2: assert(p1>>s == p2>>s)
+ const uint8_t delta = 128 - delegated_prefix_length;
+
+ if ((delegated_prefix_bits >> delta) != (excluded_prefix_bits >> delta)) {
+ isc_throw(BadValue, "excluded prefix "
+ << excluded_prefix_ << "/"
+ << static_cast<int>(excluded_prefix_length_)
+ << " must have the same common prefix part of "
+ << static_cast<int>(delegated_prefix_length)
+ << " as the delegated prefix "
+ << delegated_prefix_ << "/"
+ << static_cast<int>(delegated_prefix_length_));
+ }
+
+}
+
+Option6PDExclude::Option6PDExclude(const isc::asiolink::IOAddress& delegated_prefix,
+ const uint8_t delegated_prefix_length,
+ OptionBufferConstIter begin,
+ OptionBufferConstIter end)
+ : Option(V6, D6O_PD_EXCLUDE),
+ delegated_prefix_(delegated_prefix),
+ delegated_prefix_length_(delegated_prefix_length),
+ excluded_prefix_(IOAddress::IPV6_ZERO_ADDRESS()),
+ excluded_prefix_length_(0) {
+ unpack(begin, end);
}
-void Option6PDExclude::pack(isc::util::OutputBuffer& buf) const {
+OptionPtr
+Option6PDExclude::clone() const {
+ return (cloneInternal<Option6PDExclude>());
+}
+
+void
+Option6PDExclude::pack(isc::util::OutputBuffer& buf) const {
// Header = option code and length.
packHeader(buf);
- buf.writeData(&excluded_prefix_length_, sizeof(excluded_prefix_length_));
-
- std::vector<uint8_t> excluded_address_bytes = excluded_address_.toBytes();
- boost::dynamic_bitset<uint8_t> bits(excluded_address_bytes.rbegin(), excluded_address_bytes.rend());
- bits = bits << delegated_prefix_length_;
+ // Excluded prefix length is always 1 byte long field.
+ buf.writeUint8(excluded_prefix_length_);
- const uint8_t subtractedPrefixesOctetLength = getSubtractedPrefixesOctetLength();
- for (uint8_t i = 0U; i < subtractedPrefixesOctetLength; i++) {
- const boost::dynamic_bitset<uint8_t> tmp = bits >> 120;
+ // Retrieve entire prefix and convert it to bit representation.
+ std::vector<uint8_t> excluded_prefix_bytes = excluded_prefix_.toBytes();
+ boost::dynamic_bitset<uint8_t> bits(excluded_prefix_bytes.rbegin(),
+ excluded_prefix_bytes.rend());
- uint8_t val = static_cast<uint8_t>(tmp.to_ulong());
+ // Shifting prefix by delegated prefix length leaves us with only a
+ // subnet id part of the excluded prefix.
+ bits = bits << delegated_prefix_length_;
- //Zero padded bits follow when excluded_prefix_length_ is not divided exactly by 8
- if (i == subtractedPrefixesOctetLength - 1U) {
- uint8_t subtractedPrefixesBitLength = excluded_prefix_length_ -
- delegated_prefix_length_;
- uint8_t zeroPaddingBitLength = (8 - (subtractedPrefixesBitLength % 8)) % 8;
- val <<= zeroPaddingBitLength;
+ // Calculate subnet id length.
+ const uint8_t subnet_id_length = getSubnetIDLength();
+ for (uint8_t i = 0; i < subnet_id_length; ++i) {
+ // Retrieve bit representation of the current byte.
+ const boost::dynamic_bitset<uint8_t> first_byte = bits >> 120;
+ // Convert it to a numeric value.
+ uint8_t val = static_cast<uint8_t>(first_byte.to_ulong());
+
+ // Zero padded bits follow when excluded_prefix_length_ is not divisible by 8.
+ if (i == subnet_id_length - 1) {
+ uint8_t length_delta = excluded_prefix_length_ - delegated_prefix_length_;
+ uint8_t mask = 0xFF;
+ mask <<= (8 - (length_delta % 8));
+ val &= mask;
}
- bits = bits << 8;
- buf.writeData(&val, sizeof(val));
+ // Store calculated value in a buffer.
+ buf.writeUint8(val);
+
+ // Go to the next byte.
+ bits <<= 8;
}
}
-void Option6PDExclude::unpack(OptionBufferConstIter begin,
- OptionBufferConstIter end) {
- delegated_prefix_length_ = 0;
- excluded_prefix_length_ = *begin;
- begin += sizeof(uint8_t);
- delegated_address_ = IOAddress::IPV6_ZERO_ADDRESS();
- excluded_address_ = IOAddress::IPV6_ZERO_ADDRESS();
+void
+Option6PDExclude::unpack(OptionBufferConstIter begin,
+ OptionBufferConstIter end) {
+
+ // At this point we don't know the excluded prefix length, but the
+ // minimum requirement is that reminder of this option includes the
+ // excluded prefix length and at least 1 byte of the IPv6 subnet id.
+ if (std::distance(begin, end) < 2) {
+ isc_throw(BadValue, "truncated Prefix Exclude option");
+ }
+
+ // We can safely read the excluded prefix length and move forward.
+ excluded_prefix_length_ = *begin++;
+
+ // We parsed the excluded prefix length so we can now determine the
+ // size of the IPv6 subnet id. The reminder of the option should
+ // include data of that size. If the option size is lower than the
+ // subnet id length we report an error.
+ const unsigned int subnet_id_length = getSubnetIDLength();
+ if (subnet_id_length > std::distance(begin, end)) {
+ isc_throw(BadValue, "truncated Prefix Exclude option, expected "
+ "IPv6 subnet id length is " << subnet_id_length);
+ }
+
+ // Get binary representation of the delegated prefix.
+ std::vector<uint8_t> delegated_prefix_bytes = delegated_prefix_.toBytes();
+ // We need to calculate how many bytes include the useful data and assign
+ // zeros to remaining bytes (beyond the prefix length).
+ const uint8_t bytes_length = (delegated_prefix_length_ / 8) +
+ static_cast<uint8_t>(delegated_prefix_length_ % 8 != 0);
+ std::fill(delegated_prefix_bytes.begin() + bytes_length,
+ delegated_prefix_bytes.end(), 0);
+
+ // Convert the delegated prefix to bit format.
+ boost::dynamic_bitset<uint8_t> bits(delegated_prefix_bytes.rbegin(),
+ delegated_prefix_bytes.rend());
+
+ // Convert subnet id to bit format.
+ std::vector<uint8_t> subnet_id_bytes(begin, end);
+ boost::dynamic_bitset<uint8_t> subnet_id_bits(subnet_id_bytes.rbegin(),
+ subnet_id_bytes.rend());
+
+ // Subnet id parsed, proceed to the end of the option.
begin = end;
+
+ // Concatenate the delegated prefix with subnet id. The resulting prefix
+ // is an excluded prefix in bit format.
+ for (int i = subnet_id_bits.size() - 1; i >= 0; --i) {
+ bits.set(128 - delegated_prefix_length_ - subnet_id_bits.size() + i,
+ subnet_id_bits.test(i));
+ }
+
+ // Convert the prefix to binary format.
+ std::vector<uint8_t> bytes(V6ADDRESS_LEN);
+ boost::to_block_range(bits, bytes.rbegin());
+
+ // And create a prefix object from bytes.
+ excluded_prefix_ = IOAddress::fromBytes(AF_INET6, &bytes[0]);
+}
+
+uint16_t
+Option6PDExclude::len() const {
+ return (getHeaderLen() + sizeof(excluded_prefix_length_)
+ + getSubnetIDLength());
}
-uint16_t Option6PDExclude::len() const {
- return getHeaderLen() + sizeof(excluded_prefix_length_)
- + getSubtractedPrefixesOctetLength();
+std::string
+Option6PDExclude::toText(int indent) const {
+ std::ostringstream s;
+ s << headerToText(indent) << ": ";
+ s << excluded_prefix_ << "/"
+ << static_cast<int>(excluded_prefix_length_);
+ return (s.str());
}
-uint8_t Option6PDExclude::getSubtractedPrefixesOctetLength() const {
- // Promote what is less than 8 bits to 1 octet.
- uint8_t subtractedPrefixesBitLength = excluded_prefix_length_
- - delegated_prefix_length_ - 1;
- uint8_t subtractedPrefixesOctetLength = (subtractedPrefixesBitLength / 8) + 1;
- return subtractedPrefixesOctetLength;
+uint8_t
+Option6PDExclude::getSubnetIDLength() const {
+ uint8_t subnet_id_length_bits = excluded_prefix_length_ -
+ delegated_prefix_length_ - 1;
+ uint8_t subnet_id_length = (subnet_id_length_bits / 8) + 1;
+ return (subnet_id_length);
}
} // end of namespace isc::dhcp
#ifndef OPTION6_PDEXCLUDE_H
#define OPTION6_PDEXCLUDE_H
-#include <dhcp/option.h>
-
#include <asiolink/io_address.h>
+#include <dhcp/option.h>
#include <boost/shared_ptr.hpp>
+#include <stdint.h>
namespace isc {
namespace dhcp {
-/// @brief DHCPv6 Option class for handling list of IPv6 addresses.
+/// @brief DHCPv6 option class representing Prefix Exclude Option (RFC 6603).
///
-/// This class handles a list of IPv6 addresses. An example of such option
-/// is dns-servers option. It can also be used to handle single address.
+/// This class represents DHCPv6 Prefix Exclude option (67). This option is
+/// carried in the IA Prefix option and it conveys a single prefix which is
+/// used by the delegating router to communicate with a requesting router on
+/// the requesting router's uplink. This prefix is not used on the
+/// requesting router's downlinks (is excluded from other delegated prefixes).
class Option6PDExclude: public Option {
-
public:
- Option6PDExclude(const isc::asiolink::IOAddress& delegated_address,
- uint8_t delegated_prefix_length,
- const isc::asiolink::IOAddress& excluded_address,
- uint8_t excluded_prefix_length);
+ /// @brief Constructor.
+ ///
+ /// @param delegated_prefix Delagated prefix.
+ /// @param delegated_prefix_length Delegated prefix length.
+ /// @param excluded_prefix Excluded prefix.
+ /// @param excluded_prefix_length Excluded prefix length.
+ ///
+ /// @throw BadValue if prefixes are invalid, if excluded prefix length
+ /// is not greater than delegated prefix length or if common parts of
+ /// prefixes does not match.
+ Option6PDExclude(const isc::asiolink::IOAddress& delegated_prefix,
+ const uint8_t delegated_prefix_length,
+ const isc::asiolink::IOAddress& excluded_prefix,
+ const uint8_t excluded_prefix_length);
+
+ /// @brief Constructor, creates option instance from part of the buffer.
+ ///
+ /// This constructor is mostly used to parse Prefix Exclude options in the
+ /// received messages.
+ ///
+ /// @param begin Lower bound of the buffer to create option from.
+ /// @param end Upper bound of the buffer to create option from.
+ Option6PDExclude(const isc::asiolink::IOAddress& delegated_prefix,
+ const uint8_t delegated_prefix_length,
+ OptionBufferConstIter begin, OptionBufferConstIter end);
+
+ /// @brief Copies this option and returns a pointer to the copy.
+ virtual OptionPtr clone() const;
/// @brief Writes option in wire-format to a buffer.
///
/// byte after stored option (that is useful for writing options one after
/// another).
///
- /// @param buf pointer to a buffer
+ /// The format of the option includes excluded prefix length specified as
+ /// a number of bits. It also includes IPv6 subnet ID field which is
+ /// computed from the delegated and excluded prefixes, according to the
+ /// section 4.2 of RFC 6603.
///
- /// @throw BadValue Universe of the option is neither V4 nor V6.
+ /// @param [out] buf Pointer to a buffer.
virtual void pack(isc::util::OutputBuffer& buf) const;
/// @brief Parses received buffer.
/// @return length of the option
virtual uint16_t len() const;
- /// @brief Returns the address of the delegated address space.
+ /// @brief Returns Prefix Exclude option in textual format.
///
- /// @return address of delegated address space
- isc::asiolink::IOAddress getDelegatedAddress() const {
- return delegated_address_;
+ /// @param ident Number of spaces to be inserted before the text.
+ virtual std::string toText(int indent = 0) const;
+
+ /// @brief Returns delegated prefix.
+ isc::asiolink::IOAddress getDelegatedPrefix() const {
+ return (delegated_prefix_);
}
- /// @brief Returns the prefix length of the delegated address space.
- ///
- /// @return prefix length of delegated address space
+ /// @brief Returns delegated prefix length.
uint8_t getDelegatedPrefixLength() const {
- return delegated_prefix_length_;
+ return (delegated_prefix_length_);
}
- /// @brief Returns the address of the excluded address space.
- ///
- /// @return address of excluded address space
- isc::asiolink::IOAddress getExcludedAddress() const {
- return excluded_address_;
+ /// @brief Returns excluded prefix.
+ isc::asiolink::IOAddress getExcludedPrefix() const {
+ return (excluded_prefix_);
}
- /// @brief Returns the prefix length of the excluded address space.
- ///
- /// @return prefix length of excluded address space
+ /// @brief Returns excluded prefix length.
uint8_t getExcludedPrefixLength() const {
- return excluded_prefix_length_;
+ return (excluded_prefix_length_);
}
-protected:
- /// @brief Returns the prefix length of the excluded prefix.
+private:
+
+ /// @brief Returns IPv6 subnet ID length in octets.
///
- /// @return prefix length of excluded prefix
- uint8_t getSubtractedPrefixesOctetLength() const;
+ /// The IPv6 subnet ID length is between 1 and 16 octets.
+ uint8_t getSubnetIDLength() const;
- /// @brief The address and prefix length identifying the delegated IPV6
- /// prefix.
- /// {
- isc::asiolink::IOAddress delegated_address_;
+ /// @brief Holds delegated prefix.
+ isc::asiolink::IOAddress delegated_prefix_;
+
+ /// @brief Holds delegated prefix length,
uint8_t delegated_prefix_length_;
- /// }
- /// @brief The address and prefix length identifying the excluded IPV6
- /// prefix.
- /// {
- isc::asiolink::IOAddress excluded_address_;
+ /// @brief Holds excluded prefix.
+ isc::asiolink::IOAddress excluded_prefix_;
+
+ /// @brief Holds excluded prefix length.
uint8_t excluded_prefix_length_;
- /// }
};
-/// @brief Pointer to the @c Option6PDExclude object.
+/// @brief Pointer to the @ref Option6PDExclude object.
typedef boost::shared_ptr<Option6PDExclude> Option6PDExcludePtr;
} // isc::dhcp namespace
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
//
#include <config.h>
-#include <dhcp/option6_pdexclude.h>
#include <asiolink/io_address.h>
+#include <exceptions/exceptions.h>
+#include <dhcp/option6_pdexclude.h>
#include <dhcpsrv/pool.h>
+#include <util/buffer.h>
#include <gtest/gtest.h>
using namespace isc;
namespace {
-const IOAddress empty("::");
-const IOAddress beef("2001:db8:dead:beef::"); // /48 prefix length
-const IOAddress cafe("2001:db8:dead:cafe::"); // /48 prefix length
-const IOAddress beef01("2001:db8:dead:beef::01"); // /56 prefix length
+// 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");
-// Description
+// This test verifies that the constructor sets parameters appropriately.
TEST(Option6PDExcludeTest, constructor) {
Option6PDExclude option = Option6PDExclude(beef, 56, beef01, 60);
- EXPECT_EQ(option.getDelegatedAddress(), beef);
- EXPECT_EQ(option.getDelegatedPrefixLength(), 56);
- EXPECT_EQ(option.getExcludedAddress(), beef01);
- EXPECT_EQ(option.getExcludedPrefixLength(), 60);
- EXPECT_EQ(option.len(), Option::OPTION6_HDR_LEN +
- /* excluded_prefix_length_ AKA prefix-len is 1B */ 1 +
- /* [delegated_prefix_length_ - excluded_prefix_length_](bytes) */ 1);
+ EXPECT_EQ(beef, option.getDelegatedPrefix());
+ EXPECT_EQ(56, option.getDelegatedPrefixLength());
+ EXPECT_EQ(beef01, option.getExcludedPrefix());
+ EXPECT_EQ(60, option.getExcludedPrefixLength());
+ // 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);
}
-TEST(Option6PDExcludeTest, packing_and_unpacking) {
- EXPECT_NO_THROW(isc_throw(Exception, "Not implemented yet."));
-
- /*
- OptionBuffer data(option.getData());
-
+// 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 59 + 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);
- option.pack(buf);
+ 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()));
+}
- Option6PDExclude unpackedOption(empty, 0, empty, 0);
+// 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(IOAddress("2001:db8:dead:bee0::1"),
+ 59, vec.begin() + 4, vec.end()))
+ );
+
+ // Make sure that the option has been parsed correctly.
+ EXPECT_EQ("2001:db8:dead:bee0::1", option->getDelegatedPrefix().toText());
+ EXPECT_EQ(59, static_cast<int>(option->getDelegatedPrefixLength()));
+ EXPECT_EQ("2001:db8:dead:beef::", option->getExcludedPrefix().toText());
+ EXPECT_EQ(64, static_cast<int>(option->getExcludedPrefixLength()));
+}
+
+// This test verifies parsing option wire format with subnet id of
+// 1 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(IOAddress("2001:db8:dead::"),
+ 48, vec.begin() + 4, vec.end()))
+ );
+
+ // Make sure that the option has been parsed correctly.
+ EXPECT_EQ("2001:db8:dead::", option->getDelegatedPrefix().toText());
+ EXPECT_EQ(48, static_cast<int>(option->getDelegatedPrefixLength()));
+ EXPECT_EQ("2001:db8:dead:beef::", option->getExcludedPrefix().toText());
+ EXPECT_EQ(64, static_cast<int>(option->getExcludedPrefixLength()));
+}
- unpackedOption.unpack(data.begin(), data.end());
+// 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(IOAddress("2001:db8:dead:bee0::"),
+ 59, vec.begin() + 4, vec.end() - 1),
+ BadValue);
+
+ // Option has IPv6 subnet id of 1 byte, but it should have 2 bytes.
+ EXPECT_THROW(Option6PDExclude(IOAddress("2001:db8:dead::"), 48,
+ vec.begin() + 4, vec.end()),
+ BadValue);
+}
- EXPECT_EQ(option.getDelegatedAddress(),
- unpackedOption.getDelegatedAddress());
- EXPECT_EQ(option.getDelegatedPrefixLength(),
- unpackedOption.getDelegatedPrefixLength());
- EXPECT_EQ(option.getExcludedAddress(), unpackedOption.getExcludedAddress());
- EXPECT_EQ(option.getExcludedPrefixLength(),
- unpackedOption.getExcludedPrefixLength());
- //*/
+// 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: 2001:db8:dead:beef::/64",
+ option.toText());
}
-TEST(Option6PDExcludeTest, pool) {
- EXPECT_NO_THROW(isc_throw(Exception, "Not implemented yet."));
-
- /*
- Pool6Ptr pool6Ptr = Pool6Ptr(new Pool6(Lease::TYPE_PD, beef, cafe));
- ASSERT_TRUE(pool6Ptr);
- ASSERT_GT(pool6Ptr->getPrefixExcludedLength(), 0);
- OptionPtr opt(
- new Option6PDExclude((*l)->addr_, (*l)->prefixlen_,
- pool->getPrefixExcluded(),
- pool->getPrefixExcludedLength()));
- //*/
+// 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