]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[313-return-a-list-of-all-reservations-by-subnet-id] Finished the getAll[46] implemen...
authorFrancis Dupont <fdupont@isc.org>
Sun, 13 Jan 2019 10:40:20 +0000 (11:40 +0100)
committerFrancis Dupont <fdupont@isc.org>
Tue, 29 Jan 2019 09:49:05 +0000 (04:49 -0500)
18 files changed:
doc/Makefile.am
doc/api/reservation-get-all.json [new file with mode: 0644]
doc/docgen/cmds-list
doc/guide/api.xml
doc/guide/hooks.xml
src/lib/dhcpsrv/cql_host_data_source.cc
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/mysql_host_data_source.h
src/lib/dhcpsrv/pgsql_host_data_source.cc
src/lib/dhcpsrv/pgsql_host_data_source.h
src/lib/dhcpsrv/tests/cfg_hosts_unittest.cc
src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h
src/lib/dhcpsrv/testutils/memory_host_data_source.cc
src/lib/dhcpsrv/testutils/memory_host_data_source.h

index a049d354ba66438a8c1b7cfa11241d7c63f91a05..95f03b1849c7e4d8ccd66e0d8c93e377af06899d 100644 (file)
@@ -106,7 +106,8 @@ EXTRA_DIST += api/network6-add.json api/network6-del.json
 EXTRA_DIST += api/network6-get.json api/network6-list.json
 EXTRA_DIST += api/network6-subnet-add.json api/network6-subnet-del.json
 EXTRA_DIST += api/reservation-add.json api/reservation-del.json
-EXTRA_DIST += api/reservation-get.json api/shutdown.json
+EXTRA_DIST += api/reservation-get.json api/reservation-get-all.json
+EXTRA_DIST += api/shutdown.json
 EXTRA_DIST += api/statistic-get-all.json api/statistic-get.json
 EXTRA_DIST += api/statistic-remove-all.json api/statistic-remove.json
 EXTRA_DIST += api/statistic-reset-all.json api/statistic-reset.json
diff --git a/doc/api/reservation-get-all.json b/doc/api/reservation-get-all.json
new file mode 100644 (file)
index 0000000..75b9ef8
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "name": "reservation-get-all",
+    "brief": "Retrieve all host reservations for a specified subnet.",
+    "support": [ "kea-dhcp4", "kea-dhcp6" ],
+    "hook": "host_cmds",
+    "avail": "1.6.0",
+
+    "cmd-syntax": "{
+    \"command\": \"reservation-get-all\",
+    \"arguments\": {
+        \"subnet-id\": <integer>
+}",
+    "resp-comment": "reservation-get-all command may result in very large responses."
+}
index 64408e552b31888cb8b06cca16cf755125b8a9ff..adbdffdb03657ccbe09652887df8d4de9b3474f2 100644 (file)
@@ -51,6 +51,7 @@ network6-subnet-del
 reservation-add
 reservation-del
 reservation-get
+reservation-get-all
 shutdown
 stat-lease4-get
 stat-lease6-get
index 7b807384c34be510d98b85d04e329a538a552807..e20fa59f6bd8f02042006b86e95698aebc7f9333 100644 (file)
@@ -63,6 +63,7 @@
 , <command><link linkend="ref-reservation-add">reservation-add</link></command>
 , <command><link linkend="ref-reservation-del">reservation-del</link></command>
 , <command><link linkend="ref-reservation-get">reservation-get</link></command>
+, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
 , <command><link linkend="ref-shutdown">shutdown</link></command>
 , <command><link linkend="ref-stat-lease4-get">stat-lease4-get</link></command>
 , <command><link linkend="ref-stat-lease6-get">stat-lease6-get</link></command>
 , <command><link linkend="ref-reservation-add">reservation-add</link></command>
 , <command><link linkend="ref-reservation-del">reservation-del</link></command>
 , <command><link linkend="ref-reservation-get">reservation-get</link></command>
+, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
 , <command><link linkend="ref-shutdown">shutdown</link></command>
 , <command><link linkend="ref-stat-lease4-get">stat-lease4-get</link></command>
 , <command><link linkend="ref-statistic-get">statistic-get</link></command>
 , <command><link linkend="ref-reservation-add">reservation-add</link></command>
 , <command><link linkend="ref-reservation-del">reservation-del</link></command>
 , <command><link linkend="ref-reservation-get">reservation-get</link></command>
+, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
 , <command><link linkend="ref-shutdown">shutdown</link></command>
 , <command><link linkend="ref-stat-lease6-get">stat-lease6-get</link></command>
 , <command><link linkend="ref-statistic-get">statistic-get</link></command>
 <para xml:id="commands-host_cmds-lib">Commands supported by host_cmds hook library: <command><link linkend="ref-reservation-add">reservation-add</link></command>
 , <command><link linkend="ref-reservation-del">reservation-del</link></command>
 , <command><link linkend="ref-reservation-get">reservation-get</link></command>
+, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
 .</para>
 <para xml:id="commands-lease_cmds-lib">Commands supported by lease_cmds hook library: <command><link linkend="ref-lease4-add">lease4-add</link></command>
 , <command><link linkend="ref-lease4-del">lease4-del</link></command>
@@ -2511,6 +2515,61 @@ object appear only if specific field is set.</para>
 </section>
 <!-- end of reservation-get -->
 
