]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2757] Rebased from #275[23]
authorFrancis Dupont <fdupont@isc.org>
Wed, 5 Apr 2023 19:23:11 +0000 (21:23 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 23 May 2023 13:09:57 +0000 (15:09 +0200)
14 files changed:
src/lib/dhcpsrv/dhcpsrv_messages.cc
src/lib/dhcpsrv/dhcpsrv_messages.h
src/lib/dhcpsrv/dhcpsrv_messages.mes
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/mysql_lease_mgr.cc
src/lib/dhcpsrv/mysql_lease_mgr.h
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.h
src/lib/dhcpsrv/tests/mysql_lease_extended_info_unittest.cc
src/lib/dhcpsrv/tests/pgsql_lease_extended_info_unittest.cc
src/lib/dhcpsrv/testutils/concrete_lease_mgr.cc
src/lib/dhcpsrv/testutils/concrete_lease_mgr.h

index 40de1c65d9c69b006c35b27127915dce0f0623e2..7056296e94f55ada92f530832a051f643934eb89 100644 (file)
@@ -192,6 +192,9 @@ extern const isc::log::MessageID DHCPSRV_MYSQL_START_TRANSACTION = "DHCPSRV_MYSQ
 extern const isc::log::MessageID DHCPSRV_MYSQL_TLS_CIPHER = "DHCPSRV_MYSQL_TLS_CIPHER";
 extern const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR4 = "DHCPSRV_MYSQL_UPDATE_ADDR4";
 extern const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR6 = "DHCPSRV_MYSQL_UPDATE_ADDR6";
+extern const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4 = "DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4";
+extern const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR = "DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR";
+extern const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE = "DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE";
 extern const isc::log::MessageID DHCPSRV_NOTYPE_DB = "DHCPSRV_NOTYPE_DB";
 extern const isc::log::MessageID DHCPSRV_NO_SOCKETS_OPEN = "DHCPSRV_NO_SOCKETS_OPEN";
 extern const isc::log::MessageID DHCPSRV_OPEN_SOCKET_FAIL = "DHCPSRV_OPEN_SOCKET_FAIL";
@@ -243,6 +246,9 @@ extern const isc::log::MessageID DHCPSRV_PGSQL_START_TRANSACTION = "DHCPSRV_PGSQ
 extern const isc::log::MessageID DHCPSRV_PGSQL_TLS_SUPPORT = "DHCPSRV_PGSQL_TLS_SUPPORT";
 extern const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR4 = "DHCPSRV_PGSQL_UPDATE_ADDR4";
 extern const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR6 = "DHCPSRV_PGSQL_UPDATE_ADDR6";
+extern const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4 = "DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4";
+extern const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR = "DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR";
+extern const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE = "DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE";
 extern const isc::log::MessageID DHCPSRV_QUEUE_NCR = "DHCPSRV_QUEUE_NCR";
 extern const isc::log::MessageID DHCPSRV_QUEUE_NCR_FAILED = "DHCPSRV_QUEUE_NCR_FAILED";
 extern const isc::log::MessageID DHCPSRV_QUEUE_NCR_SKIP = "DHCPSRV_QUEUE_NCR_SKIP";
@@ -457,6 +463,9 @@ const char* values[] = {
     "DHCPSRV_MYSQL_TLS_CIPHER", "TLS cipher: %1",
     "DHCPSRV_MYSQL_UPDATE_ADDR4", "updating IPv4 lease for address %1",
     "DHCPSRV_MYSQL_UPDATE_ADDR6", "updating IPv6 lease for address %1, lease type %2",
+    "DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4", "upgrading IPv4 leases done in %1 pages with %2 updated leases",
+    "DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR", "upgrading extending info for IPv4 lease at %1 failed with %2",
+    "DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE", "upgrading IPv4 lease extended info at page %1 starting at %2 (updated %3)",
     "DHCPSRV_NOTYPE_DB", "no 'type' keyword to determine database backend: %1",
     "DHCPSRV_NO_SOCKETS_OPEN", "no interface configured to listen to DHCP traffic",
     "DHCPSRV_OPEN_SOCKET_FAIL", "failed to open socket: %1",
@@ -508,6 +517,9 @@ const char* values[] = {
     "DHCPSRV_PGSQL_TLS_SUPPORT", "Attempt to configure TLS: %1",
     "DHCPSRV_PGSQL_UPDATE_ADDR4", "updating IPv4 lease for address %1",
     "DHCPSRV_PGSQL_UPDATE_ADDR6", "updating IPv6 lease for address %1, lease type %2",
+    "DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4", "upgrading IPv4 leases done in %1 pages with %2 updated leases",
+    "DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR", "upgrading extending info for IPv4 lease at %1 failed with %2",
+    "DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE", "upgrading IPv4 lease extended info at page %1 starting at %2 (updated %3)",
     "DHCPSRV_QUEUE_NCR", "%1: Name change request to %2 DNS entry queued: %3",
     "DHCPSRV_QUEUE_NCR_FAILED", "%1: queuing %2 name change request failed for lease %3: %4",
     "DHCPSRV_QUEUE_NCR_SKIP", "%1: skip queuing name change request for lease: %2",
index 3d2db5ba9dd7f1e0c612a003ddc81ff5816cbcdf..39c56744b260d27dee49f4fea3e7d5349a26ecff 100644 (file)
@@ -193,6 +193,9 @@ extern const isc::log::MessageID DHCPSRV_MYSQL_START_TRANSACTION;
 extern const isc::log::MessageID DHCPSRV_MYSQL_TLS_CIPHER;
 extern const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR4;
 extern const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR6;
+extern const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4;
+extern const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR;
+extern const isc::log::MessageID DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE;
 extern const isc::log::MessageID DHCPSRV_NOTYPE_DB;
 extern const isc::log::MessageID DHCPSRV_NO_SOCKETS_OPEN;
 extern const isc::log::MessageID DHCPSRV_OPEN_SOCKET_FAIL;
@@ -244,6 +247,9 @@ extern const isc::log::MessageID DHCPSRV_PGSQL_START_TRANSACTION;
 extern const isc::log::MessageID DHCPSRV_PGSQL_TLS_SUPPORT;
 extern const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR4;
 extern const isc::log::MessageID DHCPSRV_PGSQL_UPDATE_ADDR6;
+extern const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4;
+extern const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR;
+extern const isc::log::MessageID DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE;
 extern const isc::log::MessageID DHCPSRV_QUEUE_NCR;
 extern const isc::log::MessageID DHCPSRV_QUEUE_NCR_FAILED;
 extern const isc::log::MessageID DHCPSRV_QUEUE_NCR_SKIP;
index 1f3dc0737c4c97cdf61b8e7916bf6a44404eb8a3..9037820ab95e1f6feac68a0b03a3427094d0869c 100644 (file)
@@ -976,6 +976,19 @@ lease from the MySQL database for the specified address.
 A debug message issued when the server is attempting to update IPv6
 lease from the MySQL database for the specified address.
 
+% DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4 upgrading IPv4 leases done in %1 pages with %2 updated leases
+The server upgraded extended info. The number of pages and the final count of
+updated leases are displayed.
+
+% DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR upgrading extending info for IPv4 lease at %1 failed with %2
+A debug message issued when the server failed to upgrade an extended info.
+The address of the lease and the error message are displayed.
+
+% DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE upgrading IPv4 lease extended info at page %1 starting at %2 (updated %3)
+A debug message issued when the server upgrades IPv4 lease extended info.
+The page number and started address, and the count of already updated leases
+are displayed.
+
 % DHCPSRV_NOTYPE_DB no 'type' keyword to determine database backend: %1
 This is an error message, logged when an attempt has been made to access
 a database backend, but where no 'type' keyword has been included in
@@ -1221,6 +1234,19 @@ lease from the PostgreSQL database for the specified address.
 A debug message issued when the server is attempting to update IPv6
 lease from the PostgreSQL database for the specified address.
 
+% DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4 upgrading IPv4 leases done in %1 pages with %2 updated leases
+The server upgraded extended info. The number of pages and the final count of
+updated leases are displayed.
+
+% DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR upgrading extending info for IPv4 lease at %1 failed with %2
+A debug message issued when the server failed to upgrade an extended info.
+The address of the lease and the error message are displayed.
+
+% DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE upgrading IPv4 lease extended info at page %1 starting at %2 (updated %3)
+A debug message issued when the server upgrades IPv4 lease extended info.
+The page number and started address, and the count of already updated leases
+are displayed.
+
 % DHCPSRV_QUEUE_NCR %1: Name change request to %2 DNS entry queued: %3
 A debug message which is logged when the NameChangeRequest to add or remove
 a DNS entries for a particular lease has been queued. The first argument
index 94be5d6a3065a75bd52bdcef6ce76c17a2af01c2..fe42783cf90261d1c065f36b8fedb44e7142d592 100644 (file)
@@ -960,6 +960,12 @@ public:
     /// @param filename File name to write leases.
     virtual void writeLeases6(const std::string& filename) = 0;
 
+    /// @brief Upgrade extended info (v4).
+    ///
+    /// @param page_size The page size used for retrieval.
+    /// @return The number of updates in the database.
+    virtual size_t upgradeExtendedInfo(const LeasePageSize& page_size) = 0;
+
     /// @brief Returns the setting indicating if lease extended info tables
     /// are enabled.
     ///
index b94c1593d8d64a213d3aaaadaf1c6357bc96bd47..5b5c7df041862762cbb31be05f7e0e1b88e58d04 100644 (file)
@@ -3032,6 +3032,11 @@ Memfile_LeaseMgr::extractExtendedInfo4(bool update, bool current) {
     return (updated);
 }
 
+size_t
+Memfile_LeaseMgr::upgradeExtendedInfo(const LeasePageSize& /* page_size */) {
+    return (0);
+}
+
 size_t
 Memfile_LeaseMgr::buildExtendedInfoTables6Internal(bool update, bool current) {
     CfgConsistencyPtr cfg;
index 0a88b31b640b92fa69fee990e860ffd2038e46bd..15c06f03143b33de4ee9b3661ef6c57cc92d2552 100644 (file)
@@ -1508,6 +1508,12 @@ public:
     /// @param filename File name to write leases.
     virtual void writeLeases6(const std::string& filename) override;
 
+    /// @brief Upgrade extended info (v4).
+    ///
+    /// @param page_size The page size used for retrieval.
+    /// @return Always return 0.
+    virtual size_t upgradeExtendedInfo(const LeasePageSize& page_size) override;
+
 protected:
 
     /// Extended information / Bulk Lease Query shared interface.
index f26c7cedf1612d984e81b24db9df63db8d3d7db4..11df3850af69f73d52a94fb47a931576b3a15074 100644 (file)
@@ -162,6 +162,15 @@ tagged_statements = { {
                             "WHERE address > ? "
                             "ORDER BY address "
                             "LIMIT ?"},
+    {MySqlLeaseMgr::GET_LEASE4_UCTX_PAGE,
+                    "SELECT address, hwaddr, client_id, "
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname, "
+                        "state, user_context, relay_id, remote_id "
+                            "FROM lease4 "
+                            "WHERE address > ? AND user_context IS NOT NULL "
+                            "ORDER BY address "
+                            "LIMIT ?"},
     {MySqlLeaseMgr::GET_LEASE4_SUBID,
                     "SELECT address, hwaddr, client_id, "
                         "valid_lifetime, expire, subnet_id, "
@@ -330,6 +339,17 @@ tagged_statements = { {
                             "WHERE address > ? "
                             "ORDER BY address "
                             "LIMIT ?"},
+    {MySqlLeaseMgr::GET_LEASE6_UCTX_PAGE,
+                    "SELECT address, duid, valid_lifetime, "
+                        "expire, subnet_id, pref_lifetime, "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname, "
+                        "hwaddr, hwtype, hwaddr_source, "
+                        "state, user_context "
+                            "FROM lease6 "
+                            "WHERE address > ? AND user_context IS NOT NULL "
+                            "ORDER BY address "
+                            "LIMIT ?"},
     {MySqlLeaseMgr::GET_LEASE6_SUBID,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
@@ -3875,6 +3895,95 @@ MySqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& remote_id,
     return (result);
 }
 
+size_t
+MySqlLeaseMgr::upgradeExtendedInfo(const LeasePageSize& page_size) {
+    auto check = CfgMgr::instance().getCurrentCfg()->
+        getConsistency()->getExtendedInfoSanityCheck();
+
+    size_t pages = 0;
+    size_t updated = 0;
+    IOAddress start_addr = IOAddress::IPV4_ZERO_ADDRESS();
+    for (;;) {
+        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+                  DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_PAGE)
+            .arg(pages)
+            .arg(start_addr.toText())
+            .arg(updated);
+
+        // Prepare WHERE clause.
+        MYSQL_BIND inbind[2];
+        memset(inbind, 0, sizeof(inbind));
+
+        // Bind start address.
+        uint32_t start_addr_data = start_addr.toUint32();
+        inbind[0].buffer_type = MYSQL_TYPE_LONG;
+        inbind[0].buffer = reinterpret_cast<char*>(&start_addr_data);
+        inbind[0].is_unsigned = MLM_TRUE;
+
+        // Bind page size value.
+        uint32_t ps = static_cast<uint32_t>(page_size.page_size_);
+        inbind[1].buffer_type = MYSQL_TYPE_LONG;
+        inbind[1].buffer = reinterpret_cast<char*>(&ps);
+        inbind[1].is_unsigned = MLM_TRUE;
+
+        Lease4Collection leases;
+
+        // Get a context.
+        {
+            MySqlLeaseContextAlloc get_context(*this);
+            MySqlLeaseContextPtr ctx = get_context.ctx_;
+
+            getLeaseCollection(ctx, GET_LEASE4_UCTX_PAGE, inbind, leases);
+        }
+
+        if (leases.empty()) {
+            // Done.
+            break;
+        }
+
+        ++pages;
+        start_addr = leases.back()->addr_;
+        for (auto lease : leases) {
+            ConstElementPtr previous_user_context = lease->getContext();
+            vector<uint8_t> previous_relay_id = lease->relay_id_;
+            vector<uint8_t> previous_remote_id = lease->remote_id_;
+            if (!previous_user_context &&
+                previous_relay_id.empty() &&
+                previous_remote_id.empty()) {
+                continue;
+            }
+            bool modified = upgradeLease4ExtendedInfo(lease, check);
+            try {
+                lease->relay_id_.clear();
+                lease->remote_id_.clear();
+                extractLease4ExtendedInfo(lease, false);
+                if (modified ||
+                    (previous_relay_id != lease->relay_id_) ||
+                    (previous_remote_id != lease->remote_id_)) {
+                    updateLease4(lease);
+                    ++updated;
+                }
+            } catch (const NoSuchLease&) {
+                // The lease was modified in parallel:
+                // as its extended info was processed just ignore.
+                continue;
+            } catch (const std::exception& ex) {
+                // Something when wrong, for instance extract failed.
+                LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+                          DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4_ERROR)
+                    .arg(lease->addr_.toText())
+                    .arg(ex.what());
+            }
+        }
+    }
+
+    LOG_INFO(dhcpsrv_logger, DHCPSRV_MYSQL_UPGRADE_EXTENDED_INFO4)
+        .arg(pages)
+        .arg(updated);
+
+    return (updated);
+}
+
 Lease6Collection
 MySqlLeaseMgr::getLeases6ByRelayId(const DUID& /* relay_id */,
                                    const IOAddress& /* link_addr */,
index 26a83fc675885416d32ab9e5f6c92a9b6b222dc4..ba9f6773686226bef876ce76607722c0300197af 100644 (file)
@@ -702,6 +702,7 @@ public:
         GET_LEASE4_HWADDR,           // Get lease4 by HW address
         GET_LEASE4_HWADDR_SUBID,     // Get lease4 by HW address & subnet ID
         GET_LEASE4_PAGE,             // Get page of leases beginning with an address
+        GET_LEASE4_UCTX_PAGE,        // Get page of leases with user context
         GET_LEASE4_SUBID,            // Get IPv4 leases by subnet ID
         GET_LEASE4_HOSTNAME,         // Get IPv4 leases by hostname
         GET_LEASE4_EXPIRE,           // Get lease4 by expiration.
@@ -718,6 +719,7 @@ public:
         GET_LEASE6_DUID_IAID,        // Get lease6 by DUID and IAID
         GET_LEASE6_DUID_IAID_SUBID,  // Get lease6 by DUID, IAID and subnet ID
         GET_LEASE6_PAGE,             // Get page of leases beginning with an address
+        GET_LEASE6_UCTX_PAGE,        // Get page of leases with user context
         GET_LEASE6_SUBID,            // Get IPv6 leases by subnet ID
         GET_LEASE6_DUID,             // Get IPv6 leases by DUID
         GET_LEASE6_HOSTNAME,         // Get IPv6 leases by hostname
@@ -1119,6 +1121,12 @@ private:
                      const asiolink::IOAddress& lower_bound_address,
                      const LeasePageSize& page_size) override;
 
+    /// @brief Upgrade extended info (v4).
+    ///
+    /// @param page_size The page size used for retrieval.
+    /// @return The number of updates in the database.
+    virtual size_t upgradeExtendedInfo(const LeasePageSize& page_size) override;
+
     /// @brief Build extended info v6 tables.
     ///
     /// @param update Update extended info in database.
index 2f590f839662f4c76ce4c14a34047aea9dbbdd13..dace3eff89b3c3314446fc78858e8f5c5e276915 100644 (file)
@@ -134,6 +134,18 @@ PgSqlTaggedStatement tagged_statements[] = {
       "ORDER BY address "
       "LIMIT $2"},
 
+    // GET_LEASE4_UCTX_PAGE
+    { 2, { OID_INT8, OID_INT8 },
+      "get_lease4_uctx_page",
+      "SELECT address, hwaddr, client_id, "
+        "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
+        "fqdn_fwd, fqdn_rev, hostname, "
+        "state, user_context, relay_id, remote_id "
+      "FROM lease4 "
+      "WHERE address > $1 AND user_context IS NOT NULL "
+      "ORDER BY address "
+      "LIMIT $2"},
+
     // GET_LEASE4_SUBID
     { 1, { OID_INT8 },
       "get_lease4_subid",
@@ -335,6 +347,19 @@ PgSqlTaggedStatement tagged_statements[] = {
       "ORDER BY address "
       "LIMIT $2"},
 
+    // GET_LEASE6_UCTX_PAGE
+    { 2, { OID_VARCHAR, OID_INT8 },
+      "get_lease6_uctx_page",
+      "SELECT address, duid, valid_lifetime, "
+        "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
+        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
+        "state, user_context "
+      "FROM lease6 "
+      "WHERE address > $1 AND user_context IS NOT NULL "
+      "ORDER BY address "
+      "LIMIT $2"},
+
     // GET_LEASE6_SUBID
     { 1, { OID_INT8 },
       "get_lease6_subid",
@@ -3010,6 +3035,91 @@ PgSqlLeaseMgr::getLeases4ByRemoteId(const OptionBuffer& remote_id,
     return (result);
 }
 
+size_t
+PgSqlLeaseMgr::upgradeExtendedInfo(const LeasePageSize& page_size) {
+    auto check = CfgMgr::instance().getCurrentCfg()->
+        getConsistency()->getExtendedInfoSanityCheck();
+
+    size_t pages = 0;
+    size_t updated = 0;
+    IOAddress start_addr = IOAddress::IPV4_ZERO_ADDRESS();
+    for (;;) {
+        LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+                  DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_PAGE)
+            .arg(pages)
+            .arg(start_addr.toText())
+            .arg(updated);
+
+        // Prepare WHERE clause.
+        PsqlBindArray bind_array;
+
+        // Bind start address.
+        uint32_t start_addr_data = start_addr.toUint32();
+        bind_array.add(start_addr_data);
+
+        // Bind page size value.
+        std::string page_size_data =
+            boost::lexical_cast<std::string>(page_size.page_size_);
+        bind_array.add(page_size_data);
+
+        Lease4Collection leases;
+
+        // Get a context.
+        {
+            PgSqlLeaseContextAlloc get_context(*this);
+            PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+            getLeaseCollection(ctx, GET_LEASE4_UCTX_PAGE, bind_array, leases);
+        }
+
+        if (leases.empty()) {
+            // Done.
+            break;
+        }
+
+        ++pages;
+        start_addr = leases.back()->addr_;
+        for (auto lease : leases) {
+            ConstElementPtr previous_user_context = lease->getContext();
+            vector<uint8_t> previous_relay_id = lease->relay_id_;
+            vector<uint8_t> previous_remote_id = lease->remote_id_;
+            if (!previous_user_context &&
+                previous_relay_id.empty() &&
+                previous_remote_id.empty()) {
+                continue;
+            }
+            bool modified = upgradeLease4ExtendedInfo(lease, check);
+            try {
+                lease->relay_id_.clear();
+                lease->remote_id_.clear();
+                extractLease4ExtendedInfo(lease, false);
+                if (modified ||
+                    (previous_relay_id != lease->relay_id_) ||
+                    (previous_remote_id != lease->remote_id_)) {
+                    updateLease4(lease);
+                    ++updated;
+                }
+            } catch (const NoSuchLease&) {
+                // The lease was modified in parallel:
+                // as its extended info was processed just ignore.
+                continue;
+            } catch (const std::exception& ex) {
+                // Something when wrong, for instance extract failed.
+                LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
+                          DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4_ERROR)
+                    .arg(lease->addr_.toText())
+                    .arg(ex.what());
+            }
+        }
+    }
+
+    LOG_INFO(dhcpsrv_logger, DHCPSRV_PGSQL_UPGRADE_EXTENDED_INFO4)
+        .arg(pages)
+        .arg(updated);
+
+    return (updated);
+}
+
 Lease6Collection
 PgSqlLeaseMgr::getLeases6ByRelayId(const DUID& /* relay_id */,
                                    const IOAddress& /* link_addr */,
index 9e4d7f126f8d11038c59dc1e19c5fbc55ae99ae7..794555abaa00be3c8eba8775abe39f4f7e15795c 100644 (file)
@@ -678,6 +678,7 @@ public:
         GET_LEASE4_HWADDR,           // Get lease4 by HW address
         GET_LEASE4_HWADDR_SUBID,     // Get lease4 by HW address & subnet ID
         GET_LEASE4_PAGE,             // Get page of leases beginning with an address
+        GET_LEASE4_UCTX_PAGE,        // Get page of leases with user context
         GET_LEASE4_SUBID,            // Get IPv4 leases by subnet ID
         GET_LEASE4_HOSTNAME,         // Get IPv4 leases by hostname
         GET_LEASE4_EXPIRE,           // Get lease4 by expiration.
@@ -694,6 +695,7 @@ public:
         GET_LEASE6_DUID_IAID,        // Get lease6 by DUID and IAID
         GET_LEASE6_DUID_IAID_SUBID,  // Get lease6 by DUID, IAID and subnet ID
         GET_LEASE6_PAGE,             // Get page of leases beginning with an address
+        GET_LEASE6_UCTX_PAGE,        // Get page of leases with user context
         GET_LEASE6_SUBID,            // Get IPv6 leases by subnet ID
         GET_LEASE6_DUID,             // Get IPv6 leases by DUID
         GET_LEASE6_HOSTNAME,         // Get IPv6 leases by hostname
@@ -1073,6 +1075,12 @@ private:
                      const asiolink::IOAddress& lower_bound_address,
                      const LeasePageSize& page_size) override;
 
+    /// @brief Upgrade extended info (v4).
+    ///
+    /// @param page_size The page size used for retrieval.
+    /// @return The number of updates in the database.
+    virtual size_t upgradeExtendedInfo(const LeasePageSize& page_size) override;
+
     /// @brief Build extended info v6 tables.
     ///
     /// @param update Update extended info in database.
index ba34f0cadfa3a6dac2b9cf67c6474250e3555307..c06fd7f8094a4de5ae7bdd135b220ad1c4cc10bd 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <asiolink/io_address.h>
 #include <cc/data.h>
+#include <dhcpsrv/cfg_consistency.h>
+#include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/mysql_lease_mgr.h>
 #include <mysql/testutils/mysql_schema.h>
@@ -122,6 +124,10 @@ public:
     /// @brief Test getLease4ByRemoteId.
     void testGetLeases4ByRemoteId();
 
+    /// @brief Test upgradeExtendedInfo.
+    void testUpgradeExtendedInfo(const CfgConsistency::ExtendedInfoSanity& check,
+                                 const LeasePageSize& page_size);
+
     /// @brief Lease manager.
     LeaseMgr* lease_mgr_;
 
@@ -614,4 +620,349 @@ TEST_F(MySqlExtendedInfoTest, getLeases4ByRemoteIdMultiThreading) {
     testGetLeases4ByRemoteId();
 }
 
+void
+MySqlExtendedInfoTest::testUpgradeExtendedInfo(const CfgConsistency::ExtendedInfoSanity& check,
+                                               const LeasePageSize& page_size) {
+    // Lease manager is created with empty tables.
+    initLease4(false);
+
+    // Create leases.
+    IOAddress addr0(ADDRESS4[0]);
+    IOAddress addr1(ADDRESS4[1]);
+    IOAddress addr2(ADDRESS4[2]);
+    IOAddress addr3(ADDRESS4[3]);
+    IOAddress addr4(ADDRESS4[4]);
+    IOAddress addr5(ADDRESS4[5]);
+    IOAddress addr6(ADDRESS4[6]);
+    IOAddress addr7(ADDRESS4[7]);
+    IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+    vector<uint8_t> relay_id = { 0xaa, 0xbb, 0xcc };
+    vector<uint8_t> relay_id2 = { 0xdd, 0xee, 0xff };
+    vector<uint8_t> remote_id = { 1, 2, 3, 4 };
+    vector<uint8_t> remote_id2 = { 5, 6, 7, 8 };
+    string user_context_txt = "{ \"ISC\": { \"relay-agent-info\": {";
+    user_context_txt += " \"sub-options\": \"0204010203040C03AABBCC\",";
+    user_context_txt += " \"relay-id\": \"AABBCC\",";
+    user_context_txt += " \"remote-id\": \"01020304\" } } }";
+    ElementPtr user_context;
+    ASSERT_NO_THROW(user_context = Element::fromJSON(user_context_txt));
+    string user_context_txt_old = "{ \"ISC\": { \"relay-agent-info\":";
+    user_context_txt_old += " \"0204010203040C03AABBCC\" } }";
+    ElementPtr user_context_old;
+    ASSERT_NO_THROW(user_context_old = Element::fromJSON(user_context_txt_old));
+    string user_context_list_txt = "{ \"ISC\": { \"relay-agent-info\": [ ] } }";
+    ElementPtr user_context_list;
+    ASSERT_NO_THROW(user_context_list = Element::fromJSON(user_context_list_txt));
+    string user_context_lower_txt = "{ \"isc\": { \"relay-agent-info\":";
+    user_context_lower_txt += " \"0204010203040c03aabbcc\" } }";
+    ElementPtr user_context_lower;
+    ASSERT_NO_THROW(user_context_lower = Element::fromJSON(user_context_lower_txt));
+    string user_context_badsub_txt = "{ \"ISC\": { \"relay-agent-info\": {";
+    user_context_badsub_txt += " \"sub-options\": \"foobar\",";
+    user_context_badsub_txt += " \"relay-id\": \"AABBCC\",";
+    user_context_badsub_txt += " \"remote-id\": \"01020304\" } } }";
+    ElementPtr user_context_badsub;
+    ASSERT_NO_THROW(user_context_badsub = Element::fromJSON(user_context_badsub_txt));
+    string user_context_extra_txt = "{ \"ISC\": { \"relay-agent-info\": {";
+    user_context_extra_txt += " \"foo\": \"bar\", ";
+    user_context_extra_txt += " \"sub-options\": \"0204010203040C03AABBCC\",";
+    user_context_extra_txt += " \"relay-id\": \"AABBCC\",";
+    user_context_extra_txt += " \"remote-id\": \"01020304\" } } }";
+    ElementPtr user_context_extra;
+    ASSERT_NO_THROW(user_context_extra = Element::fromJSON(user_context_extra_txt));
+
+    Lease4Ptr lease;
+    // lease0: addr0, ids, before: always not updated.
+    lease = leases4[0];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context);
+    lease->cltt_ = now_ - 500;
+
+    // lease1: addr1, ids, after: always not updated.
+    lease = leases4[1];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context);
+    lease->cltt_ = now_ + 500;
+
+    // lease2: addr2, no id, old user context: updated on check > NONE.
+    lease = leases4[2];
+    ASSERT_TRUE(lease);
+    lease->setContext(user_context_old);
+
+    // lease3: addr3, ids, lower case old user context: always updated.
+    lease = leases4[3];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_lower);
+
+    // Lease4: addr4, ids, bad (list) user context: updated on check > NONE.
+    lease = leases4[4];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_list);
+
+    // Lease5: addr5, other ids: always updated.
+    lease = leases4[5];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id2;
+    lease->remote_id_ = remote_id2;
+    lease->setContext(user_context);
+
+    // Lease6: addr6, ids, bad sub-options: updated on check > FIX.
+    lease = leases4[6];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_badsub);
+
+    // Lease7: addr7, ids, extra in ISC: updated on check > STRICT.
+    lease = leases4[7];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_extra);
+
+    // Add leases.
+    for (size_t i = 0; i < leases4.size(); ++i) {
+        EXPECT_TRUE(lease_mgr_->addLease(leases4[i]));
+    }
+
+    // Set extended info consistency.
+    CfgMgr::instance().getCurrentCfg()->getConsistency()->
+        setExtendedInfoSanityCheck(check);
+
+    size_t updated;
+    ASSERT_NO_THROW(updated = lease_mgr_->upgradeExtendedInfo(page_size));
+
+    // Verify result.
+    switch (check) {
+    case CfgConsistency::EXTENDED_INFO_CHECK_NONE:
+        // Updated leases: 3, 5.
+        EXPECT_EQ(updated, 2);
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_FIX:
+        // Updated leases: 2, 3, 4, 5.
+        EXPECT_EQ(updated, 4);
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_STRICT:
+        // Updated leases: 2, 3, 4, 5, 6.
+        EXPECT_EQ(updated, 5);
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC:
+    default:
+        // Updated leases: 2, 3, 4, 5, 6, 7.
+        EXPECT_EQ(updated, 6);
+        break;
+    }
+
+    // Verify stored leases.
+    Lease4Collection got;
+    // Use the page version as it returns leases in order.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases4(zero, LeasePageSize(100)));
+    ASSERT_EQ(leases4.size(), got.size());
+
+    // Check lease0.
+    lease = got[0];
+    EXPECT_EQ(*lease, *leases4[0]);
+    EXPECT_EQ(relay_id, lease->relay_id_);
+    EXPECT_EQ(remote_id, lease->remote_id_);
+
+    // Check lease1.
+    lease = got[1];
+    EXPECT_EQ(*lease, *leases4[1]);
+    EXPECT_EQ(relay_id, lease->relay_id_);
+    EXPECT_EQ(remote_id, lease->remote_id_);
+
+    // Check lease2.
+    lease = got[2];
+    Lease4Ptr expected2(new Lease4(*leases4[2]));
+    if (check == CfgConsistency::EXTENDED_INFO_CHECK_NONE) {
+        EXPECT_EQ(*lease, *expected2);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    } else {
+        expected2->setContext(user_context);
+        expected2->relay_id_ = relay_id;
+        expected2->remote_id_ = remote_id;
+        EXPECT_EQ(*lease, *expected2);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    }
+
+    // Check lease3.
+    lease = got[3];
+    Lease4Ptr expected3(new Lease4(*leases4[3]));
+    expected3->relay_id_.clear();
+    expected3->remote_id_.clear();
+    EXPECT_EQ(*lease, *expected3);
+    EXPECT_TRUE(lease->relay_id_.empty());
+    EXPECT_TRUE(lease->remote_id_.empty());
+
+    // Check lease4.
+    lease = got[4];
+    Lease4Ptr expected4(new Lease4(*leases4[4]));
+    if (check == CfgConsistency::EXTENDED_INFO_CHECK_NONE) {
+        EXPECT_EQ(*lease, *expected4);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    } else {
+        expected4->relay_id_.clear();
+        expected4->remote_id_.clear();
+        expected4->setContext(ElementPtr());
+        EXPECT_EQ(*lease, *expected4);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    }
+
+    // Check lease5.
+    lease = got[5];
+    Lease4Ptr expected5(new Lease4(*leases4[5]));
+    expected5->relay_id_ = relay_id;
+    expected5->remote_id_ = remote_id;
+    EXPECT_EQ(*lease, *expected5);
+    EXPECT_EQ(relay_id, lease->relay_id_);
+    EXPECT_EQ(remote_id, lease->remote_id_);
+
+    // Check lease6.
+    lease = got[6];
+    Lease4Ptr expected6(new Lease4(*leases4[6]));
+    if ((check != CfgConsistency::EXTENDED_INFO_CHECK_STRICT) &&
+        (check != CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC)) {
+        EXPECT_EQ(*lease, *expected6);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    } else {
+        expected6->relay_id_.clear();
+        expected6->remote_id_.clear();
+        expected6->setContext(ElementPtr());
+        EXPECT_EQ(*lease, *expected6);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    }
+
+    // Check lease7.
+    lease = got[7];
+    Lease4Ptr expected7(new Lease4(*leases4[7]));
+    if (check != CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC) {
+        EXPECT_EQ(*lease, *expected7);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    } else {
+        expected7->relay_id_.clear();
+        expected7->remote_id_.clear();
+        expected7->setContext(ElementPtr());
+        EXPECT_EQ(*lease, *expected7);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    }
+
+    // Verify getLeases4ByRelayId.
+    Lease4Collection by_relay_id;
+    EXPECT_NO_THROW(by_relay_id =
+                    lease_mgr_->getLeases4ByRelayId(relay_id,
+                                                    zero,
+                                                    LeasePageSize(100)));
+    switch (check) {
+    case CfgConsistency::EXTENDED_INFO_CHECK_NONE:
+        // Got leases: 0, 1, 4, 5, 6, 7.
+        EXPECT_EQ(6, by_relay_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_FIX:
+        // Got leases: 0, 1, 2, 5, 6, 7.
+        EXPECT_EQ(6, by_relay_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_STRICT:
+        // Got leases: 0, 1, 2, 4, 7.
+        EXPECT_EQ(5, by_relay_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC:
+    default:
+        // Got leases: 0, 1, 2, 4.
+        EXPECT_EQ(4, by_relay_id.size());
+        break;
+    }
+
+    // Verify getLeases4ByRemoteId.
+    Lease4Collection by_remote_id;
+    EXPECT_NO_THROW(by_remote_id =
+                    lease_mgr_->getLeases4ByRemoteId(remote_id,
+                                                     zero,
+                                                     LeasePageSize(100)));
+    switch (check) {
+    case CfgConsistency::EXTENDED_INFO_CHECK_NONE:
+        // Got leases: 0, 1, 4, 5, 6, 7.
+        EXPECT_EQ(6, by_remote_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_FIX:
+        // Got leases: 0, 1, 2, 5, 6, 7.
+        EXPECT_EQ(6, by_remote_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_STRICT:
+        // Got leases: 0, 1, 2, 4, 7.
+        EXPECT_EQ(5, by_remote_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC:
+    default:
+        // Got leases: 0, 1, 2, 4.
+        EXPECT_EQ(4, by_remote_id.size());
+        break;
+    }
+
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfoNone) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_NONE,
+                            LeasePageSize(100));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfoFix) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(100));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfoStrict) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+                            LeasePageSize(100));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfoPedantic) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+                            LeasePageSize(100));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfo10) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(10));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfo5) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(5));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfo2) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(2));
+}
+
+TEST_F(MySqlExtendedInfoTest, upgradeExtendedInfo1) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(1));
+}
+
 }  // namespace
