From: Marcin Siodelski Date: Fri, 10 Oct 2014 09:32:22 +0000 (+0200) Subject: [3560] Basic implementation of the Host class. X-Git-Tag: trac3162a_base~3^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e205a10dabb3445b4ff726710985cd28ae59ea8c;p=thirdparty%2Fkea.git [3560] Basic implementation of the Host class. --- diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index e035bee2d2..c1556eca76 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -57,6 +57,7 @@ libkea_dhcpsrv_la_SOURCES += dbaccess_parser.cc dbaccess_parser.h libkea_dhcpsrv_la_SOURCES += dhcpsrv_log.cc dhcpsrv_log.h libkea_dhcpsrv_la_SOURCES += dhcp_config_parser.h libkea_dhcpsrv_la_SOURCES += dhcp_parsers.cc dhcp_parsers.h +libkea_dhcpsrv_la_SOURCES += host.cc host.h libkea_dhcpsrv_la_SOURCES += key_from_key.h libkea_dhcpsrv_la_SOURCES += lease.cc lease.h libkea_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h @@ -75,6 +76,7 @@ libkea_dhcpsrv_la_SOURCES += option_space_container.h libkea_dhcpsrv_la_SOURCES += pool.cc pool.h libkea_dhcpsrv_la_SOURCES += srv_config.cc srv_config.h libkea_dhcpsrv_la_SOURCES += subnet.cc subnet.h +libkea_dhcpsrv_la_SOURCES += subnet_id.h libkea_dhcpsrv_la_SOURCES += triplet.h libkea_dhcpsrv_la_SOURCES += utils.h diff --git a/src/lib/dhcpsrv/host.cc b/src/lib/dhcpsrv/host.cc new file mode 100644 index 0000000000..ef207c0056 --- /dev/null +++ b/src/lib/dhcpsrv/host.cc @@ -0,0 +1,79 @@ +// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include + +namespace isc { +namespace dhcp { + +Host::Host(const uint8_t* identifier, const size_t identifier_len, + const IdentifierType& identifier_type, + const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id, + const asiolink::IOAddress& ipv4_reservation, + const std::string& hostname) + : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id), + ipv6_subnet_id_(ipv6_subnet_id), ipv4_reservation_(ipv4_reservation), + hostname_(hostname), dhcp4_client_classes_(), dhcp6_client_classes_() { + + decodeIdentifier(identifier, identifier_len, identifier_type); +} + +Host::Host(const std::string& identifier, const std::string& identifier_name, + const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id, + const asiolink::IOAddress& ipv4_reservation, + const std::string& hostname) + : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id), + ipv6_subnet_id_(ipv6_subnet_id), ipv4_reservation_(ipv4_reservation), + hostname_(hostname), dhcp4_client_classes_(), dhcp6_client_classes_() { + + decodeIdentifier(identifier, identifier_name); +} + +void +Host::decodeIdentifier(const uint8_t* identifier, const size_t len, + const IdentifierType& type) { + switch (type) { + case IDENT_HWADDR: + hw_address_ = HWAddrPtr(new HWAddr(identifier, len, HTYPE_ETHER)); + duid_.reset(); + break; + case IDENT_DUID: + duid_ = DuidPtr(new DUID(identifier, len)); + hw_address_.reset(); + break; + default: + isc_throw(isc::BadValue, "invalid client identifier type '" + << static_cast(type) << "' when creating host " + " instance"); + } +} + +void +Host::decodeIdentifier(const std::string& identifier, const std::string& name) { + if (name == "hw-address") { + hw_address_ = HWAddrPtr(new HWAddr(HWAddr::fromText(identifier))); + duid_.reset(); + } else if (name == "duid") { + duid_ = DuidPtr(new DUID(DUID::fromText(identifier))); + hw_address_.reset(); + } else { + isc_throw(isc::BadValue, "invalid client identifier type '" + << name << "' when creating host instance"); + } +} + + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/lib/dhcpsrv/host.h b/src/lib/dhcpsrv/host.h new file mode 100644 index 0000000000..6e452c5aab --- /dev/null +++ b/src/lib/dhcpsrv/host.h @@ -0,0 +1,154 @@ +// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef HOST_H +#define HOST_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace isc { +namespace dhcp { + +class IPv6Resrv { +public: + + enum Type { + TYPE_NA, + TYPE_PD + }; + + IPv6Resrv(const asiolink::IOAddress& address, + const uint8_t prefix_len = 128) + : address_(address), prefix_len_(prefix_len) { + } + + const asiolink::IOAddress& getAddress() const { + return (address_); + } + + uint8_t getPrefixLen() const { + return (prefix_len_); + } + + Type getType() const { + return (prefix_len_ == 128 ? TYPE_NA : TYPE_PD); + } + + void set(const asiolink::IOAddress& address, const uint8_t prefix_len) { + address_ = address; + prefix_len_ = prefix_len; + } + +private: + asiolink::IOAddress address_; + uint8_t prefix_len_; + +}; + +/// @brief Collection of IPv6 reservations for the host. +typedef std::multimap IPv6ResrvCollection; +typedef IPv6ResrvCollection::iterator IPv6ResrvIterator; +typedef std::pair IPv6ResrvRange; + +class Host { +public: + + enum IdentifierType { + IDENT_HWADDR, + IDENT_DUID + }; + + Host(const uint8_t* identifier, const size_t identifier_len, + const IdentifierType& identifier_type, + const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id, + const asiolink::IOAddress& ipv4_reservation, + const std::string& hostname = ""); + + Host(const std::string& identifier, const std::string& identifier_name, + const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id, + const asiolink::IOAddress& ipv4_reservation, + const std::string& hostname = ""); + + void addReservation(const IPv6Resrv& reservation); + + void setIdentifier(const uint8_t* identifier, const size_t identifier_len, + const IdentifierType& identifier_type); + + void setIdentifier(const std::string& identifier, const std::string& name); + + HWAddrPtr getHWAddress() const { + return (hw_address_); + } + + DuidPtr getDuid() const { + return (duid_); + } + + SubnetID getIPv4SubnetID() const { + return (ipv4_subnet_id_); + } + + SubnetID getIPv6SubnetID() const { + return (ipv6_subnet_id_); + } + + const asiolink::IOAddress& getIPv4Reservation() const { + return (ipv4_reservation_); + } + + IPv6ResrvRange getIPv6Reservations(const IPv6Resrv& type) const; + + const std::string& getHostname() const { + return (hostname_); + } + + const ClientClasses& getClientClasses4() const { + return (dhcp4_client_classes_); + } + + const ClientClasses& getClientClasses6() const { + return (dhcp6_client_classes_); + } + +private: + + void decodeIdentifier(const uint8_t* identifier, const size_t len, + const IdentifierType& type); + + void decodeIdentifier(const std::string& identifier, + const std::string& name); + + HWAddrPtr hw_address_; + DuidPtr duid_; + SubnetID ipv4_subnet_id_; + SubnetID ipv6_subnet_id_; + asiolink::IOAddress ipv4_reservation_; + IPv6ResrvCollection ipv6_reservations_; + std::string hostname_; + ClientClasses dhcp4_client_classes_; + ClientClasses dhcp6_client_classes_; +}; + +} +} + +#endif // HOST_H diff --git a/src/lib/dhcpsrv/subnet_id.h b/src/lib/dhcpsrv/subnet_id.h new file mode 100644 index 0000000000..a225f27347 --- /dev/null +++ b/src/lib/dhcpsrv/subnet_id.h @@ -0,0 +1,32 @@ +// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef SUBNET_ID_H +#define SUBNET_ID_H + +namespace isc { +namespace dhcp { + +/// @brief Defines unique IPv4 or IPv6 subnet identifier. +/// +/// Each subnet for which the DHCP service has been configured is identifed +/// by the unique value called subnet id. Right now it is represented as +/// a simple unsiged integer. In the future it may be extended to more complex +/// type. +typedef uint32_t SubnetID; + +} +} + +#endif // SUBNET_ID_H diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index 0f93ddd4ff..e5d311565f 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -64,6 +64,7 @@ libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc libdhcpsrv_unittests_SOURCES += daemon_unittest.cc libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc +libdhcpsrv_unittests_SOURCES += host_unittest.cc libdhcpsrv_unittests_SOURCES += lease_file_io.cc lease_file_io.h libdhcpsrv_unittests_SOURCES += lease_unittest.cc libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc diff --git a/src/lib/dhcpsrv/tests/host_unittest.cc b/src/lib/dhcpsrv/tests/host_unittest.cc new file mode 100644 index 0000000000..94d28fd434 --- /dev/null +++ b/src/lib/dhcpsrv/tests/host_unittest.cc @@ -0,0 +1,122 @@ +// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include + +#include +#include +#include + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::asiolink; + +namespace { + +TEST(IPv6ResrvTest, constructorAddress) { + IPv6Resrv resrv(IOAddress("2001:db8:1::cafe")); + EXPECT_EQ("2001:db8:1::cafe", resrv.getAddress().toText()); + EXPECT_EQ(128, resrv.getPrefixLen()); + EXPECT_EQ(IPv6Resrv::TYPE_NA, resrv.getType()); +} + +TEST(IPv6ResrvTest, constructorPrefix) { + IPv6Resrv resrv(IOAddress("2001:db8:1::"), 64); + EXPECT_EQ("2001:db8:1::", resrv.getAddress().toText()); + EXPECT_EQ(64, resrv.getPrefixLen()); + EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType()); +} + +TEST(IPv6ResrvTest, setPrefix) { + IPv6Resrv resrv(IOAddress("2001:db8:1::1")); + ASSERT_EQ("2001:db8:1::1", resrv.getAddress().toText()); + ASSERT_EQ(128, resrv.getPrefixLen()); + ASSERT_EQ(IPv6Resrv::TYPE_NA, resrv.getType()); + + ASSERT_NO_THROW(resrv.set(IOAddress("2001:db8::"), 48)); + EXPECT_EQ("2001:db8::", resrv.getAddress().toText()); + EXPECT_EQ(48, resrv.getPrefixLen()); + EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType()); +} + +TEST(HostTest, createFromHWAddrString) { + boost::scoped_ptr host; + ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address", + SubnetID(1), SubnetID(2), + IOAddress("192.0.2.3"), + "somehost.example.org"))); + + HWAddrPtr hwaddr = host->getHWAddress(); + ASSERT_TRUE(hwaddr); + + EXPECT_EQ("hwtype=1 01:02:03:04:05:06", hwaddr->toText()); + + EXPECT_FALSE(host->getDuid()); + EXPECT_EQ(1, host->getIPv4SubnetID()); + EXPECT_EQ(2, host->getIPv6SubnetID()); + EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText()); + EXPECT_EQ("somehost.example.org", host->getHostname()); + + // Use invalid identifier name + EXPECT_THROW(Host("01:02:03:04:05:06", "bogus", SubnetID(1), SubnetID(2), + IOAddress("192.0.2.3"), "somehost.example.org"), + isc::BadValue); + + // Use invalid HW address. + EXPECT_THROW(Host("010203040506", "hw-address", SubnetID(1), SubnetID(2), + IOAddress("192.0.2.3"), "somehost.example.org"), + isc::BadValue); +} + +TEST(HostTest, createFromDUIDString) { + boost::scoped_ptr host; + /* ASSERT_NO_THROW(host.reset(new Host("a1:b2:c3:d4:e5:06", "duid", + SubnetID(10), SubnetID(20), + IOAddress("192.0.2.5"), + "me.example.org"))); */ + + try { + host.reset(new Host("a1:b2:c3:d4:e5:06", "duid", + SubnetID(10), SubnetID(20), + IOAddress("192.0.2.5"), + "me.example.org")); + } catch (const std::exception& ex) { + std::cout << ex.what() << std::endl; + } + + DuidPtr duid = host->getDuid(); + ASSERT_TRUE(duid); + + EXPECT_EQ("a1:b2:c3:d4:e5:06", duid->toText()); + + /* EXPECT_FALSE(host->getDuid()); + EXPECT_EQ(1, host->getIPv4SubnetID()); + EXPECT_EQ(2, host->getIPv6SubnetID()); + EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText()); + EXPECT_EQ("somehost.example.org", host->getHostname()); + + // Use invalid identifier name + EXPECT_THROW(Host("01:02:03:04:05:06", "bogus", SubnetID(1), SubnetID(2), + IOAddress("192.0.2.3"), "somehost.example.org"), + isc::BadValue); + + // Use invalid HW address. + EXPECT_THROW(Host("010203040506", "hw-address", SubnetID(1), SubnetID(2), + IOAddress("192.0.2.3"), "somehost.example.org"), + isc::BadValue); */ +} + + + +} // end of anonymous namespace