+<!-- start of reservation-get-all -->
+<section xml:id="reference-reservation-get-all">
+<title>reservation-get reference</title>
+<para xml:id="ref-reservation-get-all"><command>reservation-get-all</command> - Retrieve all host reservations for a specified subnet.</para>
+
+<para>Supported by: <command><link linkend="commands-kea-dhcp4">kea-dhcp4</link></command>, <command><link linkend="commands-kea-dhcp6">kea-dhcp6</link></command></para>
+
+<para>Availability: 1.6.0 (<link linkend="commands-host_cmds-lib">host_cmds</link>  hook)</para>
+
+<para>Description and examples: See <xref linkend="command-reservation-get-all"/></para>
+
+<para>Command syntax:
+  <screen>{
+    "command": "reservation-get-all",
+    "arguments": {
+        "subnet-id": &lt;integer&gt;
+    }
+}</screen>
+Host reservations can be identified by subnet-id.</para>
+
+<para>Response syntax:
+  <screen>{
+    "result": &lt;integer&gt;,
+    "text": &lt;string&gt;,
+    "arguments": {
+        "hosts": [
+            {
+                "boot-file-name": &lt;string&gt;,
+                "comment": &lt;string&gt;
+                "client-id": &lt;string&gt;,
+                "circuit-id": &lt;string&gt;,
+                "duid": &lt;string&gt;,
+                "flex-id": &lt;string&gt;,
+                "ip-address": &lt;string (IPv4 address)&gt;,
+                "ip-addresses": [ &lt;comma separated strings&gt; ],
+                "hw-address": &lt;string&gt;,
+                "hostname": &lt;string&gt;,
+                "next-server": &lt;string (IPv4 address)&gt;,
+                "option-data-list": [ &lt;comma separated structures defining options&gt; ],
+                "prefixes": [ &lt;comma separated IPv6 prefixes&gt; ],
+                "reservation-client-classes": [ &lt;comma separated strings&gt; ],
+                "server-hostname": &lt;string&gt;,
+                "subnet-id": &lt;integer&gt;,
+                "user-context": &lt;any valid JSON&gt;,
+            },
+            ...
+        ]
+    }
+}</screen>
+
+The reservation-get-all command may result in very large responses.</para>
+
+</section>
+<!-- end of reservation-get-all -->
+
 <!-- start of shutdown -->
 <section xml:id="reference-shutdown">
 <title>shutdown reference</title>
index fb36d462afa6be6dd68ff414b3e821e420424c50..bc4bdd67ccf6e00fb909e8314819892eee84e52f 100644 (file)
@@ -1,5 +1,5 @@
 <!--
- - Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2014-2019 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
@@ -1418,9 +1418,11 @@ $
         </para>
 
         <para>
