Browse Source

[3689] Added host reservation tests

src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
    added tests:
    TEST_F(Dhcpv6SrvTest, hostReservationWithHostName)
    TEST_F(Dhcpv6SrvTest, hostReservationWithoutHostName)

src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/dhcp6/tests/dhcp6_test_utils.cc
    Dhcpv6SrvTest::createHost6() - this method was moved
    here from FqdnDhcpv6SrvTest()

src/bin/dhcp6/tests/fqdn_unittest.cc
    added tests:
    TEST_F(FqdnDhcpv6SrvTest, hostnameReservationSuffix)
    TEST_F(FqdnDhcpv6SrvTest, hostnameReservationNoSuffix)
    TEST_F(FqdnDhcpv6SrvTest, hostnameReservationDdnsDisabled)
Thomas Markwalder 10 years ago
parent
commit
c387c4ca70

+ 116 - 0
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -2094,7 +2094,123 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) {
     EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol));
 }
 
+// Verify that a host reservation is used and that the lease name is set to
+// the reservation hostname.
+TEST_F(Dhcpv6SrvTest, hostReservationWithHostName) {
+    // set duid_ for createHost6
+    generateClientId();
+
+    // create host reservation
+    IOAddress res_address("2001:db8:1:1::babe");
+    createHost6(true, IPv6Resrv::TYPE_NA, res_address, "alice");
+
+    // Let's create a REQUEST
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
+    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
+
+    // with a valid hint
+    IOAddress hint("2001:db8:1:1::dead:beef");
+    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
+
+    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
+    ia->addOption(hint_opt);
+    req->addOption(ia);
+
+    // Set client id to match duid_
+    OptionPtr clientid = generateClientId();
+    req->addOption(clientid);
+
+    // server-id is mandatory in REQUEST
+    req->addOption(srv_.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv_.processRequest(req);
+
+    // check if we get response at all
+    checkResponse(reply, DHCPV6_REPLY, 1234);
+
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
+    ASSERT_TRUE(tmp);
+
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234,
+                                                       subnet_->getT1(),
+                                                       subnet_->getT2());
+    ASSERT_TRUE(addr);
+
+    // check that we've got the address we requested
+    checkIAAddr(addr, res_address, Lease::TYPE_NA);
+
+    // check that the lease is really in the database
+    Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
+    ASSERT_TRUE(l);
+
+    // Verify that lease hostname matches the reservation name
+    EXPECT_EQ("alice", l->hostname_);
+}
+
+// Verify that a host reservation is used and that the lease name is blank
+// when the reservation hostname is blank.
+TEST_F(Dhcpv6SrvTest, hostReservationWithoutHostName) {
+    // set duid_ for createHost6
+    generateClientId();
+
+    // create host reservation
+    IOAddress res_address("2001:db8:1:1::babe");
+    createHost6(true, IPv6Resrv::TYPE_NA, res_address, "");
+
+    // Let's create a REQUEST
+    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
+    req->setRemoteAddr(IOAddress("fe80::abcd"));
+    req->setIface("eth0");
+    boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
+
+    // with a valid hint
+    IOAddress hint("2001:db8:1:1::dead:beef");
+    ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
+
+    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
+    ia->addOption(hint_opt);
+    req->addOption(ia);
+
+    // Set client id to match duid_
+    OptionPtr clientid = generateClientId();
+    req->addOption(clientid);
+
+    // server-id is mandatory in REQUEST
+    req->addOption(srv_.getServerID());
+
+    // Pass it to the server and hope for a REPLY
+    Pkt6Ptr reply = srv_.processRequest(req);
+
+    // check if we get response at all
+    checkResponse(reply, DHCPV6_REPLY, 1234);
+
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
+    ASSERT_TRUE(tmp);
+
+    // check that IA_NA was returned and that there's an address included
+    boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234,
+                                                       subnet_->getT1(),
+                                                       subnet_->getT2());
+    ASSERT_TRUE(addr);
+
+    // check that we've got the address we requested
+    checkIAAddr(addr, res_address, Lease::TYPE_NA);
+
+    // check that the lease is really in the database
+    Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
+    ASSERT_TRUE(l);
+
+    // Verify that lease hostname matches the reservation name
+    EXPECT_EQ("", l->hostname_);
+}
+
+
 /// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
 /// to call processX() methods.
 
+
 }   // end of anonymous namespace

+ 34 - 0
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -77,6 +77,40 @@ Dhcpv6SrvTest::checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
     return (addr);
 }
 
+/// @brief Utility function that creates a host reservation (duid)
+///
+/// @param add_to_host_mgr true if the reservation should be added
+/// @param type specifies reservation type (NA or PD)
+/// @param addr specifies reserved address
+/// @param hostname specifies hostname to be used in reservation
+/// @return created Host object.
+HostPtr
+Dhcpv6SrvTest::createHost6(bool add_to_host_mgr, IPv6Resrv::Type type,
+    const asiolink::IOAddress& addr, const std::string& hostname) {
+    HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+                 Host::IDENT_DUID, SubnetID(0), subnet_->getID(),
+                 asiolink::IOAddress("0.0.0.0"), hostname));
+
+    // Prefix length doesn't matter here, let's assume address is /128 and
+    // prefix is /64
+    IPv6Resrv resv(type, addr, type == IPv6Resrv::TYPE_NA? 128 : 64);
+    host->addReservation(resv);
+
+    if (add_to_host_mgr) {
+
+    // Let's add the host.
+    CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+
+    // We also need to add existing subnet
+    CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
+
+    // Commit this configuration.
+    CfgMgr::instance().commit();
+    }
+
+    return (host);
+}
+
 boost::shared_ptr<Option6IAPrefix>
 Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid,
                           uint32_t expected_t1, uint32_t expected_t2) {

+ 11 - 0
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -345,6 +345,17 @@ public:
     /// @param srv Server to be configured.
     void configure(const std::string& config, NakedDhcpv6Srv& srv);
 
+    /// @brief Utility function that creates a host reservation (duid)
+    ///
+    /// @param add_to_host_mgr true if the reservation should be added
+    /// @param type specifies reservation type (NA or PD)
+    /// @param addr specifies reserved address
+    /// @param hostname specifies hostname to be used in reservation
+    /// @return created Host object.
+    isc::dhcp::HostPtr
+    createHost6(bool add_to_host_mgr, isc::dhcp::IPv6Resrv::Type type,
+                const asiolink::IOAddress& addr, const std::string& hostname);
+
     /// @brief Checks that server response (ADVERTISE or REPLY) contains proper
     ///        IA_NA option
     ///

+ 102 - 37
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -507,40 +507,6 @@ public:
         ASSERT_NO_THROW(d2_mgr_.runReadyIO());
     }
 
