Parcourir la source

[4552] Updated Host object with DHCPv4 specific message fields.

Marcin Siodelski il y a 8 ans
Parent
commit
111e0e73ed
3 fichiers modifiés avec 151 ajouts et 10 suppressions
  1. 50 6
      src/lib/dhcpsrv/host.cc
  2. 57 2
      src/lib/dhcpsrv/host.h
  3. 44 2
      src/lib/dhcpsrv/tests/host_unittest.cc

+ 50 - 6
src/lib/dhcpsrv/host.cc

@@ -74,14 +74,20 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
            const asiolink::IOAddress& ipv4_reservation,
            const std::string& hostname,
            const std::string& dhcp4_client_classes,
-           const std::string& dhcp6_client_classes)
+           const std::string& dhcp6_client_classes,
+           const asiolink::IOAddress& next_server,
+           const std::string& server_host_name,
+           const std::string& boot_file_name)
+
     : identifier_type_(identifier_type),
       identifier_value_(), ipv4_subnet_id_(ipv4_subnet_id),
       ipv6_subnet_id_(ipv6_subnet_id),
       ipv4_reservation_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
       hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
-      dhcp6_client_classes_(dhcp6_client_classes), host_id_(0),
-      cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
+      dhcp6_client_classes_(dhcp6_client_classes),
+      next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
+      server_host_name_(server_host_name), boot_file_name_(boot_file_name),
+      host_id_(0), cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
 
     // Initialize host identifier.
     setIdentifier(identifier, identifier_len, identifier_type);
@@ -90,6 +96,11 @@ Host::Host(const uint8_t* identifier, const size_t identifier_len,
         // Validate and set IPv4 address reservation.
         setIPv4Reservation(ipv4_reservation);
     }
+
+    if (!next_server.isV4Zero()) {
+        // Validate and set next server address.
+        setNextServer(next_server);
+    }
 }
 
 Host::Host(const std::string& identifier, const std::string& identifier_name,
@@ -97,14 +108,19 @@ Host::Host(const std::string& identifier, const std::string& identifier_name,
            const asiolink::IOAddress& ipv4_reservation,
            const std::string& hostname,
            const std::string& dhcp4_client_classes,
-           const std::string& dhcp6_client_classes)
+           const std::string& dhcp6_client_classes,
+           const asiolink::IOAddress& next_server,
+           const std::string& server_host_name,
+           const std::string& boot_file_name)
     : identifier_type_(IDENT_HWADDR),
       identifier_value_(), ipv4_subnet_id_(ipv4_subnet_id),
       ipv6_subnet_id_(ipv6_subnet_id),
       ipv4_reservation_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
       hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
-      dhcp6_client_classes_(dhcp6_client_classes), host_id_(0),
-      cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
+      dhcp6_client_classes_(dhcp6_client_classes),
+      next_server_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
+      server_host_name_(server_host_name), boot_file_name_(boot_file_name),
+      host_id_(0), cfg_option4_(new CfgOption()), cfg_option6_(new CfgOption()) {
 
     // Initialize host identifier.
     setIdentifier(identifier, identifier_name);
@@ -113,6 +129,11 @@ Host::Host(const std::string& identifier, const std::string& identifier_name,
         // Validate and set IPv4 address reservation.
         setIPv4Reservation(ipv4_reservation);
     }
+
+    if (!next_server.isV4Zero()) {
+        // Validate and set next server address.
+        setNextServer(next_server);
+    }
 }
 
 const std::vector<uint8_t>&
@@ -339,6 +360,19 @@ Host::addClientClassInternal(ClientClasses& classes,
     }
 }
 