-          Currently three commands are supported: reservation-add (which adds
+          Currently four commands are supported: reservation-add (which adds
           new host reservation), reservation-get (which returns existing
-          reservation if specified criteria are matched) and reservation-del
+          reservation if specified criteria are matched), reservation-get-all
+          (which returns all reservations in a specified subnet) and
+          reservation-del
           (which attempts to delete a reservation matching specified
           criteria). To use commands that change the reservation information
           (currently these are reservation-add and reservation-del, but this
@@ -1585,7 +1587,7 @@ Here is an example of complex IPv6 reservation:
           "circuit-id", "client-id" and "flex-id", but additional types may be
           added in the future. If any new identifier types are defined in the
           future, reservation-get command will support them automatically.
-          The <command>subnet-id</command> is manadatory. Use a value of zero (0) to
+          The <command>subnet-id</command> is mandatory. Use a value of zero (0) to
           fetch a global reservation, or the id of the subnet to which the reservation
           belongs.
           </para>
@@ -1648,6 +1650,22 @@ An example result returned when the query was malformed:<screen>
 
         </section>
 
+        <section xml:id="command-reservation-get-all">
+          <title>reservation-get-all command</title>
+          <para><command>reservation-get-all</command> can be used to
+          query the host database and retrieve all reservations in a
+          specified subnet. This command uses parameters providing the
+          mandatory subnet-id. Use a value of zero (0) to fetch global
+          reservations.
+          </para>
+
+          <!-- Add example? -->
+
+          <para>The response returned by <command>reservation-get-all</command>
+          can be very long.
+          </para>
+       </section>
+
         <section xml:id="command-reservation-del">
           <title>reservation-del command</title>
           <para><command>reservation-del</command> can be used to delete a
index 6f7648ebef3d04c22af35f6741cbafcd7ae7a7e5..ad9dd5d71b26de4c51b9d26c10df282fe4d8217b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2019 Internet Systems Consortium, Inc. ("ISC")
 // Copyright (C) 2016-2017 Deutsche Telekom AG.
 //
 // Author: Andrei Pavel <andrei.pavel@qualitance.com>
@@ -311,6 +311,16 @@ public:
     // Deletes a host reservation.
     static constexpr StatementTag DELETE_HOST =
         "DELETE_HOST";
+
+    // Retrieves host information along with the IPv4 options associated
+    // with it using a subnet identifier.
+    static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID =
+        "GET_HOST_BY_IPV4_SUBNET_ID";
+
+    // Retrieves host information; IPv6 reservations and IPv6 options
+    // associated with a host using subnet identifier.
+    static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID =
+        "GET_HOST_BY_IPV6_SUBNET_ID";
     /// @}
 
     /// @brief Cassandra statements
@@ -420,6 +430,8 @@ constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS;
 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_PREFIX;
 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS;
 constexpr StatementTag CqlHostExchange::DELETE_HOST;
+constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID;
+constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID;
 
 StatementMap CqlHostExchange::tagged_statements_ = {
     {INSERT_HOST,
@@ -762,6 +774,78 @@ StatementMap CqlHostExchange::tagged_statements_ = {
      {DELETE_HOST,
       "DELETE FROM host_reservations WHERE id = ? "
       "IF EXISTS "
+     }},
+
+    {GET_HOST_BY_IPV4_SUBNET_ID,
+     {GET_HOST_BY_IPV4_SUBNET_ID,
+      "SELECT "
+      "id, "
+      "host_identifier, "
+      "host_identifier_type, "
+      "host_ipv4_subnet_id, "
+      "host_ipv6_subnet_id, "
+      "host_ipv4_address, "
+      "host_ipv4_next_server, "
+      "host_ipv4_server_hostname, "
+      "host_ipv4_boot_file_name, "
+      "auth_key, "
+      "hostname, "
+      "user_context, "
+      "host_ipv4_client_classes, "
+      "host_ipv6_client_classes, "
+      "reserved_ipv6_prefix_address, "
+      "reserved_ipv6_prefix_length, "
+      "reserved_ipv6_prefix_address_type, "
+      "iaid, "
+      "option_universe, "
+      "option_code, "
+      "option_value, "
+      "option_formatted_value, "
+      "option_space, "
+      "option_is_persistent, "
+      "option_client_class, "
+      "option_subnet_id, "
+      "option_user_context, "
+      "option_scope_id "
+      "FROM host_reservations "
+      "WHERE host_ipv4_subnet_id = ? "
+      "ALLOW FILTERING "
+     }},
+
+    {GET_HOST_BY_IPV6_SUBNET_ID,
+     {GET_HOST_BY_IPV6_SUBNET_ID,
+      "SELECT "
+      "id, "
+      "host_identifier, "
+      "host_identifier_type, "
+      "host_ipv4_subnet_id, "
+      "host_ipv6_subnet_id, "
+      "host_ipv4_address, "
+      "host_ipv4_next_server, "
+      "host_ipv4_server_hostname, "
+      "host_ipv4_boot_file_name, "
+      "auth_key, "
+      "hostname, "
+      "user_context, "
+      "host_ipv4_client_classes, "
+      "host_ipv6_client_classes, "
+      "reserved_ipv6_prefix_address, "
+      "reserved_ipv6_prefix_length, "
+      "reserved_ipv6_prefix_address_type, "
+      "iaid, "
+      "option_universe, "
+      "option_code, "
+      "option_value, "
+      "option_formatted_value, "
+      "option_space, "
+      "option_is_persistent, "
+      "option_client_class, "
+      "option_subnet_id, "
+      "option_user_context, "
+      "option_scope_id "
+      "FROM host_reservations "
+      "WHERE host_ipv6_subnet_id = ? "
+      "ALLOW FILTERING "
      }}
 };
 
@@ -905,7 +989,7 @@ CqlHostExchange::prepareExchange(const HostPtr& host,
 
         // auth_key: varchar
         auth_key_ = host->getKey().ToText();
-        
+
         // hostname: text
         hostname_ = host->getHostname();
         if (hostname_.size() > HOSTNAME_MAX_LENGTH) {
@@ -1428,6 +1512,20 @@ public:
            const uint8_t* identifier_begin,
            const size_t identifier_len) const;
 
+    /// @brief Implementation of @ref CqlHostDataSource::getAll4()
+    ///
+    /// See @ref CqlHostDataSource::getAll4() for parameter details.
+    ///
+    /// @param subnet_id identifier of the subnet to which hosts belong
+    virtual ConstHostCollection getAll4(const SubnetID& subnet_id) const;
+
+    /// @brief Implementation of @ref CqlHostDataSource::getAll6()
+    ///
+    /// See @ref CqlHostDataSource::getAll6() for parameter details.
+    ///
+    /// @param subnet_id identifier of the subnet to which hosts belong
+    virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const;
+
     /// @brief Implementation of @ref CqlHostDataSource::getAll4()
     ///
     /// See @ref CqlHostDataSource::getAll4() for parameter details.
@@ -1813,6 +1911,40 @@ CqlHostDataSourceImpl::getAll(const Host::IdentifierType& identifier_type,
     return (result);
 }
 
+ConstHostCollection
+CqlHostDataSourceImpl::getAll4(const SubnetID& subnet_id) const {
+    // Convert to CQL data types.
+    cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
+
+    // Bind to array.
+    AnyArray where_values;
+    where_values.add(&host_ipv4_subnet_id);
+
+    // Run statement.
+    ConstHostCollection result =
+        getHostCollection(CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID,
+                          where_values);
+
+    return (result);
+}
+
+ConstHostCollection
+CqlHostDataSourceImpl::getAll6(const SubnetID& subnet_id) const {
+    // Convert to CQL data types.
+    cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
+
+    // Bind to array.
+    AnyArray where_values;
+    where_values.add(&host_ipv6_subnet_id);
+
+    // Run statement.
+    ConstHostCollection result =
+        getHostCollection(CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID,
+                          where_values);
+
+    return (result);
+}
+
 ConstHostCollection
 CqlHostDataSourceImpl::getAll4(const asiolink::IOAddress& address) const {
     // Convert to CQL data types.
@@ -2099,6 +2231,20 @@ CqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
     return (impl_->getAll(identifier_type, identifier_begin, identifier_len));
 }
 
+ConstHostCollection
+CqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
+
+    return (impl_->getAll4(subnet_id));
+}
+
+ConstHostCollection
+CqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
+
+    return (impl_->getAll6(subnet_id));
+}
+
 ConstHostCollection
 CqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
index fa9dfb236538c31f83412912f135e9f4a1c886e8..448bceca19fa6df6b480f69d93d8e2c3f2a3ba8e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2019 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
@@ -129,7 +129,7 @@ public:
           bind_(columns_num_), columns_(columns_num_),
           error_(columns_num_, MLM_FALSE), host_id_(0),
           dhcp_identifier_length_(0), dhcp_identifier_type_(0),
-          dhcp4_subnet_id_(SUBNET_ID_UNUSED), 
+          dhcp4_subnet_id_(SUBNET_ID_UNUSED),
           dhcp6_subnet_id_(SUBNET_ID_UNUSED), ipv4_address_(0),
           hostname_length_(0), dhcp4_client_classes_length_(0),
           dhcp6_client_classes_length_(0),
@@ -407,7 +407,7 @@ public:
             auth_key_null_ =  auth_key.empty() ? MLM_TRUE : MLM_FALSE;
             bind_[13].buffer = auth_key_;
             bind_[13].buffer_length = auth_key.length();
-        
+
         } catch (const std::exception& ex) {
             isc_throw(DbOperationError,
                       "Could not create bind array from Host: "
@@ -542,7 +542,7 @@ public:
         bind_[13].buffer_length = auth_key_length_;
         bind_[13].length = &auth_key_length_;
         bind_[13].is_null = &auth_key_null_;
-        
+
         // Add the error flags
         setErrorIndicators(bind_, error_);
 
@@ -800,7 +800,7 @@ private:
 
     /// The length of the string for holding keys
     unsigned long auth_key_length_;
-    
+
     /// @name Boolean values indicating if values of specific columns in
     /// the database are NULL.
     //@{
@@ -1951,6 +1951,8 @@ public:
         DEL_HOST_ADDR4,         // Delete v4 host (subnet-id, addr4)
         DEL_HOST_SUBID4_ID,     // Delete v4 host (subnet-id, ident.type, identifier)
         DEL_HOST_SUBID6_ID,     // Delete v6 host (subnet-id, ident.type, identifier)
+        GET_HOST_SUBID4,        // Gets host by IPv4 SubnetID
+        GET_HOST_SUBID6,        // Gets host by IPv6 SubnetID
         NUM_STATEMENTS          // Number of statements
     };
 
@@ -2330,7 +2332,41 @@ TaggedStatementArray tagged_statements = { {
 
     {MySqlHostDataSourceImpl::DEL_HOST_SUBID6_ID,
      "DELETE FROM hosts WHERE dhcp6_subnet_id = ? AND dhcp_identifier_type=? "
-     "AND dhcp_identifier = ?"}
+     "AND dhcp_identifier = ?"},
+
+    {MySqlHostDataSourceImpl::GET_HOST_SUBID4,
+            "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
+                "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
+                "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
+                "h.dhcp4_next_server, h.dhcp4_server_hostname, "
+                "h.dhcp4_boot_file_name, h.auth_key, "
+                "o.option_id, o.code, o.value, o.formatted_value, o.space, "
+                "o.persistent, o.user_context "
+            "FROM hosts AS h "
+            "LEFT JOIN dhcp4_options AS o "
+                "ON h.host_id = o.host_id "
+            "WHERE h.dhcp4_subnet_id = ? "
+            "ORDER BY h.host_id, o.option_id"},
+
+    {MySqlHostDataSourceImpl::GET_HOST_SUBID6,
+            "SELECT h.host_id, h.dhcp_identifier, "
+                "h.dhcp_identifier_type, h.dhcp4_subnet_id, "
+                "h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
+                "h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
+
+                "h.dhcp4_next_server, h.dhcp4_server_hostname, "
+                "h.dhcp4_boot_file_name, h.auth_key, "
+                "o.option_id, o.code, o.value, o.formatted_value, o.space, "
+                "o.persistent, o.user_context, "
+                "r.reservation_id, r.address, r.prefix_len, r.type, "
+                "r.dhcp6_iaid "
+            "FROM hosts AS h "
+            "LEFT JOIN dhcp6_options AS o "
+                "ON h.host_id = o.host_id "
+            "LEFT JOIN ipv6_reservations AS r "
+                "ON h.host_id = r.host_id "
+            "WHERE h.dhcp6_subnet_id = ? "
+            "ORDER BY h.host_id, o.option_id, r.reservation_id"}
 
     }
 };
