Browse Source

[master] Merge branch 'trac4339a'

Marcin Siodelski 9 years ago
parent
commit
a065144663

+ 4 - 3
src/lib/dhcpsrv/lease.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -293,13 +293,14 @@ Lease6::toText() const {
 
     /// @todo: print out DUID
     stream << "Type:          " << typeToText(type_) << "("
-           << static_cast<int>(type_) << ")\n";
-    stream << "Address:       " << addr_ << "\n"
+           << static_cast<int>(type_) << ")\n"
+           << "Address:       " << addr_ << "\n"
            << "Prefix length: " << static_cast<int>(prefixlen_) << "\n"
            << "IAID:          " << iaid_ << "\n"
            << "Pref life:     " << preferred_lft_ << "\n"
            << "Valid life:    " << valid_lft_ << "\n"
            << "Cltt:          " << cltt_ << "\n"
+           << "DUID:          " << (duid_?duid_->toText():"(none)") << "\n"
            << "Hardware addr: " << (hwaddr_?hwaddr_->toText(false):"(none)") << "\n"
            << "Subnet ID:     " << subnet_id_ << "\n"
            << "State:         " << statesToText(state_) << "\n";

+ 3 - 2
src/lib/dhcpsrv/lease_file_loader.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -135,7 +135,8 @@ public:
                         storage.erase(lease_it);
 
                     } else {
-                        **lease_it = *lease;
+                        // Use replace to re-index leases on update.
+                        storage.replace(lease_it, lease);
                     }
                 }
 

+ 3 - 1
src/lib/dhcpsrv/tests/lease_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -838,6 +838,7 @@ TEST(Lease6Test, toText) {
              << "Pref life:     400\n"
              << "Valid life:    800\n"
              << "Cltt:          12345678\n"
+             << "DUID:          00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\n"
              << "Hardware addr: " << hwaddr->toText(false) << "\n"
              << "Subnet ID:     5678\n"
              << "State:         declined\n";
@@ -854,6 +855,7 @@ TEST(Lease6Test, toText) {
              << "Pref life:     400\n"
              << "Valid life:    800\n"
              << "Cltt:          12345678\n"
+             << "DUID:          00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\n"
              << "Hardware addr: (none)\n"
              << "Subnet ID:     5678\n"
              << "State:         declined\n";

+ 374 - 1
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -19,6 +19,7 @@
 #include <dhcpsrv/tests/test_utils.h>
 #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 #include <util/pid_file.h>
+#include <util/range_utilities.h>
 #include <util/stopwatch.h>
 #include <gtest/gtest.h>
 
@@ -232,6 +233,111 @@ public:
         return (iterations < iterations_max);
     }
 
+    /// @brief Generates a DHCPv4 lease with random content.
+    ///
+    /// The following lease parameters are randomly generated:
+    /// - HW address,
+    /// - client identifier,
+    /// - hostname,
+    /// - subnet identifier,
+    /// - client last transmission time,
+    ///
+    /// The following lease parameters are set to constant values:
+    /// - valid lifetime = 1200,
+    /// - T1 = 600,
+    /// - T2 = 900,
+    /// - DNS update forward flag = false,
+    /// - DNS update reverse flag = false,
+    ///
+    /// The lease address is set to address passed as function
+    /// argument.
+    ///
+    /// @param address Lease address.
+    ///
+    /// @return new lease with random content
+    Lease4Ptr initiateRandomLease4(const IOAddress& address) {
+
+        // Randomize HW address.
+        vector<uint8_t> mac(6);
+        fillRandom(mac.begin(), mac.end());
+        HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER));
+
+        // Let's generate clientid of random length
+        vector<uint8_t> clientid(4 + random()%20);
+        // And then fill it with random value.
+        fillRandom(clientid.begin(), clientid.end());
+
+        uint32_t valid_lft = 1200;
+        uint32_t t1 = 600;
+        uint32_t t2 = 900;
+        time_t timestamp = time(NULL) - 86400 + random()%86400;
+        bool fqdn_fwd = false;
+        bool fqdn_rev = false;
+        uint32_t subnet_id = 1000 + random()%16;
+
+        std::ostringstream hostname;
+        hostname << "hostname" << (random() % 2048);
+
+        // Return created lease.
+        return (Lease4Ptr(new Lease4(address, hwaddr, &clientid[0],
+                                     clientid.size(), valid_lft, t1, t2,
+                                     timestamp, subnet_id, fqdn_fwd,
+                                     fqdn_rev, hostname.str())));
+    }
+
+    /// @brief Generates a DHCPv6 lease with random content.
+    ///
+    /// The following lease parameters are randomly generated:
+    /// - DUID,
+    /// - IAID,
+    /// - hostname,
+    /// - subnet identifier,
+    /// - client last transmission time,
+    ///
+    /// The following lease parameters are set to constant values:
+    /// - lease type = IA_NA
+    /// - valid lifetime = 1200,
+    /// - preferred lifetime = 1000
+    /// - T1 = 600,
+    /// - T2 = 900,
+    /// - DNS update forward flag = false,
+    /// - DNS update reverse flag = false,
+    ///
+    /// The lease address is set to address passed as function
+    /// argument.
+    ///
+    /// @param address Lease address.
+    ///
+    /// @return new lease with random content
+    Lease6Ptr initiateRandomLease6(const IOAddress& address) {
+        // Let's generate DUID of random length.
+        std::vector<uint8_t> duid_vec(8 + random()%20);
+        // And then fill it with random value.
+        fillRandom(duid_vec.begin(), duid_vec.end());
+        DuidPtr duid(new DUID(duid_vec));
+
+        Lease::Type lease_type = Lease::TYPE_NA;
+        uint32_t iaid = 1 + random()%100;
+        uint32_t valid_lft = 1200;
+        uint32_t preferred_lft = 1000;
+        uint32_t t1 = 600;
+        uint32_t t2 = 900;
+        time_t timestamp = time(NULL) - 86400 + random()%86400;
+        bool fqdn_fwd = false;
+        bool fqdn_rev = false;
+        uint32_t subnet_id = 1000 + random()%16;
+
+        std::ostringstream hostname;
+        hostname << "hostname" << (random() % 2048);
+
+        // Return created lease.
+        Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid,
+                                   preferred_lft, valid_lft, t1, t2,
+                                   subnet_id, fqdn_fwd, fqdn_rev,
+                                   hostname.str()));
+        lease->cltt_ = timestamp;
+        return (lease);
+    }
 
     /// @brief Object providing access to v4 lease IO.
     LeaseFileIO io4_;