-    /// @brief Utility function that creates a host reservation (duid)
-    ///
-    /// @param add_to_host_mgr true if the reservation should be added
-    /// @param type specifies reservation type (NA or PD)
-    /// @param addr specifies reserved address
-    /// @param hostname specifies hostname to be used in reservation
-    /// @return created Host object.
-    HostPtr
-    createHost6(bool add_to_host_mgr, IPv6Resrv::Type type,
-                const asiolink::IOAddress& addr, const std::string& hostname) {
-        HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
-                              Host::IDENT_DUID, SubnetID(0), subnet_->getID(),
-                              asiolink::IOAddress("0.0.0.0"),
-                              hostname));
-
-        // Prefix length doesn't matter here, let's assume address is /128 and
-        // prefix is /64
-        IPv6Resrv resv(type, addr, type == IPv6Resrv::TYPE_NA? 128 : 64);
-        host->addReservation(resv);
-
-        if (add_to_host_mgr) {
-
-            // Let's add the host.
-            CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
-
-            // We also need to add existing subnet
-            CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
-
-            // Commit this configuration.
-            CfgMgr::instance().commit();
-        }
-        return (host);
-    }
-
     // Holds a lease used by a test.
     Lease6Ptr lease_;
 
@@ -1088,15 +1054,114 @@ TEST_F(FqdnDhcpv6SrvTest, processClientDelegation) {
                             0, 4000);
 }
 
-TEST_F(FqdnDhcpv6SrvTest, hostnameReservation) {
+// Verify that the host reservation is found and used. Lease host name and
+// FQDN should be the reservation hostname suffixed by the qualifying suffix.
+TEST_F(FqdnDhcpv6SrvTest, hostnameReservationSuffix) {
+    // Create host reservation with a partial FQDN for hostname
+    createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
+                "alice");
+
+    // Verify that the host reservation is found and lease name/FQDN are
+    // formed properly from the host name and qualifying suffix.
+    testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
+                       "alice.example.com.", 0, IOAddress("2001:db8:1:1::babe"));
+    ASSERT_EQ(1, d2_mgr_.getQueueSize());
+}
+
+// Verify that the host reservation is found and used, rather than dynamic
+// Address.  Lease host name and FQDN should be the reservation hostname
+// without a qualifying suffix.
+TEST_F(FqdnDhcpv6SrvTest, hostnameReservationNoSuffix) {
+
+    string config_str = "{ "
+        "\"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"preferred-lifetime\": 3000,"
+        "\"valid-lifetime\": 4000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ], "
+        " \"dhcp-ddns\" : {"
+        "     \"enable-updates\" : true, "
+        "     \"server-ip\" : \"::1\", "
+        "     \"server-port\" : 53001, "
+        "     \"sender-ip\" : \"::\", "
+        "     \"sender-port\" : 0, "
+        "     \"max-queue-size\" : 2048, "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"allow-client-update\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"\" },"
+        "\"valid-lifetime\": 4000 }";
+
+    configure(config_str);
+
+    ASSERT_NO_THROW(srv_->startD2());
+
+    ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
 
     createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
-                "alice.example.org.");
+                "alice.example.com");
 
     testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
-                       "alice.example.org.", 0, IOAddress("2001:db8:1:1::babe"));
+                       "alice.example.com.", 0, IOAddress("2001:db8:1:1::babe"));
     ASSERT_EQ(1, d2_mgr_.getQueueSize());
 }
 
+// Verify that the host reservation is found and used, rather than dynamic
+// Address.  Lease host name and FQDN should be the reservation hostname
+// with the qualifying suffix even though updates are disabled.
+TEST_F(FqdnDhcpv6SrvTest, hostnameReservationDdnsDisabled) {
+
+    string config_str = "{ "
+        "\"interfaces-config\": {"
+        "  \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"preferred-lifetime\": 3000,"
+        "\"valid-lifetime\": 4000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ], "
+        " \"dhcp-ddns\" : {"
+        "     \"enable-updates\" : false, "
+        "     \"server-ip\" : \"::1\", "
+        "     \"server-port\" : 53001, "
+        "     \"sender-ip\" : \"::\", "
+        "     \"sender-port\" : 0, "
+        "     \"max-queue-size\" : 2048, "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"allow-client-update\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"disabled.example.com\" },"
+        "\"valid-lifetime\": 4000 }";
+
+    configure(config_str);
+
+    ASSERT_NO_THROW(srv_->startD2());
+
+    ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
+
+    createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
+                "alice");
+
+    testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
+                       "alice.disabled.example.com.", 0, 
+                       IOAddress("2001:db8:1:1::babe"));
+}
 
 }   // end of anonymous namespace