@@ -2870,6 +2906,40 @@ MySqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
     return (result);
 }
 
+ConstHostCollection
+MySqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[1];
+    memset(inbind, 0, sizeof(inbind));
+    uint32_t subnet = subnet_id;
+    inbind[0].buffer_type = MYSQL_TYPE_LONG;
+    inbind[0].buffer = reinterpret_cast<char*>(&subnet);
+    inbind[0].is_unsigned = MLM_TRUE;
+
+    ConstHostCollection result;
+    impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID4,
+                             inbind, impl_->host_exchange_,
+                             result, false);
+    return (result);
+}
+
+ConstHostCollection
+MySqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
+    // Set up the WHERE clause value
+    MYSQL_BIND inbind[1];
+    memset(inbind, 0, sizeof(inbind));
+    uint32_t subnet = subnet_id;
+    inbind[0].buffer_type = MYSQL_TYPE_LONG;
+    inbind[0].buffer = reinterpret_cast<char*>(&subnet);
+    inbind[0].is_unsigned = MLM_TRUE;
+
+    ConstHostCollection result;
+    impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID6,
+                             inbind, impl_->host_ipv6_exchange_,
+                             result, false);
+    return (result);
+}
+
 ConstHostCollection
 MySqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
 
index 73b3058c4eab31a686bbda607612427e85e7099c..2d9509710c78e8bc726f8cf4e6cddb6b84498e73 100644 (file)
@@ -140,7 +140,7 @@ public:
     ///
     /// @return Collection of const @ref Host objects.
     virtual ConstHostCollection
