diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.cc b/src/lib/dhcpsrv/dhcpsrv_messages.cc index f0f9029dbb..68a04ae832 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.cc +++ b/src/lib/dhcpsrv/dhcpsrv_messages.cc @@ -321,9 +321,9 @@ const char* values[] = { "DHCPSRV_LEASE_SANITY_FIXED", "The lease %1 with subnet-id %2 failed subnet-id checks, but was corrected to subnet-id %3.", "DHCPSRV_MEMFILE_ADD_ADDR4", "adding IPv4 lease with address %1", "DHCPSRV_MEMFILE_ADD_ADDR6", "adding IPv6 lease with address %1", - "DHCPSRV_MEMFILE_BEGIN_BUILD_EXTENDED_INFO_TABLES6", "building extended info tables with %1 sanity check level (%2)", + "DHCPSRV_MEMFILE_BEGIN_BUILD_EXTENDED_INFO_TABLES6", "building extended info tables with %1 sanity check level%2, tables %3", "DHCPSRV_MEMFILE_BEGIN_TRANSACTION", "committing to memory file database", - "DHCPSRV_MEMFILE_BUILD_EXTENDED_INFO_TABLES6", "building extended info tables saw %1 leases, extended info sanity checks modified %2 leases and %3 leases were entered into tables", + "DHCPSRV_MEMFILE_BUILD_EXTENDED_INFO_TABLES6", "building extended info tables saw %1 leases, extended info sanity checks modified %2 / updated %3 leases and %4 leases were entered into tables", "DHCPSRV_MEMFILE_BUILD_EXTENDED_INFO_TABLES6_ERROR", "building extended info tables got an exception on the lease for %1: %2", "DHCPSRV_MEMFILE_COMMIT", "committing to memory file database", "DHCPSRV_MEMFILE_CONVERTING_LEASE_FILES", "running LFC now to convert lease files to the current schema: %1.%2", diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes index d3e04367ab..f1e2ce9917 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.mes +++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes @@ -386,10 +386,10 @@ with the specified address to the memory file backend database. A debug message issued when the server is about to add an IPv6 lease with the specified address to the memory file backend database. -% DHCPSRV_MEMFILE_BEGIN_BUILD_EXTENDED_INFO_TABLES6 building extended info tables with %1 sanity check level (%2) +% DHCPSRV_MEMFILE_BEGIN_BUILD_EXTENDED_INFO_TABLES6 building extended info tables with %1 sanity check level%2, tables %3 A debug message issued when the server is building extended info tables. -The extended info sanity check level and the fact tables are enabled or -disabled are displayed. +The extended info sanity check level, update in file when requested +and the fact tables are enabled or disabled are displayed. % DHCPSRV_MEMFILE_BEGIN_TRANSACTION committing to memory file database The code has issued a begin transaction call. For the memory file database, this is @@ -399,8 +399,9 @@ a no-op. A debug message issued when the server is building extended info tables and receives an exception processing a lease. -% DHCPSRV_MEMFILE_BUILD_EXTENDED_INFO_TABLES6 building extended info tables saw %1 leases, extended info sanity checks modified %2 leases and %3 leases were entered into tables -Extended info tables build was finished. Some statistics are displayed. +% DHCPSRV_MEMFILE_BUILD_EXTENDED_INFO_TABLES6 building extended info tables saw %1 leases, extended info sanity checks modified %2 / updated %3 leases and %4 leases were entered into tables +Extended info tables build was finished. Some statistics are displayed, the +updated in database is returned to the command interface. % DHCPSRV_MEMFILE_COMMIT committing to memory file database The code has issued a commit call. For the memory file database, this is diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index 519d7d7961..038fb4ee88 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -962,7 +962,10 @@ public: } /// @brief Build extended info v6 tables. - virtual void buildExtendedInfoTables6() = 0; + /// + /// @param update Update extended info in database. + /// @return The number of updates in the database or 0. + virtual size_t buildExtendedInfoTables6(bool update) = 0; protected: diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index 22ffd53c14..30cb0b6a4e 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -660,7 +660,9 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& param CSVLeaseFile6>(file6, lease_file6_, storage6_); - buildExtendedInfoTables6Internal(); + CfgConsistency::ExtendedInfoSanity check = + CfgMgr::instance().getStagingCfg()->getConsistency()->getExtendedInfoSanityCheck(); + static_cast(buildExtendedInfoTables6Internal(check, false)); } } @@ -2845,30 +2847,34 @@ Memfile_LeaseMgr::getLeases6ByLinkInternal(const IOAddress& link_addr, return (collection); } -void -Memfile_LeaseMgr::buildExtendedInfoTables6Internal() { +size_t +Memfile_LeaseMgr::buildExtendedInfoTables6Internal(CfgConsistency::ExtendedInfoSanity check, + bool update) { bool enabled = getExtendedInfoTablesEnabled(); - // Use staging config here. - CfgConsistency::ExtendedInfoSanity check = - CfgMgr::instance().getStagingCfg()->getConsistency()->getExtendedInfoSanityCheck(); LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_MEMFILE_BEGIN_BUILD_EXTENDED_INFO_TABLES6) .arg(CfgConsistency::sanityCheckToText(check)) + .arg(update ? " updating in file" : "") .arg(enabled ? "enabled" : "disabled"); size_t leases = 0; size_t modified = 0; + size_t updated = 0; size_t processed = 0; for (auto lease : storage6_) { - leases++; + ++leases; try { if (upgradeLease6ExtendedInfo(lease, check)) { - modified++; + ++modified; + if (update && persistLeases(V6)) { + lease_file6_->append(*lease); + ++updated; + } } if (enabled && addExtendedInfo6(lease)) { - processed++; + ++processed; } } catch (const std::exception& ex) { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, @@ -2881,7 +2887,22 @@ Memfile_LeaseMgr::buildExtendedInfoTables6Internal() { LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_BUILD_EXTENDED_INFO_TABLES6) .arg(leases) .arg(modified) + .arg(updated) .arg(processed); + + return (updated); +} + +size_t +Memfile_LeaseMgr::buildExtendedInfoTables6(bool update) { + CfgConsistency::ExtendedInfoSanity check = + CfgMgr::instance().getCurrentCfg()->getConsistency()->getExtendedInfoSanityCheck(); + if (MultiThreadingMgr::instance().getMode()) { + std::lock_guard lock(*mutex_); + return (buildExtendedInfoTables6Internal(check, update)); + } else { + return (buildExtendedInfoTables6Internal(check, update)); + } } void diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h index 4d765c2656..952eb61b9a 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -1372,12 +1372,12 @@ public: /// @brief Build extended info v6 tables. /// - /// @note: this method is a nop for memfile as tables are built at - /// start time. - virtual void buildExtendedInfoTables6() override { - isc_throw(isc::NotImplemented, - "buildExtendedInfoTables6 is not yet implemented by memfile"); - } + /// @note: this method is a nop for memfile when update is false + /// as tables are built at start time. + /// + /// @param update Update extended info in database. + /// @return The number of updates in the database or 0. + virtual size_t buildExtendedInfoTables6(bool update) override; private: @@ -1470,8 +1470,11 @@ private: /// @brief Build extended info v6 tables. /// - /// @note: called at start time. - void buildExtendedInfoTables6Internal(); + /// @param check Extended info sanity level. + /// @param update Update extended info in database. + /// @return The number of updates in the database or 0. + size_t buildExtendedInfoTables6Internal(isc::dhcp::CfgConsistency::ExtendedInfoSanity check, + bool update); public: diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc index 52bdeb97d0..ddf4a5df27 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.cc +++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc @@ -3431,5 +3431,11 @@ MySqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */, isc_throw(NotImplemented, "MySqlLeaseMgr::getLeases6ByLink not implemented"); } +size_t +MySqlLeaseMgr::buildExtendedInfoTables6(bool /* update */) { + isc_throw(isc::NotImplemented, + "MySqlLeaseMgr::buildExtendedInfoTables6 not implemented"); +} + } // namespace dhcp } // namespace isc diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h index e4c48265e6..bb503c0cc9 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.h +++ b/src/lib/dhcpsrv/mysql_lease_mgr.h @@ -1110,10 +1110,10 @@ private: const LeasePageSize& page_size) override; /// @brief Build extended info v6 tables. - virtual void buildExtendedInfoTables6() override { - isc_throw(isc::NotImplemented, - "buildExtendedInfoTables6 is not yet implemented by mysql"); - } + /// + /// @param update Update extended info in database. + /// @return The number of updates in the database or 0. + virtual size_t buildExtendedInfoTables6(bool update) override; /// @brief Context RAII Allocator. class MySqlLeaseContextAlloc { diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 96bf15a826..e9acf0faff 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -2625,5 +2625,11 @@ PgSqlLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */, isc_throw(NotImplemented, "PgSqlLeaseMgr::getLeases6ByLink not implemented"); } +size_t +PgSqlLeaseMgr::buildExtendedInfoTables6(bool /* update */) { + isc_throw(isc::NotImplemented, + "PgSqlLeaseMgr::buildExtendedInfoTables6 not implemented"); +} + } // namespace dhcp } // namespace isc diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index 8a575680ed..238eb7900b 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -1063,10 +1063,10 @@ private: const LeasePageSize& page_size) override; /// @brief Build extended info v6 tables. - virtual void buildExtendedInfoTables6() override { - isc_throw(isc::NotImplemented, - "buildExtendedInfoTables6 is not yet implemented by postgresql"); - } + /// + /// @param update Update extended info in database. + /// @return The number of updates in the database or 0. + virtual size_t buildExtendedInfoTables6(bool update) override; /// @brief Write V4 leases to a file. virtual void writeLeases4(const std::string& /*filename*/) override; diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc index 786148142f..d5577e3087 100644 --- a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc @@ -505,7 +505,7 @@ public: } /// @brief Stub implementation. - virtual void buildExtendedInfoTables6() override { + virtual size_t buildExtendedInfoTables6(bool /* update */) override { isc_throw(isc::NotImplemented, "ConcreteLeaseMgr:buildExtendedInfoTables6 not implemented"); } /// @brief Pretends to write V4 leases to a file. diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index f73874b37c..e086f83d08 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -3564,7 +3564,7 @@ TEST_F(MemfileLeaseMgrTest, buildExtendedInfoTables6) { "2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02," "200,200,8,100,0,7,0,1,1,,,1," "{ \"ISC\": { \"relays\": [ { \"hop\": 44," - " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," + " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," " \"options\": \"0x00250006010203040506003500086464646464646464\"" " } ] } },,\n" ); @@ -3644,7 +3644,7 @@ TEST_F(MemfileLeaseMgrTest, buildExtendedInfoTables6noSanitize) { "2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02," "200,200,8,100,0,7,0,1,1,,,1," "{ \"ISC\": { \"relays\": [ { \"hop\": 44," - " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," + " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," " \"options\": \"0x00250006010203040506003500086464646464646464\"" " } ] } },,\n" ); @@ -3707,7 +3707,7 @@ TEST_F(MemfileLeaseMgrTest, buildExtendedInfoTables6enabled) { "2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02," "200,200,8,100,0,7,0,1,1,,,1," "{ \"ISC\": { \"relay-info\": [ { \"hop\": 44," - " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," + " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," " \"remote-id\": \"010203040506\"," " \"relay-id\": \"6464646464646464\"," " \"options\": \"0x00250006010203040506003500086464646464646464\"" @@ -3786,7 +3786,7 @@ TEST_F(MemfileLeaseMgrTest, buildExtendedInfoTables6disabled) { "2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02," "200,200,8,100,0,7,0,1,1,,,1," "{ \"ISC\": { \"relay-info\": [ { \"hop\": 44," - " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," + " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," " \"remote-id\": \"010203040506\"," " \"relay-id\": \"6464646464646464\"," " \"options\": \"0x00250006010203040506003500086464646464646464\"" @@ -3814,4 +3814,101 @@ TEST_F(MemfileLeaseMgrTest, buildExtendedInfoTables6disabled) { EXPECT_TRUE(lease_mgr->link_addr6_.empty()); } +/// @brief Checks that buildExtendedInfoTables6 updates when explicitly +/// requested. +TEST_F(MemfileLeaseMgrTest, buildExtendedInfoTables6ExplicitSanitize) { + // Add some leases to the CSV file: one empty map, one old extended + // info format. + string lease_file = getLeaseFilePath("leasefile6_0.csv"); + LeaseFileIO io(lease_file); + string content = + "address,duid,valid_lifetime,expire,subnet_id,pref_lifetime," + "lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname," + "hwaddr,state,user_context,hwtype,hwaddr_source\n" + + "2001:db8:1::1,01:01:01:01:01:01:01:01:01:01:01:01:01," + "400,1000,8,100,0,7,0,1,1,,,1," + "{},,\n" + + "2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02," + "200,200,8,100,0,7,0,1,1,,,1," + "{ \"ISC\": { \"relays\": [ { \"hop\": 44," + " \"link\": \"2001:db8::4\", \"peer\": \"2001:db8::5\"," + " \"options\": \"0x00250006010203040506003500086464646464646464\"" + " } ] } },,\n"; + io.writeFile(content); + + // Disable sanitizing. + CfgMgr::instance().getStagingCfg()->getConsistency()-> + setExtendedInfoSanityCheck(CfgConsistency::EXTENDED_INFO_CHECK_NONE); + + // Start the lease manager. + DatabaseConnection::ParameterMap pmap; + pmap["type"] = "memfile"; + pmap["universe"] = "6"; + pmap["name"] = lease_file; + pmap["lfc-interval"] = "0"; + boost::scoped_ptr lease_mgr; + EXPECT_NO_THROW(lease_mgr.reset(new NakedMemfileLeaseMgr(pmap))); + + // Check the lease with empty user context was not updated. + Lease6Ptr lease = lease_mgr->getLease6(Lease::TYPE_NA, + IOAddress("2001:db8:1::1")); + ASSERT_TRUE(lease); + ConstElementPtr user_context = lease->getContext(); + ASSERT_TRUE(user_context); + ASSERT_EQ(Element::map, user_context->getType()); + EXPECT_TRUE(user_context->empty()); + + // Check the lease with extended info was not upgraded. + lease = lease_mgr->getLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::2")); + ASSERT_TRUE(lease); + user_context = lease->getContext(); + ASSERT_TRUE(user_context); + ConstElementPtr isc = user_context->get("ISC"); + ASSERT_TRUE(isc); + EXPECT_TRUE(isc->contains("relays")); + EXPECT_FALSE(isc->contains("relay-info")); + + // Enable sanitizing. + CfgMgr::instance().getCurrentCfg()->getConsistency()-> + setExtendedInfoSanityCheck(CfgConsistency::EXTENDED_INFO_CHECK_FIX); + + // Now run buildExtendedInfoTables6 with update set to true. + size_t updated = 0; + EXPECT_NO_THROW(updated = lease_mgr->buildExtendedInfoTables6(true)); + EXPECT_EQ(2, updated); + + // Check the lease with empty user context was updated. + lease = lease_mgr->getLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1")); + ASSERT_TRUE(lease); + EXPECT_FALSE(lease->getContext()); + + // Check the lease with extended info was upgraded. + lease = lease_mgr->getLease6(Lease::TYPE_NA, IOAddress("2001:db8:1::2")); + ASSERT_TRUE(lease); + user_context = lease->getContext(); + ASSERT_TRUE(user_context); + isc = user_context->get("ISC"); + ASSERT_TRUE(isc); + EXPECT_FALSE(isc->contains("relays")); + EXPECT_TRUE(isc->contains("relay-info")); + + // Check the lease file was updated. + string new_content = + "2001:db8:1::1,01:01:01:01:01:01:01:01:01:01:01:01:01," + "400,1000,8,100,0,7,0,1,1,,,1,,,\n" + + "2001:db8:1::2,02:02:02:02:02:02:02:02:02:02:02:02:02," + "200,200,8,100,0,7,0,1,1,,,1," + "{ \"ISC\": { \"relay-info\": [ { \"hop\": 44," + " \"link\": \"2001:db8::4\"," + " \"options\": \"0x00250006010203040506003500086464646464646464\"" + ", \"peer\": \"2001:db8::5\"," + " \"relay-id\": \"6464646464646464\"," + " \"remote-id\": \"010203040506\" } ] } },,\n"; + string expected = content + new_content; + EXPECT_EQ(expected, io.readFile()); +} + } // namespace