#include <dhcpsrv/host.h>
#include <util/strutil.h>
#include <exceptions/exceptions.h>
+#include <sstream>
namespace isc {
namespace dhcp {
prefix_len_ = prefix_len;
}
+std::string
+IPv6Resrv::toText() const {
+ std::ostringstream s;
+ s << prefix_;
+ // For PD, append prefix length.
+ if (getType() == TYPE_PD) {
+ s << "/" << static_cast<int>(prefix_len_);
+ }
+ return (s.str());
+}
+
bool
IPv6Resrv::operator==(const IPv6Resrv& other) const {
return (prefix_ == other.prefix_ &&
void
Host::addReservation(const IPv6Resrv& reservation) {
+ // Check if it is not duplicating existing reservation.
+ if (hasReservation(reservation)) {
+ isc_throw(isc::InvalidOperation, "failed on attempt to add a duplicated"
+ " host reservation for " << reservation.toText());
+ }
+ // Add it.
ipv6_reservations_.insert(IPv6ResrvTuple(reservation.getType(),
reservation));
}
return (ipv6_reservations_.equal_range(type));
}
+bool
+Host::hasReservation(const IPv6Resrv& reservation) const {
+ IPv6ResrvRange reservations = getIPv6Reservations(reservation.getType());
+ if (std::distance(reservations.first, reservations.second) > 0) {
+ for (IPv6ResrvIterator it = reservations.first;
+ it != reservations.second; ++it) {
+ if (it->second == reservation) {
+ return (true);
+ }
+ }
+ }
+
+ // No matching reservations found.
+ return (false);
+}
+
void
Host::addClientClassInternal(ClientClasses& classes,
const std::string& class_name) {
/// multicast address or the prefix length is greater than 128.
void set(const asiolink::IOAddress& prefix, const uint8_t prefix_len);
+ /// @brief Returns information about the reservation in the textual format.
+ std::string toText() const;
+
/// @brief Equality operator.
///
/// @param other Reservation to compare to.
/// the specified type.
IPv6ResrvRange getIPv6Reservations(const IPv6Resrv::Type& type) const;
+ /// @brief Checks if specified IPv6 reservation exists for the host.
+ ///
+ /// @param reservation A reservation to be checked for the host.
+ ///
+ /// @return true if the reservation already exists for the host, false
+ /// otherwise.
+ bool hasReservation(const IPv6Resrv& reservation) const;
+
/// @brief Sets new hostname.
///
/// @param hostname New hostname.
EXPECT_THROW(parser.build(config_element), DhcpConfigError);
}
+// This test verifies that the configuration parser throws an exception
+// when empty address has been specified.
+TEST_F(HostReservationParserTest, dhcp6NullAddress) {
+ std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+ "\"ip-addresses\": [ \"\" ],"
+ "\"prefixes\": [ ] }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ HostReservationParser6 parser(SubnetID(12));
+ EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
+// This test verifies that the configuration parser throws an exception
+// when invalid prefix length is specified.
+TEST_F(HostReservationParserTest, dhcp6InvalidPrefixLength) {
+ std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+ "\"prefixes\": [ \"2001:db8:1::/abc\" ] }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ HostReservationParser6 parser(SubnetID(12));
+ EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
+// This test verifies that the configuration parser throws an exception
+// when empty prefix is specified.
+TEST_F(HostReservationParserTest, dhcp6NullPrefix) {
+ std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+ "\"prefixes\": [ \"/64\" ] }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ HostReservationParser6 parser(SubnetID(12));
+ EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
+// This test verifies that the configuration parser throws an exception
+// when only slash is specified for the prefix..
+TEST_F(HostReservationParserTest, dhcp6NullPrefix2) {
+ std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+ "\"prefixes\": [ \"/\" ] }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ HostReservationParser6 parser(SubnetID(12));
+ EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
+// This test verifies that the configuration parser throws an exception
+// when the same address is reserved twice.
+TEST_F(HostReservationParserTest, dhcp6DuplicatedAddress) {
+ std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+ "\"ip-addresses\": [ \"2001:db8:1::1\", \"2001:db8:1::1\" ] }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ HostReservationParser6 parser(SubnetID(12));
+ EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
+// This test verifies that the configuration parser throws an exception
+// when the same prefix is reserved twice.
+TEST_F(HostReservationParserTest, dhcp6DuplicatedPrefix) {
+ std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\","
+ "\"prefixes\": [ \"2001:db8:0101::/64\", \"2001:db8:0101::/64\" ] }";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ HostReservationParser6 parser(SubnetID(12));
+ EXPECT_THROW(parser.build(config_element), DhcpConfigError);
+}
+
} // end of anonymous namespace
EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType());
}
+// This test verifies that the toText() function prints correctly.
+TEST(IPv6ResrvTest, toText) {
+ IPv6Resrv resrv_prefix(IOAddress("2001:db8:1::"), 64);
+ EXPECT_EQ("2001:db8:1::/64", resrv_prefix.toText());
+
+ IPv6Resrv resrv_address(IOAddress("2001:db8:111::23"));
+ EXPECT_EQ("2001:db8:111::23", resrv_address.toText());
+}
+
// This test verifies that invalid prefix is rejected.
TEST(IPv6ResrvTest, constructorInvalidPrefix) {
// IPv4 address is invalid for IPv6 reservation.
host->addReservation(IPv6Resrv(IOAddress("2001:db8:1::1")));
);
+ // Check that reservations exist.
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1::cafe"))));
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1:1::"),
+ 64)));
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1:2::"),
+ 64)));
+ EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1::1"))));
+
// Get only NA reservations.
IPv6ResrvRange addresses = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
ASSERT_EQ(2, std::distance(addresses.first, addresses.second));