-    getAll4(const SubnetID& subnet_id) const override;
+    getAll4(const SubnetID& subnet_id) const;
 
     /// @brief Return all hosts in a DHCPv6 subnet.
     ///
@@ -151,7 +151,7 @@ public:
     ///
     /// @return Collection of const @ref Host objects.
     virtual ConstHostCollection
-    getAll6(const SubnetID& subnet_id) const override;
+    getAll6(const SubnetID& subnet_id) const;
 
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
index 6c2aa8cb5dcfde27e3f48fc69b50185dacdcb437..0edb189939974e3d58ff3fb111fe8bcb8063b88e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2019 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
@@ -257,12 +257,12 @@ public:
 
             // add auth keys
             std::string key = host->getKey().ToText();
-            if (key.empty()) { 
+            if (key.empty()) {
                 bind_array->addNull();
             } else {
                 bind_array->add(key);
             }
-        
+
         } catch (const std::exception& ex) {
             host_.reset();
             isc_throw(DbOperationError,
@@ -1293,6 +1293,8 @@ public:
         DEL_HOST_ADDR4,         // Delete v4 host (subnet-id, addr4)
         DEL_HOST_SUBID4_ID,     // Delete v4 host (subnet-id, ident.type, identifier)
         DEL_HOST_SUBID6_ID,     // Delete v6 host (subnet-id, ident.type, identifier)
+        GET_HOST_SUBID4,        // Gets host by IPv4 SubnetID
+        GET_HOST_SUBID6,        // Gets host by IPv6 SubnetID
         NUM_STATEMENTS          // Number of statements
     };
 
@@ -1714,6 +1716,50 @@ TaggedStatementArray tagged_statements = { {
      "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 "
      "AND dhcp_identifier_type = $2 "
      "AND dhcp_identifier = $3"
+    },
+
+    // PgSqlHostDataSourceImpl::GET_HOST_SUBID4
+    // Retrieves host information along with the DHCPv4 options associated with
+    // it. Left joining the dhcp4_options table results in multiple rows being
+    // returned for the same host. The host is retrieved by subnet id.
+    {1,
+     { OID_INT8 }, "get_host_subid4",
+     "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
+     "  h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
+     "  h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
+     "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
+     "  h.dhcp4_boot_file_name, h.auth_key, "
+     "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
+     "  o.persistent, o.user_context "
+     "FROM hosts AS h "
+     "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
+     "WHERE h.dhcp4_subnet_id = $1 "
+     "ORDER BY h.host_id, o.option_id"
+    },
+
+    // PgSqlHostDataSourceImpl::GET_HOST_SUBID6
+    // Retrieves host information, IPv6 reservations and DHCPv6 options
+    // associated with a host using IPv6 subnet id. This query returns
+    // host information for a single host. However, multiple rows are
+    // returned due to left joining IPv6 reservations and DHCPv6 options.
+    // The number of rows returned is multiplication of number of existing
+    // IPv6 reservations and DHCPv6 options.
+    {1,
+     { OID_INT8 }, "get_host_subid6",
+     "SELECT h.host_id, h.dhcp_identifier, "
+     "  h.dhcp_identifier_type, h.dhcp4_subnet_id, "
+     "  h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
+     "  h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
+     "  h.dhcp4_next_server, h.dhcp4_server_hostname, "
+     "  h.dhcp4_boot_file_name, h.auth_key, "
+     "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
+     "  o.persistent, o.user_context, "
+     "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
+     "FROM hosts AS h "
+     "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
+     "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
+     "WHERE h.dhcp6_subnet_id = $1 "
+     "ORDER BY h.host_id, o.option_id, r.reservation_id"
     }
 }
 };
@@ -2097,6 +2143,38 @@ PgSqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
     return (result);
 }
 