index 0f7d21c5a485978995ce55f96bd19e8cadcc8367..67aa319d13d7ffe4955480f6917de07159da2eb2 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <asiolink/io_address.h>
 #include <cc/data.h>
+#include <dhcpsrv/cfg_consistency.h>
+#include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/pgsql_lease_mgr.h>
 #include <pgsql/testutils/pgsql_schema.h>
@@ -122,6 +124,10 @@ public:
     /// @brief Test getLease4ByRemoteId.
     void testGetLeases4ByRemoteId();
 
+    /// @brief Test upgradeExtendedInfo.
+    void testUpgradeExtendedInfo(const CfgConsistency::ExtendedInfoSanity& check,
+                                 const LeasePageSize& page_size);
+
     /// @brief Lease manager.
     LeaseMgr* lease_mgr_;
 
@@ -614,4 +620,349 @@ TEST_F(PgSqlExtendedInfoTest, getLeases4ByRemoteIdMultiThreading) {
     testGetLeases4ByRemoteId();
 }
 
+void
+PgSqlExtendedInfoTest::testUpgradeExtendedInfo(const CfgConsistency::ExtendedInfoSanity& check,
+                                               const LeasePageSize& page_size) {
+    // Lease manager is created with empty tables.
+    initLease4(false);
+
+    // Create leases.
+    IOAddress addr0(ADDRESS4[0]);
+    IOAddress addr1(ADDRESS4[1]);
+    IOAddress addr2(ADDRESS4[2]);
+    IOAddress addr3(ADDRESS4[3]);
+    IOAddress addr4(ADDRESS4[4]);
+    IOAddress addr5(ADDRESS4[5]);
+    IOAddress addr6(ADDRESS4[6]);
+    IOAddress addr7(ADDRESS4[7]);
+    IOAddress zero = IOAddress::IPV4_ZERO_ADDRESS();
+    vector<uint8_t> relay_id = { 0xaa, 0xbb, 0xcc };
+    vector<uint8_t> relay_id2 = { 0xdd, 0xee, 0xff };
+    vector<uint8_t> remote_id = { 1, 2, 3, 4 };
+    vector<uint8_t> remote_id2 = { 5, 6, 7, 8 };
+    string user_context_txt = "{ \"ISC\": { \"relay-agent-info\": {";
+    user_context_txt += " \"sub-options\": \"0204010203040C03AABBCC\",";
+    user_context_txt += " \"relay-id\": \"AABBCC\",";
+    user_context_txt += " \"remote-id\": \"01020304\" } } }";
+    ElementPtr user_context;
+    ASSERT_NO_THROW(user_context = Element::fromJSON(user_context_txt));
+    string user_context_txt_old = "{ \"ISC\": { \"relay-agent-info\":";
+    user_context_txt_old += " \"0204010203040C03AABBCC\" } }";
+    ElementPtr user_context_old;
+    ASSERT_NO_THROW(user_context_old = Element::fromJSON(user_context_txt_old));
+    string user_context_list_txt = "{ \"ISC\": { \"relay-agent-info\": [ ] } }";
+    ElementPtr user_context_list;
+    ASSERT_NO_THROW(user_context_list = Element::fromJSON(user_context_list_txt));
+    string user_context_lower_txt = "{ \"isc\": { \"relay-agent-info\":";
+    user_context_lower_txt += " \"0204010203040c03aabbcc\" } }";
+    ElementPtr user_context_lower;
+    ASSERT_NO_THROW(user_context_lower = Element::fromJSON(user_context_lower_txt));
+    string user_context_badsub_txt = "{ \"ISC\": { \"relay-agent-info\": {";
+    user_context_badsub_txt += " \"sub-options\": \"foobar\",";
+    user_context_badsub_txt += " \"relay-id\": \"AABBCC\",";
+    user_context_badsub_txt += " \"remote-id\": \"01020304\" } } }";
+    ElementPtr user_context_badsub;
+    ASSERT_NO_THROW(user_context_badsub = Element::fromJSON(user_context_badsub_txt));
+    string user_context_extra_txt = "{ \"ISC\": { \"relay-agent-info\": {";
+    user_context_extra_txt += " \"foo\": \"bar\", ";
+    user_context_extra_txt += " \"sub-options\": \"0204010203040C03AABBCC\",";
+    user_context_extra_txt += " \"relay-id\": \"AABBCC\",";
+    user_context_extra_txt += " \"remote-id\": \"01020304\" } } }";
+    ElementPtr user_context_extra;
+    ASSERT_NO_THROW(user_context_extra = Element::fromJSON(user_context_extra_txt));
+
+    Lease4Ptr lease;
+    // lease0: addr0, ids, before: always not updated.
+    lease = leases4[0];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context);
+    lease->cltt_ = now_ - 500;
+
+    // lease1: addr1, ids, after: always not updated.
+    lease = leases4[1];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context);
+    lease->cltt_ = now_ + 500;
+
+    // lease2: addr2, no id, old user context: updated on check > NONE.
+    lease = leases4[2];
+    ASSERT_TRUE(lease);
+    lease->setContext(user_context_old);
+
+    // lease3: addr3, ids, lower case old user context: always updated.
+    lease = leases4[3];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_lower);
+
+    // Lease4: addr4, ids, bad (list) user context: updated on check > NONE.
+    lease = leases4[4];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_list);
+
+    // Lease5: addr5, other ids: always updated.
+    lease = leases4[5];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id2;
+    lease->remote_id_ = remote_id2;
+    lease->setContext(user_context);
+
+    // Lease6: addr6, ids, bad sub-options: updated on check > FIX.
+    lease = leases4[6];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_badsub);
+
+    // Lease7: addr7, ids, extra in ISC: updated on check > STRICT.
+    lease = leases4[7];
+    ASSERT_TRUE(lease);
+    lease->relay_id_ = relay_id;
+    lease->remote_id_ = remote_id;
+    lease->setContext(user_context_extra);
+
+    // Add leases.
+    for (size_t i = 0; i < leases4.size(); ++i) {
+        EXPECT_TRUE(lease_mgr_->addLease(leases4[i]));
+    }
+
+    // Set extended info consistency.
+    CfgMgr::instance().getCurrentCfg()->getConsistency()->
+        setExtendedInfoSanityCheck(check);
+
+    size_t updated;
+    ASSERT_NO_THROW(updated = lease_mgr_->upgradeExtendedInfo(page_size));
+
+    // Verify result.
+    switch (check) {
+    case CfgConsistency::EXTENDED_INFO_CHECK_NONE:
+        // Updated leases: 3, 5.
+        EXPECT_EQ(updated, 2);
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_FIX:
+        // Updated leases: 2, 3, 4, 5.
+        EXPECT_EQ(updated, 4);
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_STRICT:
+        // Updated leases: 2, 3, 4, 5, 6.
+        EXPECT_EQ(updated, 5);
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC:
+    default:
+        // Updated leases: 2, 3, 4, 5, 6, 7.
+        EXPECT_EQ(updated, 6);
+        break;
+    }
+
+    // Verify stored leases.
+    Lease4Collection got;
+    // Use the page version as it returns leases in order.
+    EXPECT_NO_THROW(got = lease_mgr_->getLeases4(zero, LeasePageSize(100)));
+    ASSERT_EQ(leases4.size(), got.size());
+
+    // Check lease0.
+    lease = got[0];
+    EXPECT_EQ(*lease, *leases4[0]);
+    EXPECT_EQ(relay_id, lease->relay_id_);
+    EXPECT_EQ(remote_id, lease->remote_id_);
+
+    // Check lease1.
+    lease = got[1];
+    EXPECT_EQ(*lease, *leases4[1]);
+    EXPECT_EQ(relay_id, lease->relay_id_);
+    EXPECT_EQ(remote_id, lease->remote_id_);
+
+    // Check lease2.
+    lease = got[2];
+    Lease4Ptr expected2(new Lease4(*leases4[2]));
+    if (check == CfgConsistency::EXTENDED_INFO_CHECK_NONE) {
+        EXPECT_EQ(*lease, *expected2);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    } else {
+        expected2->setContext(user_context);
+        expected2->relay_id_ = relay_id;
+        expected2->remote_id_ = remote_id;
+        EXPECT_EQ(*lease, *expected2);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    }
+
+    // Check lease3.
+    lease = got[3];
+    Lease4Ptr expected3(new Lease4(*leases4[3]));
+    expected3->relay_id_.clear();
+    expected3->remote_id_.clear();
+    EXPECT_EQ(*lease, *expected3);
+    EXPECT_TRUE(lease->relay_id_.empty());
+    EXPECT_TRUE(lease->remote_id_.empty());
+
+    // Check lease4.
+    lease = got[4];
+    Lease4Ptr expected4(new Lease4(*leases4[4]));
+    if (check == CfgConsistency::EXTENDED_INFO_CHECK_NONE) {
+        EXPECT_EQ(*lease, *expected4);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    } else {
+        expected4->relay_id_.clear();
+        expected4->remote_id_.clear();
+        expected4->setContext(ElementPtr());
+        EXPECT_EQ(*lease, *expected4);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    }
+
+    // Check lease5.
+    lease = got[5];
+    Lease4Ptr expected5(new Lease4(*leases4[5]));
+    expected5->relay_id_ = relay_id;
+    expected5->remote_id_ = remote_id;
+    EXPECT_EQ(*lease, *expected5);
+    EXPECT_EQ(relay_id, lease->relay_id_);
+    EXPECT_EQ(remote_id, lease->remote_id_);
+
+    // Check lease6.
+    lease = got[6];
+    Lease4Ptr expected6(new Lease4(*leases4[6]));
+    if ((check != CfgConsistency::EXTENDED_INFO_CHECK_STRICT) &&
+        (check != CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC)) {
+        EXPECT_EQ(*lease, *expected6);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    } else {
+        expected6->relay_id_.clear();
+        expected6->remote_id_.clear();
+        expected6->setContext(ElementPtr());
+        EXPECT_EQ(*lease, *expected6);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    }
+
+    // Check lease7.
+    lease = got[7];
+    Lease4Ptr expected7(new Lease4(*leases4[7]));
+    if (check != CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC) {
+        EXPECT_EQ(*lease, *expected7);
+        EXPECT_EQ(relay_id, lease->relay_id_);
+        EXPECT_EQ(remote_id, lease->remote_id_);
+    } else {
+        expected7->relay_id_.clear();
+        expected7->remote_id_.clear();
+        expected7->setContext(ElementPtr());
+        EXPECT_EQ(*lease, *expected7);
+        EXPECT_TRUE(lease->relay_id_.empty());
+        EXPECT_TRUE(lease->remote_id_.empty());
+    }
+
+    // Verify getLeases4ByRelayId.
+    Lease4Collection by_relay_id;
+    EXPECT_NO_THROW(by_relay_id =
+                    lease_mgr_->getLeases4ByRelayId(relay_id,
+                                                    zero,
+                                                    LeasePageSize(100)));
+    switch (check) {
+    case CfgConsistency::EXTENDED_INFO_CHECK_NONE:
+        // Got leases: 0, 1, 4, 5, 6, 7.
+        EXPECT_EQ(6, by_relay_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_FIX:
+        // Got leases: 0, 1, 2, 5, 6, 7.
+        EXPECT_EQ(6, by_relay_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_STRICT:
+        // Got leases: 0, 1, 2, 4, 7.
+        EXPECT_EQ(5, by_relay_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC:
+    default:
+        // Got leases: 0, 1, 2, 4.
+        EXPECT_EQ(4, by_relay_id.size());
+        break;
+    }
+
+    // Verify getLeases4ByRemoteId.
+    Lease4Collection by_remote_id;
+    EXPECT_NO_THROW(by_remote_id =
+                    lease_mgr_->getLeases4ByRemoteId(remote_id,
+                                                     zero,
+                                                     LeasePageSize(100)));
+    switch (check) {
+    case CfgConsistency::EXTENDED_INFO_CHECK_NONE:
+        // Got leases: 0, 1, 4, 5, 6, 7.
+        EXPECT_EQ(6, by_remote_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_FIX:
+        // Got leases: 0, 1, 2, 5, 6, 7.
+        EXPECT_EQ(6, by_remote_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_STRICT:
+        // Got leases: 0, 1, 2, 4, 7.
+        EXPECT_EQ(5, by_remote_id.size());
+        break;
+
+    case CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC:
+    default:
+        // Got leases: 0, 1, 2, 4.
+        EXPECT_EQ(4, by_remote_id.size());
+        break;
+    }
+
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfoNone) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_NONE,
+                            LeasePageSize(100));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfoFix) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(100));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfoStrict) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+                            LeasePageSize(100));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfoPedantic) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+                            LeasePageSize(100));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfo10) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(10));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfo5) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(5));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfo2) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(2));
+}
+
+TEST_F(PgSqlExtendedInfoTest, upgradeExtendedInfo1) {
+    testUpgradeExtendedInfo(CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+                            LeasePageSize(1));
+}
+
 }  // namespace