+void
+Host::setNextServer(const asiolink::IOAddress& next_server) {
+    if (!next_server.isV4()) {
+        isc_throw(isc::BadValue, "next server address '" << next_server
+                  << "' is not a valid IPv4 address");
+    } else if (next_server.isV4Zero() || next_server.isV4Bcast()) {
+        isc_throw(isc::BadValue, "invalid next server address '"
+                  << next_server << "'");
+    }
+
+    next_server_ = next_server;
+}
+
 std::string
 Host::toText() const {
     std::ostringstream s;
@@ -363,6 +397,16 @@ Host::toText() const {
     s << " ipv4_reservation=" << (ipv4_reservation_.isV4Zero() ? "(no)" :
                                   ipv4_reservation_.toText());
 
+    // Add next server.
+    s << " siaddr=" << (next_server_.isV4Zero() ? "(no)" :
+                             next_server_.toText());
+
+    // Add server host name.
+    s << " sname=" << (server_host_name_.empty() ? "(empty)" : server_host_name_);
+
+    // Add boot file name.
+    s << " file=" << (boot_file_name_.empty() ? "(empty)" : boot_file_name_);
+
     if (ipv6_reservations_.empty()) {
         s << " ipv6_reservations=(none)";
 

+ 57 - 2
src/lib/dhcpsrv/host.h

@@ -214,6 +214,9 @@ public:
     /// separated by commas. The names get trimmed by this constructor.
     /// @param dhcp6_client_classes A string holding DHCPv6 client class names
     /// separated by commas. The names get trimmed by this constructor.
+    /// @param next_server IPv4 address of next server (siaddr).
+    /// @param server_host_name Server host name (a.k.a. sname).
+    /// @param boot_file_name Boot file name (a.k.a. file).
     ///
     /// @throw BadValue if the provided values are invalid. In particular,
     /// if the identifier is invalid.
@@ -223,7 +226,10 @@ public:
          const asiolink::IOAddress& ipv4_reservation,
          const std::string& hostname = "",
          const std::string& dhcp4_client_classes = "",
-         const std::string& dhcp6_client_classes = "");
+         const std::string& dhcp6_client_classes = "",
+         const asiolink::IOAddress& next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS(),
+         const std::string& server_host_name = "",
+         const std::string& boot_file_name = "");
 
     /// @brief Constructor.
     ///
@@ -258,6 +264,9 @@ public:
     /// separated by commas. The names get trimmed by this constructor.
     /// @param dhcp6_client_classes A string holding DHCPv6 client class names
     /// separated by commas. The names get trimmed by this constructor.
+    /// @param next_server IPv4 address of next server (siaddr).
+    /// @param server_host_name Server host name (a.k.a. sname).
+    /// @param boot_file_name Boot file name (a.k.a. file).
     ///
     /// @throw BadValue if the provided values are invalid. In particular,
     /// if the identifier is invalid.
@@ -266,7 +275,10 @@ public:
          const asiolink::IOAddress& ipv4_reservation,
          const std::string& hostname = "",
          const std::string& dhcp4_client_classes = "",
-         const std::string& dhcp6_client_classes = "");
+         const std::string& dhcp6_client_classes = "",
+         const asiolink::IOAddress& next_server = asiolink::IOAddress::IPV4_ZERO_ADDRESS(),
+         const std::string& server_host_name = "",
+         const std::string& boot_file_name = "");
 
     /// @brief Replaces currently used identifier with a new identifier.
     ///
@@ -449,6 +461,43 @@ public:
         return (dhcp6_client_classes_);
     }
 
+    /// @brief Sets new value for next server field (siaddr).
+    ///
+    /// @param next_server New address of a next server.
+    ///
+    /// @throw isc::BadValue if the provided address is not an IPv4 address,
+    /// is a 0 address or broadcast address.
+    void setNextServer(const asiolink::IOAddress& next_server);
+
+    /// @brief Returns value of next server field (siaddr).
+    const asiolink::IOAddress& getNextServer() const {
+        return (next_server_);
+    }
+
+    /// @brief Sets new value for server hostname (sname).
+    ///
+    /// @param server_host_name New value for server hostname.
+    void setServerHostname(const std::string& server_host_name) {
+        server_host_name_ = server_host_name;
+    }
+
+    /// @brief Returns value of server hostname (sname).
+    std::string getServerHostname() const {
+        return (server_host_name_);
+    }
+
+    /// @brief Sets new value for boot file name (file).
+    ///
+    /// @param boot_file_name New value of boot file name.
+    void setBootFileName(const std::string& boot_file_name) {
+        boot_file_name_ = boot_file_name;
+    }
+
+    /// @brief Returns value of boot file name (file).
+    std::string getBootFileName() const {
+        return (boot_file_name_);
+    }
+
     /// @brief Returns pointer to the DHCPv4 option data configuration for
     /// this host.
     ///
@@ -527,6 +576,12 @@ private:
     ClientClasses dhcp4_client_classes_;
     /// @brief Collection of classes associated with a DHCPv6 client.
     ClientClasses dhcp6_client_classes_;
+    /// @brief Next server (a.k.a. siaddr, carried in DHCPv4 message).
+    asiolink::IOAddress next_server_;
+    /// @brief Server host name (a.k.a. sname, carried in DHCPv4 message).
+    std::string server_host_name_;
+    /// @brief Boot file name (a.k.a. file, carried in DHCPv4 message)
+    std::string boot_file_name_;
 
     /// @brief HostID (a unique identifier assigned when the host is stored in
     ///                MySQL or Pgsql)

+ 44 - 2
src/lib/dhcpsrv/tests/host_unittest.cc

@@ -192,7 +192,11 @@ TEST_F(HostTest, createFromHWAddrString) {
     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")));
+                                        "somehost.example.org",
+                                        std::string(), std::string(),
+                                        IOAddress("192.0.0.2"),
+                                        "server-hostname.example.org",
+                                        "bootfile.efi")));
     // The HW address should be set to non-null.
     HWAddrPtr hwaddr = host->getHWAddress();
     ASSERT_TRUE(hwaddr);
