mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-03 07:25:18 +00:00
[5376] Accept explicitly configured server identifiers in inbound msgs.
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <dhcp/iface_mgr.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcp/option4_addrlst.h>
|
||||
#include <dhcp/option_custom.h>
|
||||
#include <dhcp/option_int.h>
|
||||
#include <dhcp/option_int_array.h>
|
||||
#include <dhcp/option_vendor.h>
|
||||
@@ -27,6 +28,7 @@
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/cfg_host_operations.h>
|
||||
#include <dhcpsrv/cfg_iface.h>
|
||||
#include <dhcpsrv/cfg_shared_networks.h>
|
||||
#include <dhcpsrv/cfg_subnets4.h>
|
||||
#include <dhcpsrv/lease_mgr.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
@@ -62,6 +64,7 @@
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
@@ -2824,7 +2827,53 @@ Dhcpv4Srv::acceptServerId(const Pkt4Ptr& query) const {
|
||||
// performance hit should be acceptable. If it turns out to
|
||||
// be significant, we will have to cache server identifiers
|
||||
// when sockets are opened.
|
||||
return (IfaceMgr::instance().hasOpenSocket(server_id));
|
||||
if (IfaceMgr::instance().hasOpenSocket(server_id)) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
// There are some cases when an administrator explicitly sets server
|
||||
// identifier (option 54) that should be used for a given, subnet,
|
||||
// network etc. It doesn't have to be an address assigned to any of
|
||||
// the server interfaces. Thus, we have to check if the server
|
||||
// identifier received is the one that we explicitly set in the
|
||||
// server configuration. At this point, we don't know which subnet
|
||||
// the client belongs to so we can't match the server id with any
|
||||
// subnet. We simply check if this server identifier is configured
|
||||
// anywhere. This should be good enough to eliminate exchanges
|
||||
// with other servers in the same network.
|
||||
|
||||
/// @todo Currently we only check subnet identifiers configured on the
|
||||
/// subnet level, shared network level and global level. This should
|
||||
/// be sufficient for most of cases. At this point, trying to support
|
||||
/// server identifiers on the class level seems to be an overkill and
|
||||
/// is probably not needed. Same with host reservations. In fact,
|
||||
/// at this point we don't know the reservations for the client
|
||||
/// communicating with the server. We may revise some of these choices
|
||||
/// in the future.
|
||||
|
||||
SrvConfigPtr cfg = CfgMgr::instance().getCurrentCfg();
|
||||
|
||||
// Check if there is at least one subnet configured with this server
|
||||
// identifier.
|
||||
ConstCfgSubnets4Ptr cfg_subnets = cfg->getCfgSubnets4();
|
||||
if (cfg_subnets->hasSubnetWithServerId(server_id)) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
// This server identifier is not configured for any of the subnets, so
|
||||
// check on the shared network level.
|
||||
CfgSharedNetworks4Ptr cfg_networks = cfg->getCfgSharedNetworks4();
|
||||
if (cfg_networks->hasSubnetWithServerId(server_id)) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
// Finally, it is possible that the server identifier is specified
|
||||
// on the global level.
|
||||
ConstCfgOptionPtr cfg_global_options = cfg->getCfgOption();
|
||||
OptionCustomPtr opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
|
||||
(cfg_global_options->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
|
||||
|
||||
return (opt_server_id && (opt_server_id->readAddress() == server_id));
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -88,8 +88,9 @@ namespace {
|
||||
///
|
||||
/// - Configuration 7:
|
||||
/// - Used for testing custom value of dhcp-server-identifier option.
|
||||
/// - 1 subnets: 10.0.0.0/24 and 192.0.2.0/24
|
||||
/// - Custom server identifier specified for each subnet.
|
||||
/// - 3 subnets: 10.0.0.0/24, 192.0.2.0/26 and 192.0.2.64/26
|
||||
/// - Custom server identifier specified for 2 subnets subnet.
|
||||
/// - Custom server identifier specified at global level.
|
||||
///
|
||||
/// - Configuration 8:
|
||||
/// - Simple configuration with a single subnet and single pool
|
||||
@@ -291,6 +292,12 @@ const char* DORA_CONFIGS[] = {
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"valid-lifetime\": 600,"
|
||||
"\"option-data\": ["
|
||||
" {"
|
||||
" \"name\": \"dhcp-server-identifier\","
|
||||
" \"data\": \"3.4.5.6\""
|
||||
" }"
|
||||
"],"
|
||||
"\"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"10.0.0.0/24\", "
|
||||
@@ -304,8 +311,8 @@ const char* DORA_CONFIGS[] = {
|
||||
" ]"
|
||||
" },"
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.10-192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/26\", "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.10-192.0.2.63\" } ],"
|
||||
" \"interface\": \"eth1\","
|
||||
" \"option-data\": ["
|
||||
" {"
|
||||
@@ -313,7 +320,13 @@ const char* DORA_CONFIGS[] = {
|
||||
" \"data\": \"2.3.4.5\""
|
||||
" }"
|
||||
" ]"
|
||||
|
||||
" },"
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.64/26\", "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.65-192.0.2.100\" } ],"
|
||||
" \"relay\": {"
|
||||
" \"ip-address\": \"10.2.3.4\""
|
||||
" }"
|
||||
" }"
|
||||
"]"
|
||||
"}",
|
||||
@@ -1625,11 +1638,24 @@ TEST_F(DORATest, customServerIdentifier) {
|
||||
// Repeat the test for different subnet.
|
||||
Dhcp4Client client2(client1.getServer(), Dhcp4Client::SELECTING);
|
||||
client2.setIfaceName("eth1");
|
||||
|
||||
ASSERT_NO_THROW(client2.doDORA());
|
||||
ASSERT_TRUE(client2.getContext().response_);
|
||||
resp = client2.getContext().response_;
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
EXPECT_EQ("2.3.4.5", client2.config_.serverid_.toText());
|
||||
|
||||
// Create relayed client which will be assigned a lease from the third
|
||||
// subnet. This subnet inherits server identifier value from the global
|
||||
// scope.
|
||||
Dhcp4Client client3(client1.getServer(), Dhcp4Client::SELECTING);
|
||||
client3.useRelay(true, IOAddress("10.2.3.4"));
|
||||
|
||||
ASSERT_NO_THROW(client3.doDORA());
|
||||
ASSERT_TRUE(client3.getContext().response_);
|
||||
resp = client3.getContext().response_;
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
EXPECT_EQ("3.4.5.6", client3.config_.serverid_.toText());
|
||||
}
|
||||
|
||||
// Starting tests which require MySQL backend availability. Those tests
|
||||
|
@@ -808,6 +808,59 @@ const char* NETWORKS_CONFIG[] = {
|
||||
" ]"
|
||||
"}",
|
||||
|
||||
// Configuration #15
|
||||
// - two shared networks, each comes with its own server identifier.
|
||||
"{"
|
||||
" \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
" },"
|
||||
" \"valid-lifetime\": 600,"
|
||||
" \"shared-networks\": ["
|
||||
" {"
|
||||
" \"name\": \"frog\","
|
||||
" \"interface\": \"eth1\","
|
||||
" \"option-data\": ["
|
||||
" {"
|
||||
" \"name\": \"dhcp-server-identifier\","
|
||||
" \"data\": \"1.2.3.4\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"192.0.2.0/26\","
|
||||
" \"id\": 10,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"192.0.2.1 - 192.0.2.63\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"dog\","
|
||||
" \"interface\": \"eth0\","
|
||||
" \"option-data\": ["
|
||||
" {"
|
||||
" \"name\": \"dhcp-server-identifier\","
|
||||
" \"data\": \"2.3.4.5\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"subnet4\": ["
|
||||
" {"
|
||||
" \"subnet\": \"10.0.0.0/26\","
|
||||
" \"id\": 1000,"
|
||||
" \"pools\": ["
|
||||
" {"
|
||||
" \"pool\": \"10.0.0.1 - 10.0.0.63\""
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
" ]"
|
||||
"}"
|
||||
|
||||
};
|
||||
|
||||
/// @Brief Test fixture class for DHCPv4 server using shared networks.
|
||||
@@ -1661,4 +1714,44 @@ TEST_F(Dhcpv4SharedNetworkTest, sharedNetworkSelectedByClass) {
|
||||
});
|
||||
}
|
||||
|
||||
// This test verifies that custom server identifier can be specified for a
|
||||
// shared network.
|
||||
TEST_F(Dhcpv4SharedNetworkTest, customServerIdentifier) {
|
||||
Dhcp4Client client1(Dhcp4Client::SELECTING);
|
||||
client1.setIfaceName("eth1");
|
||||
|
||||
// Configure DHCP server.
|
||||
ASSERT_NO_THROW(configure(NETWORKS_CONFIG[15], *client1.getServer()));
|
||||
|
||||
testAssigned([this, &client1] {
|
||||
ASSERT_NO_THROW(client1.doDORA());
|
||||
});
|
||||
|
||||
// Make sure that the server responded.
|
||||
ASSERT_TRUE(client1.getContext().response_);
|
||||
Pkt4Ptr resp = client1.getContext().response_;
|
||||
// Make sure that the server has responded with DHCPACK.
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
// The explicitly configured server identifier should take precedence
|
||||
// over generated server identifier.
|
||||
EXPECT_EQ("1.2.3.4", client1.config_.serverid_.toText());
|
||||
|
||||
// Create another client using different interface.
|
||||
Dhcp4Client client2(client1.getServer(), Dhcp4Client::SELECTING);
|
||||
client2.setIfaceName("eth0");
|
||||
|
||||
testAssigned([this, &client2] {
|
||||
ASSERT_NO_THROW(client2.doDORA());
|
||||
});
|
||||
|
||||
// Make sure that the server responded.
|
||||
ASSERT_TRUE(client2.getContext().response_);
|
||||
resp = client2.getContext().response_;
|
||||
// Make sure that the server has responded with DHCPACK.
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
// The explicitly configured server identifier should take precedence
|
||||
// over generated server identifier.
|
||||
EXPECT_EQ("2.3.4.5", client2.config_.serverid_.toText());
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@@ -101,7 +101,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_shared_networks.cc 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
|
||||
|
24
src/lib/dhcpsrv/cfg_shared_networks.cc
Normal file
24
src/lib/dhcpsrv/cfg_shared_networks.cc
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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 <config.h>
|
||||
#include <dhcpsrv/cfg_shared_networks.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
bool
|
||||
CfgSharedNetworks4::hasSubnetWithServerId(const IOAddress& server_id) const {
|
||||
const auto& index = networks_.get<SharedNetworkServerIdIndexTag>();
|
||||
auto network_it = index.find(server_id);
|
||||
return (network_it != index.cend());
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
@@ -7,6 +7,7 @@
|
||||
#ifndef CFG_SHARED_NETWORKS_H
|
||||
#define CFG_SHARED_NETWORKS_H
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <cc/cfg_to_element.h>
|
||||
#include <cc/data.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
@@ -112,6 +113,15 @@ public:
|
||||
return (&networks_);
|
||||
}
|
||||
|
||||
/// @brief Checks if specified server identifier has been specified for
|
||||
/// any network.
|
||||
///
|
||||
/// @param server_id Server identifier.
|
||||
///
|
||||
/// @return true if there is a network with a specified server identifier.
|
||||
bool hasSubnetWithServerId(const asiolink::IOAddress& server_id) const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
/// @brief Pointer to the configuration of IPv4 shared networks.
|
||||
|
@@ -68,6 +68,13 @@ CfgSubnets4::getByPrefix(const std::string& subnet_text) const {
|
||||
return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet4Ptr());
|
||||
}
|
||||
|
||||
bool
|
||||
CfgSubnets4::hasSubnetWithServerId(const asiolink::IOAddress& server_id) const {
|
||||
const auto& index = subnets_.get<SubnetServerIdIndexTag>();
|
||||
auto subnet_it = index.find(server_id);
|
||||
return (subnet_it != index.cend());
|
||||
}
|
||||
|
||||
Subnet4Ptr
|
||||
CfgSubnets4::selectSubnet4o6(const SubnetSelector& selector) const {
|
||||
|
||||
|
@@ -91,6 +91,14 @@ public:
|
||||
/// subnet doesn't exist.
|
||||
ConstSubnet4Ptr getByPrefix(const std::string& subnet_prefix) const;
|
||||
|
||||
/// @brief Checks if specified server identifier has been specified for
|
||||
/// any subnet.
|
||||
///
|
||||
/// @param server_id Server identifier.
|
||||
///
|
||||
/// @return true if there is a subnet with a specified server identifier.
|
||||
bool hasSubnetWithServerId(const asiolink::IOAddress& server_id) const;
|
||||
|
||||
/// @brief Returns a pointer to the selected subnet.
|
||||
///
|
||||
/// This method tries to retrieve the subnet for the client using various
|
||||
|
@@ -4,8 +4,13 @@
|
||||
// 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 <dhcp/dhcp4.h>
|
||||
#include <dhcp/option_custom.h>
|
||||
#include <dhcp/option_space.h>
|
||||
#include <dhcpsrv/network.h>
|
||||
#include <boost/pointer_cast.hpp>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::data;
|
||||
|
||||
namespace isc {
|
||||
@@ -112,6 +117,21 @@ Network4::toElement() const {
|
||||
return (map);
|
||||
}
|
||||
|
||||
IOAddress
|
||||
Network4::getServerId() const {
|
||||
try {
|
||||
OptionCustomPtr opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
|
||||
(cfg_option_->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
|
||||
if (opt_server_id) {
|
||||
return (opt_server_id->readAddress());
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
// Ignore any exceptions and simply return empty buffer.
|
||||
}
|
||||
|
||||
return (IOAddress::IPV4_ZERO_ADDRESS());
|
||||
}
|
||||
|
||||
ElementPtr
|
||||
Network6::toElement() const {
|
||||
ElementPtr map = Network::toElement();
|
||||
|
@@ -337,6 +337,12 @@ public:
|
||||
/// @return A pointer to unparsed network configuration.
|
||||
virtual data::ElementPtr toElement() const;
|
||||
|
||||
/// @brief Returns binary representation of the dhcp-server-identifier option (54).
|
||||
///
|
||||
/// @return Server identifier option as IPv4 address. Zero IPv4 address
|
||||
/// indicates that server identifier hasn't been specified.
|
||||
virtual asiolink::IOAddress getServerId() const;
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Should server use client identifiers for client lease
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#ifndef SHARED_NETWORK_H
|
||||
#define SHARED_NETWORK_H
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <cc/data.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <dhcpsrv/assignable_network.h>
|
||||
@@ -30,6 +31,9 @@ struct SharedNetworkRandomAccessIndexTag { };
|
||||
/// @brief A tag for accessing index by shared network name.
|
||||
struct SharedNetworkNameIndexTag { };
|
||||
|
||||
/// @brief A tag for accessing index by server identifier.
|
||||
struct SharedNetworkServerIdIndexTag { };
|
||||
|
||||
/// @brief Shared network holding IPv4 subnets.
|
||||
///
|
||||
/// Specialization of the @ref Network4 class for IPv4 shared networks.
|
||||
@@ -149,7 +153,15 @@ typedef boost::multi_index_container<
|
||||
boost::multi_index::tag<SharedNetworkNameIndexTag>,
|
||||
boost::multi_index::const_mem_fun<SharedNetwork4, std::string,
|
||||
&SharedNetwork4::getName>
|
||||
>,
|
||||
// Third index allows for access by server identifier specified for the
|
||||
// network.
|
||||
boost::multi_index::ordered_non_unique<
|
||||
boost::multi_index::tag<SharedNetworkServerIdIndexTag>,
|
||||
boost::multi_index::const_mem_fun<Network4, asiolink::IOAddress,
|
||||
&Network4::getServerId>
|
||||
>
|
||||
|
||||
>
|
||||
> SharedNetwork4Collection;
|
||||
|
||||
|
@@ -613,13 +613,20 @@ struct SubnetSubnetIdIndexTag { };
|
||||
/// @brief Tag for the index for searching by subnet prefix.
|
||||
struct SubnetPrefixIndexTag { };
|
||||
|
||||
/// @brief Multi index container holding subnets.
|
||||
/// @brief Tag for the index for searching by server identifier.
|
||||
struct SubnetServerIdIndexTag { };
|
||||
|
||||
/// @brief A collection of @c Subnet4 objects
|
||||
///
|
||||
/// This multi index container can hold pointers to @ref Subnet4 or
|
||||
/// @ref Subnet6 objects representing subnets. It provides indexes for
|
||||
/// subnet lookups using subnet properties such as: subnet identifier
|
||||
/// or subnet prefix. It also provides a random access index which
|
||||
/// allows for using the container like a vector.
|
||||
/// This container provides a set of indexes which can be used to retrieve
|
||||
/// subnets by various properties.
|
||||
///
|
||||
/// This multi index container can hold pointers to @ref Subnet4
|
||||
/// objects representing subnets. It provides indexes for subnet lookups
|
||||
/// using subnet properties such as: subnet identifier,
|
||||
/// subnet prefix or server identifier specified for a subnet. It also
|
||||
/// provides a random access index which allows for using the container
|
||||
/// like a vector.
|
||||
///
|
||||
/// The random access index is used by the DHCP servers which perform
|
||||
/// a full scan on subnets to find the one that matches some specific
|
||||
@@ -632,12 +639,61 @@ struct SubnetPrefixIndexTag { };
|
||||
/// @todo We should consider optimizing subnet selection by leveraging
|
||||
/// the indexing capabilities of this container, e.g. searching for
|
||||
/// a subnet by interface name, relay address etc.
|
||||
///
|
||||
/// @tparam SubnetType Type of the subnet: @ref Subnet4 or @ref Subnet6.
|
||||
template<typename SubnetType>
|
||||
using SubnetCollection = boost::multi_index_container<
|
||||
typedef boost::multi_index_container<
|
||||
// Multi index container holds pointers to the subnets.
|
||||
boost::shared_ptr<SubnetType>,
|
||||
Subnet4Ptr,
|
||||
// The following holds all indexes.
|
||||
boost::multi_index::indexed_by<
|
||||
// First is the random access index allowing for accessing
|
||||
// objects just like we'd do with a vector.
|
||||
boost::multi_index::random_access<
|
||||
boost::multi_index::tag<SubnetRandomAccessIndexTag>
|
||||
>,
|
||||
// Second index allows for searching using subnet identifier.
|
||||
boost::multi_index::ordered_unique<
|
||||
boost::multi_index::tag<SubnetSubnetIdIndexTag>,
|
||||
boost::multi_index::const_mem_fun<Subnet, SubnetID, &Subnet::getID>
|
||||
>,
|
||||
// Third index allows for searching using an output from toText function.
|
||||
boost::multi_index::ordered_unique<
|
||||
boost::multi_index::tag<SubnetPrefixIndexTag>,
|
||||
boost::multi_index::const_mem_fun<Subnet, std::string, &Subnet::toText>
|
||||
>,
|
||||
|
||||
// Fourth index allows for searching using an output from getServerId
|
||||
boost::multi_index::ordered_non_unique<
|
||||
boost::multi_index::tag<SubnetServerIdIndexTag>,
|
||||
boost::multi_index::const_mem_fun<Network4, asiolink::IOAddress,
|
||||
&Network4::getServerId>
|
||||
>
|
||||
>
|
||||
> Subnet4Collection;
|
||||
|
||||
/// @brief A collection of @c Subnet6 objects
|
||||
///
|
||||
/// This container provides a set of indexes which can be used to retrieve
|
||||
/// subnets by various properties.
|
||||
///
|
||||
/// This multi index container can hold pointers to @ref Subnet6 objects
|
||||
/// representing subnets. It provides indexes for subnet lookups using
|
||||
/// subnet properties such as: subnet identifier or subnet prefix. It
|
||||
/// also provides a random access index which allows for using the
|
||||
/// container like a vector.
|
||||
///
|
||||
/// The random access index is used by the DHCP servers which perform
|
||||
/// a full scan on subnets to find the one that matches some specific
|
||||
/// criteria for subnet selection.
|
||||
///
|
||||
/// The remaining indexes are used for searching for a specific subnet
|
||||
/// as a result of receiving a command over the control API, e.g.
|
||||
/// when 'subnet-get' command is received.
|
||||
///
|
||||
/// @todo We should consider optimizing subnet selection by leveraging
|
||||
/// the indexing capabilities of this container, e.g. searching for
|
||||
/// a subnet by interface name, relay address etc.
|
||||
typedef boost::multi_index_container<
|
||||
// Multi index container holds pointers to the subnets.
|
||||
Subnet6Ptr,
|
||||
// The following holds all indexes.
|
||||
boost::multi_index::indexed_by<
|
||||
// First is the random access index allowing for accessing
|
||||
@@ -656,19 +712,7 @@ using SubnetCollection = boost::multi_index_container<
|
||||
boost::multi_index::const_mem_fun<Subnet, std::string, &Subnet::toText>
|
||||
>
|
||||
>
|
||||
>;
|
||||
|
||||
/// @brief A collection of @c Subnet4 objects
|
||||
///
|
||||
/// This container provides a set of indexes which can be used to retrieve
|
||||
/// subnets by various properties.
|
||||
typedef SubnetCollection<Subnet4> Subnet4Collection;
|
||||
|
||||
/// @brief A collection of @c Subnet6 objects
|
||||
///
|
||||
/// This container provides a set of indexes which can be used to retrieve
|
||||
/// subnets by various properties.
|
||||
typedef SubnetCollection<Subnet6> Subnet6Collection;
|
||||
> Subnet6Collection;
|
||||
|
||||
//@}
|
||||
|
||||
|
@@ -6,6 +6,10 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <dhcp/classify.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcp/option_custom.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcp/option_space.h>
|
||||
#include <dhcp/tests/iface_mgr_test_config.h>
|
||||
#include <dhcpsrv/shared_network.h>
|
||||
#include <dhcpsrv/cfg_subnets4.h>
|
||||
@@ -856,4 +860,23 @@ TEST(CfgSubnets4Test, getSubnet) {
|
||||
EXPECT_EQ(Subnet4Ptr(), cfg.getSubnet(400)); // no such subnet
|
||||
}
|
||||
|
||||
// This test verifies that hasSubnetWithServerId returns correct value.
|
||||
TEST(CfgSubnets4Test, hasSubnetWithServerId) {
|
||||
CfgSubnets4 cfg;
|
||||
|
||||
// Initially, there is no server identifier option present.
|
||||
EXPECT_FALSE(cfg.hasSubnetWithServerId(IOAddress("1.2.3.4")));
|
||||
|
||||
OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
|
||||
DHO_DHCP_SERVER_IDENTIFIER);
|
||||
OptionCustomPtr opt_server_id(new OptionCustom(*def, Option::V4));
|
||||
opt_server_id->writeAddress(IOAddress("1.2.3.4"));
|
||||
Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3, 100));
|
||||
subnet->getCfgOption()->add(opt_server_id, false, DHCP4_OPTION_SPACE);
|
||||
cfg.add(subnet);
|
||||
|
||||
EXPECT_TRUE(cfg.hasSubnetWithServerId(IOAddress("1.2.3.4")));
|
||||
EXPECT_FALSE(cfg.hasSubnetWithServerId(IOAddress("2.3.4.5")));
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@@ -7,13 +7,19 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/dhcp4.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_custom.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/option_space.h>
|
||||
#include <dhcpsrv/shared_network.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <limits>
|
||||
@@ -497,6 +503,28 @@ TEST(Subnet4Test, PoolType) {
|
||||
EXPECT_THROW(subnet->addPool(pool5), BadValue);
|
||||
}
|
||||
|
||||
// Tests if correct value of server identifier is returned when getServerId is
|
||||
// called.
|
||||
TEST(Subnet4Test, getServerId) {
|
||||
// Initially, the subnet has no server identifier.
|
||||
Subnet4 subnet(IOAddress("192.2.0.0"), 16, 1, 2, 3);
|
||||
EXPECT_TRUE(subnet.getServerId().isV4Zero());
|
||||
|
||||
// Add server identifier.
|
||||
OptionDefinitionPtr option_def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
|
||||
DHO_DHCP_SERVER_IDENTIFIER);
|
||||
OptionCustomPtr option_server_id(new OptionCustom(*option_def, Option::V4));
|
||||
option_server_id->writeAddress(IOAddress("1.2.3.4"));
|
||||
|
||||
CfgOptionPtr cfg_option = subnet.getCfgOption();
|
||||
cfg_option->add(option_server_id, false, DHCP4_OPTION_SPACE);
|
||||
|
||||
// Verify that the server identifier returned by the Subnet4 object is
|
||||
// correct.
|
||||
OptionBuffer server_id_buf = { 1, 2, 3, 4 };
|
||||
EXPECT_EQ("1.2.3.4", subnet.getServerId().toText());
|
||||
}
|
||||
|
||||
// Tests for Subnet6
|
||||
|
||||
TEST(Subnet6Test, constructor) {
|
||||
|
Reference in New Issue
Block a user