+ConstHostCollection
+PgSqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
+    // Set up the WHERE clause value
+    PsqlBindArrayPtr bind_array(new PsqlBindArray());
+
+    // Add the subnet id.
+    bind_array->add(subnet_id);
+
+    ConstHostCollection result;
+    impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID4,
+                             bind_array, impl_->host_exchange_,
+                             result, false);
+
+    return (result);
+}
+
+ConstHostCollection
+PgSqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
+    // Set up the WHERE clause value
+    PsqlBindArrayPtr bind_array(new PsqlBindArray());
+
+    // Add the subnet id.
+    bind_array->add(subnet_id);
+
+    ConstHostCollection result;
+    impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6,
+                             bind_array, impl_->host_ipv6_exchange_,
+                             result, false);
+
+    return (result);
+}
+
 ConstHostCollection
 PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
 
index f829d973bb3b9e888df7c2682556ba749e5cafd6..e93f4f9e1fdf4ea2ff397b731ff91b18486703ac 100644 (file)
@@ -167,7 +167,7 @@ public:
     ///
     /// @return Collection of const @ref Host objects.
     virtual ConstHostCollection
-    getAll4(const SubnetID& subnet_id) const override;
+    getAll4(const SubnetID& subnet_id) const;
 
     /// @brief Return all hosts in a DHCPv6 subnet.
     ///
@@ -178,7 +178,7 @@ public:
     ///
     /// @return Collection of const @ref Host objects.
     virtual ConstHostCollection
-    getAll6(const SubnetID& subnet_id) const override;
+    getAll6(const SubnetID& subnet_id) const;
 
     /// @brief Returns a collection of hosts using the specified IPv4 address.
     ///
index b105750b4f488b38dafbfa30afc41e87295d5048..010550a5ae86e1b621889a56d4d0c86efdbd4882 100644 (file)
@@ -206,6 +206,64 @@ TEST_F(CfgHostsTest, getAllRepeatingHosts) {
     }
 }
 
