From: Marcin Siodelski Date: Tue, 2 Oct 2018 09:09:19 +0000 (+0200) Subject: [#93,!51] Added options management in MySQL DHCPv4 config backend. X-Git-Tag: 5-netconf-extend-syntax_base~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f33dc7ddd8489dea9d39129f3751975779b33ef;p=thirdparty%2Fkea.git [#93,!51] Added options management in MySQL DHCPv4 config backend. --- diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc index bb3790c335..7fa569869b 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc @@ -10,10 +10,13 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -28,6 +31,7 @@ using namespace isc::db; using namespace isc::data; using namespace isc::asiolink; +using namespace isc::util; namespace isc { namespace dhcp { @@ -53,13 +57,18 @@ public: 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, @@ -68,6 +77,10 @@ public: 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 }; @@ -119,14 +132,27 @@ public: MySqlBinding::createInteger(), // pool: start_address MySqlBinding::createInteger(), // pool: end_address MySqlBinding::createInteger(), // pool: subnet_id - MySqlBinding::createTimestamp() // pool: modification_ts + MySqlBinding::createTimestamp(), // pool: modification_ts + MySqlBinding::createInteger(), // option: option_id + MySqlBinding::createInteger(), // option: code + MySqlBinding::createBlob(65536), // option: value + MySqlBinding::createString(8192), // option: formatted_value + MySqlBinding::createString(128), // option: space + MySqlBinding::createInteger(), // option: persistent + MySqlBinding::createInteger(), // option: dhcp4_subnet_id + MySqlBinding::createInteger(), // option: scope_id + MySqlBinding::createString(65536), // option: user_context + MySqlBinding::createString(128), // option: shared_network_name + MySqlBinding::createInteger(), // 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; @@ -251,12 +277,25 @@ public: (out_bindings[21]->getInteger() != 0) && (out_bindings[22]->getInteger() != 0) && ((last_pool_id == 0) || - (out_bindings[20]->getInteger() != last_pool_id))) { + (out_bindings[20]->getInteger() > last_pool_id))) { last_pool_id = out_bindings[20]->getInteger(); Pool4Ptr pool(new Pool4(IOAddress(out_bindings[21]->getInteger()), IOAddress(out_bindings[22]->getInteger()))); last_subnet->addPool(pool); } + + // Parse option. + if (!out_bindings[25]->amNull() && + ((last_option_id == 0) || + (last_option_id < out_bindings[25]->getInteger()))) { + last_option_id = out_bindings[25]->getInteger(); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 25); + if (desc) { + last_subnet->getCfgOption()->add(*desc, desc->space_name_); + } + } + }); } @@ -373,9 +412,8 @@ public: 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(subnet->getID())); @@ -388,6 +426,17 @@ public: createPool4(boost::dynamic_pointer_cast(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(); } @@ -464,12 +513,26 @@ public: MySqlBinding::createString(65536), // require_client_classes MySqlBinding::createInteger(), // reservation_mode MySqlBinding::createString(65536), // user_context - MySqlBinding::createInteger() // valid_lifetime + MySqlBinding::createInteger(), // valid_lifetime + MySqlBinding::createInteger(), // option: option_id + MySqlBinding::createInteger(), // option: code + MySqlBinding::createBlob(65536), // option: value + MySqlBinding::createString(8192), // option: formatted_value + MySqlBinding::createString(128), // option: space + MySqlBinding::createInteger(), // option: persistent + MySqlBinding::createInteger(), // option: dhcp4_subnet_id + MySqlBinding::createInteger(), // option: scope_id + MySqlBinding::createString(65536), // option: user_context + MySqlBinding::createString(128), // option: shared_network_name + MySqlBinding::createInteger(), // 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()) { @@ -559,6 +622,18 @@ public: shared_networks.push_back(last_network); } + + // Parse option. + if (!out_bindings[13]->amNull() && + ((last_option_id == 0) || + (last_option_id < out_bindings[13]->getInteger()))) { + last_option_id = out_bindings[13]->getInteger(); + + OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 13); + if (desc) { + last_network->getCfgOption()->add(*desc, desc->space_name_); + } + } }); } @@ -612,27 +687,106 @@ public: 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(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createInteger(static_cast(option->persistent_)), + MySqlBinding::createNull(), + MySqlBinding::createInteger(static_cast(subnet_id)), + MySqlBinding::createInteger(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(static_cast(subnet_id))); + in_bindings.push_back(MySqlBinding::createInteger(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(option->option_->getType()), + createOptionValueBinding(option), + MySqlBinding::condCreateString(option->formatted_value_), + MySqlBinding::condCreateString(option->space_name_), + MySqlBinding::createInteger(static_cast(option->persistent_)), + MySqlBinding::createNull(), + MySqlBinding::createNull(), + MySqlBinding::createInteger(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(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. @@ -685,6 +839,58 @@ public: 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(static_cast(subnet_id)), + MySqlBinding::createInteger(static_cast(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(static_cast(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. @@ -759,6 +965,74 @@ public: // 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(static_cast(subnet_id)), + MySqlBinding::createInteger(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(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(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. @@ -795,11 +1069,24 @@ TaggedStatementArray 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, @@ -828,11 +1115,24 @@ TaggedStatementArray 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_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, @@ -861,10 +1161,23 @@ TaggedStatementArray 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 " - "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, @@ -893,11 +1206,24 @@ TaggedStatementArray 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.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, @@ -914,10 +1240,23 @@ TaggedStatementArray tagged_statements = { { " 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, @@ -934,8 +1273,21 @@ TaggedStatementArray tagged_statements = { { " 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. @@ -953,8 +1305,21 @@ TaggedStatementArray tagged_statements = { { " 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" }, @@ -1008,6 +1373,46 @@ TaggedStatementArray tagged_statements = { { "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(" @@ -1074,6 +1479,23 @@ TaggedStatementArray tagged_statements = { { "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" @@ -1130,6 +1552,42 @@ TaggedStatementArray tagged_statements = { { " 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 " @@ -1165,7 +1623,29 @@ TaggedStatementArray tagged_statements = { { // 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 = ?" } } }; @@ -1302,20 +1782,28 @@ MySqlConfigBackendDHCPv4::createUpdateOptionDef4(const ServerSelector& server_se 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 @@ -1380,11 +1868,19 @@ MySqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& /* server_selector } 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 diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h index 52d0539099..09ee3d48d4 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.h @@ -169,7 +169,18 @@ public: /// @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. /// @@ -179,7 +190,7 @@ public: 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. /// @@ -193,7 +204,7 @@ public: 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. /// @@ -282,6 +293,19 @@ public: 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. diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc index 51e8f5990f..0d953956e6 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc @@ -6,6 +6,11 @@ #include #include +#include +#include +#include +#include +#include #include #include #include @@ -13,6 +18,7 @@ using namespace isc::data; using namespace isc::db; +using namespace isc::util; namespace isc { namespace dhcp { @@ -162,6 +168,100 @@ MySqlConfigBackendImpl::getOptionDefs(const int index, }); } +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(), // option_id + MySqlBinding::createInteger(), // code + MySqlBinding::createBlob(65536), // value + MySqlBinding::createString(8192), // formatted_value + MySqlBinding::createString(128), // space + MySqlBinding::createInteger(), // persistent + MySqlBinding::createInteger(), // dhcp4_subnet_id + MySqlBinding::createInteger(), // scope_id + MySqlBinding::createString(65536), // user_context + MySqlBinding::createString(128), // shared_network_name + MySqlBinding::createInteger(), // 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()))) { + last_option_id = out_bindings[0]->getInteger(); + + 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(); + + 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 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 split_vec; + boost::split(split_vec, formatted_value, boost::is_any_of(",")); + option = def->optionFactory(universe, code, split_vec); + } + } + + bool persistent = static_cast((*(first_binding + 5))->getIntegerOrDefault(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(); @@ -192,5 +292,22 @@ MySqlConfigBackendImpl::createInputRequiredClassesBinding(const NetworkPtr& netw 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(buf.getData()); + std::vector 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 diff --git a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h index ffb9c9c887..dff9de8282 100644 --- a/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h +++ b/src/hooks/dhcp/mysql_cb/mysql_cb_impl.h @@ -8,7 +8,9 @@ #define MYSQL_CONFIG_BACKEND_IMPL_H #include +#include #include +#include #include #include #include @@ -64,6 +66,47 @@ public: 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 @@ -95,6 +138,13 @@ public: 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_; diff --git a/src/hooks/dhcp/mysql_cb/tests/Makefile.am b/src/hooks/dhcp/mysql_cb/tests/Makefile.am index 747d2c3ad0..4bc925598d 100644 --- a/src/hooks/dhcp/mysql_cb/tests/Makefile.am +++ b/src/hooks/dhcp/mysql_cb/tests/Makefile.am @@ -32,7 +32,8 @@ mysql_cb_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS) 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 diff --git a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc index cd13eaffbe..7ccb133840 100644 --- a/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc +++ b/src/hooks/dhcp/mysql_cb/tests/mysql_cb_dhcp4_unittest.cc @@ -5,10 +5,16 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include +#include #include +#include +#include +#include +#include +#include #include #include -#include +#include #include #include #include @@ -19,11 +25,12 @@ using namespace isc::db; 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. @@ -49,6 +56,7 @@ public: } // Create test data. + initTestOptions(); initTestSubnets(); initTestSharedNetworks(); initTestOptionDefs(); @@ -96,6 +104,19 @@ public: 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 @@ -137,6 +158,19 @@ public: 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 @@ -178,6 +212,58 @@ public: 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(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(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(Option::V4, 1, false, false, 312131), + desc.space_name_ = "vendor-encapsulated-options"; + test_options_.push_back(OptionDescriptorPtr(new OptionDescriptor(desc))); + + desc = createAddressOption(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(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. @@ -198,6 +284,9 @@ public: /// @brief Holds pointers to option definitions used in tests. std::vector test_option_defs_; + /// @brief Holds pointers to options used in tests. + std::vector test_options_; + /// @brief Holds timestamp values used in tests. std::map timestamps_; @@ -565,6 +654,104 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedOptionDefinitions4) { 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_); +} } diff --git a/src/lib/dhcpsrv/cfg_option.cc b/src/lib/dhcpsrv/cfg_option.cc index 49e4fe9d35..1ef4d9061a 100644 --- a/src/lib/dhcpsrv/cfg_option.cc +++ b/src/lib/dhcpsrv/cfg_option.cc @@ -22,8 +22,9 @@ namespace dhcp { 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_)); } diff --git a/src/lib/dhcpsrv/cfg_option.h b/src/lib/dhcpsrv/cfg_option.h index d29914f888..a3fa37066a 100644 --- a/src/lib/dhcpsrv/cfg_option.h +++ b/src/lib/dhcpsrv/cfg_option.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ namespace dhcp { /// 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_; @@ -57,6 +58,17 @@ public: /// 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 @@ -68,7 +80,8 @@ public: 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); }; @@ -77,14 +90,15 @@ public: /// @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()); }; diff --git a/src/lib/dhcpsrv/config_backend_dhcp4.h b/src/lib/dhcpsrv/config_backend_dhcp4.h index af318d0dcf..69632fa630 100644 --- a/src/lib/dhcpsrv/config_backend_dhcp4.h +++ b/src/lib/dhcpsrv/config_backend_dhcp4.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -170,7 +171,18 @@ public: /// @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. /// @@ -180,7 +192,7 @@ public: 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. /// @@ -194,7 +206,7 @@ public: 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. /// @@ -283,6 +295,19 @@ public: 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. diff --git a/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc b/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc index 79a9287634..cd89e99ad6 100644 --- a/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc +++ b/src/lib/dhcpsrv/config_backend_pool_dhcp4.cc @@ -185,17 +185,28 @@ ConfigBackendPoolDHCPv4::createUpdateOptionDef4(const db::BackendSelector& backe void ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector, const db::ServerSelector& server_selector, - const OptionPtr& option) { + const OptionDescriptorPtr& option) { createUpdateDeleteProperty (&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 + (&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 (&ConfigBackendDHCPv4::createUpdateOption4, backend_selector, server_selector, subnet_id, option); @@ -206,8 +217,9 @@ ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_ const db::ServerSelector& server_selector, const IOAddress& pool_start_address, const IOAddress& pool_end_address, - const OptionPtr& option) { + const OptionDescriptorPtr& option) { createUpdateDeleteProperty + const OptionDescriptorPtr&> (&ConfigBackendDHCPv4::createUpdateOption4, backend_selector, server_selector, pool_start_address, pool_end_address, option); } @@ -300,6 +312,17 @@ ConfigBackendPoolDHCPv4::deleteOption4(const db::BackendSelector& backend_select 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 + (&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, diff --git a/src/lib/dhcpsrv/config_backend_pool_dhcp4.h b/src/lib/dhcpsrv/config_backend_pool_dhcp4.h index 3ac592dfeb..21bc3504d6 100644 --- a/src/lib/dhcpsrv/config_backend_pool_dhcp4.h +++ b/src/lib/dhcpsrv/config_backend_pool_dhcp4.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -204,7 +205,20 @@ public: 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. /// @@ -216,7 +230,7 @@ public: 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. /// @@ -232,7 +246,7 @@ public: 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. /// @@ -344,6 +358,21 @@ public: 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. diff --git a/src/lib/dhcpsrv/testutils/Makefile.am b/src/lib/dhcpsrv/testutils/Makefile.am index a56e0e6eb0..f525236531 100644 --- a/src/lib/dhcpsrv/testutils/Makefile.am +++ b/src/lib/dhcpsrv/testutils/Makefile.am @@ -16,6 +16,7 @@ libdhcpsrvtest_la_SOURCES = config_result_check.cc config_result_check.h 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 diff --git a/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc b/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc new file mode 100644 index 0000000000..bbb536362c --- /dev/null +++ b/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc @@ -0,0 +1,55 @@ +// 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 + +#include +#include +#include + +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 diff --git a/src/lib/dhcpsrv/testutils/generic_backend_unittest.h b/src/lib/dhcpsrv/testutils/generic_backend_unittest.h new file mode 100644 index 0000000000..34a1b571da --- /dev/null +++ b/src/lib/dhcpsrv/testutils/generic_backend_unittest.h @@ -0,0 +1,199 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +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 + OptionDescriptor createOption(const Option::Universe& universe, + const uint16_t option_type, + const bool persist, + const bool formatted, + const DataType& value) const { + boost::shared_ptr 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 + OptionDescriptor createOption(const uint16_t option_type, + const bool persist, + const bool formatted, + const DataType& value) const { + boost::shared_ptr 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 + 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 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 + diff --git a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc index ce14d9192f..b054945199 100644 --- a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc @@ -43,12 +43,11 @@ namespace isc { namespace dhcp { namespace test { -GenericHostDataSourceTest::GenericHostDataSourceTest() : hdsptr_() { - LibDHCP::clearRuntimeOptionDefs(); +GenericHostDataSourceTest::GenericHostDataSourceTest() + : GenericBackendTest(), hdsptr_() { } GenericHostDataSourceTest::~GenericHostDataSourceTest() { - LibDHCP::clearRuntimeOptionDefs(); hdsptr_.reset(); } @@ -88,34 +87,6 @@ GenericHostDataSourceTest::DuidToHWAddr(const DuidPtr& duid) { 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, diff --git a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h index 46653bb382..935b8922c3 100644 --- a/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h +++ b/src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,7 @@ namespace test { /// /// 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). @@ -63,150 +64,6 @@ public: 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 - OptionDescriptor createOption(const Option::Universe& universe, - const uint16_t option_type, - const bool persist, - const bool formatted, - const DataType& value) const { - boost::shared_ptr 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 - OptionDescriptor createOption(const uint16_t option_type, - const bool persist, - const bool formatted, - const DataType& value) const { - boost::shared_ptr 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 - 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 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. @@ -240,21 +97,6 @@ public: 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: diff --git a/src/share/database/scripts/mysql/dhcpdb_create.mysql b/src/share/database/scripts/mysql/dhcpdb_create.mysql index 2d325a49ef..b4046f8dc7 100644 --- a/src/share/database/scripts/mysql/dhcpdb_create.mysql +++ b/src/share/database/scripts/mysql/dhcpdb_create.mysql @@ -768,6 +768,11 @@ CREATE INDEX timestamp_index ON logs (timestamp); 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` -- ----------------------------------------------------- diff --git a/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in b/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in index 5c3105ffdd..89f8896b83 100644 --- a/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in +++ b/src/share/database/scripts/mysql/upgrade_6.0_to_7.0.sh.in @@ -112,6 +112,10 @@ UPDATE dhcp4_options SET dhcp4_subnet_id = NULL WHERE dhcp4_subnet_id = 0; 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,