Commit 76dd46f7 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac5305'

# Conflicts:
#	src/lib/dhcpsrv/parsers/dhcp_parsers.cc
#	src/lib/dhcpsrv/subnet.cc
#	src/lib/dhcpsrv/subnet.h
parents 840824fe 38719d4f
......@@ -148,7 +148,7 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
}
// Find static reservations if not disabled for our subnet.
if (subnet->getHostReservationMode() != Subnet::HR_DISABLED) {
if (subnet->getHostReservationMode() != Network::HR_DISABLED) {
// Before we can check for static reservations, we need to prepare a set
// of identifiers to be used for this.
setHostIdentifiers();
......
......@@ -290,6 +290,15 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "shared-networks") {
/// @todo We need to create instance of SharedNetworks4ListParser
/// and parse the list of the shared networks into the
/// CfgSharedNetworks4 object. One additional step is then to
/// add subnets from the CfgSharedNetworks4 into CfgSubnets4
/// as well.
continue;
}
// Timers are not used in the global scope. Their values are derived
// to specific subnets (see SimpleParser6::deriveParameters).
// decline-probation-period, dhcp4o6-port, echo-client-id are
......
......@@ -4314,22 +4314,22 @@ TEST_F(Dhcp4ParserTest, hostReservationPerSubnet) {
Subnet4Ptr subnet;
subnet = subnets->selectSubnet(IOAddress("192.0.2.1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode());
// Subnet 2
subnet = subnets->selectSubnet(IOAddress("192.0.3.1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_OUT_OF_POOL, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode());
// Subnet 3
subnet = subnets->selectSubnet(IOAddress("192.0.4.1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_DISABLED, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_DISABLED, subnet->getHostReservationMode());
// Subnet 4
subnet = subnets->selectSubnet(IOAddress("192.0.5.1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode());
}
/// Check that the decline-probation-period has a default value when not
......
......@@ -270,7 +270,7 @@ HWAddrPtr Dhcpv4SrvTest::generateHWAddr(size_t size /*= 6*/) {
}
void Dhcpv4SrvTest::checkAddressParams(const Pkt4Ptr& rsp,
const SubnetPtr subnet,
const Subnet4Ptr subnet,
bool t1_present,
bool t2_present) {
......
......@@ -326,7 +326,7 @@ public:
/// present (false)
/// @param t2_present check that t2 must be present (true) or must not be
/// present (false)
void checkAddressParams(const Pkt4Ptr& rsp, const SubnetPtr subnet,
void checkAddressParams(const Pkt4Ptr& rsp, const Subnet4Ptr subnet,
bool t1_present = false,
bool t2_present = false);
......
......@@ -6135,6 +6135,7 @@ public:
};
/// Test a configuration
TEST_P(Dhcp4GetConfigTest, run) {
// configurations have not been extracted yet
if (max_config_counter == 0) {
......@@ -6199,8 +6200,14 @@ TEST_P(Dhcp4GetConfigTest, run) {
EXPECT_TRUE(isEquivalent(unparsed, unparsed2));
}
#if 0
// This test is temporarily disabled. The shared subnets structures have been
// implemented (#5305), but the parsers are not there yet, so grammar will fail
// when parseDHCP4 is called. That's comping up in #5357.
/// Define the parameterized test loop
INSTANTIATE_TEST_CASE_P(Dhcp4GetConfigTest, Dhcp4GetConfigTest,
::testing::Range(static_cast<size_t>(0), max_config_counter));
#endif
};
......@@ -16,7 +16,7 @@
#include <dhcp4/tests/get_config_unittest.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcp4/json_config_parser.h>
#include <dhcp4/simple_parser4.h>
#include <dhcpsrv/parsers/simple_parser4.h>
#include <boost/algorithm/string.hpp>
#include <gtest/gtest.h>
......
......@@ -309,7 +309,7 @@ Dhcpv6Srv::initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx) {
// are stored in order of preference. The server will use them in that
// order to search for host reservations.
if (ctx.subnet_ &&
(ctx.subnet_->getHostReservationMode() != Subnet::HR_DISABLED)) {
(ctx.subnet_->getHostReservationMode() != Network::HR_DISABLED)) {
const ConstCfgHostOperationsPtr cfg =
CfgMgr::instance().getCurrentCfg()->getCfgHostOperations6();
BOOST_FOREACH(const Host::IdentifierType& id_type,
......
......@@ -382,6 +382,15 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
continue;
}
if (config_pair.first == "shared-networks") {
/// @todo We need to create instance of SharedNetworks4ListParser
/// and parse the list of the shared networks into the
/// CfgSharedNetworks4 object. One additional step is then to
/// add subnets from the CfgSharedNetworks6 into CfgSubnets6
/// as well.
continue;
}
// Timers are not used in the global scope. Their values are derived
// to specific subnets (see SimpleParser6::deriveParameters).
// decline-probation-period and dhcp4o6-port are handled in the
......
......@@ -4697,22 +4697,22 @@ TEST_F(Dhcp6ParserTest, hostReservationPerSubnet) {
Subnet6Ptr subnet;
subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode());
// Subnet 2
subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_OUT_OF_POOL, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_OUT_OF_POOL, subnet->getHostReservationMode());
// Subnet 3
subnet = subnets->selectSubnet(IOAddress("2001:db8:3::1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_DISABLED, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_DISABLED, subnet->getHostReservationMode());
// Subnet 4
subnet = subnets->selectSubnet(IOAddress("2001:db8:4::1"));
ASSERT_TRUE(subnet);
EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
EXPECT_EQ(Network::HR_ALL, subnet->getHostReservationMode());
}
/// The goal of this test is to verify that configuration can include
......
......@@ -6051,8 +6051,14 @@ TEST_P(Dhcp6GetConfigTest, run) {
EXPECT_TRUE(isEquivalent(unparsed, unparsed2));
}
#if 0
// This test is temporarily disabled. The shared subnets structures have been
// implemented (#5305), but the parsers are not there yet, so grammar will fail
// when parseDHCP4 is called. That's comping up in #5357.
/// Define the parameterized test loop
INSTANTIATE_TEST_CASE_P(Dhcp6GetConfigTest, Dhcp6GetConfigTest,
::testing::Range(static_cast<size_t>(0), max_config_counter));
#endif
};
......@@ -16,7 +16,7 @@
#include <dhcp6/tests/get_config_unittest.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/simple_parser6.h>
#include <dhcpsrv/parsers/simple_parser6.h>
#include <boost/algorithm/string.hpp>
#include <gtest/gtest.h>
......
......@@ -88,6 +88,7 @@ libkea_dhcpsrv_la_SOURCES =
libkea_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
libkea_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libkea_dhcpsrv_la_SOURCES += alloc_engine_log.cc alloc_engine_log.h
libkea_dhcpsrv_la_SOURCES += assignable_network.h
libkea_dhcpsrv_la_SOURCES += base_host_data_source.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
libkea_dhcpsrv_la_SOURCES += cfg_4o6.cc cfg_4o6.h
......@@ -101,6 +102,7 @@ libkea_dhcpsrv_la_SOURCES += cfg_host_operations.cc cfg_host_operations.h
libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h
libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h
libkea_dhcpsrv_la_SOURCES += cfg_rsoo.cc cfg_rsoo.h
libkea_dhcpsrv_la_SOURCES += cfg_shared_networks.h
libkea_dhcpsrv_la_SOURCES += cfg_subnets4.cc cfg_subnets4.h
libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h
......@@ -138,6 +140,7 @@ libkea_dhcpsrv_la_SOURCES += mysql_host_data_source.cc mysql_host_data_source.h
endif
libkea_dhcpsrv_la_SOURCES += ncr_generator.cc ncr_generator.h
libkea_dhcpsrv_la_SOURCES += network.cc network.h
if HAVE_PGSQL
libkea_dhcpsrv_la_SOURCES += pgsql_connection.cc pgsql_connection.h
......@@ -150,6 +153,7 @@ libkea_dhcpsrv_la_SOURCES += cql_lease_mgr.cc cql_lease_mgr.h
libkea_dhcpsrv_la_SOURCES += cql_connection.cc cql_connection.h
endif
libkea_dhcpsrv_la_SOURCES += pool.cc pool.h
libkea_dhcpsrv_la_SOURCES += shared_network.cc shared_network.h
libkea_dhcpsrv_la_SOURCES += srv_config.cc srv_config.h
libkea_dhcpsrv_la_SOURCES += subnet.cc subnet.h
libkea_dhcpsrv_la_SOURCES += subnet_id.h
......@@ -178,6 +182,9 @@ libkea_dhcpsrv_la_SOURCES += parsers/ifaces_config_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/ifaces_config_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/option_data_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/option_data_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/shared_network_parser.cc
libkea_dhcpsrv_la_SOURCES += parsers/shared_network_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/shared_networks_list_parser.h
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser4.cc
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser4.h
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser6.cc
......
......@@ -18,6 +18,7 @@
#include <dhcpsrv/host.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/ncr_generator.h>
#include <dhcpsrv/network.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_manager.h>
#include <dhcpsrv/callout_handle_store.h>
......@@ -570,7 +571,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
}
// Check which host reservation mode is supported in this subnet.
Subnet::HRMode hr_mode = ctx.subnet_->getHostReservationMode();
Network::HRMode hr_mode = ctx.subnet_->getHostReservationMode();
Lease6Collection leases;
......@@ -597,7 +598,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
// it has been reserved for us we would have already allocated a lease.
ConstHostPtr host;
if (hr_mode != Subnet::HR_DISABLED) {
if (hr_mode != Network::HR_DISABLED) {
host = HostMgr::instance().get6(ctx.subnet_->getID(), hint);
}
......@@ -633,7 +634,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
if (lease->expired()) {
ConstHostPtr host;
if (hr_mode != Subnet::HR_DISABLED) {
if (hr_mode != Network::HR_DISABLED) {
host = HostMgr::instance().get6(ctx.subnet_->getID(), hint);
}
......@@ -677,7 +678,7 @@ AllocEngine::allocateUnreservedLeases6(ClientContext6& ctx) {
/// In-pool reservations: Check if this address is reserved for someone
/// else. There is no need to check for whom it is reserved, because if
/// it has been reserved for us we would have already allocated a lease.
if (hr_mode == Subnet::HR_ALL &&
if (hr_mode == Network::HR_ALL &&
HostMgr::instance().get6(ctx.subnet_->getID(), candidate)) {
// Don't allocate.
......@@ -847,7 +848,7 @@ AllocEngine::removeNonmatchingReservedLeases6(ClientContext6& ctx,
// host reservation is disabled (so there are no reserved leases),
// just return.
if (existing_leases.empty() || !ctx.subnet_ ||
(ctx.subnet_->getHostReservationMode() == Subnet::HR_DISABLED) ) {
(ctx.subnet_->getHostReservationMode() == Network::HR_DISABLED) ) {
return;
}
......
// Copyright (C) 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef ASSIGNABLE_NETWORK_H
#define ASSIGNABLE_NETWORK_H
#include <dhcpsrv/network.h>
namespace isc {
namespace dhcp {
/// @brief Represents a network that can be associated with a subnet.
///
/// This class represents a network that can be associated with a subnet
/// using @c Subnet::setSharedNetwork method. This class is a friend
/// of a @ref Subnet class, so it can call its @c Subnet::setSharedNetwork
/// private method. Association of a network with a subnet must be always
/// conducted using this class. This prevents unwanted replacements of
/// shared networks within subnets.
class AssignableNetwork {
protected:
/// @brief Virtual destructor.
virtual ~AssignableNetwork() { }
/// @brief Returns shared pointer to this object.
///
/// This abstract method must be implemented by derived classes to
/// return shared pointers the derivation.
///
/// @return Pointer to this network.
virtual NetworkPtr sharedFromThis() = 0;
/// @brief Associates a subnet with this network.
///
/// @param subnet Pointer to a subnet to be associated with the network.
///
/// @tparam SubnetPtr Type of the subnet pointer.
template<typename SubnetPtr>
void setSharedNetwork(const SubnetPtr& subnet) {
subnet->setSharedNetwork(sharedFromThis());
}
/// @brief Removes association of a subnet with a network.
///
/// @param subnet Pointer to a subnet for which association should be
/// removed.
///
/// @tparam SubnetPtr Type of the subnet pointer.
template<typename SubnetPtr>
void clearSharedNetwork(const SubnetPtr& subnet) {
subnet->setSharedNetwork(NetworkPtr());
}
};
} // end of namespace isc::dhcp
} // end of namespace isc
#endif // ASSIGNABLE_NETWORK_H
// Copyright (C) 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef CFG_SHARED_NETWORKS_H
#define CFG_SHARED_NETWORKS_H
#include <cc/cfg_to_element.h>
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <dhcpsrv/shared_network.h>
#include <boost/shared_ptr.hpp>
#include <string>
namespace isc {
namespace dhcp {
/// @brief This class holds configuration of shared networks.
///
/// This is a generic class implementing basic functions such as shared network
/// addition, removal and retrieval. It also dumps configuration in the JSON
/// format.
///
/// There are specializations of this class implemented as
/// @ref CfgSharedNetworks4 and @ref CfgSharedNetworks6 for IPv4 and IPv6 cases
/// repspectively.
///
/// @tparam Type of the pointer to a shared network, i.e. @ref SharedNetwork4Ptr
/// or @ref SharedNetwork6Ptr.
template<typename SharedNetworkPtrType, typename SharedNetworkCollection>
class CfgSharedNetworks : public data::CfgToElement {
public:
/// @brief Adds new shared network to the configuration.
///
/// @param network Pointer to a network
///
/// @throw isc::BadValue when name is a duplicate of existing network's
/// name.
void add(const SharedNetworkPtrType& network) {
if (getByName(network->getName())) {
isc_throw(BadValue, "duplicate network '" << network->getName() <<
"' found in the configuration");
}
networks_.push_back(network);
}
/// @brief Deletes shared network from the configuration.
///
/// @param name Name of the network to be deleted.
///
/// @throw isc::BadValue if the network can't be found.
void del(const std::string& name) {
auto& index = networks_.template get<SharedNetworkNameIndexTag>();
auto shared_network = index.find(name);
if (shared_network != index.end()) {
index.erase(shared_network);
} else {
isc_throw(BadValue, "unable to delete non-existing network '"
<< name << "' from shared networks configuration");
}
}
/// @brief Retrieves shared network by name.
///
/// @param name Name of the network to be retrieved.
///
/// @return Pointer to the shared network or null pointer if the network
/// is not found.
SharedNetworkPtrType getByName(const std::string& name) const {
const auto& index = networks_.template get<SharedNetworkNameIndexTag>();
auto shared_network = index.find(name);
if (shared_network != index.cend()) {
return (*shared_network);
}
return (SharedNetworkPtrType());
}
/// @brief Unparses shared networks configuration.
///
/// @return Element object representing a list of shared networks held
/// within configuration. The networks are sorted by their names.
virtual data::ElementPtr toElement() const {
data::ElementPtr list = data::Element::createList();
// Insert shared networks sorted by their names into the list.
const auto& index = networks_.template get<SharedNetworkNameIndexTag>();
for (auto shared_network = index.begin(); shared_network != index.end();
++shared_network) {
list->add((*shared_network)->toElement());
}
return (list);
}
protected:
/// @brief Multi index container holding shared networks.
SharedNetworkCollection networks_;
};
/// @brief Represents configuration of IPv4 shared networks.
class CfgSharedNetworks4 : public CfgSharedNetworks<SharedNetwork4Ptr,
SharedNetwork4Collection> {
public:
/// @brief Returns pointer to all configured shared networks.
const SharedNetwork4Collection* getAll() const {
return (&networks_);
}
};
/// @brief Pointer to the configuration of IPv4 shared networks.
typedef boost::shared_ptr<CfgSharedNetworks4> CfgSharedNetworks4Ptr;
/// @brief Represents configuration of IPv6 shared networks.
class CfgSharedNetworks6 : public CfgSharedNetworks<SharedNetwork6Ptr,
SharedNetwork6Collection> {
public:
/// @brief Returns pointer to all configured shared networks.
const SharedNetwork6Collection* getAll() const {
return (&networks_);
}
};
/// @brief Pointer to the configuration of IPv6 shared networks.
typedef boost::shared_ptr<CfgSharedNetworks6> CfgSharedNetworks6Ptr;
} // end of namespace isc::dhcp
} // end of namespace isc
#endif // CFG_SHARED_NETWORKS_H
// Copyright (C) 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <dhcpsrv/network.h>
using namespace isc::data;
namespace isc {
namespace dhcp {
Network::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr)
:addr_(addr) {
}
bool
Network::clientSupported(const isc::dhcp::ClientClasses& classes) const {
if (white_list_.empty()) {
// There is no class defined for this network, so we do
// support everyone.
return (true);
}
for (ClientClasses::const_iterator it = white_list_.begin();
it != white_list_.end(); ++it) {
if (classes.contains(*it)) {
return (true);
}
}
return (false);
}
void
Network::allowClientClass(const isc::dhcp::ClientClass& class_name) {
white_list_.insert(class_name);
}
ElementPtr
Network::toElement() const {
ElementPtr map = Element::createMap();
// Set interface
const std::string& iface = getIface();
if (!iface.empty()) {
map->set("interface", Element::create(iface));
}
// Set relay info
const RelayInfo& relay_info = getRelayInfo();
ElementPtr relay = Element::createMap();
relay->set("ip-address", Element::create(relay_info.addr_.toText()));
map->set("relay", relay);
// Set client-class
const ClientClasses& cclasses = 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 renew-timer
map->set("renew-timer",
Element::create(static_cast<long long>
(getT1().get())));
// Set rebind-timer
map->set("rebind-timer",
Element::create(static_cast<long long>
(getT2().get())));
// Set valid-lifetime
map->set("valid-lifetime",
Element::create(static_cast<long long>
(getValid().get())));
// Set reservation mode
Network::HRMode hrmode = getHostReservationMode();
std::string mode;
switch (hrmode) {
case HR_DISABLED:
mode = "disabled";
break;
case HR_OUT_OF_POOL:
mode = "out-of-pool";
break;
case HR_ALL:
mode = "all";
break;
default:
isc_throw(ToElementError,
"invalid host reservation mode: " << hrmode);
}
map->set("reservation-mode", Element::create(mode));
// Set options
ConstCfgOptionPtr opts = getCfgOption();
map->set("option-data", opts->toElement());
return (map);
}
ElementPtr
Network4::toElement() const {
ElementPtr map = Network::toElement();
// Set match-client-id
map->set("match-client-id", Element::create(getMatchClientId()));
return (map);
}
ElementPtr
Network6::toElement() const {
ElementPtr map = Network::toElement();
// Set preferred-lifetime
map->set("preferred-lifetime",
Element::create(static_cast<long long>
(getPreferred().get())));
// Set interface-id
const OptionPtr& ifaceid = 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));
}