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
--- /dev/null
+{
+ "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."
+}
reservation-add
reservation-del
reservation-get
+reservation-get-all
shutdown
stat-lease4-get
stat-lease6-get
, <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>
</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": <integer>
+ }
+}</screen>
+Host reservations can be identified by subnet-id.</para>
+
+<para>Response syntax:
+ <screen>{
+ "result": <integer>,
+ "text": <string>,
+ "arguments": {
+ "hosts": [
+ {
+ "boot-file-name": <string>,
+ "comment": <string>
+ "client-id": <string>,
+ "circuit-id": <string>,
+ "duid": <string>,
+ "flex-id": <string>,
+ "ip-address": <string (IPv4 address)>,
+ "ip-addresses": [ <comma separated strings> ],
+ "hw-address": <string>,
+ "hostname": <string>,
+ "next-server": <string (IPv4 address)>,
+ "option-data-list": [ <comma separated structures defining options> ],
+ "prefixes": [ <comma separated IPv6 prefixes> ],
+ "reservation-client-classes": [ <comma separated strings> ],
+ "server-hostname": <string>,
+ "subnet-id": <integer>,
+ "user-context": <any valid JSON>,
+ },
+ ...
+ ]
+ }
+}</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>
<!--
- - 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
</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
"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>
</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
-// 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>
// 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
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,
{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 "
}}
};
// auth_key: varchar
auth_key_ = host->getKey().ToText();
-
+
// hostname: text
hostname_ = host->getHostname();
if (hostname_.size() > HOSTNAME_MAX_LENGTH) {
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.
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.
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);
-// 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
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),
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: "
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_);
/// 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.
//@{
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
};
{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"}
}
};
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 {
///
/// @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.
///
///
/// @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.
///
-// 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
// 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,
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
};
"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"
}
}
};
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 {
///
/// @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.
///
///
/// @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.
///
}
}
+// 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) {
-// 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>
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) {
-// 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
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) {
-// 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
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) {
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.
// 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 =
// 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 =
-// 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
/// 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.
///
}
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
void
MemHostDataSource::add(const HostPtr& host) {
+ host->setHostId(++next_host_id_);
store_.push_back(host);
}
/// @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;
/// @brief Store
std::vector<HostPtr> store_;
+
+ /// @brief Next host id
+ uint64_t next_host_id_;
};
/// Pointer to the Mem host data source.