#include <database/db_exceptions.h>
#include <dhcp/classify.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
#include <dhcp/option_data_types.h>
+#include <dhcp/option_space.h>
#include <dhcpsrv/network.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/lease.h>
+#include <util/buffer.h>
#include <mysql/mysql_connection.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
using namespace isc::db;
using namespace isc::data;
using namespace isc::asiolink;
+using namespace isc::util;
namespace isc {
namespace dhcp {
GET_OPTION_DEF4_CODE_SPACE,
GET_ALL_OPTION_DEFS4,
GET_MODIFIED_OPTION_DEFS4,
+ GET_OPTION4_SUBNET_ID_CODE_SPACE,
+ GET_OPTION4_SHARED_NETWORK_CODE_SPACE,
INSERT_SUBNET4,
INSERT_POOL4,
INSERT_SHARED_NETWORK4,
INSERT_OPTION_DEF4,
+ INSERT_OPTION4,
UPDATE_SUBNET4,
UPDATE_SHARED_NETWORK4,
UPDATE_OPTION_DEF4,
+ UPDATE_OPTION4_SUBNET_ID,
+ UPDATE_OPTION4_SHARED_NETWORK,
DELETE_SUBNET4_ID,
DELETE_SUBNET4_PREFIX,
DELETE_ALL_SUBNETS4,
DELETE_ALL_SHARED_NETWORKS4,
DELETE_OPTION_DEF4_CODE_NAME,
DELETE_ALL_OPTION_DEFS4,
+ DELETE_OPTION4_SUBNET_ID,
+ DELETE_OPTION4_SHARED_NETWORK,
+ DELETE_OPTIONS4_SUBNET_ID,
+ DELETE_OPTIONS4_SHARED_NETWORK,
NUM_STATEMENTS
};
MySqlBinding::createInteger<uint32_t>(), // pool: start_address
MySqlBinding::createInteger<uint32_t>(), // pool: end_address
MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id
- MySqlBinding::createTimestamp() // pool: modification_ts
+ MySqlBinding::createTimestamp(), // pool: modification_ts
+ MySqlBinding::createInteger<uint64_t>(), // option: option_id
+ MySqlBinding::createInteger<uint8_t>(), // option: code
+ MySqlBinding::createBlob(65536), // option: value
+ MySqlBinding::createString(8192), // option: formatted_value
+ MySqlBinding::createString(128), // option: space
+ MySqlBinding::createInteger<uint8_t>(), // option: persistent
+ MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id
+ MySqlBinding::createInteger<uint8_t>(), // option: scope_id
+ MySqlBinding::createString(65536), // option: user_context
+ MySqlBinding::createString(128), // option: shared_network_name
+ MySqlBinding::createInteger<uint64_t>(), // option: pool_id
+ MySqlBinding::createTimestamp() //option: modification_ts
};
uint64_t last_pool_id = 0;
+ uint64_t last_option_id = 0;
// Execute actual query.
conn_.selectQuery(index, in_bindings, out_bindings,
- [&subnets, &last_pool_id]
+ [this, &subnets, &last_pool_id, &last_option_id]
(MySqlBindingCollection& out_bindings) {
// Get pointer to the last subnet in the collection.
Subnet4Ptr last_subnet;
(out_bindings[21]->getInteger<uint32_t>() != 0) &&
(out_bindings[22]->getInteger<uint32_t>() != 0) &&
((last_pool_id == 0) ||
- (out_bindings[20]->getInteger<uint64_t>() != last_pool_id))) {
+ (out_bindings[20]->getInteger<uint64_t>() > last_pool_id))) {
last_pool_id = out_bindings[20]->getInteger<uint64_t>();
Pool4Ptr pool(new Pool4(IOAddress(out_bindings[21]->getInteger<uint32_t>()),
IOAddress(out_bindings[22]->getInteger<uint32_t>())));
last_subnet->addPool(pool);
}
+
+ // Parse option.
+ if (!out_bindings[25]->amNull() &&
+ ((last_option_id == 0) ||
+ (last_option_id < out_bindings[25]->getInteger<uint64_t>()))) {
+ last_option_id = out_bindings[25]->getInteger<uint64_t>();
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 25);
+ if (desc) {
+ last_subnet->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
+
});
}
in_bindings);
} catch (const DuplicateEntry&) {
- // Delete existing pools in case the updated subnet contains different
- // set of pools.
deletePools4(subnet);
+ deleteOptions4(existing_subnet);
// Need to add one more binding for WHERE clause.
in_bindings.push_back(MySqlBinding::createInteger<uint32_t>(subnet->getID()));
createPool4(boost::dynamic_pointer_cast<Pool4>(pool), subnet);
}
+ // (Re)create options.
+ auto option_spaces = subnet->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = subnet->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy(new OptionDescriptor(*desc));
+ desc_copy->space_name_ = option_space;
+ createUpdateOption4(selector, subnet->getID(), desc_copy);
+ }
+ }
+
transaction.commit();
}
MySqlBinding::createString(65536), // require_client_classes
MySqlBinding::createInteger<uint8_t>(), // reservation_mode
MySqlBinding::createString(65536), // user_context
- MySqlBinding::createInteger<uint32_t>() // valid_lifetime
+ MySqlBinding::createInteger<uint32_t>(), // valid_lifetime
+ MySqlBinding::createInteger<uint64_t>(), // option: option_id
+ MySqlBinding::createInteger<uint8_t>(), // option: code
+ MySqlBinding::createBlob(65536), // option: value
+ MySqlBinding::createString(8192), // option: formatted_value
+ MySqlBinding::createString(128), // option: space
+ MySqlBinding::createInteger<uint8_t>(), // option: persistent
+ MySqlBinding::createInteger<uint32_t>(), // option: dhcp4_subnet_id
+ MySqlBinding::createInteger<uint8_t>(), // option: scope_id
+ MySqlBinding::createString(65536), // option: user_context
+ MySqlBinding::createString(128), // option: shared_network_name
+ MySqlBinding::createInteger<uint64_t>(), // option: pool_id
+ MySqlBinding::createTimestamp() //option: modification_ts
};
uint64_t last_network_id = 0;
+ uint64_t last_option_id = 0;
+
conn_.selectQuery(index, in_bindings, out_bindings,
- [&shared_networks, &last_network_id]
+ [this, &shared_networks, &last_network_id, &last_option_id]
(MySqlBindingCollection& out_bindings) {
SharedNetwork4Ptr last_network;
if (!shared_networks.empty()) {
shared_networks.push_back(last_network);
}
+
+ // Parse option.
+ if (!out_bindings[13]->amNull() &&
+ ((last_option_id == 0) ||
+ (last_option_id < out_bindings[13]->getInteger<uint64_t>()))) {
+ last_option_id = out_bindings[13]->getInteger<uint64_t>();
+
+ OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 13);
+ if (desc) {
+ last_network->getCfgOption()->add(*desc, desc->space_name_);
+ }
+ }
});
}
in_bindings);
} catch (const DuplicateEntry&) {
+ deleteOptions4(shared_network);
+
// Need to add one more binding for WHERE clause.
in_bindings.push_back(MySqlBinding::createString(shared_network->getName()));
conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_SHARED_NETWORK4,
in_bindings);
}
+ // (Re)create options.
+ auto option_spaces = shared_network->getCfgOption()->getOptionSpaceNames();
+ for (auto option_space : option_spaces) {
+ OptionContainerPtr options = shared_network->getCfgOption()->getAll(option_space);
+ for (auto desc = options->begin(); desc != options->end(); ++desc) {
+ OptionDescriptorPtr desc_copy(new OptionDescriptor(*desc));
+ desc_copy->space_name_ = option_space;
+ createUpdateOption4(selector, shared_network->getName(), desc_copy);
+ }
+ }
+
transaction.commit();
}
- /// @brief Sends query to the database to retrieve multiple option
- /// definitions.
+ /// @brief Sends query to insert or update DHCP option in a subnet.
///
- /// Query should order option definitions by id.
+ /// @param selector Server selector.
+ /// @param subnet_id Identifier of the subnet the option belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption4(const ServerSelector& selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option) {
+
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
+ createOptionValueBinding(option),
+ MySqlBinding::condCreateString(option->formatted_value_),
+ MySqlBinding::condCreateString(option->space_name_),
+ MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option->persistent_)),
+ MySqlBinding::createNull(),
+ MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
+ MySqlBinding::createInteger<uint8_t>(1),
+ createInputContextBinding(option),
+ MySqlBinding::createNull(),
+ MySqlBinding::createNull(),
+ MySqlBinding::createTimestamp(option->getModificationTime())
+ };
+
+ OptionDescriptorPtr existing_option = getOption4(selector, subnet_id,
+ option->option_->getType(),
+ option->space_name_);
+ if (existing_option) {
+ in_bindings.push_back(MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)));
+ in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(option->option_->getType()));
+ in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID,
+ in_bindings);
+
+ } else {
+ conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4,
+ in_bindings);
+ }
+ }
+
+ /// @brief Sends query to insert or update DHCP option in a shared network.
///
- /// @param index Index of the query to be used.
- /// @param in_bindings Input bindings specifying selection criteria. The
- /// size of the bindings collection must match the number of placeholders
- /// in the prepared statement. The input bindings collection must be empty
- /// if the query contains no WHERE clause.
- /// @param [out] option_defs Reference to the container where fetched
- /// option definitions will be inserted.
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network the option
+ /// belongs to.
+ /// @param option Pointer to the option descriptor encapsulating the option.
+ void createUpdateOption4(const ServerSelector& selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createInteger<uint8_t>(option->option_->getType()),
+ createOptionValueBinding(option),
+ MySqlBinding::condCreateString(option->formatted_value_),
+ MySqlBinding::condCreateString(option->space_name_),
+ MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(option->persistent_)),
+ MySqlBinding::createNull(),
+ MySqlBinding::createNull(),
+ MySqlBinding::createInteger<uint8_t>(4),
+ createInputContextBinding(option),
+ MySqlBinding::createString(shared_network_name),
+ MySqlBinding::createNull(),
+ MySqlBinding::createTimestamp(option->getModificationTime())
+ };
+
+ OptionDescriptorPtr existing_option = getOption4(selector, shared_network_name,
+ option->option_->getType(),
+ option->space_name_);
+ if (existing_option) {
+ in_bindings.push_back(MySqlBinding::createString(shared_network_name));
+ in_bindings.push_back(MySqlBinding::createInteger<uint8_t>(option->option_->getType()));
+ in_bindings.push_back(MySqlBinding::condCreateString(option->space_name_));
+ conn_.updateDeleteQuery(MySqlConfigBackendDHCPv4Impl::
+ UPDATE_OPTION4_SHARED_NETWORK,
+ in_bindings);
+ } else {
+ conn_.insertQuery(MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4, in_bindings);
+ }
+ }
/// @brief Sends query to retrieve single option definition by code and
/// option space.
return (option_defs);
}
+ /// @brief Sends query to retrieve single option by code and option space
+ /// for a giben subnet id.
+ ///
+ /// @param selector Server selector.
+ /// @param subnet_id Subnet identifier.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option descriptor or NULL if such
+ /// option doesn't exist.
+ OptionDescriptorPtr getOption4(const ServerSelector& /* selector */,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ OptionContainer options;
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
+ MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code)),
+ MySqlBinding::createString(space)
+ };
+ getOptions(GET_OPTION4_SUBNET_ID_CODE_SPACE, in_bindings, Option::V4,
+ options);
+ return (options.empty() ? OptionDescriptorPtr() :
+ OptionDescriptorPtr(new OptionDescriptor(*options.begin())));
+ }
+
+ /// @brief Sends query to retrieve single option by code and option space
+ /// for a given shared network.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Shared network name.
+ /// @param code Option code.
+ /// @param space Option space name.
+ ///
+ /// @return Pointer to the returned option descriptor or NULL if such
+ /// option doesn't exist.
+ OptionDescriptorPtr getOption4(const ServerSelector& /* selector */,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ OptionContainer options;
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(shared_network_name),
+ MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(code)),
+ MySqlBinding::createString(space)
+ };
+ getOptions(GET_OPTION4_SHARED_NETWORK_CODE_SPACE, in_bindings, Option::V4,
+ options);
+ return (options.empty() ? OptionDescriptorPtr() :
+ OptionDescriptorPtr(new OptionDescriptor(*options.begin())));
+ }
+
/// @brief Sends query to insert or update option definition.
///
/// @param server_selector Server selector.
// Run DELETE.
return (conn_.updateDeleteQuery(DELETE_OPTION_DEF4_CODE_NAME, in_bindings));
}
+
+ /// @brief Deletes subnet level option.
+ ///
+ /// @param selector Server selector.
+ /// @param subnet_id Identifier of the subnet to which deleted option
+ /// belongs.
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ void deleteOption4(const db::ServerSelector& /* selector */,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet_id)),
+ MySqlBinding::createInteger<uint8_t>(code),
+ MySqlBinding::createString(space)
+ };
+
+ // Run DELETE.
+ conn_.updateDeleteQuery(DELETE_OPTION4_SUBNET_ID, in_bindings);
+ }
+
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network which deleted
+ /// option belongs to
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ void deleteOption4(const db::ServerSelector& /* selector */,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(shared_network_name),
+ MySqlBinding::createInteger<uint8_t>(code),
+ MySqlBinding::createString(space)
+ };
+
+ // Run DELETE.
+ conn_.updateDeleteQuery(DELETE_OPTION4_SHARED_NETWORK, in_bindings);
+ }
+
+ /// @brief Deletes options belonging to a subnet from the database.
+ ///
+ /// @param subnet Pointer to the subnet for which options should be
+ /// deleted.
+ void deleteOptions4(const Subnet4Ptr& subnet) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createInteger<uint32_t>(subnet->getID())
+ };
+
+ // Run DELETE.
+ conn_.updateDeleteQuery(DELETE_OPTIONS4_SUBNET_ID, in_bindings);
+ }
+
+ /// @brief Deletes options belonging to a shared network from the database.
+ ///
+ /// @param subnet Pointer to the subnet for which options should be
+ /// deleted.
+ void deleteOptions4(const SharedNetwork4Ptr& shared_network) {
+ MySqlBindingCollection in_bindings = {
+ MySqlBinding::createString(shared_network->getName())
+ };
+
+ // Run DELETE.
+ conn_.updateDeleteQuery(DELETE_OPTIONS4_SHARED_NETWORK, in_bindings);
+ }
};
/// @brief Array of tagged statements.
" p.start_address,"
" p.end_address,"
" p.subnet_id,"
- " p.modification_ts "
+ " p.modification_ts,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_subnet AS s "
"LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id "
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id "
"WHERE s.subnet_id = ? "
- "ORDER BY s.subnet_id, p.id" },
+ "ORDER BY s.subnet_id, p.id, o.option_id" },
// Select subnet by prefix.
{ MySqlConfigBackendDHCPv4Impl::GET_SUBNET4_PREFIX,
" p.start_address,"
" p.end_address,"
" p.subnet_id,"
- " p.modification_ts "
+ " p.modification_ts,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_subnet AS s "
"LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id "
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id "
"WHERE s.subnet_prefix = ? "
- "ORDER BY s.subnet_id, p.id" },
+ "ORDER BY s.subnet_id, p.id, o.option_id" },
// Select all subnets.
{ MySqlConfigBackendDHCPv4Impl::GET_ALL_SUBNETS4,
" p.start_address,"
" p.end_address,"
" p.subnet_id,"
- " p.modification_ts "
+ " p.modification_ts,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_subnet AS s "
"LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id "
- "ORDER BY s.subnet_id" },
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id "
+ "ORDER BY s.subnet_id, p.id, o.option_id" },
// Select subnets having modification time later than X.
{ MySqlConfigBackendDHCPv4Impl::GET_MODIFIED_SUBNETS4,
" p.start_address,"
" p.end_address,"
" p.subnet_id,"
- " p.modification_ts "
+ " p.modification_ts,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_subnet AS s "
"LEFT JOIN dhcp4_pool AS p ON s.subnet_id = p.subnet_id "
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 1 AND s.subnet_id = o.dhcp4_subnet_id "
"WHERE s.modification_ts > ? "
- "ORDER BY s.subnet_id" },
+ "ORDER BY s.subnet_id, p.id, o.option_id" },
// Select shared network by name.
{ MySqlConfigBackendDHCPv4Impl::GET_SHARED_NETWORK4_NAME,
" n.require_client_classes,"
" n.reservation_mode,"
" n.user_context,"
- " n.valid_lifetime "
+ " n.valid_lifetime,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_shared_network AS n "
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name "
"WHERE n.name = ? "
- "ORDER BY n.id" },
+ "ORDER BY n.id, o.option_id" },
// Select all shared networks.
{ MySqlConfigBackendDHCPv4Impl::GET_ALL_SHARED_NETWORKS4,
" n.require_client_classes,"
" n.reservation_mode,"
" n.user_context,"
- " n.valid_lifetime "
+ " n.valid_lifetime,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_shared_network AS n "
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name "
"ORDER BY n.id" },
// Select modified shared networks.
" n.require_client_classes,"
" n.reservation_mode,"
" n.user_context,"
- " n.valid_lifetime "
+ " n.valid_lifetime,"
+ " o.option_id,"
+ " o.code,"
+ " o.value,"
+ " o.formatted_value,"
+ " o.space,"
+ " o.persistent,"
+ " o.dhcp4_subnet_id,"
+ " o.scope_id,"
+ " o.user_context,"
+ " o.shared_network_name,"
+ " o.pool_id,"
+ " o.modification_ts "
"FROM dhcp4_shared_network AS n "
+ "LEFT JOIN dhcp4_options AS o ON o.scope_id = 4 AND n.name = o.shared_network_name "
"WHERE n.modification_ts > ? "
"ORDER BY n.id" },
"WHERE modification_ts > ? "
"ORDER BY d.id" },
+ // Retrieves an option for a given subnet, option code and space.
+ { MySqlConfigBackendDHCPv4Impl::GET_OPTION4_SUBNET_ID_CODE_SPACE,
+ "SELECT"
+ " option_id,"
+ " code,"
+ " value,"
+ " formatted_value,"
+ " space,"
+ " persistent,"
+ " dhcp4_subnet_id,"
+ " scope_id,"
+ " user_context,"
+ " shared_network_name,"
+ " pool_id,"
+ " modification_ts "
+ "FROM dhcp4_options "
+ "WHERE scope_id = 1 AND dhcp4_subnet_id = ? AND"
+ " code = ? AND space = ? "
+ "ORDER BY option_id" },
+
+ // Retrieves an option for a given shared network, option code and space.
+ { MySqlConfigBackendDHCPv4Impl::GET_OPTION4_SHARED_NETWORK_CODE_SPACE,
+ "SELECT"
+ " option_id,"
+ " code,"
+ " value,"
+ " formatted_value,"
+ " space,"
+ " persistent,"
+ " dhcp4_subnet_id,"
+ " scope_id,"
+ " user_context,"
+ " shared_network_name,"
+ " pool_id,"
+ " modification_ts "
+ "FROM dhcp4_options "
+ "WHERE scope_id = 4 AND shared_network_name = ? AND"
+ " code = ? AND space = ? "
+ "ORDER BY option_id" },
+
// Insert a subnet.
{ MySqlConfigBackendDHCPv4Impl::INSERT_SUBNET4,
"INSERT INTO dhcp4_subnet("
"user_context"
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" },
+ // Insert subnet specific option.
+ { MySqlConfigBackendDHCPv4Impl::INSERT_OPTION4,
+ "INSERT INTO dhcp4_options ("
+ "code,"
+ "value,"
+ "formatted_value,"
+ "space,"
+ "persistent,"
+ "dhcp_client_class,"
+ "dhcp4_subnet_id,"
+ "scope_id,"
+ "user_context,"
+ "shared_network_name,"
+ "pool_id,"
+ "modification_ts"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" },
+
// Update existing subnet.
{ MySqlConfigBackendDHCPv4Impl::UPDATE_SUBNET4,
"UPDATE dhcp4_subnet SET"
" user_context = ? "
"WHERE code = ? AND space = ?" },
+ // Update existing subnet level option.
+ { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SUBNET_ID,
+ "UPDATE dhcp4_options SET"
+ " code = ?,"
+ " value = ?,"
+ " formatted_value = ?,"
+ " space = ?,"
+ " persistent = ?,"
+ " dhcp_client_class = ?,"
+ " dhcp4_subnet_id = ?,"
+ " scope_id = ?,"
+ " user_context = ?,"
+ " shared_network_name = ?,"
+ " pool_id = ?,"
+ " modification_ts = ? "
+ "WHERE scope_id = 1 AND dhcp4_subnet_id = ? AND code = ? AND space = ?"
+ },
+
+ // Update existing shared network level option.
+ { MySqlConfigBackendDHCPv4Impl::UPDATE_OPTION4_SHARED_NETWORK,
+ "UPDATE dhcp4_options SET"
+ " code = ?,"
+ " value = ?,"
+ " formatted_value = ?,"
+ " space = ?,"
+ " persistent = ?,"
+ " dhcp_client_class = ?,"
+ " dhcp4_subnet_id = ?,"
+ " scope_id = ?,"
+ " user_context = ?,"
+ " shared_network_name = ?,"
+ " pool_id = ?,"
+ " modification_ts = ? "
+ "WHERE scope_id = 4 AND shared_network_name = ? AND code = ? AND space = ?"
+ },
+
// Delete subnet by id.
{ MySqlConfigBackendDHCPv4Impl::DELETE_SUBNET4_ID,
"DELETE FROM dhcp4_subnet "
// Delete all option definitions.
{ MySqlConfigBackendDHCPv4Impl::DELETE_ALL_OPTION_DEFS4,
- "DELETE FROM dhcp4_option_def" }
+ "DELETE FROM dhcp4_option_def" },
+
+ // Delete single option from a subnet.
+ { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SUBNET_ID,
+ "DELETE FROM dhcp4_options "
+ "WHERE scope_id = 1 AND dhcp4_subnet_id = ?"
+ " AND code = ? AND space = ?" },
+
+ // Delete single option from a shared network.
+ { MySqlConfigBackendDHCPv4Impl::DELETE_OPTION4_SHARED_NETWORK,
+ "DELETE FROM dhcp4_options "
+ "WHERE scope_id = 4 AND shared_network_name = ?"
+ " AND code = ? AND space = ?" },
+
+ // Delete options belonging to a subnet.
+ { MySqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SUBNET_ID,
+ "DELETE FROM dhcp4_options "
+ "WHERE scope_id = 1 AND dhcp4_subnet_id = ?" },
+
+ // Delete options belonging to a shared_network.
+ { MySqlConfigBackendDHCPv4Impl::DELETE_OPTIONS4_SHARED_NETWORK,
+ "DELETE FROM dhcp4_options "
+ "WHERE scope_id = 4 AND shared_network_name = ?" }
}
};
void
MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& /* server_selector */,
- const OptionPtr& /* option */) {
+ const OptionDescriptorPtr& /* option */) {
}
void
-MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& /* server_selector */,
- const SubnetID& /* subnet_id */,
- const OptionPtr& /* option */) {
+MySqlConfigBackendDHCPv4::createUpdateOption4(const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option) {
+ impl_->createUpdateOption4(selector, shared_network_name, option);
+}
+
+void
+MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& selector,
+ const SubnetID& subnet_id,
+ const OptionDescriptorPtr& option) {
+ impl_->createUpdateOption4(selector, subnet_id, option);
}
void
MySqlConfigBackendDHCPv4::createUpdateOption4(const ServerSelector& /* server_selector */,
const asiolink::IOAddress& /* pool_start_address */,
const asiolink::IOAddress& /* pool_end_address */,
- const OptionPtr& /* option */) {
+ const OptionDescriptorPtr& /* option */) {
}
void
}
uint64_t
-MySqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector */,
- const SubnetID& /* subnet_id */,
- const uint16_t /* code */,
- const std::string& /* space */) {
- return (0);
+MySqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ impl_->deleteOption4(selector, shared_network_name, code, space);
+}
+
+void
+MySqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& selector,
+ const SubnetID& subnet_id,
+ const uint16_t code,
+ const std::string& space) {
+ impl_->deleteOption4(selector, subnet_id, code, space);
}
uint64_t
/// @param option Option to be added or updated.
virtual void
createUpdateOption4(const db::ServerSelector& server_selector,
- const OptionPtr& option);
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates shared network level option.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of a shared network to which option
+ /// belongs.
+ /// @param option Option to be added or updated.
+ virtual void
+ createUpdateOption4(const db::ServerSelector& selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option);
/// @brief Creates or updates subnet level option.
///
virtual void
createUpdateOption4(const db::ServerSelector& server_selector,
const SubnetID& subnet_id,
- const OptionPtr& option);
+ const OptionDescriptorPtr& option);
/// @brief Creates or updates pool level option.
///
createUpdateOption4(const db::ServerSelector& server_selector,
const asiolink::IOAddress& pool_start_address,
const asiolink::IOAddress& pool_end_address,
- const OptionPtr& option);
+ const OptionDescriptorPtr& option);
/// @brief Creates or updates global string parameter.
///
deleteOption4(const db::ServerSelector& server_selector, const uint16_t code,
const std::string& space);
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network which deleted
+ /// option belongs to
+ /// @param code Code of the deleted option.
+ /// @param space Option space of the deleted option.
+ virtual void
+ deleteOption4(const db::ServerSelector& selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space);
+
/// @brief Deletes subnet level option.
///
/// @param server_selector Server selector.
#include <mysql_cb_impl.h>
#include <asiolink/io_address.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option_space.h>
+#include <util/buffer.h>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
#include <mysql.h>
#include <mysqld_error.h>
#include <cstdint>
using namespace isc::data;
using namespace isc::db;
+using namespace isc::util;
namespace isc {
namespace dhcp {
});
}
+void
+MySqlConfigBackendImpl::getOptions(const int index,
+ const db::MySqlBindingCollection& in_bindings,
+ const Option::Universe& universe,
+ OptionContainer& options) {
+ // Create output bindings. The order must match that in the prepared
+ // statement.
+ MySqlBindingCollection out_bindings = {
+ MySqlBinding::createInteger<uint64_t>(), // option_id
+ MySqlBinding::createInteger<uint8_t>(), // code
+ MySqlBinding::createBlob(65536), // value
+ MySqlBinding::createString(8192), // formatted_value
+ MySqlBinding::createString(128), // space
+ MySqlBinding::createInteger<uint8_t>(), // persistent
+ MySqlBinding::createInteger<uint32_t>(), // dhcp4_subnet_id
+ MySqlBinding::createInteger<uint8_t>(), // scope_id
+ MySqlBinding::createString(65536), // user_context
+ MySqlBinding::createString(128), // shared_network_name
+ MySqlBinding::createInteger<uint64_t>(), // pool_id
+ MySqlBinding::createTimestamp() //modification_ts
+ };
+
+ uint64_t last_option_id = 0;
+
+ conn_.selectQuery(index, in_bindings, out_bindings,
+ [this, universe, &options, &last_option_id]
+ (MySqlBindingCollection& out_bindings) {
+ // Parse option.
+ if (!out_bindings[0]->amNull() &&
+ ((last_option_id == 0) ||
+ (last_option_id < out_bindings[0]->getInteger<uint64_t>()))) {
+ last_option_id = out_bindings[0]->getInteger<uint64_t>();
+
+ OptionDescriptorPtr desc = processOptionRow(universe, out_bindings.begin());
+ if (desc) {
+ options.push_back(*desc);
+ }
+ }
+ });
+}
+
+OptionDescriptorPtr
+MySqlConfigBackendImpl::processOptionRow(const Option::Universe& universe,
+ MySqlBindingCollection::iterator first_binding) {
+ std::string space = (*(first_binding + 4))->getStringOrDefault(DHCP4_OPTION_SPACE);
+ uint16_t code = (*(first_binding + 1))->getInteger<uint8_t>();
+
+ OptionDefinitionPtr def = LibDHCP::getOptionDef(space, code);
+ if (!def && (space != DHCP4_OPTION_SPACE) && (space != DHCP6_OPTION_SPACE)) {
+ uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
+ if (vendor_id > 0) {
+ def = LibDHCP::getVendorOptionDef(universe, vendor_id, code);
+ }
+ }
+
+ if (!def) {
+ def = LibDHCP::getRuntimeOptionDef(space, code);
+ }
+
+ std::vector<uint8_t> blob;
+ if (!(*(first_binding + 2))->amNull()) {
+ blob = (*(first_binding + 2))->getBlob();
+ }
+ OptionBuffer buf(blob.begin(), blob.end());
+
+ std::string formatted_value = (*(first_binding + 3))->getStringOrDefault("");
+
+ OptionPtr option;
+ if (!def) {
+ option.reset(new Option(universe, code, buf.begin(), buf.end()));
+
+ } else {
+ if (formatted_value.empty()) {
+ option = def->optionFactory(universe, code, buf.begin(),
+ buf.end());
+ } else {
+ // Spit the value specified in comma separated values
+ // format.
+ std::vector<std::string> split_vec;
+ boost::split(split_vec, formatted_value, boost::is_any_of(","));
+ option = def->optionFactory(universe, code, split_vec);
+ }
+ }
+
+ bool persistent = static_cast<bool>((*(first_binding + 5))->getIntegerOrDefault<uint8_t>(0));
+
+ OptionDescriptorPtr desc(new OptionDescriptor(option, persistent, formatted_value));
+ desc->space_name_ = space;
+
+ desc->setModificationTime((*(first_binding + 11))->getTimestamp());
+
+ return (desc);
+}
+
MySqlBindingPtr
MySqlConfigBackendImpl::createInputRelayBinding(const NetworkPtr& network) {
ElementPtr relay_element = Element::createList();
MySqlBinding::createNull());
}
+MySqlBindingPtr
+MySqlConfigBackendImpl::createOptionValueBinding(const OptionDescriptorPtr& option) {
+ OptionPtr opt = option->option_;
+ if (option->formatted_value_.empty() && (opt->len() > opt->getHeaderLen())) {
+ OutputBuffer buf(opt->len());
+ opt->pack(buf);
+ const char* buf_ptr = static_cast<const char*>(buf.getData());
+ std::vector<uint8_t> blob(buf_ptr + opt->getHeaderLen(),
+ buf_ptr + buf.getLength());
+ return (MySqlBinding::createBlob(blob.begin(), blob.end()));
+
+ }
+
+ return (MySqlBinding::createNull());
+}
+
+
} // end of namespace isc::dhcp
} // end of namespace isc
#define MYSQL_CONFIG_BACKEND_IMPL_H
#include <database/database_connection.h>
+#include <dhcp/option.h>
#include <dhcp/option_definition.h>
+#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/network.h>
#include <mysql/mysql_binding.h>
#include <mysql/mysql_connection.h>
const db::MySqlBindingCollection& in_bindings,
OptionDefContainer& option_defs);
+ /// @brief Sends query to the database to retrieve multiple options.
+ ///
+ /// Query should order by option_id.
+ ///
+ /// @param index Index of the query to be used.
+ /// @param in_bindings Input bindings specifying selection criteria. The
+ /// size of the bindings collection must match the number of placeholders
+ /// in the prepared statement. The input bindings collection must be empty
+ /// if the query contains no WHERE clause.
+ /// @param universe Option universe, i.e. V4 or V6.
+ /// @param [out] options Reference to the container where fetched options
+ /// will be inserted.
+ void getOptions(const int index,
+ const db::MySqlBindingCollection& in_bindings,
+ const Option::Universe& universe,
+ OptionContainer& options);
+
+ /// @brief Returns DHCP option instance from output bindings.
+ ///
+ /// The following is the expected order of columns specified in the SELECT
+ /// query:
+ /// - option_id,
+ /// - code,
+ /// - value,
+ /// - formatted_value,
+ /// - space,
+ /// - persistent,
+ /// - dhcp4_subnet_id,
+ /// - scope_id,
+ /// - user_context,
+ /// - shared_network_name,
+ /// - pool_id,
+ /// - modification_ts
+ ///
+ /// @param universe V4 or V6.
+ /// @param first_binding Iterator of the output binding containing
+ /// option_id.
+ OptionDescriptorPtr
+ processOptionRow(const Option::Universe& universe,
+ db::MySqlBindingCollection::iterator first_binding);
+
/// @brief Creates input binding for relay addresses.
///
/// @param network Pointer to a shared network or subnet for which binding
db::MySqlBinding::createNull());
}
+ /// @brief Creates input binding for option value parameter.
+ ///
+ /// @param option Option descriptor holding option for which binding is to
+ /// be created.
+ /// @return Pointer to the binding (possibly null binding if formatted
+ /// value is non-empty.
+ db::MySqlBindingPtr createOptionValueBinding(const OptionDescriptorPtr& option);
/// @brief Represents connection to the MySQL database.
db::MySqlConnection conn_;
mysql_cb_unittests_CXXFLAGS = $(AM_CXXFLAGS)
-mysql_cb_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/mysql_cb/libmysqlcb.la
+mysql_cb_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la
+mysql_cb_unittests_LDADD += $(top_builddir)/src/hooks/dhcp/mysql_cb/libmysqlcb.la
mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
mysql_cb_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+#include <mysql_cb_dhcp4.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_space.h>
+#include <dhcp/option_string.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
-#include <mysql_cb_dhcp4.h>
+#include <dhcpsrv/testutils/generic_backend_unittest.h>
#include <mysql/testutils/mysql_schema.h>
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
using namespace isc::db::test;
using namespace isc::data;
using namespace isc::dhcp;
+using namespace isc::dhcp::test;
namespace {
/// @brief Test fixture class for @c MySqlConfigBackendDHCPv4.
-class MySqlConfigBackendDHCPv4Test : public ::testing::Test {
+class MySqlConfigBackendDHCPv4Test : public GenericBackendTest {
public:
/// @brief Constructor.
}
// Create test data.
+ initTestOptions();
initTestSubnets();
initTestSharedNetworks();
initTestOptionDefs();
Pool4Ptr pool2(new Pool4(IOAddress("192.0.2.50"), IOAddress("192.0.2.60")));
subnet->addPool(pool2);
+ // Add several options to the subnet.
+ subnet->getCfgOption()->add(test_options_[0]->option_,
+ test_options_[0]->persistent_,
+ test_options_[0]->space_name_);
+
+ subnet->getCfgOption()->add(test_options_[1]->option_,
+ test_options_[1]->persistent_,
+ test_options_[1]->space_name_);
+
+ subnet->getCfgOption()->add(test_options_[2]->option_,
+ test_options_[2]->persistent_,
+ test_options_[2]->space_name_);
+
test_subnets_.push_back(subnet);
// Adding another subnet with the same subnet id to test
shared_network->setContext(user_context);
shared_network->setValid(5555);
+ // Add several options to the shared network.
+ shared_network->getCfgOption()->add(test_options_[2]->option_,
+ test_options_[2]->persistent_,
+ test_options_[2]->space_name_);
+
+ shared_network->getCfgOption()->add(test_options_[3]->option_,
+ test_options_[3]->persistent_,
+ test_options_[3]->space_name_);
+
+ shared_network->getCfgOption()->add(test_options_[4]->option_,
+ test_options_[4]->persistent_,
+ test_options_[4]->space_name_);
+
test_networks_.push_back(shared_network);
// Adding another shared network called "level1" to test
test_option_defs_.push_back(option_def);
}
+ /// @brief Creates several DHCP options used in tests.
+ void initTestOptions() {
+ ElementPtr user_context = Element::createMap();
+ user_context->set("foo", Element::create("bar"));
+
+ OptionDefSpaceContainer defs;
+
+ OptionDescriptor desc =
+ createOption<OptionString>(Option::V4, DHO_BOOT_FILE_NAME,
+ true, false, "my-boot-file");
+ desc.space_name_ = DHCP4_OPTION_SPACE;
+ desc.setContext(user_context);
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createOption<OptionUint8>(Option::V4, DHO_DEFAULT_IP_TTL,
+ false, true, 64);
+ desc.space_name_ = DHCP4_OPTION_SPACE;
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createOption<OptionUint32>(Option::V4, 1, false, false, 312131),
+ desc.space_name_ = "vendor-encapsulated-options";
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createAddressOption<Option4AddrLst>(254, true, true,
+ "192.0.2.3");
+ desc.space_name_ = DHCP4_OPTION_SPACE;
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createEmptyOption(Option::V4, 1, true);
+ desc.space_name_ = "isc";
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ desc = createAddressOption<Option4AddrLst>(2, false, true, "10.0.0.5",
+ "10.0.0.3", "10.0.3.4");
+ desc.space_name_ = "isc";
+ test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc)));
+
+ // Add definitions for DHCPv4 non-standard options.
+ defs.addItem(OptionDefinitionPtr(new OptionDefinition(
+ "vendor-encapsulated-1", 1, "uint32")),
+ "vendor-encapsulated-options");
+ defs.addItem(OptionDefinitionPtr(new OptionDefinition(
+ "option-254", 254, "ipv4-address", true)),
+ DHCP4_OPTION_SPACE);
+ defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-1", 1, "empty")), "isc");
+ defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-2", 2, "ipv4-address", true)),
+ "isc");
+
+ // Register option definitions.
+ LibDHCP::setRuntimeOptionDefs(defs);
+ }
+
/// @brief Initialize posix time values used in tests.
void initTimestamps() {
// Current time minus 1 hour to make sure it is in the past.
/// @brief Holds pointers to option definitions used in tests.
std::vector<OptionDefinitionPtr> test_option_defs_;
+ /// @brief Holds pointers to options used in tests.
+ std::vector<OptionDescriptorPtr> test_options_;
+
/// @brief Holds timestamp values used in tests.
std::map<std::string, boost::posix_time::ptime> timestamps_;
ASSERT_TRUE(option_defs.empty());
}
+// This test verifies that subnet level option can be added, updated and
+// deleted.
+TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteSubnetOption4) {
+ // Insert new subnet.
+ Subnet4Ptr subnet = test_subnets_[1];
+ cbptr_->createUpdateSubnet4(ServerSelector::UNASSIGNED(), subnet);
+
+ // Fetch this subnet by subnet identifier.
+ Subnet4Ptr returned_subnet = cbptr_->getSubnet4(ServerSelector::UNASSIGNED(),
+ subnet->getID());
+ ASSERT_TRUE(returned_subnet);
+
+ OptionDescriptorPtr opt_boot_file_name = test_options_[0];
+ cbptr_->createUpdateOption4(ServerSelector::UNASSIGNED(), subnet->getID(),
+ opt_boot_file_name);
+
+ returned_subnet = cbptr_->getSubnet4(ServerSelector::UNASSIGNED(),
+ subnet->getID());
+ ASSERT_TRUE(returned_subnet);
+
+ OptionDescriptor returned_opt_boot_file_name =
+ returned_subnet->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_BOOT_FILE_NAME);
+ ASSERT_TRUE(returned_opt_boot_file_name.option_);
+ EXPECT_TRUE(returned_opt_boot_file_name.equals(*opt_boot_file_name));
+
+ opt_boot_file_name->persistent_ = !opt_boot_file_name->persistent_;
+ cbptr_->createUpdateOption4(ServerSelector::UNASSIGNED(), subnet->getID(),
+ opt_boot_file_name);
+
+ returned_subnet = cbptr_->getSubnet4(ServerSelector::UNASSIGNED(),
+ subnet->getID());
+ ASSERT_TRUE(returned_subnet);
+ returned_opt_boot_file_name =
+ returned_subnet->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_BOOT_FILE_NAME);
+ ASSERT_TRUE(returned_opt_boot_file_name.option_);
+ EXPECT_TRUE(returned_opt_boot_file_name.equals(*opt_boot_file_name));
+
+ cbptr_->deleteOption4(ServerSelector::UNASSIGNED(), subnet->getID(),
+ opt_boot_file_name->option_->getType(),
+ opt_boot_file_name->space_name_);
+
+ returned_subnet = cbptr_->getSubnet4(ServerSelector::UNASSIGNED(),
+ subnet->getID());
+ ASSERT_TRUE(returned_subnet);
+
+ EXPECT_FALSE(returned_subnet->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_BOOT_FILE_NAME).option_);
+}
+
+// This test verifies that shared network level option can be added,
+// updated and deleted.
+TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateDeleteSharedNetworkOption4) {
+ // Insert new shared network.
+ SharedNetwork4Ptr shared_network = test_networks_[1];
+ cbptr_->createUpdateSharedNetwork4(ServerSelector::UNASSIGNED(),
+ shared_network);
+
+ // Fetch this shared network by name.
+ SharedNetwork4Ptr returned_network =
+ cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(),
+ shared_network->getName());
+ ASSERT_TRUE(returned_network);
+
+ OptionDescriptorPtr opt_boot_file_name = test_options_[0];
+ cbptr_->createUpdateOption4(ServerSelector::UNASSIGNED(),
+ shared_network->getName(),
+ opt_boot_file_name);
+
+ returned_network = cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(),
+ shared_network->getName());
+ ASSERT_TRUE(returned_network);
+
+ OptionDescriptor returned_opt_boot_file_name =
+ returned_network->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_BOOT_FILE_NAME);
+ ASSERT_TRUE(returned_opt_boot_file_name.option_);
+ EXPECT_TRUE(returned_opt_boot_file_name.equals(*opt_boot_file_name));
+
+ opt_boot_file_name->persistent_ = !opt_boot_file_name->persistent_;
+ cbptr_->createUpdateOption4(ServerSelector::UNASSIGNED(),
+ shared_network->getName(),
+ opt_boot_file_name);
+
+ returned_network = cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(),
+ shared_network->getName());
+ ASSERT_TRUE(returned_network);
+ returned_opt_boot_file_name =
+ returned_network->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_BOOT_FILE_NAME);
+ ASSERT_TRUE(returned_opt_boot_file_name.option_);
+ EXPECT_TRUE(returned_opt_boot_file_name.equals(*opt_boot_file_name));
+
+ cbptr_->deleteOption4(ServerSelector::UNASSIGNED(),
+ shared_network->getName(),
+ opt_boot_file_name->option_->getType(),
+ opt_boot_file_name->space_name_);
+ returned_network = cbptr_->getSharedNetwork4(ServerSelector::UNASSIGNED(),
+ shared_network->getName());
+ ASSERT_TRUE(returned_network);
+ EXPECT_FALSE(returned_network->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_BOOT_FILE_NAME).option_);
+}
}
bool
OptionDescriptor::equals(const OptionDescriptor& other) const {
- return (persistent_ == other.persistent_ &&
- formatted_value_ == other.formatted_value_ &&
+ return ((persistent_ == other.persistent_) &&
+ (formatted_value_ == other.formatted_value_) &&
+ (space_name_ == other.space_name_) &&
option_->equals(other.option_));
}
#include <dhcp/option.h>
#include <dhcp/option_space_container.h>
#include <cc/cfg_to_element.h>
+#include <cc/stamped_element.h>
#include <cc/user_context.h>
#include <dhcpsrv/key_from_key.h>
#include <boost/multi_index_container.hpp>
/// for this option. This information comprises whether this option is sent
/// to DHCP client only on request (persistent = false) or always
/// (persistent = true).
-class OptionDescriptor : public data::UserContext {
+class OptionDescriptor : public data::StampedElement, public data::UserContext {
public:
/// @brief Option instance.
OptionPtr option_;
/// for the option which carries IPv6 address, a number and a text.
std::string formatted_value_;
+ /// @brief Option space name.
+ ///
+ /// Options are associated with option spaces. Typically, such association
+ /// is made when the option is stored in the @c OptionContainer. However,
+ /// in some cases it is also required to associate option with the particular
+ /// option space outside of the container. In particular, when the option
+ /// is fetched from a database. The database configuration backend will
+ /// set option space upon return of the option. In other cases this value
+ /// won't be set.
+ std::string space_name_;
+
/// @brief Constructor.
///
/// @param opt option
const std::string& formatted_value = "",
data::ConstElementPtr user_context = data::ConstElementPtr())
: option_(opt), persistent_(persist),
- formatted_value_(formatted_value) {
+ formatted_value_(formatted_value),
+ space_name_() {
setContext(user_context);
};
/// @param persist if true option is always sent.
OptionDescriptor(bool persist)
: option_(OptionPtr()), persistent_(persist),
- formatted_value_() {};
+ formatted_value_(), space_name_() {};
/// @brief Constructor.
///
/// @param desc descriptor
OptionDescriptor(const OptionDescriptor& desc)
: option_(desc.option_), persistent_(desc.persistent_),
- formatted_value_(desc.formatted_value_) {
+ formatted_value_(desc.formatted_value_),
+ space_name_(desc.space_name_) {
setContext(desc.getContext());
};
#include <database/server_selector.h>
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
+#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <util/optional_value.h>
/// @param option Option to be added or updated.
virtual void
createUpdateOption4(const db::ServerSelector& server_selector,
- const OptionPtr& option) = 0;
+ const OptionDescriptorPtr& option) = 0;
+
+ /// @brief Creates or updates shared network level option.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of a shared network to which option
+ /// belongs.
+ /// @param option Option to be added or updated.
+ virtual void
+ createUpdateOption4(const db::ServerSelector& selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option) = 0;
/// @brief Creates or updates subnet level option.
///
virtual void
createUpdateOption4(const db::ServerSelector& server_selector,
const SubnetID& subnet_id,
- const OptionPtr& option) = 0;
+ const OptionDescriptorPtr& option) = 0;
/// @brief Creates or updates pool level option.
///
createUpdateOption4(const db::ServerSelector& server_selector,
const asiolink::IOAddress& pool_start_address,
const asiolink::IOAddress& pool_end_address,
- const OptionPtr& option) = 0;
+ const OptionDescriptorPtr& option) = 0;
/// @brief Creates or updates global string parameter.
///
deleteOption4(const db::ServerSelector& server_selector, const uint16_t code,
const std::string& space) = 0;
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network which option
+ /// belongs to.
+ /// @param code Code of the option to be deleted.
+ /// @param space Option space of the option to be deleted.
+ virtual void
+ deleteOption4(const db::ServerSelector& selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) = 0;
+
/// @brief Deletes subnet level option.
///
/// @param server_selector Server selector.
void
ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector,
const db::ServerSelector& server_selector,
- const OptionPtr& option) {
+ const OptionDescriptorPtr& option) {
createUpdateDeleteProperty<void, const OptionPtr&>
(&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
server_selector, option);
}
+void
+ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector,
+ const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option) {
+ createUpdateDeleteProperty<const std::string&, const OptionDescriptorPtr&>
+ (&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
+ server_selector, shared_network_name, option);
+}
+
+
void
ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector,
const db::ServerSelector& server_selector,
const SubnetID& subnet_id,
- const OptionPtr& option) {
+ const OptionDescriptorPtr& option) {
createUpdateDeleteProperty<void, const SubnetID&, const OptionPtr&>
(&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
server_selector, subnet_id, option);
const db::ServerSelector& server_selector,
const IOAddress& pool_start_address,
const IOAddress& pool_end_address,
- const OptionPtr& option) {
+ const OptionDescriptorPtr& option) {
createUpdateDeleteProperty<void, const IOAddress&, const IOAddress&, const OptionPtr&>
+ const OptionDescriptorPtr&>
(&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
server_selector, pool_start_address, pool_end_address, option);
}
code, space));
}
+void
+ConfigBackendPoolDHCPv4::deleteOption4(const db::BackendSelector& backend_selector,
+ const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) {
+ createUpdateDeleteProperty<const std::string&, uint16_t, const std::string&>
+ (&ConfigBackendDHCPv4::deleteOption4, backend_selector, server_selector,
+ shared_network_name, code, space);
+}
+
uint64_t
ConfigBackendPoolDHCPv4::deleteOption4(const db::BackendSelector& backend_selector,
const db::ServerSelector& server_selector,
#include <database/server_selector.h>
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
+#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/config_backend_dhcp4.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
virtual void
createUpdateOption4(const db::BackendSelector& backend_selector,
const db::ServerSelector& server_selector,
- const OptionPtr& option);
+ const OptionDescriptorPtr& option);
+
+ /// @brief Creates or updates shared network level option.
+ ///
+ /// @param backend_selector Backend selector.
+ /// @param server_selector Server selector.
+ /// @param shared_network_name Name of a shared network to which option
+ /// belongs.
+ /// @param option Option to be added or updated.
+ virtual void
+ createUpdateOption4(const db::BackendSelector& backend_selector,
+ const db::ServerSelector& server_selector,
+ const std::string& shared_network_name,
+ const OptionDescriptorPtr& option);
/// @brief Creates or updates subnet level option.
///
createUpdateOption4(const db::BackendSelector& backend_selector,
const db::ServerSelector& server_selector,
const SubnetID& subnet_id,
- const OptionPtr& option);
+ const OptionDescriptorPtr& option);
/// @brief Creates or updates pool level option.
///
const db::ServerSelector& server_selector,
const asiolink::IOAddress& pool_start_address,
const asiolink::IOAddress& pool_end_address,
- const OptionPtr& option);
+ const OptionDescriptorPtr& option);
/// @brief Creates or updates global string parameter.
///
const uint16_t code,
const std::string& space);
+ /// @brief Deletes shared network level option.
+ ///
+ /// @param backend_selector Backend selector.
+ /// @param selector Server selector.
+ /// @param shared_network_name Name of the shared network which option
+ /// belongs to.
+ /// @param code Code of the option to be deleted.
+ /// @param space Option space of the option to be deleted.
+ virtual void
+ deleteOption4(const db::BackendSelector& backend_selector,
+ const db::ServerSelector& selector,
+ const std::string& shared_network_name,
+ const uint16_t code,
+ const std::string& space) = 0;
+
/// @brief Deletes subnet level option.
///
/// @param backend_selector Backend selector.
libdhcpsrvtest_la_SOURCES += dhcp4o6_test_ipc.cc dhcp4o6_test_ipc.h
libdhcpsrvtest_la_SOURCES += host_data_source_utils.cc host_data_source_utils.h
libdhcpsrvtest_la_SOURCES += memory_host_data_source.cc memory_host_data_source.h
+libdhcpsrvtest_la_SOURCES += generic_backend_unittest.cc generic_backend_unittest.h
libdhcpsrvtest_la_SOURCES += generic_host_data_source_unittest.cc generic_host_data_source_unittest.h
libdhcpsrvtest_la_SOURCES += lease_file_io.cc lease_file_io.h
--- /dev/null
+// Copyright (C) 2018 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option_vendor.h>
+#include <dhcpsrv/testutils/generic_backend_unittest.h>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+GenericBackendTest::GenericBackendTest() {
+ LibDHCP::clearRuntimeOptionDefs();
+}
+
+GenericBackendTest::~GenericBackendTest() {
+ LibDHCP::clearRuntimeOptionDefs();
+}
+
+OptionDescriptor
+GenericBackendTest::createEmptyOption(const Option::Universe& universe,
+ const uint16_t option_type,
+ const bool persist) const {
+ OptionPtr option(new Option(universe, option_type));
+ OptionDescriptor desc(option, persist);
+ return (desc);
+}
+
+OptionDescriptor
+GenericBackendTest::createVendorOption(const Option::Universe& universe,
+ const bool persist,
+ const bool formatted,
+ const uint32_t vendor_id) const {
+ OptionVendorPtr option(new OptionVendor(universe, vendor_id));
+
+ std::ostringstream s;
+ if (formatted) {
+ // Vendor id comprises vendor-id field, for which we need to
+ // assign a value in the textual (formatted) format.
+ s << vendor_id;
+ }
+
+ OptionDescriptor desc(option, persist, s.str());
+ return (desc);
+}
+
+
+} // end of namespace isc::dhcp::test
+} // end of namespace isc::dhcp
+} // end of namespace isc
--- /dev/null
+// Copyright (C) 2018 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef GENERIC_BACKEND_UNITTEST_H
+#define GENERIC_BACKEND_UNITTEST_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/cfg_option.h>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief Generic test fixture class with utility functions for
+/// testing database backends.
+class GenericBackendTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor.
+ GenericBackendTest();
+
+ /// @brief Virtual destructor.
+ virtual ~GenericBackendTest();
+
+ /// @brief Creates an option descriptor holding an empty option.
+ ///
+ /// @param universe V4 or V6.
+ /// @param option_type Option type.
+ /// @param persist A boolean flag indicating if the option is always
+ /// returned to the client or only when requested.
+ ///
+ /// @return Descriptor holding an empty option.
+ OptionDescriptor createEmptyOption(const Option::Universe& universe,
+ const uint16_t option_type,
+ const bool persist) const;
+
+ /// @brief Creates an instance of the option for which it is possible to
+ /// specify universe, option type, persistence flag and value in
+ /// the constructor.
+ ///
+ /// Examples of options that can be created using this function are:
+ /// - @ref OptionString
+ /// - different variants of @ref OptionInt.
+ ///
+ /// @param universe V4 or V6.
+ /// @param option_type Option type.
+ /// @param persist A boolean flag indicating if the option is always
+ /// returned to the client or only when requested.
+ /// @param formatted A boolean value selecting if the formatted option
+ /// value should be used (if true), or binary value (if false).
+ /// @param value Option value to be assigned to the option.
+ /// @tparam OptionType Class encapsulating the option.
+ /// @tparam DataType Option value data type.
+ ///
+ /// @return Descriptor holding an instance of the option created.
+ template<typename OptionType, typename DataType>
+ OptionDescriptor createOption(const Option::Universe& universe,
+ const uint16_t option_type,
+ const bool persist,
+ const bool formatted,
+ const DataType& value) const {
+ boost::shared_ptr<OptionType> option(new OptionType(universe, option_type,
+ value));
+ std::ostringstream s;
+ if (formatted) {
+ // Using formatted option value. Convert option value to a
+ // textual format.
+ s << value;
+ }
+ OptionDescriptor desc(option, persist, s.str());
+ return (desc);
+ }
+
+ /// @brief Creates an instance of the option for which it is possible to
+ /// specify option type, persistence flag and value in the constructor.
+ ///
+ /// Examples of options that can be created using this function are:
+ /// - @ref Option4AddrLst
+ /// - @ref Option6AddrLst
+ ///
+ /// @param option_type Option type.
+ /// @param persist A boolean flag indicating if the option is always
+ /// returned to the client or only when requested.
+ /// @param formatted A boolean value selecting if the formatted option
+ /// value should be used (if true), or binary value (if false).
+ /// @param value Option value to be assigned to the option.
+ /// @tparam OptionType Class encapsulating the option.
+ /// @tparam DataType Option value data type.
+ ///
+ /// @return Descriptor holding an instance of the option created.
+ template<typename OptionType, typename DataType>
+ OptionDescriptor createOption(const uint16_t option_type,
+ const bool persist,
+ const bool formatted,
+ const DataType& value) const {
+ boost::shared_ptr<OptionType> option(new OptionType(option_type, value));
+
+ std::ostringstream s;
+ if (formatted) {
+ // Using formatted option value. Convert option value to a
+ // textual format.
+ s << value;
+ }
+
+ OptionDescriptor desc(option, persist, s.str());
+ return (desc);
+ }
+
+ /// @brief Creates an instance of the option holding list of IP addresses.
+ ///
+ /// @param option_type Option type.
+ /// @param persist A boolean flag indicating if the option is always
+ /// returned to the client or only when requested.
+ /// @param formatted A boolean value selecting if the formatted option
+ /// value should be used (if true), or binary value (if false).
+ /// @param address1 First address to be included. If address is empty, it is
+ /// not included.
+ /// @param address2 Second address to be included. If address is empty, it
+ /// is not included.
+ /// @param address3 Third address to be included. If address is empty, it
+ /// is not included.
+ /// @tparam OptionType Class encapsulating the option.
+ ///
+ /// @return Descriptor holding an instance of the option created.
+ template<typename OptionType>
+ OptionDescriptor
+ createAddressOption(const uint16_t option_type,
+ const bool persist,
+ const bool formatted,
+ const std::string& address1 = "",
+ const std::string& address2 = "",
+ const std::string& address3 = "") const {
+ std::ostringstream s;
+ // First address.
+ typename OptionType::AddressContainer addresses;
+ if (!address1.empty()) {
+ addresses.push_back(asiolink::IOAddress(address1));
+ if (formatted) {
+ s << address1;
+ }
+ }
+ // Second address.
+ if (!address2.empty()) {
+ addresses.push_back(asiolink::IOAddress(address2));
+ if (formatted) {
+ if (s.tellp() != std::streampos(0)) {
+ s << ",";
+ }
+ s << address2;
+ }
+ }
+ // Third address.
+ if (!address3.empty()) {
+ addresses.push_back(asiolink::IOAddress(address3));
+ if (formatted) {
+ if (s.tellp() != std::streampos(0)) {
+ s << ",";
+ }
+ s << address3;
+ }
+ }
+
+ boost::shared_ptr<OptionType> option(new OptionType(option_type,
+ addresses));
+ OptionDescriptor desc(option, persist, s.str());
+ return (desc);
+ }
+
+ /// @brief Creates an instance of the vendor option.
+ ///
+ /// @param universe V4 or V6.
+ /// @param persist A boolean flag indicating if the option is always
+ /// returned to the client or only when requested.
+ /// @param formatted A boolean value selecting if the formatted option
+ /// value should be used (if true), or binary value (if false).
+ /// @param vendor_id Vendor identifier.
+ ///
+ /// @return Descriptor holding an instance of the option created.
+ OptionDescriptor createVendorOption(const Option::Universe& universe,
+ const bool persist,
+ const bool formatted,
+ const uint32_t vendor_id) const;
+};
+
+} // end of namespace isc::dhcp::test
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif
+
namespace dhcp {
namespace test {
-GenericHostDataSourceTest::GenericHostDataSourceTest() : hdsptr_() {
- LibDHCP::clearRuntimeOptionDefs();
+GenericHostDataSourceTest::GenericHostDataSourceTest()
+ : GenericBackendTest(), hdsptr_() {
}
GenericHostDataSourceTest::~GenericHostDataSourceTest() {
- LibDHCP::clearRuntimeOptionDefs();
hdsptr_.reset();
}
return (HWAddrPtr(new HWAddr(duid->getDuid(), HTYPE_ETHER)));
}
-
-OptionDescriptor
-GenericHostDataSourceTest::createEmptyOption(const Option::Universe& universe,
- const uint16_t option_type,
- const bool persist) const {
- OptionPtr option(new Option(universe, option_type));
- OptionDescriptor desc(option, persist);
- return (desc);
-}
-
-OptionDescriptor
-GenericHostDataSourceTest::createVendorOption(const Option::Universe& universe,
- const bool persist,
- const bool formatted,
- const uint32_t vendor_id) const {
- OptionVendorPtr option(new OptionVendor(universe, vendor_id));
-
- std::ostringstream s;
- if (formatted) {
- // Vendor id comprises vendor-id field, for which we need to
- // assign a value in the textual (formatted) format.
- s << vendor_id;
- }
-
- OptionDescriptor desc(option, persist, s.str());
- return (desc);
-}
-
void
GenericHostDataSourceTest::addTestOptions(const HostPtr& host,
const bool formatted,
#include <asiolink/io_address.h>
#include <dhcpsrv/base_host_data_source.h>
#include <dhcpsrv/host.h>
+#include <dhcpsrv/testutils/generic_backend_unittest.h>
#include <dhcp/classify.h>
#include <dhcp/option.h>
#include <boost/algorithm/string/join.hpp>
///
/// It contains utility functions for test purposes.
/// All concrete HostDataSource test classes should be derived from it.
-class GenericHostDataSourceTest : public ::testing::Test {
+class GenericHostDataSourceTest : public GenericBackendTest {
public:
/// @brief Universe (V4 or V6).
static bool compareHostsForSort6(const ConstHostPtr& host1,
const ConstHostPtr& host2);
- /// @brief Creates an option descriptor holding an empty option.
- ///
- /// @param universe V4 or V6.
- /// @param option_type Option type.
- /// @param persist A boolean flag indicating if the option is always
- /// returned to the client or only when requested.
- ///
- /// @return Descriptor holding an empty option.
- OptionDescriptor createEmptyOption(const Option::Universe& universe,
- const uint16_t option_type,
- const bool persist) const;
-
- /// @brief Creates an instance of the option for which it is possible to
- /// specify universe, option type, persistence flag and value in
- /// the constructor.
- ///
- /// Examples of options that can be created using this function are:
- /// - @ref OptionString
- /// - different variants of @ref OptionInt.
- ///
- /// @param universe V4 or V6.
- /// @param option_type Option type.
- /// @param persist A boolean flag indicating if the option is always
- /// returned to the client or only when requested.
- /// @param formatted A boolean value selecting if the formatted option
- /// value should be used (if true), or binary value (if false).
- /// @param value Option value to be assigned to the option.
- /// @tparam OptionType Class encapsulating the option.
- /// @tparam DataType Option value data type.
- ///
- /// @return Descriptor holding an instance of the option created.
- template<typename OptionType, typename DataType>
- OptionDescriptor createOption(const Option::Universe& universe,
- const uint16_t option_type,
- const bool persist,
- const bool formatted,
- const DataType& value) const {
- boost::shared_ptr<OptionType> option(new OptionType(universe, option_type,
- value));
- std::ostringstream s;
- if (formatted) {
- // Using formatted option value. Convert option value to a
- // textual format.
- s << value;
- }
- OptionDescriptor desc(option, persist, s.str());
- return (desc);
- }
-
- /// @brief Creates an instance of the option for which it is possible to
- /// specify option type, persistence flag and value in the constructor.
- ///
- /// Examples of options that can be created using this function are:
- /// - @ref Option4AddrLst
- /// - @ref Option6AddrLst
- ///
- /// @param option_type Option type.
- /// @param persist A boolean flag indicating if the option is always
- /// returned to the client or only when requested.
- /// @param formatted A boolean value selecting if the formatted option
- /// value should be used (if true), or binary value (if false).
- /// @param value Option value to be assigned to the option.
- /// @tparam OptionType Class encapsulating the option.
- /// @tparam DataType Option value data type.
- ///
- /// @return Descriptor holding an instance of the option created.
- template<typename OptionType, typename DataType>
- OptionDescriptor createOption(const uint16_t option_type,
- const bool persist,
- const bool formatted,
- const DataType& value) const {
- boost::shared_ptr<OptionType> option(new OptionType(option_type, value));
-
- std::ostringstream s;
- if (formatted) {
- // Using formatted option value. Convert option value to a
- // textual format.
- s << value;
- }
-
- OptionDescriptor desc(option, persist, s.str());
- return (desc);
- }
-
- /// @brief Creates an instance of the option holding list of IP addresses.
- ///
- /// @param option_type Option type.
- /// @param persist A boolean flag indicating if the option is always
- /// returned to the client or only when requested.
- /// @param formatted A boolean value selecting if the formatted option
- /// value should be used (if true), or binary value (if false).
- /// @param address1 First address to be included. If address is empty, it is
- /// not included.
- /// @param address2 Second address to be included. If address is empty, it
- /// is not included.
- /// @param address3 Third address to be included. If address is empty, it
- /// is not included.
- /// @tparam OptionType Class encapsulating the option.
- ///
- /// @return Descriptor holding an instance of the option created.
- template<typename OptionType>
- OptionDescriptor
- createAddressOption(const uint16_t option_type,
- const bool persist,
- const bool formatted,
- const std::string& address1 = "",
- const std::string& address2 = "",
- const std::string& address3 = "") const {
- std::ostringstream s;
- // First address.
- typename OptionType::AddressContainer addresses;
- if (!address1.empty()) {
- addresses.push_back(asiolink::IOAddress(address1));
- if (formatted) {
- s << address1;
- }
- }
- // Second address.
- if (!address2.empty()) {
- addresses.push_back(asiolink::IOAddress(address2));
- if (formatted) {
- if (s.tellp() != std::streampos(0)) {
- s << ",";
- }
- s << address2;
- }
- }
- // Third address.
- if (!address3.empty()) {
- addresses.push_back(asiolink::IOAddress(address3));
- if (formatted) {
- if (s.tellp() != std::streampos(0)) {
- s << ",";
- }
- s << address3;
- }
- }
-
- boost::shared_ptr<OptionType> option(new OptionType(option_type,
- addresses));
- OptionDescriptor desc(option, persist, s.str());
- return (desc);
- }
-
/// @brief Returns number of entries in the v4 options table.
///
/// This utility method is expected to be implemented by specific backends.
return (-1);
}
- /// @brief Creates an instance of the vendor option.
- ///
- /// @param universe V4 or V6.
- /// @param persist A boolean flag indicating if the option is always
- /// returned to the client or only when requested.
- /// @param formatted A boolean value selecting if the formatted option
- /// value should be used (if true), or binary value (if false).
- /// @param vendor_id Vendor identifier.
- ///
- /// @return Descriptor holding an instance of the option created.
- OptionDescriptor createVendorOption(const Option::Universe& universe,
- const bool persist,
- const bool formatted,
- const uint32_t vendor_id) const;
-
/// @brief Adds multiple options into the host.
///
/// This method creates the following options into the host object:
ALTER TABLE hosts
ADD COLUMN auth_key VARCHAR(16) NULL;
+
+# Add scope for shared network specific options.
+INSERT INTO dhcp_option_scope (scope_id, scope_name)
+ VALUES(4, "shared-network");
+
-- -----------------------------------------------------
-- Table `modification`
-- -----------------------------------------------------
UPDATE hosts SET dhcp6_subnet_id = NULL WHERE dhcp6_subnet_id = 0;
UPDATE dhcp6_options SET dhcp6_subnet_id = NULL WHERE dhcp6_subnet_id = 0;
+# Add scope for shared network specific options.
+INSERT INTO dhcp_option_scope (scope_id, scope_name)
+ VALUES(4, "shared-network");
+
# Create table modification
CREATE TABLE IF NOT EXISTS modification (
id TINYINT(3) NOT NULL,