Parcourir la source

[3560] Basic implementation of the Host class.

Marcin Siodelski il y a 10 ans
Parent
commit
e205a10dab

+ 2 - 0
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
 

+ 79 - 0
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 <dhcpsrv/host.h>
+#include <exceptions/exceptions.h>
+
+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<int>(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

+ 154 - 0
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 <asiolink/io_address.h>
+#include <dhcp/classify.h>
+#include <dhcp/duid.h>
+#include <dhcp/hwaddr.h>
+#include <dhcpsrv/subnet_id.h>
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+
+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<IPv6Resrv::Type, IPv6Resrv> IPv6ResrvCollection;
+typedef IPv6ResrvCollection::iterator IPv6ResrvIterator;
+typedef std::pair<IPv6ResrvIterator, IPv6ResrvIterator> 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

+ 32 - 0
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

+ 1 - 0
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

+ 122 - 0
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 <config.h>
+
+#include <dhcpsrv/host.h>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+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> 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> 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