Commit 894aeb04 authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[master] Added subnet manipulation support

    Merge branch 'trac5314'
parents fde84942 ac93de29
This diff is collapsed.
This diff is collapsed.
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <cc/command_interpreter.h> #include <cc/command_interpreter.h>
#include <config/hooked_command_mgr.h> #include <config/hooked_command_mgr.h>
#include <config/config_log.h> #include <config/config_log.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_manager.h> #include <hooks/hooks_manager.h>
#include <hooks/server_hooks.h> #include <hooks/server_hooks.h>
#include <boost/pointer_cast.hpp> #include <boost/pointer_cast.hpp>
...@@ -19,7 +20,7 @@ namespace isc { ...@@ -19,7 +20,7 @@ namespace isc {
namespace config { namespace config {
HookedCommandMgr::HookedCommandMgr() HookedCommandMgr::HookedCommandMgr()
: BaseCommandMgr(), callout_handle_(HooksManager::createCalloutHandle()) { : BaseCommandMgr() {
} }
bool bool
...@@ -31,25 +32,25 @@ HookedCommandMgr::delegateCommandToHookLibrary(const std::string& cmd_name, ...@@ -31,25 +32,25 @@ HookedCommandMgr::delegateCommandToHookLibrary(const std::string& cmd_name,
ConstElementPtr hook_response; ConstElementPtr hook_response;
if (HooksManager::commandHandlersPresent(cmd_name)) { if (HooksManager::commandHandlersPresent(cmd_name)) {
callout_handle_ = HooksManager::createCalloutHandle(); CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
// Set status to normal. // Set status to normal.
callout_handle_->setStatus(CalloutHandle::NEXT_STEP_CONTINUE); callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
// Delete previously set arguments. // Delete previously set arguments.
callout_handle_->deleteAllArguments(); callout_handle->deleteAllArguments();
ConstElementPtr command = original_cmd ? original_cmd : ConstElementPtr command = original_cmd ? original_cmd :
createCommand(cmd_name, params); createCommand(cmd_name, params);
// And pass it to the hook library. // And pass it to the hook library.
callout_handle_->setArgument("command", command); callout_handle->setArgument("command", command);
callout_handle_->setArgument("response", hook_response); callout_handle->setArgument("response", hook_response);
HooksManager::callCommandHandlers(cmd_name, *callout_handle_); HooksManager::callCommandHandlers(cmd_name, *callout_handle);
// The callouts should set the response. // The callouts should set the response.
callout_handle_->getArgument("response", hook_response); callout_handle->getArgument("response", hook_response);
answer = boost::const_pointer_cast<Element>(hook_response); answer = boost::const_pointer_cast<Element>(hook_response);
...@@ -63,10 +64,6 @@ ConstElementPtr ...@@ -63,10 +64,6 @@ ConstElementPtr
HookedCommandMgr::handleCommand(const std::string& cmd_name, HookedCommandMgr::handleCommand(const std::string& cmd_name,
const ConstElementPtr& params, const ConstElementPtr& params,
const ConstElementPtr& original_cmd) { const ConstElementPtr& original_cmd) {
if (!callout_handle_) {
isc_throw(Unexpected, "callout handle not configured for the Command "
"Manager: this is a programming error");
}
// The 'list-commands' is a special case. Hook libraries do not implement // The 'list-commands' is a special case. Hook libraries do not implement
// this command. We determine what commands are supported by the hook // this command. We determine what commands are supported by the hook
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <cc/data.h> #include <cc/data.h>
#include <config/base_command_mgr.h> #include <config/base_command_mgr.h>
#include <hooks/callout_handle.h>
namespace isc { namespace isc {
namespace config { namespace config {
...@@ -47,13 +46,6 @@ public: ...@@ -47,13 +46,6 @@ public:
protected: protected:
/// @brief Returns callout handle to the derived class.
///
/// @return const pointer to the callout handle.
const isc::hooks::CalloutHandlePtr& getCalloutHandle() const {
return (callout_handle_);
}
/// @brief Handles the command within the hooks libraries. /// @brief Handles the command within the hooks libraries.
/// ///
/// This method checks if the hooks libraries are installed which implement /// This method checks if the hooks libraries are installed which implement
...@@ -91,8 +83,6 @@ protected: ...@@ -91,8 +83,6 @@ protected:
const isc::data::ConstElementPtr& params, const isc::data::ConstElementPtr& params,
const isc::data::ConstElementPtr& original_cmd); const isc::data::ConstElementPtr& original_cmd);
/// @brief Pointer to a callout handle used by this class.
isc::hooks::CalloutHandlePtr callout_handle_;
}; };
} // end of namespace isc::config } // end of namespace isc::config
......
...@@ -34,6 +34,20 @@ CfgSubnets4::add(const Subnet4Ptr& subnet) { ...@@ -34,6 +34,20 @@ CfgSubnets4::add(const Subnet4Ptr& subnet) {
subnets_.push_back(subnet); subnets_.push_back(subnet);
} }
ConstSubnet4Ptr
CfgSubnets4::getBySubnetId(const SubnetID& subnet_id) const {
const auto& index = subnets_.get<SubnetSubnetIdIndexTag>();
auto subnet_it = index.find(subnet_id);
return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet4Ptr());
}
ConstSubnet4Ptr
CfgSubnets4::getByPrefix(const std::string& subnet_text) const {
const auto& index = subnets_.get<SubnetPrefixIndexTag>();
auto subnet_it = index.find(subnet_text);
return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet4Ptr());
}
Subnet4Ptr Subnet4Ptr
CfgSubnets4::selectSubnet4o6(const SubnetSelector& selector) const { CfgSubnets4::selectSubnet4o6(const SubnetSelector& selector) const {
...@@ -297,106 +311,7 @@ CfgSubnets4::toElement() const { ...@@ -297,106 +311,7 @@ CfgSubnets4::toElement() const {
// Iterate subnets // Iterate subnets
for (Subnet4Collection::const_iterator subnet = subnets_.cbegin(); for (Subnet4Collection::const_iterator subnet = subnets_.cbegin();
subnet != subnets_.cend(); ++subnet) { subnet != subnets_.cend(); ++subnet) {
// Prepare the map result->add((*subnet)->toElement());
ElementPtr map = Element::createMap();
// Set subnet id
SubnetID id = (*subnet)->getID();
map->set("id", Element::create(static_cast<long long>(id)));
// Set relay info
const Subnet::RelayInfo& relay_info = (*subnet)->getRelayInfo();
ElementPtr relay = Element::createMap();
relay->set("ip-address", Element::create(relay_info.addr_.toText()));
map->set("relay", relay);
// Set subnet
map->set("subnet", Element::create((*subnet)->toText()));
// Set interface
const std::string& iface = (*subnet)->getIface();
map->set("interface", Element::create(iface));
// Set renew-timer
map->set("renew-timer",
Element::create(static_cast<long long>
((*subnet)->getT1().get())));
// Set rebind-timer
map->set("rebind-timer",
Element::create(static_cast<long long>
((*subnet)->getT2().get())));
// Set valid-lifetime
map->set("valid-lifetime",
Element::create(static_cast<long long>
((*subnet)->getValid().get())));
// Set pools
const PoolCollection& pools = (*subnet)->getPools(Lease::TYPE_V4);
ElementPtr pool_list = Element::createList();
for (PoolCollection::const_iterator pool = pools.cbegin();
pool != pools.cend(); ++pool) {
// Prepare the map for a pool (@todo move this code to pool.cc)
ElementPtr pool_map = Element::createMap();
// Set pool
const IOAddress& first = (*pool)->getFirstAddress();
const IOAddress& last = (*pool)->getLastAddress();
std::string range = first.toText() + "-" + last.toText();
// Try to output a prefix (vs a range)
int prefix_len = prefixLengthFromRange(first, last);
if (prefix_len >= 0) {
std::ostringstream oss;
oss << first.toText() << "/" << prefix_len;
range = oss.str();
}
pool_map->set("pool", Element::create(range));
// Set user-context
ConstElementPtr context = (*pool)->getContext();
if (!isNull(context)) {
pool_map->set("user-context", context);
}
// Set pool options
ConstCfgOptionPtr opts = (*pool)->getCfgOption();
pool_map->set("option-data", opts->toElement());
// Push on the pool list
pool_list->add(pool_map);
}
map->set("pools", pool_list);
// Set host reservation-mode
Subnet::HRMode hrmode = (*subnet)->getHostReservationMode();
std::string mode;
switch (hrmode) {
case Subnet::HR_DISABLED:
mode = "disabled";
break;
case Subnet::HR_OUT_OF_POOL:
mode = "out-of-pool";
break;
case Subnet::HR_ALL:
mode = "all";
break;
default:
isc_throw(ToElementError,
"invalid host reservation mode: " << hrmode);
}
map->set("reservation-mode", Element::create(mode));
// Set match-client-id
map->set("match-client-id",
Element::create((*subnet)->getMatchClientId()));
// Set next-server
map->set("next-server",
Element::create((*subnet)->getSiaddr().toText()));
// Set DHCP4o6
const Cfg4o6& d4o6 = (*subnet)->get4o6();
isc::data::merge(map, d4o6.toElement());
// Set client-class
const ClientClasses& cclasses = (*subnet)->getClientClasses();
if (cclasses.size() > 1) {
isc_throw(ToElementError, "client-class has too many items: "
<< cclasses.size());
} else if (!cclasses.empty()) {
map->set("client-class", Element::create(*cclasses.cbegin()));
}
// Set options
ConstCfgOptionPtr opts = (*subnet)->getCfgOption();
map->set("option-data", opts->toElement());
// Not supported: interface-id
// Not supported: rapid-commit
// Push on the list
result->add(map);
} }
return (result); return (result);
} }
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
#include <asiolink/io_address.h> #include <asiolink/io_address.h>
#include <cc/cfg_to_element.h> #include <cc/cfg_to_element.h>
#include <dhcpsrv/subnet.h> #include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h> #include <dhcpsrv/subnet_selector.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <string>
namespace isc { namespace isc {
namespace dhcp { namespace dhcp {
...@@ -48,6 +50,40 @@ public: ...@@ -48,6 +50,40 @@ public:
return (&subnets_); return (&subnets_);
} }
/// @brief Returns const pointer to a subnet identified by the specified
/// subnet identifier.
///
/// The const pointer is returned by this method to prevent a caller from
/// modifying the subnet configuration. Modifications to subnet configuration
/// is dangerous and must be done carefully. The subnets' configruation is
/// held in the multi index container and any modifications to the subnet
/// id or subnet prefix must trigger re-indexing of multi index container.
/// There is no possibility to enforce this when the non-const pointer is
/// returned.
///
/// @param subnet_id Subnet identifier.
///
/// @return Pointer to the @c Subnet4 object or null pointer if such
/// subnet doesn't exist.
ConstSubnet4Ptr getBySubnetId(const SubnetID& subnet_id) const;
/// @brief Returns const pointer to a subnet which matches the specified
/// prefix in the canonical form.
///
/// The const pointer is returned by this method to prevent a caller from
/// modifying the subnet configuration. Modifications to subnet configuration
/// is dangerous and must be done carefully. The subnets' configruation is
/// held in the multi index container and any modifications to the subnet
/// id or subnet prefix must trigger re-indexing of multi index container.
/// There is no possibility to enforce this when the non-const pointer is
/// returned.
///
/// @param subnet_prefix Subnet prefix, e.g. 10.2.3.0/24
///
/// @return Pointer to the @c Subnet4 object or null pointer if such
/// subnet doesn't exist.
ConstSubnet4Ptr getByPrefix(const std::string& subnet_prefix) const;
/// @brief Returns a pointer to the selected subnet. /// @brief Returns a pointer to the selected subnet.
/// ///
/// This method tries to retrieve the subnet for the client using various /// This method tries to retrieve the subnet for the client using various
......
...@@ -33,6 +33,20 @@ CfgSubnets6::add(const Subnet6Ptr& subnet) { ...@@ -33,6 +33,20 @@ CfgSubnets6::add(const Subnet6Ptr& subnet) {
subnets_.push_back(subnet); subnets_.push_back(subnet);
} }
ConstSubnet6Ptr
CfgSubnets6::getBySubnetId(const SubnetID& subnet_id) const {
const auto& index = subnets_.get<SubnetSubnetIdIndexTag>();
auto subnet_it = index.find(subnet_id);
return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet6Ptr());
}
ConstSubnet6Ptr
CfgSubnets6::getByPrefix(const std::string& subnet_text) const {
const auto& index = subnets_.get<SubnetPrefixIndexTag>();
auto subnet_it = index.find(subnet_text);
return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet6Ptr());
}
Subnet6Ptr Subnet6Ptr
CfgSubnets6::selectSubnet(const SubnetSelector& selector) const { CfgSubnets6::selectSubnet(const SubnetSelector& selector) const {
Subnet6Ptr subnet; Subnet6Ptr subnet;
...@@ -254,171 +268,7 @@ CfgSubnets6::toElement() const { ...@@ -254,171 +268,7 @@ CfgSubnets6::toElement() const {
// Iterate subnets // Iterate subnets
for (Subnet6Collection::const_iterator subnet = subnets_.cbegin(); for (Subnet6Collection::const_iterator subnet = subnets_.cbegin();
subnet != subnets_.cend(); ++subnet) { subnet != subnets_.cend(); ++subnet) {
// Prepare the map result->add((*subnet)->toElement());
ElementPtr map = Element::createMap();
// Set subnet id
SubnetID id = (*subnet)->getID();
map->set("id", Element::create(static_cast<long long>(id)));
// Set relay info
const Subnet::RelayInfo& relay_info = (*subnet)->getRelayInfo();
ElementPtr relay = Element::createMap();
relay->set("ip-address", Element::create(relay_info.addr_.toText()));
map->set("relay", relay);
// Set subnet
map->set("subnet", Element::create((*subnet)->toText()));
// Set interface
const std::string& iface = (*subnet)->getIface();
map->set("interface", Element::create(iface));
// Set interface-id
const OptionPtr& ifaceid = (*subnet)->getInterfaceId();
if (ifaceid) {
std::vector<uint8_t> bin = ifaceid->getData();
std::string ifid;
ifid.resize(bin.size());
if (!bin.empty()) {
std::memcpy(&ifid[0], &bin[0], bin.size());
}
map->set("interface-id", Element::create(ifid));
} else {
map->set("interface-id", Element::create(std::string()));
}
// Set renew-timer
map->set("renew-timer",
Element::create(static_cast<long long>
((*subnet)->getT1().get())));
// Set rebind-timer
map->set("rebind-timer",
Element::create(static_cast<long long>
((*subnet)->getT2().get())));
// Set preferred-lifetime
map->set("preferred-lifetime",
Element::create(static_cast<long long>
((*subnet)->getPreferred().get())));
// Set valid-lifetime
map->set("valid-lifetime",
Element::create(static_cast<long long>
((*subnet)->getValid().get())));
// Set rapid-commit
bool rapid_commit = (*subnet)->getRapidCommit();
map->set("rapid-commit", Element::create(rapid_commit));
// Set pools
const PoolCollection& pools = (*subnet)->getPools(Lease::TYPE_NA);
ElementPtr pool_list = Element::createList();
for (PoolCollection::const_iterator pool = pools.cbegin();
pool != pools.cend(); ++pool) {
// Prepare the map for a pool (@todo move this code to pool.cc)
ElementPtr pool_map = Element::createMap();
// Set pool
const IOAddress& first = (*pool)->getFirstAddress();
const IOAddress& last = (*pool)->getLastAddress();
std::string range = first.toText() + "-" + last.toText();
// Try to output a prefix (vs a range)
int prefix_len = prefixLengthFromRange(first, last);
if (prefix_len >= 0) {
std::ostringstream oss;
oss << first.toText() << "/" << prefix_len;
range = oss.str();
}
pool_map->set("pool", Element::create(range));
// Set user-context
ConstElementPtr context = (*pool)->getContext();
if (!isNull(context)) {
pool_map->set("user-context", context);
}
// Set pool options
ConstCfgOptionPtr opts = (*pool)->getCfgOption();
pool_map->set("option-data", opts->toElement());
// Push on the pool list
pool_list->add(pool_map);
}
map->set("pools", pool_list);
// Set pd-pools
const PoolCollection& pdpools = (*subnet)->getPools(Lease::TYPE_PD);
ElementPtr pdpool_list = Element::createList();
for (PoolCollection::const_iterator pool = pdpools.cbegin();
pool != pdpools.cend(); ++pool) {
// Get it as a Pool6 (@todo move this code to pool.cc)
const Pool6* pdpool = dynamic_cast<Pool6*>(pool->get());
if (!pdpool) {
isc_throw(ToElementError, "invalid pd-pool pointer");
}
// Prepare the map for a pd-pool
ElementPtr pool_map = Element::createMap();
// Set prefix
const IOAddress& prefix = pdpool->getFirstAddress();
pool_map->set("prefix", Element::create(prefix.toText()));
// Set prefix-len (get it from min - max)
const IOAddress& last = pdpool->getLastAddress();
int prefix_len = prefixLengthFromRange(prefix, last);
if (prefix_len < 0) {
// The pool is bad: give up
isc_throw(ToElementError, "invalid prefix range "
<< prefix.toText() << "-" << last.toText());
}
pool_map->set("prefix-len", Element::create(prefix_len));
// Set delegated-len
uint8_t len = pdpool->getLength();
pool_map->set("delegated-len",
Element::create(static_cast<int>(len)));
// Set excluded prefix
const Option6PDExcludePtr& xopt =
pdpool->getPrefixExcludeOption();
if (xopt) {
const IOAddress& xprefix =
xopt->getExcludedPrefix(prefix, len);
pool_map->set("excluded-prefix",
Element::create(xprefix.toText()));
uint8_t xlen = xopt->getExcludedPrefixLength();
pool_map->set("excluded-prefix-len",
Element::create(static_cast<int>(xlen)));
} else {
pool_map->set("excluded-prefix",
Element::create(std::string("::")));
pool_map->set("excluded-prefix-len", Element::create(0));
}
// Set user-context
ConstElementPtr context = pdpool->getContext();
if (!isNull(context)) {
pool_map->set("user-context", context);
}
// Set pool options
ConstCfgOptionPtr opts = pdpool->getCfgOption();
pool_map->set("option-data", opts->toElement());
// Push on the pool list
pdpool_list->add(pool_map);
}
map->set("pd-pools", pdpool_list);
// Set host reservation-mode
Subnet::HRMode hrmode = (*subnet)->getHostReservationMode();
std::string mode;
switch (hrmode) {
case Subnet::HR_DISABLED:
mode = "disabled";
break;
case Subnet::HR_OUT_OF_POOL:
mode = "out-of-pool";
break;
case Subnet::HR_ALL:
mode = "all";
break;
default:
isc_throw(ToElementError,
"invalid host reservation mode: " << hrmode);
}
map->set("reservation-mode", Element::create(mode));
// Set client-class
const ClientClasses& cclasses = (*subnet)->getClientClasses();
if (cclasses.size() > 1) {
isc_throw(ToElementError, "client-class has too many items: "
<< cclasses.size());
} else if (!cclasses.empty()) {
map->set("client-class", Element::create(*cclasses.cbegin()));
}
// Set options
ConstCfgOptionPtr opts = (*subnet)->getCfgOption();
map->set("option-data", opts->toElement());
// Push on the list
result->add(map);
} }
return (result); return (result);
} }
......
// Copyright (C) 2014-2015,2017 Internet Systems Consortium, Inc. ("ISC") // Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// //
// This Source Code Form is subject to the terms of the Mozilla Public // 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 // License, v. 2.0. If a copy of the MPL was not distributed with this
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
#include <dhcp/option.h> #include <dhcp/option.h>
#include <cc/cfg_to_element.h> #include <cc/cfg_to_element.h>
#include <dhcpsrv/subnet.h> #include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h> #include <dhcpsrv/subnet_selector.h>
#include <util/optional_value.h> #include <util/optional_value.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <string>
namespace isc { namespace isc {
namespace dhcp { namespace dhcp {
...@@ -49,6 +51,40 @@ public: ...@@ -49,6 +51,40 @@ public:
return (&subnets_); return (&subnets_);
} }
/// @brief Returns const pointer to a subnet identified by the specified
/// subnet identifier.
///
/// The const pointer is returned by this method to prevent a caller from
/// modifying the subnet configuration. Modifications to subnet configuration
/// is dangerous and must be done carefully. The subnets' configuration is
/// held in the multi index container and any modifications to the subnet
/// id or subnet prefix must trigger re-indexing of multi index container.
/// There is no possibility to enforce this when the non-const pointer is
/// returned.
///
/// @param subnet_id Subnet identifier.
///
/// @return Pointer to the @c Subnet6 object or null pointer if such
/// subnet doesn't exist.
ConstSubnet6Ptr getBySubnetId(const SubnetID& subnet_id) const;
/// @brief Returns const pointer to a subnet which matches the specified
/// prefix in the canonical form.
///
/// The const pointer is returned by this method to prevent a caller from
/// modifying the subnet configuration. Modifications to subnet configuration
/// is dangerous and must be done carefully. The subnets' configruation is
/// held in the multi index container and any modifications to the subnet
/// id or subnet prefix must trigger re-indexing of multi index container.
/// There is no possibility to enforce this when the non-const pointer is
/// returned.
///
/// @param subnet_prefix Subnet prefix, e.g. 2001:db8:1::/64
///
/// @return Pointer to the @c Subnet6 object or null pointer if such
/// subnet doesn't exist.
ConstSubnet6Ptr getByPrefix(const std::string& subnet_prefix) const;