+// This test checks that hosts in the same subnet can be retrieved from
+// the host configuration.
+TEST_F(CfgHostsTest, getAll4BySubnet) {
+    CfgHosts cfg;
+    // Add 25 hosts identified by HW address in the same subnet.
+    for (unsigned i = 0; i < 25; ++i) {
+        cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
+                                 "hw-address",
+                                 SubnetID(1), SubnetID(1),
+                                 addressesa_[i])));
+    }
+
+    // Check that other subnets are empty.
+    HostCollection hosts = cfg.getAll4(SubnetID(100));
+    EXPECT_EQ(0, hosts.size());
+
+    // Try to retrieve all added reservations.
+    hosts = cfg.getAll4(SubnetID(1));
+    ASSERT_EQ(25, hosts.size());
+    for (unsigned i = 0; i < 25; ++i) {
+        EXPECT_EQ(1, hosts[i]->getIPv4SubnetID());
+        EXPECT_EQ(addressesa_[i].toText(),
+                  hosts[i]->getIPv4Reservation().toText());
+    }
+}
+
+// This test checks that hosts in the same subnet can be retrieved from
+// the host configuration.
+TEST_F(CfgHostsTest, getAll6BySubnet) {
+    CfgHosts cfg;
+    // Add 25 hosts identified by DUID in the same subnet.
+    for (unsigned i = 0; i < 25; ++i) {
+        HostPtr host = HostPtr(new Host(duids_[i]->toText(), "duid",
+                                        SubnetID(1), SubnetID(1),
+                                        IOAddress("0.0.0.0")));
+        host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+                                       increase(IOAddress("2001:db8:1::1"),
+                                                i)));
+        cfg.add(host);
+    }
+
+    // Check that other subnets are empty.
+    HostCollection hosts = cfg.getAll6(SubnetID(100));
+    EXPECT_EQ(0, hosts.size());
+
+    // Try to retrieve all added reservations.
+    hosts = cfg.getAll6(SubnetID(1));
+    ASSERT_EQ(25, hosts.size());
+    for (unsigned i = 0; i < 25; ++i) {
+        EXPECT_EQ(1, hosts[i]->getIPv6SubnetID());
+        IPv6ResrvRange reservations =
+            hosts[i]->getIPv6Reservations(IPv6Resrv::TYPE_NA);
+        ASSERT_EQ(1, std::distance(reservations.first, reservations.second));
+        EXPECT_EQ(increase(IOAddress("2001:db8:1::1"), i),
+                  reservations.first->second.getPrefix());
+    }
+}
+
 // This test checks that all reservations for the specified IPv4 address can
 // be retrieved.
 TEST_F(CfgHostsTest, getAll4ByAddress) {
index 5900136d48db2b269c85e2cca4b7d06ebbf208e3..7380f9501004f40ade6ee750576d939b48a1d950 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC")
 // Copyright (C) 2016-2017 Deutsche Telekom AG.
 //
 // Author: Andrei Pavel <andrei.pavel@qualitance.com>
@@ -293,6 +293,16 @@ TEST_F(CqlHostDataSourceTest, DISABLED_testReadOnlyDatabase) {
     testReadOnlyDatabase(CQL_VALID_TYPE);
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+TEST_F(CqlHostDataSourceTest, getAll4BySubnet) {
+    testGetAll4(Host::IDENT_HWADDR);
+}
+
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+TEST_F(CqlHostDataSourceTest, getAll6BySubnet) {
+    testGetAll6(Host::IDENT_DUID);
+}
+
 // Test verifies if a host reservation can be added and later retrieved by IPv4
 // address. Host uses hw address as identifier.
 TEST_F(CqlHostDataSourceTest, basic4HWAddr) {
index 32c0272ec31fbaef9cde57a6f425923b405c2665..7fb48610a17a246c37e5ff24d044874e09a99589 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2019 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
@@ -311,6 +311,16 @@ TEST_F(MySqlHostDataSourceTest, maxSubnetId6) {
     testMaxSubnetId6();
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+TEST_F(MySqlHostDataSourceTest, getAll4BySubnet) {
+    testGetAll4(Host::IDENT_HWADDR);
+}
+
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+TEST_F(MySqlHostDataSourceTest, getAll6BySubnet) {
+    testGetAll6(Host::IDENT_DUID);
+}
+
 // Test verifies if a host reservation can be added and later retrieved by IPv4
 // address. Host uses client-id (DUID) as identifier.
 TEST_F(MySqlHostDataSourceTest, basic4ClientId) {
index 89bd6db260d369db790bd3b95fa2bbff4dba1039..22bd07fa67179953675acdeb87555d5f473d1e71 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2019 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
@@ -296,6 +296,16 @@ TEST_F(PgSqlHostDataSourceTest, maxSubnetId6) {
     testMaxSubnetId6();
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAll4BySubnet) {
+    testGetAll4(Host::IDENT_HWADDR);
+}
+
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAll6BySubnet) {
+    testGetAll6(Host::IDENT_DUID);
+}
+
 // Test verifies if a host reservation can be added and later retrieved by IPv4
 // address. Host uses client-id (DUID) as identifier.
 TEST_F(PgSqlHostDataSourceTest, basic4ClientId) {
index 8a53dd5930c3dc797ffa6f21cca181ad08e3eb8c..e1530a0aec3e6b02f57c88bbf48ed64d48e49f32 100644 (file)
@@ -356,6 +356,92 @@ void GenericHostDataSourceTest::testMaxSubnetId6() {
     EXPECT_FALSE(host_by_id);
 }
 
+void
+GenericHostDataSourceTest::testGetAll4(const Host::IdentifierType& id) {
+    // Make sure we have a pointer to the host data source.
+    ASSERT_TRUE(hdsptr_);
+
+    // Let's create a couple of hosts...
+    HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", id);
+    HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", id);
+    HostPtr host3 = HostDataSourceUtils::initializeHost4("192.0.2.3", id);
+    HostPtr host4 = HostDataSourceUtils::initializeHost4("192.0.2.4", id);
+
+    // Set them in the same subnets.
+    SubnetID subnet4 = host1->getIPv4SubnetID();
+    host2->setIPv4SubnetID(subnet4);
+    host3->setIPv4SubnetID(subnet4);
+    host4->setIPv4SubnetID(subnet4);
+    SubnetID subnet6 = host1->getIPv6SubnetID();
+    host2->setIPv6SubnetID(subnet6);
+    host3->setIPv6SubnetID(subnet6);
+    host4->setIPv6SubnetID(subnet6);
+
+    // ... and add them to the data source.
+    ASSERT_NO_THROW(hdsptr_->add(host1));
+    ASSERT_NO_THROW(hdsptr_->add(host2));
+    ASSERT_NO_THROW(hdsptr_->add(host3));
+    ASSERT_NO_THROW(hdsptr_->add(host4));
+
+    // And then try to retrieve them back.
+    ConstHostCollection from_hds = hdsptr_->getAll4(subnet4);
+
+    // Make sure we got something back.
+    ASSERT_EQ(4, from_hds.size());
+
+    // Then let's check that what we got seems correct.
+    // There is no ORDER BY in Cassandra so skip it.
+    if (hdsptr_->getType() != "cql") {
+        HostDataSourceUtils::compareHosts(host1, from_hds[0]);
+        HostDataSourceUtils::compareHosts(host2, from_hds[1]);
+        HostDataSourceUtils::compareHosts(host3, from_hds[2]);
+        HostDataSourceUtils::compareHosts(host4, from_hds[3]);
+    }
+}
+
+void
+GenericHostDataSourceTest::testGetAll6(const Host::IdentifierType& id) {
+    // Make sure we have a pointer to the host data source.
+    ASSERT_TRUE(hdsptr_);
+
+    // Let's create a couple of hosts...
+    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", id, false);
+    HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", id, false);
+    HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3", id, false);
+    HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4", id, false);
+
+    // Set them in the same subnets.
+    SubnetID subnet4 = host1->getIPv4SubnetID();
+    host2->setIPv4SubnetID(subnet4);
+    host3->setIPv4SubnetID(subnet4);
+    host4->setIPv4SubnetID(subnet4);
+    SubnetID subnet6 = host1->getIPv6SubnetID();
+    host2->setIPv6SubnetID(subnet6);
+    host3->setIPv6SubnetID(subnet6);
+    host4->setIPv6SubnetID(subnet6);
+
+    // ... and add them to the data source.
+    ASSERT_NO_THROW(hdsptr_->add(host1));
+    ASSERT_NO_THROW(hdsptr_->add(host2));
+    ASSERT_NO_THROW(hdsptr_->add(host3));
+    ASSERT_NO_THROW(hdsptr_->add(host4));
+
+    // And then try to retrieve them back.
+    ConstHostCollection from_hds = hdsptr_->getAll6(subnet6);
+
+    // Make sure we got something back.
+    ASSERT_EQ(4, from_hds.size());
+
+    // Then let's check that what we got seems correct.
+    // There is no ORDER BY in Cassandra so skip it.
+    if (hdsptr_->getType() != "cql") {
+        HostDataSourceUtils::compareHosts(host1, from_hds[0]);
+        HostDataSourceUtils::compareHosts(host2, from_hds[1]);
+        HostDataSourceUtils::compareHosts(host3, from_hds[2]);
+        HostDataSourceUtils::compareHosts(host4, from_hds[3]);
+    }
+}
+
 void
 GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
     // Make sure we have a pointer to the host data source.
@@ -1024,8 +1110,8 @@ void GenericHostDataSourceTest::testOptionsReservations4(const bool formatted,
 
     // getAll4(subnet_id)
     ConstHostCollection hosts_by_subnet = hdsptr_->getAll4(subnet_id);
-    // Not yet implemented.
-    EXPECT_EQ(0, hosts_by_subnet.size());
+    ASSERT_EQ(1, hosts_by_subnet.size());
+    ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_subnet.begin()));
 
     // getAll4(address)
     ConstHostCollection hosts_by_addr =
@@ -1079,8 +1165,8 @@ GenericHostDataSourceTest::testOptionsReservations46(const bool formatted) {
 
     // getAll6(subnet_id)
     ConstHostCollection hosts_by_subnet = hdsptr_->getAll6(subnet_id);
-    // Not yet implemented.
-    EXPECT_EQ(0, hosts_by_subnet.size());
+    EXPECT_EQ(1, hosts_by_subnet.size());
+    // Don't compare as getAll6() returns the v6 part only.
 
     // getAll(identifier_type, identifier, identifier_size)
     ConstHostCollection hosts_by_id =
index 935b8922c34d1c15db795ad3c6f512eac586523d..c6cc028c198624a2760df4cf69a7b6f399e42bb6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2019 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
@@ -178,6 +178,20 @@ public:
     /// Uses gtest macros to report failures.
     void testMaxSubnetId6();
 
+    /// @brief Test that Verifies that IPv4 host reservations in the
+    /// same subnet can be retrieved properly.
+    ///
+    /// Uses gtest macros to report failures.
+    /// @param id Identifier type.
+    void testGetAll4(const Host::IdentifierType& id);
+
+    /// @brief Test that Verifies that IPv6 host reservations in the
+    /// same subnet can be retrieved properly.
+    ///
+    /// Uses gtest macros to report failures.
+    /// @param id Identifier type.
+    void testGetAll6(const Host::IdentifierType& id);
+
     /// @brief Test inserts several hosts with unique IPv4 address and
     ///        checks that they can be retrieved properly.
     ///
index 3c28949d5f6c3a6d782560fc7d745de1d5cf2cb5..fd07827c65808ecd4e9188539ec21402f14aea85 100644 (file)
@@ -23,13 +23,27 @@ MemHostDataSource::getAll(const Host::IdentifierType& /*identifier_type*/,
 }
 
 ConstHostCollection
-MemHostDataSource::getAll4(const SubnetID& /*subnet_id*/) const {
-    return (ConstHostCollection());
+MemHostDataSource::getAll4(const SubnetID& subnet_id) const {
+    ConstHostCollection hosts;
+    for (auto h = store_.begin(); h != store_.end(); ++h) {
+        // Keep it when subnet_id matchs.
+        if ((*h)->getIPv4SubnetID() == subnet_id) {
+            hosts.push_back(*h);
+        }
+    }
+    return (hosts);
 }
 
 ConstHostCollection
-MemHostDataSource::getAll6(const SubnetID& /*subnet_id*/) const {
-    return (ConstHostCollection());
+MemHostDataSource::getAll6(const SubnetID& subnet_id) const {
+    ConstHostCollection hosts;
+    for (auto h = store_.begin(); h != store_.end(); ++h) {
+        // Keep it when subnet_id matchs.
+        if ((*h)->getIPv6SubnetID() == subnet_id) {
+            hosts.push_back(*h);
+        }
+    }
+    return (hosts);
 }
 
 ConstHostCollection
@@ -129,6 +143,7 @@ MemHostDataSource::get6(const SubnetID& subnet_id,
 
 void
 MemHostDataSource::add(const HostPtr& host) {
+    host->setHostId(++next_host_id_);
     store_.push_back(host);
 }
 
index 380a6dba2373c970b03681ff610b7cd66d4af70d..370e5fe6eb7d6a7aa54398f175917acd5d6fee46 100644 (file)
@@ -48,16 +48,12 @@ public:
 
     /// @brief Return all hosts in a DHCPv4 subnet.
     ///
-    /// Currently not implemented.
-    ///
     /// @param subnet_id Subnet identifier.
     virtual ConstHostCollection
     getAll4(const SubnetID& subnet_id) const;
 
     /// @brief Return all hosts in a DHCPv6 subnet.
     ///
-    /// Currently not implemented.
-    ///
     /// @param subnet_id Subnet identifier.
     virtual ConstHostCollection
     getAll6(const SubnetID& subnet_id) const;
@@ -211,6 +207,9 @@ protected:
 
     /// @brief Store
     std::vector<HostPtr> store_;
+
+    /// @brief Next host id
+    uint64_t next_host_id_;
 };
 
 /// Pointer to the Mem host data source.