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

[master] Added subnet manipulation support

    Merge branch 'trac5314'
parents fde84942 ac93de29
This diff is collapsed.
This diff is collapsed.
......@@ -7,6 +7,7 @@
#include <cc/command_interpreter.h>
#include <config/hooked_command_mgr.h>
#include <config/config_log.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_manager.h>
#include <hooks/server_hooks.h>
#include <boost/pointer_cast.hpp>
......@@ -19,7 +20,7 @@ namespace isc {
namespace config {
HookedCommandMgr::HookedCommandMgr()
: BaseCommandMgr(), callout_handle_(HooksManager::createCalloutHandle()) {
: BaseCommandMgr() {
}
bool
......@@ -31,25 +32,25 @@ HookedCommandMgr::delegateCommandToHookLibrary(const std::string& cmd_name,
ConstElementPtr hook_response;
if (HooksManager::commandHandlersPresent(cmd_name)) {
callout_handle_ = HooksManager::createCalloutHandle();
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
// Set status to normal.
callout_handle_->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
// Delete previously set arguments.
callout_handle_->deleteAllArguments();
callout_handle->deleteAllArguments();
ConstElementPtr command = original_cmd ? original_cmd :
createCommand(cmd_name, params);
// And pass it to the hook library.
callout_handle_->setArgument("command", command);
callout_handle_->setArgument("response", hook_response);
callout_handle->setArgument("command", command);
callout_handle->setArgument("response", hook_response);
HooksManager::callCommandHandlers(cmd_name, *callout_handle_);
HooksManager::callCommandHandlers(cmd_name, *callout_handle);
// 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);
......@@ -63,10 +64,6 @@ ConstElementPtr
HookedCommandMgr::handleCommand(const std::string& cmd_name,
const ConstElementPtr& params,
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
// this command. We determine what commands are supported by the hook
......
......@@ -9,7 +9,6 @@
#include <cc/data.h>
#include <config/base_command_mgr.h>
#include <hooks/callout_handle.h>
namespace isc {
namespace config {
......@@ -47,13 +46,6 @@ public:
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.
///
/// This method checks if the hooks libraries are installed which implement
......@@ -91,8 +83,6 @@ protected:
const isc::data::ConstElementPtr& params,
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
......
......@@ -34,6 +34,20 @@ CfgSubnets4::add(const Subnet4Ptr& 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
CfgSubnets4::selectSubnet4o6(const SubnetSelector& selector) const {
......@@ -297,106 +311,7 @@ CfgSubnets4::toElement() const {
// Iterate subnets
for (Subnet4Collection::const_iterator subnet = subnets_.cbegin();
subnet != subnets_.cend(); ++subnet) {
// Prepare the map
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);
result->add((*subnet)->toElement());
}
return (result);
}
......
......@@ -10,8 +10,10 @@
#include <asiolink/io_address.h>
#include <cc/cfg_to_element.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h>
#include <boost/shared_ptr.hpp>
#include <string>
namespace isc {
namespace dhcp {
......@@ -48,6 +50,40 @@ public:
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.
///
/// This method tries to retrieve the subnet for the client using various
......
......@@ -33,6 +33,20 @@ CfgSubnets6::add(const Subnet6Ptr& 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
CfgSubnets6::selectSubnet(const SubnetSelector& selector) const {
Subnet6Ptr subnet;
......@@ -254,171 +268,7 @@ CfgSubnets6::toElement() const {
// Iterate subnets
for (Subnet6Collection::const_iterator subnet = subnets_.cbegin();
subnet != subnets_.cend(); ++subnet) {
// Prepare the map
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);
result->add((*subnet)->toElement());
}
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
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -11,9 +11,11 @@
#include <dhcp/option.h>
#include <cc/cfg_to_element.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h>
#include <util/optional_value.h>
#include <boost/shared_ptr.hpp>
#include <string>
namespace isc {
namespace dhcp {
......@@ -49,6 +51,40 @@ public:
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;
/// @brief Selects a subnet using parameters specified in the selector.
///
/// This method tries to retrieve the subnet for the client using various
......
......@@ -10,6 +10,7 @@
#include <sstream>
using namespace isc::asiolink;
using namespace isc::data;
namespace isc {
namespace dhcp {
......@@ -74,6 +75,46 @@ Pool4::Pool4( const isc::asiolink::IOAddress& prefix, uint8_t prefix_len)
capacity_ = addrsInRange(prefix, last_);
}
data::ElementPtr
Pool::toElement() const {
// Prepare the map
ElementPtr map = Element::createMap();
// Set user-context
ConstElementPtr context = getContext();
if (!isNull(context)) {
map->set("user-context", context);
}
// Set pool options
ConstCfgOptionPtr opts = getCfgOption();
map->set("option-data", opts->toElement());
return (map);
}
data::ElementPtr
Pool4::toElement() const {
// Prepare the map
ElementPtr map = Pool::toElement();
// Set pool
const IOAddress& first = getFirstAddress();
const IOAddress& last = 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();
}
map->set("pool", Element::create(range));
return (map);
}
Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
: Pool(type, first, last), prefix_len_(128), pd_exclude_option_() {
......@@ -235,6 +276,72 @@ Pool6::init(const Lease::Type& type,
}
}
data::ElementPtr
Pool6::toElement() const {
// Prepare the map
ElementPtr map = Pool::toElement();
switch (getType()) {
case Lease::TYPE_NA: {
const IOAddress& first = getFirstAddress();
const IOAddress& last = 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();
}
map->set("pool", Element::create(range));
break;
}
case Lease::TYPE_PD: {
// Set prefix
const IOAddress& prefix = getFirstAddress();
map->set("prefix", Element::create(prefix.toText()));
// Set prefix-len (get it from min - max)
const IOAddress& last = 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());
}
// Set delegated-len
uint8_t len = getLength();
map->set("delegated-len", Element::create(static_cast<int>(len)));
// Set excluded prefix
const Option6PDExcludePtr& xopt = getPrefixExcludeOption();
if (xopt) {
const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, len);
map->set("excluded-prefix"