@@ -205,6 +209,9 @@ TEST_F(HostTest, createFromHWAddrString) {
     EXPECT_EQ(2, host->getIPv6SubnetID());
     EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
     EXPECT_EQ("somehost.example.org", host->getHostname());
+    EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
+    EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
+    EXPECT_EQ("bootfile.efi", host->getBootFileName());
 
     // Use invalid identifier name
     EXPECT_THROW(Host("01:02:03:04:05:06", "bogus", SubnetID(1), SubnetID(2),
@@ -264,7 +271,12 @@ TEST_F(HostTest, createFromHWAddrBinary) {
                                         Host::IDENT_HWADDR,
                                         SubnetID(1), SubnetID(2),
                                         IOAddress("192.0.2.3"),
-                                        "somehost.example.org")));
+                                        "somehost.example.org",
+                                        std::string(), std::string(),
+                                        IOAddress("192.0.0.2"),
+                                        "server-hostname.example.org",
+                                        "bootfile.efi")));
+
     // Hardware address should be non-null.
     HWAddrPtr hwaddr = host->getHWAddress();
     ASSERT_TRUE(hwaddr);
@@ -277,6 +289,9 @@ TEST_F(HostTest, createFromHWAddrBinary) {
     EXPECT_EQ(2, host->getIPv6SubnetID());
     EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
     EXPECT_EQ("somehost.example.org", host->getHostname());
+    EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
+    EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
+    EXPECT_EQ("bootfile.efi", host->getBootFileName());
 }
 
 // This test verifies that it is possible to create a Host object using
@@ -644,11 +659,17 @@ TEST_F(HostTest, setValues) {
     host->setIPv6SubnetID(SubnetID(234));
     host->setIPv4Reservation(IOAddress("10.0.0.1"));
     host->setHostname("other-host.example.org");
+    host->setNextServer(IOAddress("192.0.2.2"));
+    host->setServerHostname("server-hostname.example.org");
+    host->setBootFileName("bootfile.efi");
 
     EXPECT_EQ(123, host->getIPv4SubnetID());
     EXPECT_EQ(234, host->getIPv6SubnetID());
     EXPECT_EQ("10.0.0.1", host->getIPv4Reservation().toText());
     EXPECT_EQ("other-host.example.org", host->getHostname());
+    EXPECT_EQ("192.0.2.2", host->getNextServer().toText());
+    EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
+    EXPECT_EQ("bootfile.efi", host->getBootFileName());
 
     // Remove IPv4 reservation.
     host->removeIPv4Reservation();
@@ -664,6 +685,12 @@ TEST_F(HostTest, setValues) {
     // Broadcast address can't be set.
     EXPECT_THROW(host->setIPv4Reservation(IOAddress::IPV4_BCAST_ADDRESS()),
                  isc::BadValue);
+
+    // Zero or broadcast are invalid addresses for next server.
+    EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
+                 isc::BadValue);
+    EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_BCAST_ADDRESS()),
+                                     isc::BadValue);
 }
 
 // Test that Host constructors initialize client classes from string.
@@ -918,6 +945,9 @@ TEST_F(HostTest, toText) {
     EXPECT_EQ("hwaddr=010203040506 ipv4_subnet_id=1 ipv6_subnet_id=2"
               " hostname=myhost.example.com"
               " ipv4_reservation=192.0.2.3"
+              " siaddr=(no)"
+              " sname=(empty)"
+              " file=(empty)"
               " ipv6_reservation0=2001:db8:1::cafe"
               " ipv6_reservation1=2001:db8:1::1"
               " ipv6_reservation2=2001:db8:1:1::/64"
@@ -931,6 +961,9 @@ TEST_F(HostTest, toText) {
 
     EXPECT_EQ("hwaddr=010203040506 ipv6_subnet_id=2"
               " hostname=(empty) ipv4_reservation=(no)"
+              " siaddr=(no)"
+              " sname=(empty)"
+              " file=(empty)"
               " ipv6_reservation0=2001:db8:1::cafe"
               " ipv6_reservation1=2001:db8:1::1"
               " ipv6_reservation2=2001:db8:1:1::/64"
@@ -945,6 +978,9 @@ TEST_F(HostTest, toText) {
                                         "myhost")));
 
     EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
+              " siaddr=(no)"
+              " sname=(empty)"
+              " file=(empty)"
               " ipv6_reservations=(none)", host->toText());
 
     // Add some classes.
@@ -952,6 +988,9 @@ TEST_F(HostTest, toText) {
     host->addClientClass4("router");
 
     EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
+              " siaddr=(no)"
+              " sname=(empty)"
+              " file=(empty)"
               " ipv6_reservations=(none)"
               " dhcp4_class0=modem dhcp4_class1=router",
               host->toText());
@@ -960,6 +999,9 @@ TEST_F(HostTest, toText) {
     host->addClientClass6("device");
 
     EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
+              " siaddr=(no)"
+              " sname=(empty)"
+              " file=(empty)"
               " ipv6_reservations=(none)"
               " dhcp4_class0=modem dhcp4_class1=router"
               " dhcp6_class0=device dhcp6_class1=hub",