@@ -1513,4 +1619,271 @@ TEST_F(MemfileLeaseMgrTest, leaseUpgrade6) {
     EXPECT_EQ(result_file_contents, input_file.readFile());
 }
 
+// This test verifies that the indexes of the container holding
+// DHCPv4 leases are updated correctly when a lease is updated.
+TEST_F(MemfileLeaseMgrTest, lease4ContainerIndexUpdate) {
+
+    const uint32_t seed = 12345678; // Used to initialize the random generator
+    const uint32_t leases_cnt = 100; // Number of leases generated per round.
+    const uint32_t updates_cnt = 5; // Number of times existing leases are updated
+
+    const string leasefile(getLeaseFilePath("leasefile4_0.csv"));
+
+    // Parameters for the lease file. Make sure the leases are persistent, so they
+    // are written to disk.
+    DatabaseConnection::ParameterMap pmap;
+    pmap["universe"] = "4";
+    pmap["name"] = leasefile;
+    pmap["persist"] = "true";
+
+    srand(seed);
+
+    IOAddress addr("10.0.0.1"); // Let's generate leases sequentially
+
+    // Recreate Memfile_LeaseMgr.
+    LeaseMgrFactory::destroy();
+    ASSERT_NO_THROW(lmptr_ = new Memfile_LeaseMgr(pmap));
+
+    // We will store addresses here, so it will be easier to randomly
+    // pick a lease.
+    std::vector<IOAddress> lease_addresses;
+
+    // Generarate random leases. We remember their addresses in
+    // lease_addresses.
+    for (uint32_t i = 0; i < leases_cnt; ++i) {
+        Lease4Ptr lease = initiateRandomLease4(addr);
+        lease_addresses.push_back(addr);
+        ASSERT_NO_THROW(lmptr_->addLease(lease));
+        addr = IOAddress::increase(addr);
+    }
+
+    // Check that we inserted correct number of leases.
+    ASSERT_EQ(leases_cnt, lease_addresses.size());
+
+    // Now, conduct updates. We call initiateRandomLease4(), so most
+    // of the fields are randomly changed. The only constant field
+    // is the address.
+    for (uint32_t i = 0; i < updates_cnt; ++i) {
+        uint32_t offset = random() % lease_addresses.size();
+        Lease4Ptr existing(lmptr_->getLease4(lease_addresses[offset]));
+        Lease4Ptr updated(initiateRandomLease4(lease_addresses[offset]));
+
+        // Update a lease with new data but preserve lease address.
+        // This update should also cause lease container indexes to
+        // be updated.
+        ASSERT_NO_THROW(lmptr_->updateLease4(updated))
+            << "Attempt " << i << " out of " << updates_cnt
+            << ":Failed to update lease for address "
+            << lease_addresses[offset];
+    }
+
+    // Re-create lease manager to cause it to reload leases
+    // from a lease file. We want to make sure that lease
+    // container is rebuilt correctly and the indexes are
+    // consistent with lease information held.
+    ASSERT_NO_THROW({
+        LeaseMgrFactory::destroy();
+        lmptr_ = new Memfile_LeaseMgr(pmap);
+    });
+
+    // Ok, let's check if the leases are really accessible.
+    // First, build an array of leases. Get them by address.
+    // This should work in general, as we haven't updated the addresses.
+    std::vector<Lease4Ptr> leases;
+    for (uint32_t i = 0; i < lease_addresses.size(); ++i) {
+        Lease4Ptr from_mgr = lmptr_->getLease4(lease_addresses[i]);
+        ASSERT_TRUE(from_mgr) << "Lease for address " << lease_addresses[i].toText()
+                              << " not found";
+        leases.push_back(from_mgr);
+    }
+
+    ASSERT_EQ(leases_cnt, leases.size());
+
+    // Now do the actual checks.
+    for (uint32_t i = 0; i < leases.size(); ++i) {
+        Lease4Ptr tested = leases[i];
+
+        // Get the lease by different access patterns.
+        // In properly working lease manager all queries should return
+        // exactly the same lease.
+
+        std::string error_desc = " which indicates that the lease indexes were"
+            " not updated correctly when the lease was updated.";
+
+        // Retrieve lease by address.
+        Lease4Ptr lease_by_address = lmptr_->getLease4(tested->addr_);
+        ASSERT_TRUE(lease_by_address)
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease4(addr)"
+            << error_desc;
+        detailCompareLease(tested, lease_by_address);
+
+        // Retrieve lease by HW address and subnet id.
+        Lease4Ptr lease_by_hwaddr_subnet = lmptr_->getLease4(*tested->hwaddr_,
+                                                             tested->subnet_id_);
+        ASSERT_TRUE(lease_by_hwaddr_subnet)
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease4(hwaddr, subnet_id)"
+            << error_desc;
+        detailCompareLease(tested, lease_by_hwaddr_subnet);
+
+        // Retrieve lease by client identifier and subnet id.
+        Lease4Ptr lease_by_clientid_subnet = lmptr_->getLease4(*tested->client_id_,
+                                                               tested->subnet_id_);
+        ASSERT_TRUE(lease_by_clientid_subnet)
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease4(clientid, subnet_id)"
+            << error_desc;
+        detailCompareLease(tested, lease_by_clientid_subnet);
+
+        // Retrieve lease by client id, HW address and subnet.
+        Lease4Ptr lease_by_clientid_hwaddr_subnet = lmptr_->getLease4(*tested->client_id_,
+                                                                      *tested->hwaddr_,
+                                                                      tested->subnet_id_);
+        ASSERT_TRUE(lease_by_clientid_hwaddr_subnet)
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease4(clientid, hwaddr, subnet_id)"
+            << error_desc;
+        detailCompareLease(tested, lease_by_clientid_hwaddr_subnet);
+
+        // Retrieve lease by HW address.
+        Lease4Collection leases_by_hwaddr = lmptr_->getLease4(*tested->hwaddr_);
+        ASSERT_EQ(1, leases_by_hwaddr.size());
+        detailCompareLease(tested, leases_by_hwaddr[0]);
+
+        // Retrieve lease by client identifier.
+        Lease4Collection leases_by_client_id = lmptr_->getLease4(*tested->client_id_);
+        ASSERT_EQ(1, leases_by_client_id.size());
+        detailCompareLease(tested, leases_by_client_id[0]);
+    }
+}
+
+// This test verifies that the indexes of the container holding
+// DHCPv4 leases are updated correctly when a lease is updated.
+TEST_F(MemfileLeaseMgrTest, lease6ContainerIndexUpdate) {
+
+    const uint32_t seed = 12345678; // Used to initialize the random generator
+    const uint32_t leases_cnt = 100; // Number of leases generated per round.
+    const uint32_t updates_cnt = 5; // Number of times existing leases are updated
+
+    const string leasefile(getLeaseFilePath("leasefile6_0.csv"));
+
+    // Parameters for the lease file. Make sure the leases are persistent, so they
+    // are written to disk.
+    DatabaseConnection::ParameterMap pmap;
+    pmap["universe"] = "6";
+    pmap["name"] = leasefile;
+    pmap["persist"] = "true";
+
+    srand(seed);
+
+    IOAddress addr("2001:db8:1::1"); // Let's generate leases sequentially
+
+    // Recreate Memfile_LeaseMgr.
+    LeaseMgrFactory::destroy();
+    ASSERT_NO_THROW(lmptr_ = new Memfile_LeaseMgr(pmap));
+
+    // We will store addresses here, so it will be easier to randomly
+    // pick a lease.
+    std::vector<IOAddress> lease_addresses;
+
+    // Generarate random leases. We remember their addresses in
+    // lease_addresses.
+    for (uint32_t i = 0; i < leases_cnt; ++i) {
+        Lease6Ptr lease = initiateRandomLease6(addr);
+        lease_addresses.push_back(addr);
+        ASSERT_NO_THROW(lmptr_->addLease(lease));
+        addr = IOAddress::increase(addr);
+    }
+
+    // Check that we inserted correct number of leases.
+    ASSERT_EQ(leases_cnt, lease_addresses.size());
+
+    // Now, conduct updates. We call initiateRandomLease6(), so most
+    // of the fields are randomly changed. The only constant field
+    // is the address.
+    for (uint32_t i = 0; i < updates_cnt; ++i) {
+        uint32_t offset = random() % lease_addresses.size();
+        Lease6Ptr existing(lmptr_->getLease6(Lease::TYPE_NA,
+                                             lease_addresses[offset]));
+        Lease6Ptr updated(initiateRandomLease6(lease_addresses[offset]));
+
+        // Update a lease with new data but preserve lease address.
+        // This update should also cause lease container indexes to
+        // be updated.
+        ASSERT_NO_THROW(lmptr_->updateLease6(updated))
+            << "Attempt " << i << " out of " << updates_cnt
+            << ":Failed to update lease for address "
+            << lease_addresses[offset];
+    }
+
+    // Re-create lease manager to cause it to reload leases
+    // from a lease file. We want to make sure that lease
+    // container is rebuilt correctly and the indexes are
+    // consistent with lease information held.
+    ASSERT_NO_THROW({
+        LeaseMgrFactory::destroy();
+        lmptr_ = new Memfile_LeaseMgr(pmap);
+    });
+
+    // Ok, let's check if the leases are really accessible.
+    // First, build an array of leases. Get them by address.
+    // This should work in general, as we haven't updated the addresses.
+    std::vector<Lease6Ptr> leases;
+    for (uint32_t i = 0; i < lease_addresses.size(); ++i) {
+        Lease6Ptr from_mgr = lmptr_->getLease6(Lease::TYPE_NA,
+                                               lease_addresses[i]);
+        ASSERT_TRUE(from_mgr) << "Lease for address " << lease_addresses[i].toText()
+                              << " not found";
+        leases.push_back(from_mgr);
+    }
+
+    ASSERT_EQ(leases_cnt, leases.size());
+
+    // Now do the actual checks.
+    for (uint32_t i = 0; i < leases.size(); ++i) {
+        Lease6Ptr tested = leases[i];
+
+        // Get the lease by different access patterns.
+        // In properly working lease manager all queries should return
+        // exactly the same lease.
+
+        std::string error_desc = " which indicates that the lease indexes were"
+            " not updated correctly when the lease was updated.";
+
+        // Retrieve lease by address.
+        Lease6Ptr lease_by_address = lmptr_->getLease6(Lease::TYPE_NA,
+                                                       tested->addr_);
+        ASSERT_TRUE(lease_by_address)
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease6(addr)"
+            << error_desc;
+        detailCompareLease(tested, lease_by_address);
+
+        // Retrieve lease by type, DUID, IAID.
+        Lease6Collection leases_by_duid_iaid = lmptr_->getLeases6(tested->type_,
+                                                                  *tested->duid_,
+                                                                  tested->iaid_);
+        ASSERT_EQ(1, leases_by_duid_iaid.size());
+        ASSERT_TRUE(leases_by_duid_iaid[0])
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease6(type, duid, iaid)"
+            << error_desc;
+        detailCompareLease(tested, leases_by_duid_iaid[0]);
+
+        // Retrieve lease by type, DUID, IAID, subnet identifier.
+        Lease6Collection leases_by_duid_iaid_subnet =
+            lmptr_->getLeases6(tested->type_, *tested->duid_,
+                               tested->iaid_, tested->subnet_id_);
+        ASSERT_EQ(1, leases_by_duid_iaid_subnet.size());
+        ASSERT_TRUE(leases_by_duid_iaid_subnet[0])
+            << "Lease " << tested->addr_.toText()
+            << " not found by getLease6(type, duid, iaid, subnet_id)"
+            << error_desc;
+        detailCompareLease(tested, leases_by_duid_iaid_subnet[0]);
+    }
+}
+
+
+
 }; // end of anonymous namespace