diff options
Diffstat (limited to 'src')
21 files changed, 1212 insertions, 8 deletions
diff --git a/src/lib/dhcpsrv/base_host_data_source.h b/src/lib/dhcpsrv/base_host_data_source.h index dae3977be2..cb59481140 100644 --- a/src/lib/dhcpsrv/base_host_data_source.h +++ b/src/lib/dhcpsrv/base_host_data_source.h @@ -136,6 +136,41 @@ public: virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const = 0; + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const = 0; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const = 0; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const = 0; + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// This method implements paged browsing of host databases. The diff --git a/src/lib/dhcpsrv/cfg_hosts.cc b/src/lib/dhcpsrv/cfg_hosts.cc index 81051cb4e6..f93467665c 100644 --- a/src/lib/dhcpsrv/cfg_hosts.cc +++ b/src/lib/dhcpsrv/cfg_hosts.cc @@ -83,6 +83,64 @@ CfgHosts::getAll6(const SubnetID& subnet_id) { } ConstHostCollection +CfgHosts::getAllbyHostname(const std::string& hostname) const { + // Do not issue logging message here because it will be logged by + // the getAllbyHostnameInternal method. + ConstHostCollection collection; + getAllbyHostnameInternal<ConstHostCollection>(hostname, collection); + return (collection); +} + +HostCollection +CfgHosts::getAllbyHostname(const std::string& hostname) { + // Do not issue logging message here because it will be logged by + // the getAllbyHostnameInternal method. + HostCollection collection; + getAllbyHostnameInternal<HostCollection>(hostname, collection); + return (collection); +} + +ConstHostCollection +CfgHosts::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + // Do not issue logging message here because it will be logged by + // the getAllbyHostnameInternal4 method. + ConstHostCollection collection; + getAllbyHostnameInternal4<ConstHostCollection>(hostname, subnet_id, collection); + return (collection); +} + +HostCollection +CfgHosts::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) { + // Do not issue logging message here because it will be logged by + // the getAllbyHostnameInternal4 method. + HostCollection collection; + getAllbyHostnameInternal4<HostCollection>(hostname, subnet_id, collection); + return (collection); +} + +ConstHostCollection +CfgHosts::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + // Do not issue logging message here because it will be logged by + // the getAllbyHostnameInternal6 method. + ConstHostCollection collection; + getAllbyHostnameInternal6<ConstHostCollection>(hostname, subnet_id, collection); + return (collection); +} + +HostCollection +CfgHosts::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) { + // Do not issue logging message here because it will be logged by + // the getAllbyHostnameInternal6 method. + HostCollection collection; + getAllbyHostnameInternal6<HostCollection>(hostname, subnet_id, collection); + return (collection); +} + +ConstHostCollection CfgHosts::getPage4(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, @@ -275,6 +333,106 @@ CfgHosts::getAllInternal6(const SubnetID& subnet_id, template<typename Storage> void +CfgHosts::getAllbyHostnameInternal(const std::string& hostname, + Storage& storage) const { + + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_GET_ALL_HOSTNAME) + .arg(hostname); + + // Use try hostname. + const HostContainerIndex5& idx = hosts_.get<5>(); + + // Append each Host object to the storage. + for (HostContainerIndex5::iterator host = idx.lower_bound(hostname); + host != idx.upper_bound(hostname); + ++host) { + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA, + HOSTS_CFG_GET_ALL_HOSTNAME_HOST) + .arg(hostname) + .arg((*host)->toText()); + storage.push_back(*host); + } + + // Log how many hosts have been found. + LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, HOSTS_CFG_GET_ALL_HOSTNAME_COUNT) + .arg(hostname) + .arg(storage.size()); +} + +template<typename Storage> +void +CfgHosts::getAllbyHostnameInternal4(const std::string& hostname, + const SubnetID& subnet_id, + Storage& storage) const { + + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, + HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4) + .arg(hostname); + + // Use try hostname. + const HostContainerIndex5& idx = hosts_.get<5>(); + + // Append each Host object to the storage. + for (HostContainerIndex5::iterator host = idx.lower_bound(hostname); + host != idx.upper_bound(hostname); + ++host) { + if ((*host)->getIPv4SubnetID() != subnet_id) { + continue; + } + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA, + HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST) + .arg(hostname) + .arg(subnet_id) + .arg((*host)->toText()); + storage.push_back(*host); + } + + // Log how many hosts have been found. + LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, + HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT) + .arg(hostname) + .arg(subnet_id) + .arg(storage.size()); +} + +template<typename Storage> +void +CfgHosts::getAllbyHostnameInternal6(const std::string& hostname, + const SubnetID& subnet_id, + Storage& storage) const { + + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, + HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6) + .arg(hostname); + + // Use try hostname. + const HostContainerIndex5& idx = hosts_.get<5>(); + + // Append each Host object to the storage. + for (HostContainerIndex5::iterator host = idx.lower_bound(hostname); + host != idx.upper_bound(hostname); + ++host) { + if ((*host)->getIPv6SubnetID() != subnet_id) { + continue; + } + LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE_DETAIL_DATA, + HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST) + .arg(hostname) + .arg(subnet_id) + .arg((*host)->toText()); + storage.push_back(*host); + } + + // Log how many hosts have been found. + LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS, + HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT) + .arg(hostname) + .arg(subnet_id) + .arg(storage.size()); +} + +template<typename Storage> +void CfgHosts::getPageInternal4(const SubnetID& subnet_id, uint64_t lower_host_id, const HostPageSize& page_size, diff --git a/src/lib/dhcpsrv/cfg_hosts.h b/src/lib/dhcpsrv/cfg_hosts.h index 2f0fb862c8..54edd268e2 100644 --- a/src/lib/dhcpsrv/cfg_hosts.h +++ b/src/lib/dhcpsrv/cfg_hosts.h @@ -119,6 +119,76 @@ public: virtual HostCollection getAll6(const SubnetID& subnet_id); + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const; + + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of @c Host objects. + virtual HostCollection + getAllbyHostname(const std::string& hostname); + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of @c Host objects. + virtual HostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id); + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of @c Host objects. + virtual HostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id); + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// This method returns a page of @c Host objects which represent @@ -476,6 +546,52 @@ private: void getAllInternal6(const SubnetID& subnet_id, Storage& storage) const; + /// @brief Return all hosts with a hostname. + /// + /// This private method is called by the @c CfgHosts::getAllbyHostname + /// method which finds the @c Host objects in a specified subnet. + /// The retrieved objects are appended to the @c storage container. + /// + /// @param hostname The lower case hostname. + /// @param [out] storage Container to which the retrieved objects are + /// appended. + /// @tparam One of the @c ConstHostCollection of @c HostCollection. + template<typename Storage> + void getAllbyHostnameInternal(const std::string& hostname, + Storage& storage) const; + + /// @brief Return all hosts with a hostname and a DHCPv4 subnet. + /// + /// This private method is called by the @c CfgHosts::getAllbyHostname4 + /// method which finds the @c Host objects in a specified subnet. + /// The retrieved objects are appended to the @c storage container. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// @param [out] storage Container to which the retrieved objects are + /// appended. + /// @tparam One of the @c ConstHostCollection of @c HostCollection. + template<typename Storage> + void getAllbyHostnameInternal4(const std::string& hostname, + const SubnetID& subnet_id, + Storage& storage) const; + + /// @brief Return all hosts with a hostname and a DHCPv6 subnet. + /// + /// This private method is called by the @c CfgHosts::getAllbyHostname6 + /// method which finds the @c Host objects in a specified subnet. + /// The retrieved objects are appended to the @c storage container. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// @param [out] storage Container to which the retrieved objects are + /// appended. + /// @tparam One of the @c ConstHostCollection of @c HostCollection. + template<typename Storage> + void getAllbyHostnameInternal6(const std::string& hostname, + const SubnetID& subnet_id, + Storage& storage) const; + /// @brief Returns a page of @c Host objects in a DHCPv4 subnet. /// /// This private method is called by the @c CfgHosts::getPage4 diff --git a/src/lib/dhcpsrv/cql_host_data_source.cc b/src/lib/dhcpsrv/cql_host_data_source.cc index 34f6d3e272..085c9da46c 100644 --- a/src/lib/dhcpsrv/cql_host_data_source.cc +++ b/src/lib/dhcpsrv/cql_host_data_source.cc @@ -259,7 +259,7 @@ public: // Inserts all parameters belonging to any reservation from a single host. static constexpr StatementTag INSERT_HOST = "INSERT_HOST"; - // Retrieves hosts information, IPv6 reservations and both IPv4 and IPv6 + // Retrieves host information, IPv6 reservations and both IPv4 and IPv6 // options associated with it. static constexpr StatementTag GET_HOST = "GET_HOST"; @@ -314,6 +314,21 @@ public: static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID = "GET_HOST_BY_IPV6_SUBNET_ID"; + // Retrieves host information, IPv6 reservations and both IPv4 and IPv6 + // options associated with it using hostname. + static constexpr StatementTag GET_HOST_BY_HOST_NAME = + "GET_HOST_BY_HOST_NAME"; + + // Retrieves host information along with the IPv4 options associated + // with it using hostname and subnet identifier. + static constexpr StatementTag GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID = + "GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID"; + + // Retrieves host information; IPv6 reservations and IPv6 options + // associated with it using hostname and subnet identifier. + static constexpr StatementTag GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID = + "GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID"; + // Retrieves host information along with the IPv4 options associated // with it using a subnet identifier from first host (paging). static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_LIMIT = @@ -469,6 +484,9 @@ constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_PREFIX; constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS; constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID; constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID; +constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_NAME; +constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID; +constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID; constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_LIMIT; constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_LIMIT; constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY; @@ -901,6 +919,119 @@ StatementMap CqlHostExchange::tagged_statements_ = { "ALLOW FILTERING " }}, + {GET_HOST_BY_HOST_NAME, + {GET_HOST_BY_HOST_NAME, + "SELECT " + "key, " + "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 hosts " + "WHERE hostname = ? " + "ALLOW FILTERING " + }}, + + {GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID, + {GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID, + "SELECT " + "key, " + "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 hosts " + "WHERE hostname = ? " + "AND host_ipv4_subnet_id = ? " + "ALLOW FILTERING " + }}, + + {GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID, + {GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID, + "SELECT " + "key, " + "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 hosts " + "WHERE hostname = ? " + "AND host_ipv6_subnet_id = ? " + "ALLOW FILTERING " + }}, + {GET_HOST_BY_IPV4_SUBNET_ID_LIMIT, {GET_HOST_BY_IPV4_SUBNET_ID_LIMIT, "SELECT " @@ -1914,6 +2045,32 @@ public: /// @param subnet_id identifier of the subnet to which hosts belong virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const; + /// @brief Implementation of @ref CqlHostDataSource::getAllbyHostname() + /// + /// See @ref CqlHostDataSource::getAllbyHostname() for parameter details. + /// + /// @param hostname The lower case hostname. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const; + + /// @brief Implementation of @ref CqlHostDataSource::getAllbyHostname4() + /// + /// See @ref CqlHostDataSource::getAllbyHostname4() for parameter details. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Implementation of @ref CqlHostDataSource::getAllbyHostname6() + /// + /// See @ref CqlHostDataSource::getAllbyHostname6() for parameter details. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + /// @brief Implementation of @ref CqlHostDataSource::getPage4() /// /// See @ref CqlHostDataSource::getPage4() for parameter details. @@ -2449,6 +2606,63 @@ CqlHostDataSourceImpl::getAll6(const SubnetID& subnet_id) const { return (result); } +ConstHostCollection +CqlHostDataSourceImpl::getAllbyHostname(const std::string& hostname) const { + // Convert to CQL data types. + std::string hostname_ = hostname; + + // Bind to array. + AnyArray where_values; + where_values.add(&hostname_); + + // Run statement. + ConstHostCollection result = + getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_NAME, + where_values); + + return (result); +} + +ConstHostCollection +CqlHostDataSourceImpl::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + // Convert to CQL data types. + std::string hostname_ = hostname; + cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id); + + // Bind to array. + AnyArray where_values; + where_values.add(&hostname_); + where_values.add(&host_ipv4_subnet_id); + + // Run statement. + ConstHostCollection result = + getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID, + where_values); + + return (result); +} + +ConstHostCollection +CqlHostDataSourceImpl::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + // Convert to CQL data types. + std::string hostname_ = hostname; + cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id); + + // Bind to array. + AnyArray where_values; + where_values.add(&hostname_); + where_values.add(&host_ipv6_subnet_id); + + // Run statement. + ConstHostCollection result = + getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID, + where_values); + + return (result); +} + // There are some problems implementing this for Cassandra. // Attempts show the per page ordering does not work and // it is not possible to order by TOKEN(host_id). @@ -3035,6 +3249,29 @@ CqlHostDataSource::getAll6(const SubnetID& subnet_id) const { } ConstHostCollection +CqlHostDataSource::getAllbyHostname(const std::string& hostname) const { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL); + + return (impl_->getAllbyHostname(hostname)); +} + +ConstHostCollection +CqlHostDataSource::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL); + + return (impl_->getAllbyHostname4(hostname, subnet_id)); +} + +ConstHostCollection +CqlHostDataSource::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL); + + return (impl_->getAllbyHostname6(hostname, subnet_id)); +} + +ConstHostCollection CqlHostDataSource::getPage4(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, diff --git a/src/lib/dhcpsrv/cql_host_data_source.h b/src/lib/dhcpsrv/cql_host_data_source.h index cac22825f5..c90e3b1f55 100644 --- a/src/lib/dhcpsrv/cql_host_data_source.h +++ b/src/lib/dhcpsrv/cql_host_data_source.h @@ -193,6 +193,41 @@ public: virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const override; + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const override; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const override; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const override; + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// Not implemented. diff --git a/src/lib/dhcpsrv/host.h b/src/lib/dhcpsrv/host.h index 8c81ca8a5c..ad60da7c47 100644 --- a/src/lib/dhcpsrv/host.h +++ b/src/lib/dhcpsrv/host.h @@ -16,6 +16,7 @@ #include <dhcpsrv/cfg_option.h> #include <dhcpsrv/subnet_id.h> #include <boost/shared_ptr.hpp> +#include <boost/algorithm/string.hpp> #include <list> #include <map> #include <string> @@ -569,6 +570,11 @@ public: return (hostname_); } + /// @brief Returns reserved hostname in lower case. + std::string getLowerHostname() const { + return (boost::algorithm::to_lower_copy(hostname_)); + } + /// @brief Adds new client class for DHCPv4. /// /// @param class_name Class name. diff --git a/src/lib/dhcpsrv/host_container.h b/src/lib/dhcpsrv/host_container.h index ae21449c4e..55692cf25d 100644 --- a/src/lib/dhcpsrv/host_container.h +++ b/src/lib/dhcpsrv/host_container.h @@ -88,6 +88,13 @@ typedef boost::multi_index_container< // Index using values returned by the @c Host::getHostId boost::multi_index::const_mem_fun<Host, uint64_t, &Host::getHostId> + >, + + // Sixth index is used to search for the host using hostname + boost::multi_index::ordered_non_unique< + // Index using values returned by the @c Host::getLowerHostname + boost::multi_index::const_mem_fun<Host, std::string, + &Host::getLowerHostname> > > > HostContainer; @@ -141,6 +148,11 @@ typedef HostContainer::nth_index<4>::type HostContainerIndex4; typedef std::pair<HostContainerIndex4::iterator, HostContainerIndex4::iterator> HostContainerIndex4Range; +/// @brief Sixth index type in the @c HostContainer. +/// +/// This index allows for searching for @c Host objects using a hostname. +typedef HostContainer::nth_index<5>::type HostContainerIndex5; + /// @brief Defines one entry for the Host Container for v6 hosts /// /// It's essentially a pair of (IPv6 reservation, Host pointer). diff --git a/src/lib/dhcpsrv/host_mgr.cc b/src/lib/dhcpsrv/host_mgr.cc index 6903d9ce84..ebcab3bdc3 100644 --- a/src/lib/dhcpsrv/host_mgr.cc +++ b/src/lib/dhcpsrv/host_mgr.cc @@ -136,6 +136,42 @@ HostMgr::getAll6(const SubnetID& subnet_id) const { } ConstHostCollection +HostMgr::getAllbyHostname(const std::string& hostname) const { + ConstHostCollection hosts = getCfgHosts()->getAllbyHostname(hostname); + for (auto source : alternate_sources_) { + ConstHostCollection hosts_plus = source->getAllbyHostname(hostname); + hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end()); + } + return (hosts); +} + +ConstHostCollection +HostMgr::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + ConstHostCollection hosts = getCfgHosts()->getAllbyHostname4(hostname, + subnet_id); + for (auto source : alternate_sources_) { + ConstHostCollection hosts_plus = source->getAllbyHostname4(hostname, + subnet_id); + hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end()); + } + return (hosts); +} + +ConstHostCollection +HostMgr::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + ConstHostCollection hosts = getCfgHosts()->getAllbyHostname6(hostname, + subnet_id); + for (auto source : alternate_sources_) { + ConstHostCollection hosts_plus = source->getAllbyHostname6(hostname, + subnet_id); + hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end()); + } + return (hosts); +} + +ConstHostCollection HostMgr::getPage4(const SubnetID& subnet_id, size_t& source_index, uint64_t lower_host_id, diff --git a/src/lib/dhcpsrv/host_mgr.h b/src/lib/dhcpsrv/host_mgr.h index caedff49b6..357b156328 100644 --- a/src/lib/dhcpsrv/host_mgr.h +++ b/src/lib/dhcpsrv/host_mgr.h @@ -160,6 +160,41 @@ public: virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const; + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// This method returns a page of @c Host objects representing diff --git a/src/lib/dhcpsrv/hosts_messages.cc b/src/lib/dhcpsrv/hosts_messages.cc index c210ee2c54..7fa76c6907 100644 --- a/src/lib/dhcpsrv/hosts_messages.cc +++ b/src/lib/dhcpsrv/hosts_messages.cc @@ -1,4 +1,4 @@ -// File created from ../../../src/lib/dhcpsrv/hosts_messages.mes on Fri Feb 08 2019 20:31 +// File created from ../../../src/lib/dhcpsrv/hosts_messages.mes on Sun Sep 29 2019 01:57 #include <cstddef> #include <log/message_types.h> @@ -21,6 +21,15 @@ extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS4_HOST = "HOSTS_CFG_GE extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6 = "HOSTS_CFG_GET_ALL_ADDRESS6"; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6_COUNT = "HOSTS_CFG_GET_ALL_ADDRESS6_COUNT"; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6_HOST = "HOSTS_CFG_GET_ALL_ADDRESS6_HOST"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME = "HOSTS_CFG_GET_ALL_HOSTNAME"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_COUNT = "HOSTS_CFG_GET_ALL_HOSTNAME_COUNT"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_HOST = "HOSTS_CFG_GET_ALL_HOSTNAME_HOST"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4 = "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT = "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST = "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6 = "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT = "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT"; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST = "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST"; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER = "HOSTS_CFG_GET_ALL_IDENTIFIER"; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT = "HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT"; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER_HOST = "HOSTS_CFG_GET_ALL_IDENTIFIER_HOST"; @@ -75,6 +84,15 @@ const char* values[] = { "HOSTS_CFG_GET_ALL_ADDRESS6", "get all hosts with reservations for IPv6 address %1", "HOSTS_CFG_GET_ALL_ADDRESS6_COUNT", "using address %1, found %2 host(s)", "HOSTS_CFG_GET_ALL_ADDRESS6_HOST", "using address %1 found host: %2", + "HOSTS_CFG_GET_ALL_HOSTNAME", "get all hosts with reservations for hostname %1", + "HOSTS_CFG_GET_ALL_HOSTNAME_COUNT", "using hostname %1, found %2 host(s)", + "HOSTS_CFG_GET_ALL_HOSTNAME_HOST", "using hostname %1, found host: %2", + "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4", "get all hosts with reservations for hostname %1 and IPv4 subnet %2", + "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT", "using hostname %1 and IPv4 subnet %2, found %3 host(s)", + "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST", "using hostname %1 and IPv4 subnet %2, found host: %3", + "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6", "get all hosts with reservations for hostname %1 and IPv6 subnet %2", + "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT", "using hostname %1 and IPv6 subnet %2, found %3 host(s)", + "HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST", "using hostname %1 and IPv6 subnet %2, found host: %3", "HOSTS_CFG_GET_ALL_IDENTIFIER", "get all hosts with reservations using identifier: %1", "HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT", "using identifier %1, found %2 host(s)", "HOSTS_CFG_GET_ALL_IDENTIFIER_HOST", "using identifier: %1, found host: %2", diff --git a/src/lib/dhcpsrv/hosts_messages.h b/src/lib/dhcpsrv/hosts_messages.h index 6a13da5754..5d636c3f73 100644 --- a/src/lib/dhcpsrv/hosts_messages.h +++ b/src/lib/dhcpsrv/hosts_messages.h @@ -1,4 +1,4 @@ -// File created from ../../../src/lib/dhcpsrv/hosts_messages.mes on Fri Feb 08 2019 20:31 +// File created from ../../../src/lib/dhcpsrv/hosts_messages.mes on Sun Sep 29 2019 01:57 #ifndef HOSTS_MESSAGES_H #define HOSTS_MESSAGES_H @@ -22,6 +22,15 @@ extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS4_HOST; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6_COUNT; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_ADDRESS6_HOST; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_COUNT; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_HOST; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT; +extern const isc::log::MessageID HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT; extern const isc::log::MessageID HOSTS_CFG_GET_ALL_IDENTIFIER_HOST; diff --git a/src/lib/dhcpsrv/hosts_messages.mes b/src/lib/dhcpsrv/hosts_messages.mes index d6dc7542aa..a44d6ea725 100644 --- a/src/lib/dhcpsrv/hosts_messages.mes +++ b/src/lib/dhcpsrv/hosts_messages.mes @@ -73,6 +73,49 @@ This debug message is issued when found host with the reservation for the specified IPv6 address. The arguments specify the IPv6 address and the detailed description of the host found. +% HOSTS_CFG_GET_ALL_HOSTNAME get all hosts with reservations for hostname %1 +This debug message is issued when starting to retrieve all hosts with +the specific hostname. The argument specifies hostname. + +% HOSTS_CFG_GET_ALL_HOSTNAME_COUNT using hostname %1, found %2 host(s) +This debug message include the details of the host found using the +hostname. The arguments specify hostname and the number of hosts found +respectively. + +% HOSTS_CFG_GET_ALL_HOSTNAME_HOST using hostname %1, found host: %2 +This debug message includes the details of the host found using the hostname. +The arguments specify hostname and found host details respectively. + +% HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4 get all hosts with reservations for hostname %1 and IPv4 subnet %2 +This debug message is issued when starting to retrieve all hosts with +the specific hostname connected to the specific DHCPv4 subnet. The argument +specifies hostname and subnet id. + +% HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_COUNT using hostname %1 and IPv4 subnet %2, found %3 host(s) +This debug message include the details of the host found using the +hostname and the DHCPv4 subnet id. The arguments specify hostname, +subnet id and the number of hosts found respectively. + +% HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID4_HOST using hostname %1 and IPv4 subnet %2, found host: %3 +This debug message includes the details of the host found using the +hostname and the DHCPv4 subnet id. The arguments specify hostname, +subnet id and found host details respectively. + +% HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6 get all hosts with reservations for hostname %1 and IPv6 subnet %2 +This debug message is issued when starting to retrieve all hosts with +the specific hostname connected to the specific DHCPv6 subnet. The argument +specifies hostname and subnet id. + +% HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_COUNT using hostname %1 and IPv6 subnet %2, found %3 host(s) +This debug message include the details of the host found using the +hostname and the DHCPv6 subnet id. The arguments specify hostname, +subnet id and the number of hosts found respectively. + +% HOSTS_CFG_GET_ALL_HOSTNAME_SUBNET_ID6_HOST using hostname %1 and IPv6 subnet %2, found host: %3 +This debug message includes the details of the host found using the +hostname and the DHCPv6 subnet id. The arguments specify hostname, +subnet id and found host details respectively. + % HOSTS_CFG_GET_ALL_IDENTIFIER get all hosts with reservations using identifier: %1 This debug message is issued when starting to retrieve reservations for all hosts identified by HW address or DUID. The argument holds both the identifier diff --git a/src/lib/dhcpsrv/mysql_host_data_source.cc b/src/lib/dhcpsrv/mysql_host_data_source.cc index 4eddbdc68d..3c0c2d7c38 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.cc +++ b/src/lib/dhcpsrv/mysql_host_data_source.cc @@ -1915,6 +1915,9 @@ public: GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix GET_HOST_SUBID4, // Get hosts by IPv4 SubnetID GET_HOST_SUBID6, // Get hosts by IPv6 SubnetID + GET_HOST_HOSTNAME, // Get host by hostname + GET_HOST_HOSTNAME_SUBID4, // Get host by hostname and IPv4 SubnetID + GET_HOST_HOSTNAME_SUBID6, // Get host by hostname and IPv6 SubnetID GET_HOST_SUBID4_PAGE, // Get hosts by IPv4 SubnetID beginning by HID GET_HOST_SUBID6_PAGE, // Get hosts by IPv6 SubnetID beginning by HID INSERT_HOST, // Insert new host to collection @@ -2308,6 +2311,73 @@ TaggedStatementArray tagged_statements = { { "WHERE h.dhcp6_subnet_id = ? " "ORDER BY h.host_id, o.option_id, r.reservation_id"}, + // Retrieves host information, IPv6 reservations and both DHCPv4 and + // DHCPv6 options associated with the host. The LEFT JOIN clause is used + // to retrieve information from 4 different tables using a single query. + // Hence, this query returns multiple rows for a single host. + {MySqlHostDataSourceImpl::GET_HOST_HOSTNAME, + "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, " + "o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " + "o4.persistent, o4.user_context, " + "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " + "o6.persistent, o6.user_context, " + "r.reservation_id, r.address, r.prefix_len, r.type, " + "r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp4_options AS o4 " + "ON h.host_id = o4.host_id " + "LEFT JOIN dhcp6_options AS o6 " + "ON h.host_id = o6.host_id " + "LEFT JOIN ipv6_reservations AS r " + "ON h.host_id = r.host_id " + "WHERE h.hostname = ? " + "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id"}, + + // Retrieves host information and DHCPv4 options using hostname and + // subnet identifier. Left joining the dhcp4_options table results in + // multiple rows being returned for the same host. + {MySqlHostDataSourceImpl::GET_HOST_HOSTNAME_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.hostname = ? AND h.dhcp4_subnet_id = ? " + "ORDER BY h.host_id, o.option_id"}, + + // Retrieves host information, IPv6 reservations and DHCPv6 options + // using hostname and subnet identifier. The number of rows returned + // is a multiplication of number of IPv6 reservations and DHCPv6 options. + {MySqlHostDataSourceImpl::GET_HOST_HOSTNAME_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.hostname = ? AND h.dhcp6_subnet_id = ? " + "ORDER BY h.host_id, o.option_id, r.reservation_id"}, + // 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. Hosts are retrieved by IPv4 subnet id @@ -2973,6 +3043,86 @@ MySqlHostDataSource::getAll6(const SubnetID& subnet_id) const { } ConstHostCollection +MySqlHostDataSource::getAllbyHostname(const std::string& hostname) const { + // Set up the WHERE clause value + MYSQL_BIND inbind[1]; + memset(inbind, 0, sizeof(inbind)); + + // Hostname + char hostname_[HOSTNAME_MAX_LEN]; + strncpy(hostname_, hostname.c_str(), HOSTNAME_MAX_LEN - 1); + unsigned long length = hostname.length(); + inbind[0].buffer_type = MYSQL_TYPE_STRING; + inbind[0].buffer = reinterpret_cast<char*>(hostname_); + inbind[0].buffer_length = length; + inbind[0].length = &length; + + ConstHostCollection result; + impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_HOSTNAME, + inbind, impl_->host_ipv46_exchange_, + result, false); + return (result); +} + +ConstHostCollection +MySqlHostDataSource::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + // Set up the WHERE clause value + MYSQL_BIND inbind[2]; + memset(inbind, 0, sizeof(inbind)); + + // Hostname + char hostname_[HOSTNAME_MAX_LEN]; + strncpy(hostname_, hostname.c_str(), HOSTNAME_MAX_LEN - 1); + unsigned long length = hostname.length(); + inbind[0].buffer_type = MYSQL_TYPE_STRING; + inbind[0].buffer = reinterpret_cast<char*>(hostname_); + inbind[0].buffer_length = length; + inbind[0].length = &length; + + // Subnet ID + uint32_t subnet = subnet_id; + inbind[1].buffer_type = MYSQL_TYPE_LONG; + inbind[1].buffer = reinterpret_cast<char*>(&subnet); + inbind[1].is_unsigned = MLM_TRUE; + + ConstHostCollection result; + impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4, + inbind, impl_->host_exchange_, + result, false); + return (result); +} + +ConstHostCollection +MySqlHostDataSource::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + // Set up the WHERE clause value + MYSQL_BIND inbind[2]; + memset(inbind, 0, sizeof(inbind)); + + // Hostname + char hostname_[HOSTNAME_MAX_LEN]; + strncpy(hostname_, hostname.c_str(), HOSTNAME_MAX_LEN - 1); + unsigned long length = hostname.length(); + inbind[0].buffer_type = MYSQL_TYPE_STRING; + inbind[0].buffer = reinterpret_cast<char*>(hostname_); + inbind[0].buffer_length = length; + inbind[0].length = &length; + + // Subnet ID + uint32_t subnet = subnet_id; + inbind[1].buffer_type = MYSQL_TYPE_LONG; + inbind[1].buffer = reinterpret_cast<char*>(&subnet); + inbind[1].is_unsigned = MLM_TRUE; + + ConstHostCollection result; + impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4, + inbind, impl_->host_ipv6_exchange_, + result, false); + return (result); +} + +ConstHostCollection MySqlHostDataSource::getPage4(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, diff --git a/src/lib/dhcpsrv/mysql_host_data_source.h b/src/lib/dhcpsrv/mysql_host_data_source.h index 6f1e3b5c67..759f3304fa 100644 --- a/src/lib/dhcpsrv/mysql_host_data_source.h +++ b/src/lib/dhcpsrv/mysql_host_data_source.h @@ -153,6 +153,41 @@ public: virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const; + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// This method returns a page of @c Host objects which represent diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.cc b/src/lib/dhcpsrv/pgsql_host_data_source.cc index e3a005df0f..7ea6f61e6b 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.cc +++ b/src/lib/dhcpsrv/pgsql_host_data_source.cc @@ -1290,6 +1290,9 @@ public: GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix GET_HOST_SUBID4, // Gets hosts by IPv4 SubnetID GET_HOST_SUBID6, // Gets hosts by IPv6 SubnetID + GET_HOST_HOSTNAME, // Gets hosts by hostname + GET_HOST_HOSTNAME_SUBID4, // Gets hosts by hostname and IPv4 SubnetID + GET_HOST_HOSTNAME_SUBID6, // Gets hosts by hostname and IPv6 SubnetID GET_HOST_SUBID4_PAGE, // Gets hosts by IPv4 SubnetID beginning by HID GET_HOST_SUBID6_PAGE, // Gets hosts by IPv6 SubnetID beginning by HID INSERT_HOST, // Insert new host to collection @@ -1694,6 +1697,81 @@ TaggedStatementArray tagged_statements = { { "ORDER BY h.host_id, o.option_id, r.reservation_id" }, + // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME + // Retrieves host information, IPv6 reservations and both DHCPv4 and + // DHCPv6 options associated with all hosts using the hostname. + // The LEFT JOIN clause is used to retrieve information from 4 different + // tables using a single query. Hence, this query returns multiple rows + // for a single host. + {1, + { OID_VARCHAR }, + "get_host_hostname", + "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, " + " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " + " o4.persistent, o4.user_context, " + " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " + " o6.persistent, o6.user_context, " + " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " + "FROM hosts AS h " + "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id " + "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id " + "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " + "WHERE lower(h.hostname) = $1 " + "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id" + }, + + // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4 + // Retrieves host information for all hosts with a hostname in a subnet, + // along with the DHCPv4 options associated with it. Left joining + // the dhcp4_options table results in multiple rows being returned for + // the same host. + {2, + { OID_VARCHAR, OID_INT8 }, + "get_host_hostname_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 lower(h.hostname) = $1 AND h.dhcp4_subnet_id = $2 " + "ORDER BY h.host_id, o.option_id" + }, + + // PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6 + // Retrieves host information, IPv6 reservations and DHCPv6 options + // associated with all hosts using the hostname and the IPv6 subnet id. + // This query returns host information for many hosts. 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 for each host in a subnet. + {2, + { OID_VARCHAR, OID_INT8 }, + "get_host_hostname_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 lower(h.hostname) = $1 AND h.dhcp6_subnet_id = $2 " + "ORDER BY h.host_id, o.option_id, r.reservation_id" + }, + // PgSqlHostDataSourceImpl::GET_HOST_SUBID4_PAGE // Retrieves host information along with the DHCPv4 options associated with // it. Left joining the dhcp4_options table results in multiple rows being @@ -1761,7 +1839,7 @@ TaggedStatementArray tagged_statements = { { "RETURNING host_id" }, - //PgSqlHostDataSourceImpl::INSERT_V6_RESRV + // PgSqlHostDataSourceImpl::INSERT_V6_RESRV // Inserts a single IPv6 reservation into 'reservations' table. {5, { OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 }, @@ -2237,6 +2315,61 @@ PgSqlHostDataSource::getAll6(const SubnetID& subnet_id) const { } ConstHostCollection +PgSqlHostDataSource::getAllbyHostname(const std::string& hostname) const { + // Set up the WHERE clause value + PsqlBindArrayPtr bind_array(new PsqlBindArray()); + + // Add the hostname. + bind_array->add(hostname); + + ConstHostCollection result; + impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME, + bind_array, impl_->host_ipv46_exchange_, + result, false); + return (result); +} + +ConstHostCollection +PgSqlHostDataSource::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + // Set up the WHERE clause value + PsqlBindArrayPtr bind_array(new PsqlBindArray()); + + // Add the hostname. + bind_array->add(hostname); + + // Add the subnet id. + bind_array->add(subnet_id); + + ConstHostCollection result; + impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID4, + bind_array, impl_->host_exchange_, + result, false); + + return (result); +} + +ConstHostCollection +PgSqlHostDataSource::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + // Set up the WHERE clause value + PsqlBindArrayPtr bind_array(new PsqlBindArray()); + + // Add the hostname. + bind_array->add(hostname); + + // Add the subnet id. + bind_array->add(subnet_id); + + ConstHostCollection result; + impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_HOSTNAME_SUBID6, + bind_array, impl_->host_ipv6_exchange_, + result, false); + + return (result); +} + +ConstHostCollection PgSqlHostDataSource::getPage4(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, diff --git a/src/lib/dhcpsrv/pgsql_host_data_source.h b/src/lib/dhcpsrv/pgsql_host_data_source.h index f3b1f55205..29711e13a6 100644 --- a/src/lib/dhcpsrv/pgsql_host_data_source.h +++ b/src/lib/dhcpsrv/pgsql_host_data_source.h @@ -182,6 +182,41 @@ public: virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const; + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of const @c Host objects. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// This method implements paged browsing of host databases. The diff --git a/src/lib/dhcpsrv/tests/host_cache_unittest.cc b/src/lib/dhcpsrv/tests/host_cache_unittest.cc index d24f249d06..8e1b196136 100644 --- a/src/lib/dhcpsrv/tests/host_cache_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_cache_unittest.cc @@ -611,6 +611,20 @@ public: return (getCollection()); } + ConstHostCollection getAllbyHostname(const std::string&) const { + return (getCollection()); + } + + ConstHostCollection getAllbyHostname4(const std::string&, + const SubnetID&) const { + return (getCollection()); + } + + ConstHostCollection getAllbyHostname6(const std::string&, + const SubnetID&) const { + return (getCollection()); + } + ConstHostCollection getPage4(const SubnetID&, size_t&, uint64_t, const HostPageSize&) const { return (getCollection()); diff --git a/src/lib/dhcpsrv/tests/host_unittest.cc b/src/lib/dhcpsrv/tests/host_unittest.cc index fb7cac2746..3c4c448e69 100644 --- a/src/lib/dhcpsrv/tests/host_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_unittest.cc @@ -665,19 +665,20 @@ TEST_F(HostTest, setValues) { ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address", SubnetID(1), SubnetID(2), IOAddress("192.0.2.3"), - "some-host.example.org"))); + "some-host.eXAMple.org"))); ASSERT_EQ(1, host->getIPv4SubnetID()); ASSERT_EQ(2, host->getIPv6SubnetID()); ASSERT_EQ("192.0.2.3", host->getIPv4Reservation().toText()); - ASSERT_EQ("some-host.example.org", host->getHostname()); + ASSERT_EQ("some-host.eXAMple.org", host->getHostname()); + ASSERT_EQ("some-host.example.org", host->getLowerHostname()); ASSERT_FALSE(host->getContext()); ASSERT_FALSE(host->getNegative()); host->setIPv4SubnetID(SubnetID(123)); host->setIPv6SubnetID(SubnetID(234)); host->setIPv4Reservation(IOAddress("10.0.0.1")); - host->setHostname("other-host.example.org"); + host->setHostname("other-host.eXAMple.org"); host->setNextServer(IOAddress("192.0.2.2")); host->setServerHostname("server-hostname.example.org"); host->setBootFileName("bootfile.efi"); @@ -690,7 +691,8 @@ TEST_F(HostTest, setValues) { EXPECT_EQ(123, host->getIPv4SubnetID()); EXPECT_EQ(234, host->getIPv6SubnetID()); EXPECT_EQ("10.0.0.1", host->getIPv4Reservation().toText()); - EXPECT_EQ("other-host.example.org", host->getHostname()); + EXPECT_EQ("other-host.eXAMple.org", host->getHostname()); + ASSERT_EQ("other-host.example.org", host->getLowerHostname()); EXPECT_EQ("192.0.2.2", host->getNextServer().toText()); EXPECT_EQ("server-hostname.example.org", host->getServerHostname()); EXPECT_EQ("bootfile.efi", host->getBootFileName()); diff --git a/src/lib/dhcpsrv/testutils/memory_host_data_source.cc b/src/lib/dhcpsrv/testutils/memory_host_data_source.cc index ba9a6bfd63..094889ccd8 100644 --- a/src/lib/dhcpsrv/testutils/memory_host_data_source.cc +++ b/src/lib/dhcpsrv/testutils/memory_host_data_source.cc @@ -47,6 +47,46 @@ MemHostDataSource::getAll6(const SubnetID& subnet_id) const { } ConstHostCollection +MemHostDataSource::getAllbyHostname(const std::string& hostname) const { + ConstHostCollection hosts; + for (auto h = store_.begin(); h != store_.end(); ++h) { + // Keep it when hostname matchs. + if ((*h)->getLowerHostname() == hostname) { + hosts.push_back(*h); + } + } + return (hosts); +} + +ConstHostCollection +MemHostDataSource::getAllbyHostname4(const std::string& hostname, + const SubnetID& subnet_id) const { + ConstHostCollection hosts; + for (auto h = store_.begin(); h != store_.end(); ++h) { + // Keep it when hostname and subnet_id match. + if (((*h)->getLowerHostname() == hostname) && + ((*h)->getIPv4SubnetID() == subnet_id)) { + hosts.push_back(*h); + } + } + return (hosts); +} + +ConstHostCollection +MemHostDataSource::getAllbyHostname6(const std::string& hostname, + const SubnetID& subnet_id) const { + ConstHostCollection hosts; + for (auto h = store_.begin(); h != store_.end(); ++h) { + // Keep it when hostname and subnet_id match. + if (((*h)->getLowerHostname() == hostname) && + ((*h)->getIPv6SubnetID() == subnet_id)) { + hosts.push_back(*h); + } + } + return (hosts); +} + +ConstHostCollection MemHostDataSource::getPage4(const SubnetID& subnet_id, size_t& /*source_index*/, uint64_t lower_host_id, diff --git a/src/lib/dhcpsrv/testutils/memory_host_data_source.h b/src/lib/dhcpsrv/testutils/memory_host_data_source.h index a1577a41c0..993ab26cdf 100644 --- a/src/lib/dhcpsrv/testutils/memory_host_data_source.h +++ b/src/lib/dhcpsrv/testutils/memory_host_data_source.h @@ -58,6 +58,26 @@ public: virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const; + /// @brief Return all hosts with a hostname. + /// + /// @param hostname The lower case hostname. + virtual ConstHostCollection + getAllbyHostname(const std::string& hostname) const; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + virtual ConstHostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + virtual ConstHostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const; + /// @brief Return range of hosts in a DHCPv4 subnet. /// /// @param subnet_id Subnet identifier. diff --git a/src/lib/dhcpsrv/writable_host_data_source.h b/src/lib/dhcpsrv/writable_host_data_source.h index 38a3842517..1f68b79a47 100644 --- a/src/lib/dhcpsrv/writable_host_data_source.h +++ b/src/lib/dhcpsrv/writable_host_data_source.h @@ -57,6 +57,41 @@ public: virtual HostCollection getAll6(const SubnetID& subnet_id) = 0; + /// @brief Return all hosts with a hostname. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname. + /// + /// @param hostname The lower case hostname. + /// + /// @return Collection of @c Host objects. + virtual HostCollection + getAllbyHostname(const std::string& hostname) = 0; + + /// @brief Return all hosts with a hostname in a DHCPv4 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of @c Host objects. + virtual HostCollection + getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) = 0; + + /// @brief Return all hosts with a hostname in a DHCPv6 subnet. + /// + /// This method returns all @c Host objects which represent reservations + /// using a specified hostname in a specified subnet. + /// + /// @param hostname The lower case hostname. + /// @param subnet_id Subnet identifier. + /// + /// @return Collection of @c Host objects. + virtual HostCollection + getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) = 0; + /// @brief Returns range of hosts in a DHCPv4 subnet. /// /// This method implements paged browsing of host databases. The |