index d04fd34ccc024610ce0fdaece4f5f059d2f7083b..f89d883df064e6226f73b43e8f543c5692559a99 100644 (file)
@@ -291,6 +291,11 @@ ConcreteLeaseMgr::getLeases6ByLink(const IOAddress& /* link_addr */,
     isc_throw(NotImplemented, "ConcreteLeaseMgr::getLeases6ByLink not implemented");
 }
 
+size_t
+ConcreteLeaseMgr::upgradeExtendedInfo(const LeasePageSize& /* page_size */) {
+    return (0);
+}
+
 size_t
 ConcreteLeaseMgr::buildExtendedInfoTables6(bool /* update */,
                                            bool /* current */) {
index 3b97a492b34861af91de3448199681eb31e3c9e1..14cab968e804fc20b05d04224d6316212e1300af 100644 (file)
@@ -377,6 +377,10 @@ public:
                      const asiolink::IOAddress& /* lower_bound_address */,
                      const LeasePageSize& /* page_size */) override;
 
+    /// @brief Stub implementation.
+    virtual size_t
+    upgradeExtendedInfo(const LeasePageSize& /* page_size */) override;
+
     /// @brief Stub implementation.
     virtual size_t buildExtendedInfoTables6(bool /* update */,
                                             bool /* current */) override;