mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 05:27:55 +00:00
[3625] Use CfgSubnets6 to obtain subnet information.
This commit is contained in:
parent
6c956ebafc
commit
4a5895b993
@ -38,6 +38,7 @@
|
||||
#include <dhcpsrv/lease_mgr.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/subnet_selector.h>
|
||||
#include <dhcpsrv/utils.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <hooks/callout_handle.h>
|
||||
@ -868,43 +869,25 @@ Dhcpv6Srv::sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
|
||||
|
||||
Subnet6Ptr
|
||||
Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
|
||||
// Initialize subnet selector with the values used to select the subnet.
|
||||
SubnetSelector selector;
|
||||
selector.iface_name_ = question->getIface();
|
||||
selector.remote_address_ = question->getRemoteAddr();
|
||||
selector.first_relay_linkaddr_ = IOAddress("::");
|
||||
selector.client_classes_ = question->classes_;
|
||||
|
||||
Subnet6Ptr subnet;
|
||||
|
||||
if (question->relay_info_.empty()) {
|
||||
// This is a direct (non-relayed) message
|
||||
|
||||
// Try to find a subnet if received packet from a directly connected client
|
||||
subnet = CfgMgr::instance().getSubnet6(question->getIface(),
|
||||
question->classes_);
|
||||
if (!subnet) {
|
||||
// If no subnet was found, try to find it based on remote address
|
||||
subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr(),
|
||||
question->classes_);
|
||||
}
|
||||
} else {
|
||||
|
||||
// This is a relayed message
|
||||
OptionPtr interface_id = question->getAnyRelayOption(D6O_INTERFACE_ID,
|
||||
Pkt6::RELAY_GET_FIRST);
|
||||
if (interface_id) {
|
||||
subnet = CfgMgr::instance().getSubnet6(interface_id,
|
||||
question->classes_);
|
||||
}
|
||||
|
||||
if (!subnet) {
|
||||
// If no interface-id was specified (or not configured on server),
|
||||
// let's try address matching
|
||||
IOAddress link_addr = question->relay_info_.back().linkaddr_;
|
||||
|
||||
// if relay filled in link_addr field, then let's use it
|
||||
if (link_addr != IOAddress("::")) {
|
||||
subnet = CfgMgr::instance().getSubnet6(link_addr,
|
||||
question->classes_, true);
|
||||
}
|
||||
}
|
||||
// Initialize fields specific to relayed messages.
|
||||
if (!question->relay_info_.empty()) {
|
||||
selector.first_relay_linkaddr_ = question->relay_info_.back().linkaddr_;
|
||||
selector.interface_id_ =
|
||||
question->getAnyRelayOption(D6O_INTERFACE_ID,
|
||||
Pkt6::RELAY_GET_FIRST);
|
||||
}
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
|
||||
getCfgSubnets6()->selectSubnet(selector);
|
||||
|
||||
|
||||
// Let's execute all callouts registered for subnet6_receive
|
||||
if (HooksManager::calloutsPresent(Hooks.hook_index_subnet6_select_)) {
|
||||
CalloutHandlePtr callout_handle = getCalloutHandle(question);
|
||||
@ -919,7 +902,9 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
|
||||
// We pass pointer to const collection for performance reasons.
|
||||
// Otherwise we would get a non-trivial performance penalty each
|
||||
// time subnet6_select is called.
|
||||
callout_handle->setArgument("subnet6collection", CfgMgr::instance().getSubnets6());
|
||||
callout_handle->setArgument("subnet6collection",
|
||||
CfgMgr::instance().getCurrentCfg()->
|
||||
getCfgSubnets6()->getAll());
|
||||
|
||||
// Call user (and server-side) callouts
|
||||
HooksManager::callCallouts(Hooks.hook_index_subnet6_select_, *callout_handle);
|
||||
|
@ -344,7 +344,7 @@ public:
|
||||
// subnet id is invalid (duplicate). Thus, we catch exceptions
|
||||
// here to append a position in the configuration string.
|
||||
try {
|
||||
isc::dhcp::CfgMgr::instance().addSubnet6(sub6ptr);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(sub6ptr);
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< subnet->getPosition() << ")");
|
||||
@ -534,12 +534,6 @@ public:
|
||||
///
|
||||
/// @param subnets_list pointer to a list of IPv6 subnets
|
||||
void build(ConstElementPtr subnets_list) {
|
||||
// @todo: Implement more subtle reconfiguration than toss
|
||||
// the old one and replace with the new one.
|
||||
|
||||
// remove old subnets
|
||||
isc::dhcp::CfgMgr::instance().deleteSubnets6();
|
||||
|
||||
BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
|
||||
ParserPtr parser(new Subnet6ConfigParser("subnet"));
|
||||
parser->build(subnet);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <dhcpsrv/addr_utilities.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/subnet_selector.h>
|
||||
#include <dhcpsrv/testutils/config_result_check.h>
|
||||
#include <hooks/hooks_manager.h>
|
||||
|
||||
@ -247,13 +248,13 @@ public:
|
||||
getOptionFromSubnet(const IOAddress& subnet_address,
|
||||
const uint16_t option_code,
|
||||
const uint16_t expected_options_count = 1) {
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(subnet_address,
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(subnet_address, classify_);
|
||||
if (!subnet) {
|
||||
/// @todo replace toText() with the use of operator <<.
|
||||
ADD_FAILURE() << "A subnet for the specified address "
|
||||
<< subnet_address.toText()
|
||||
<< "does not exist in Config Manager";
|
||||
<< " does not exist in Config Manager";
|
||||
}
|
||||
OptionContainerPtr options =
|
||||
subnet->getCfgOption()->getAll("dhcp6");
|
||||
@ -469,6 +470,8 @@ public:
|
||||
const uint16_t option_code,
|
||||
const uint8_t* expected_data,
|
||||
const size_t expected_data_len) {
|
||||
CfgMgr::instance().clear();
|
||||
|
||||
std::string config = createConfigWithOption(params);
|
||||
ASSERT_TRUE(executeConfiguration(config, "parse option configuration"));
|
||||
|
||||
@ -557,8 +560,8 @@ TEST_F(Dhcp6ParserTest, subnetGlobalDefaults) {
|
||||
|
||||
// Now check if the configuration was indeed handled and we have
|
||||
// expected pool configured.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
EXPECT_EQ(1000, subnet->getT1());
|
||||
EXPECT_EQ(2000, subnet->getT2());
|
||||
@ -605,7 +608,10 @@ TEST_F(Dhcp6ParserTest, multipleSubnets) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
|
||||
|
||||
@ -660,7 +666,10 @@ TEST_F(Dhcp6ParserTest, multipleSubnetsExplicitIDs) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
|
||||
|
||||
@ -796,7 +805,10 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
|
||||
|
||||
@ -805,7 +817,9 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
subnets = CfgMgr::instance().getSubnets6();
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(3, subnets->size()); // We expect 3 subnets now (4th is removed)
|
||||
|
||||
@ -820,12 +834,16 @@ TEST_F(Dhcp6ParserTest, reconfigureRemoveSubnet) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Do reconfiguration
|
||||
json = Element::fromJSON(config_second_removed);
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
subnets = CfgMgr::instance().getSubnets6();
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(3, subnets->size()); // We expect 4 subnets
|
||||
|
||||
@ -863,8 +881,8 @@ TEST_F(Dhcp6ParserTest, subnetLocal) {
|
||||
// returned value should be 0 (configuration success)
|
||||
checkResult(status, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
EXPECT_EQ(1, subnet->getT1());
|
||||
EXPECT_EQ(2, subnet->getT2());
|
||||
@ -898,8 +916,8 @@ TEST_F(Dhcp6ParserTest, subnetInterface) {
|
||||
// returned value should be 0 (configuration success)
|
||||
checkResult(status, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
EXPECT_EQ(valid_iface_, subnet->getIface());
|
||||
}
|
||||
@ -931,8 +949,8 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceBogus) {
|
||||
checkResult(status, 1);
|
||||
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
EXPECT_FALSE(subnet);
|
||||
}
|
||||
|
||||
@ -993,16 +1011,20 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceId) {
|
||||
|
||||
// Try to get a subnet based on bogus interface-id option
|
||||
OptionBuffer tmp(bogus_interface_id.begin(), bogus_interface_id.end());
|
||||
OptionPtr ifaceid(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(ifaceid, classify_);
|
||||
SubnetSelector selector;
|
||||
selector.first_relay_linkaddr_ = IOAddress("5000::1");
|
||||
selector.interface_id_.reset(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(selector);
|
||||
EXPECT_FALSE(subnet);
|
||||
|
||||
// Now try to get subnet for valid interface-id value
|
||||
tmp = OptionBuffer(valid_interface_id.begin(), valid_interface_id.end());
|
||||
ifaceid.reset(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
|
||||
subnet = CfgMgr::instance().getSubnet6(ifaceid, classify_);
|
||||
selector.interface_id_.reset(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
|
||||
subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(selector);
|
||||
ASSERT_TRUE(subnet);
|
||||
EXPECT_TRUE(ifaceid->equals(subnet->getInterfaceId()));
|
||||
EXPECT_TRUE(selector.interface_id_->equals(subnet->getInterfaceId()));
|
||||
}
|
||||
|
||||
|
||||
@ -1084,7 +1106,8 @@ TEST_F(Dhcp6ParserTest, multiplePools) {
|
||||
ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
|
||||
checkResult(status, 0);
|
||||
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(2, subnets->size()); // We expect 2 subnets
|
||||
|
||||
@ -1163,8 +1186,8 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) {
|
||||
// returned value must be 1 (configuration parse error)
|
||||
checkResult(x, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
EXPECT_EQ(1000, subnet->getT1());
|
||||
EXPECT_EQ(2000, subnet->getT2());
|
||||
@ -1205,8 +1228,8 @@ TEST_F(Dhcp6ParserTest, pdPoolBasics) {
|
||||
checkResult(x, 0);
|
||||
|
||||
// Test that we can retrieve the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// Fetch the collection of PD pools. It should have 1 entry.
|
||||
@ -1277,8 +1300,8 @@ TEST_F(Dhcp6ParserTest, pdPoolList) {
|
||||
checkResult(x, 0);
|
||||
|
||||
// Test that we can retrieve the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// Fetch the collection of NA pools. It should have 1 entry.
|
||||
@ -1333,8 +1356,8 @@ TEST_F(Dhcp6ParserTest, subnetAndPrefixDelegated) {
|
||||
checkResult(x, 0);
|
||||
|
||||
// Test that we can retrieve the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
@ -2027,8 +2050,8 @@ TEST_F(Dhcp6ParserTest, optionDataDefaults) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
|
||||
ASSERT_EQ(2, options->size());
|
||||
@ -2122,8 +2145,8 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
|
||||
checkResult(status, 0);
|
||||
|
||||
// Options should be now available for the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
// Try to get the option from the space dhcp6.
|
||||
OptionDescriptor desc1 = subnet->getCfgOption()->get("dhcp6", 38);
|
||||
@ -2278,8 +2301,8 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
|
||||
checkResult(status, 0);
|
||||
|
||||
// Get the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// We should have one option available.
|
||||
@ -2341,8 +2364,8 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet1 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet1);
|
||||
OptionContainerPtr options1 = subnet1->getCfgOption()->getAll("dhcp6");
|
||||
ASSERT_EQ(1, options1->size());
|
||||
@ -2367,8 +2390,8 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
|
||||
sizeof(subid_expected));
|
||||
|
||||
// Test another subnet in the same way.
|
||||
Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet2 = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:2::4"), classify_);
|
||||
ASSERT_TRUE(subnet2);
|
||||
OptionContainerPtr options2 = subnet2->getCfgOption()->getAll("dhcp6");
|
||||
ASSERT_EQ(1, options2->size());
|
||||
@ -2402,8 +2425,6 @@ TEST_F(Dhcp6ParserTest, optionDataBoolean) {
|
||||
ASSERT_TRUE(executeConfiguration(config, "parse configuration with a"
|
||||
" boolean value"));
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// The subnet should now hold one option with the code 1000.
|
||||
OptionDescriptor desc =
|
||||
getOptionFromSubnet(IOAddress("2001:db8:1::5"), 1000);
|
||||
@ -2538,8 +2559,8 @@ TEST_F(Dhcp6ParserTest, optionDataLowerCase) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
|
||||
ASSERT_EQ(1, options->size());
|
||||
@ -2581,8 +2602,8 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
OptionContainerPtr options = subnet->getCfgOption()->getAll("dhcp6");
|
||||
ASSERT_EQ(1, options->size());
|
||||
@ -2659,8 +2680,8 @@ TEST_F(Dhcp6ParserTest, vendorOptionsHex) {
|
||||
checkResult(status, 0);
|
||||
|
||||
// Options should be now available for the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// Try to get the option from the vendor space 4491
|
||||
@ -2721,8 +2742,8 @@ TEST_F(Dhcp6ParserTest, vendorOptionsCsv) {
|
||||
checkResult(status, 0);
|
||||
|
||||
// Options should be now available for the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// Try to get the option from the vendor space 4491
|
||||
@ -2864,8 +2885,8 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) {
|
||||
checkResult(status, 0);
|
||||
|
||||
// Get the subnet.
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// We should have one option available.
|
||||
@ -3151,8 +3172,8 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfo) {
|
||||
// returned value should be 0 (configuration success)
|
||||
checkResult(status, 0);
|
||||
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::1"),
|
||||
classify_);
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
|
||||
selectSubnet(IOAddress("2001:db8:1::1"), classify_);
|
||||
ASSERT_TRUE(subnet);
|
||||
EXPECT_EQ("2001:db8:1::abcd", subnet->getRelayInfo().addr_.toText());
|
||||
}
|
||||
@ -3191,7 +3212,8 @@ TEST_F(Dhcp6ParserTest, classifySubnets) {
|
||||
EXPECT_NO_THROW(x = configureDhcp6Server(srv_, json));
|
||||
checkResult(x, 0);
|
||||
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(4, subnets->size()); // We expect 4 subnets
|
||||
|
||||
|
@ -233,7 +233,8 @@ TEST_F(ConfirmTest, relayedClientNoAddress) {
|
||||
// Configure the server.
|
||||
configure(CONFIRM_CONFIGS[1], *client.getServer());
|
||||
// Make sure we ended-up having expected number of subnets configured.
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_EQ(2, subnets->size());
|
||||
// Client to send relayed message.
|
||||
client.useRelay();
|
||||
@ -255,7 +256,7 @@ TEST_F(ConfirmTest, relayedClientNoSubnet) {
|
||||
ASSERT_NO_FATAL_FAILURE(requestLease(CONFIRM_CONFIGS[1], 2, client));
|
||||
// Now that the client has a lease, let's remove any subnets to check
|
||||
// how the server would respond to the Confirm.
|
||||
ASSERT_NO_THROW(CfgMgr::instance().deleteSubnets6());
|
||||
ASSERT_NO_THROW(CfgMgr::instance().clear());
|
||||
// Send Confirm message to the server.
|
||||
ASSERT_NO_THROW(client.doConfirm());
|
||||
// Client should have received a status code option and this option should
|
||||
|
@ -182,7 +182,7 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
|
||||
ElementPtr config = Element::fromJSON(config_txt);
|
||||
|
||||
// Make sure there are no subnets configured.
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().clear();
|
||||
|
||||
// Now send the command
|
||||
int rcode = -1;
|
||||
@ -192,11 +192,12 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
|
||||
EXPECT_EQ(0, rcode); // Expect success
|
||||
|
||||
// Check that the config was indeed applied.
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
|
||||
EXPECT_EQ(3, subnets->size());
|
||||
|
||||
// Clean up after the test.
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().clear();
|
||||
}
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
@ -128,6 +128,7 @@ Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
|
||||
|
||||
void
|
||||
Dhcp6SrvD2Test::configure(const std::string& config, bool exp_result) {
|
||||
CfgMgr::instance().clear();
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
ConstElementPtr status;
|
||||
|
||||
|
@ -53,7 +53,8 @@ Dhcpv6MessageTest::requestLease(const std::string& config,
|
||||
// Configure the server.
|
||||
configure(config, *client.getServer());
|
||||
// Make sure we ended-up having expected number of subnets configured.
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_EQ(subnets_num, subnets->size());
|
||||
// Do the actual 4-way exchange.
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
@ -63,8 +64,8 @@ Dhcpv6MessageTest::requestLease(const std::string& config,
|
||||
// subnets.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6 lease_client = client.getLease(0);
|
||||
ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client.addr_,
|
||||
ClientClasses()));
|
||||
ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
|
||||
selectSubnet(lease_client.addr_, ClientClasses()));
|
||||
// Check that the client's lease matches the information on the server
|
||||
// side.
|
||||
Lease6Ptr lease_server = checkLease(lease_client);
|
||||
|
@ -1182,8 +1182,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
|
||||
|
||||
// CASE 1: We have only one subnet defined and we received local traffic.
|
||||
// The only available subnet used to be picked, but not anymore
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
pkt->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
@ -1196,38 +1197,42 @@ TEST_F(Dhcpv6SrvTest, selectSubnetAddr) {
|
||||
// We should NOT select it.
|
||||
|
||||
// Identical steps as in case 1, but repeated for clarity
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
pkt->setRemoteAddr(IOAddress("2001:db8:abcd::2345"));
|
||||
Subnet6Ptr selected = srv.selectSubnet(pkt);
|
||||
EXPECT_FALSE(selected);
|
||||
|
||||
// CASE 3: We have three subnets defined and we received local traffic.
|
||||
// Nothing should be selected.
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
pkt->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
selected = srv.selectSubnet(pkt);
|
||||
EXPECT_FALSE(selected);
|
||||
|
||||
// CASE 4: We have three subnets defined and we received relayed traffic
|
||||
// that came out of subnet 2. We should select subnet2 then
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
pkt->setRemoteAddr(IOAddress("2001:db8:2::baca"));
|
||||
selected = srv.selectSubnet(pkt);
|
||||
EXPECT_EQ(selected, subnet2);
|
||||
|
||||
// CASE 5: We have three subnets defined and we received relayed traffic
|
||||
// that came out of undefined subnet. We should select nothing
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
pkt->setRemoteAddr(IOAddress("2001:db8:4::baca"));
|
||||
EXPECT_FALSE(srv.selectSubnet(pkt));
|
||||
}
|
||||
@ -1246,8 +1251,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
|
||||
|
||||
// CASE 1: We have only one subnet defined and it is available via eth0.
|
||||
// Packet came from eth0. The only available subnet should be selected
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
pkt->setIface("eth0");
|
||||
@ -1257,8 +1263,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
|
||||
|
||||
// CASE 2: We have only one subnet defined and it is available via eth0.
|
||||
// Packet came from eth1. We should not select it
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
pkt->setIface("eth1");
|
||||
|
||||
@ -1268,10 +1275,11 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
|
||||
// CASE 3: We have only 3 subnets defined, one over eth0, one remote and
|
||||
// one over wifi1.
|
||||
// Packet came from eth1. We should not select it
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
pkt->setIface("eth0");
|
||||
EXPECT_EQ(subnet1, srv.selectSubnet(pkt));
|
||||
@ -1298,8 +1306,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
|
||||
|
||||
// CASE 1: We have only one subnet defined and we received relayed traffic.
|
||||
// The only available subnet should NOT be selected.
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
pkt->relay_info_.push_back(relay);
|
||||
@ -1309,19 +1318,21 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
|
||||
|
||||
// CASE 2: We have three subnets defined and we received relayed traffic.
|
||||
// Nothing should be selected.
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
selected = srv.selectSubnet(pkt);
|
||||
EXPECT_EQ(selected, subnet2);
|
||||
|
||||
// CASE 3: We have three subnets defined and we received relayed traffic
|
||||
// that came out of subnet 2. We should select subnet2 then
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Source of the packet should have no meaning. Selection is based
|
||||
// on linkaddr field in the relay
|
||||
@ -1331,10 +1342,11 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
|
||||
|
||||
// CASE 4: We have three subnets defined and we received relayed traffic
|
||||
// that came out of undefined subnet. We should select nothing
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
pkt->relay_info_.clear();
|
||||
relay.linkaddr_ = IOAddress("2001:db8:4::1234");
|
||||
pkt->relay_info_.push_back(relay);
|
||||
@ -1357,8 +1369,9 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
|
||||
|
||||
// CASE 1: We have only one subnet defined and it is for interface-id "relay1"
|
||||
// Packet came with interface-id "relay2". We should not select subnet1
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
Pkt6::RelayInfo relay;
|
||||
@ -1374,18 +1387,20 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) {
|
||||
|
||||
// CASE 2: We have only one subnet defined and it is for interface-id "relay2"
|
||||
// Packet came with interface-id "relay2". We should select it
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet2); // just a single subnet
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2); // just a single subnet
|
||||
CfgMgr::instance().commit();
|
||||
selected = srv.selectSubnet(pkt);
|
||||
EXPECT_EQ(selected, subnet2);
|
||||
|
||||
// CASE 3: We have only 3 subnets defined: one remote for interface-id "relay1",
|
||||
// one remote for interface-id "relay2" and third local
|
||||
// packet comes with interface-id "relay2". We should select subnet2
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().addSubnet6(subnet1);
|
||||
CfgMgr::instance().addSubnet6(subnet2);
|
||||
CfgMgr::instance().addSubnet6(subnet3);
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
EXPECT_EQ(subnet2, srv.selectSubnet(pkt));
|
||||
}
|
||||
@ -1938,7 +1953,8 @@ TEST_F(Dhcpv6SrvTest, relayOverride) {
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
// Let's get the subnet configuration objects
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_EQ(2, subnets->size());
|
||||
|
||||
// Let's get them for easy reference
|
||||
@ -2014,7 +2030,8 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) {
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
// Let's get the subnet configuration objects
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_EQ(2, subnets->size());
|
||||
|
||||
// Let's get them for easy reference
|
||||
|
@ -36,8 +36,9 @@ Dhcpv6SrvTest::Dhcpv6SrvTest()
|
||||
64));
|
||||
subnet_->addPool(pool_);
|
||||
|
||||
isc::dhcp::CfgMgr::instance().deleteSubnets6();
|
||||
isc::dhcp::CfgMgr::instance().addSubnet6(subnet_);
|
||||
isc::dhcp::CfgMgr::instance().clear();
|
||||
isc::dhcp::CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
||||
isc::dhcp::CfgMgr::instance().commit();
|
||||
|
||||
// configure PD pool
|
||||
pd_pool_ = isc::dhcp::Pool6Ptr
|
||||
@ -604,6 +605,8 @@ Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
|
||||
int rcode;
|
||||
ConstElementPtr comment = config::parseAnswer(rcode, status);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
}
|
||||
|
||||
// Generate IA_NA option with specified parameters
|
||||
|
@ -348,7 +348,7 @@ public:
|
||||
///
|
||||
/// Removes existing configuration.
|
||||
~Dhcpv6SrvTest() {
|
||||
isc::dhcp::CfgMgr::instance().deleteSubnets6();
|
||||
isc::dhcp::CfgMgr::instance().clear();
|
||||
};
|
||||
|
||||
/// @brief Runs DHCPv6 configuration from the JSON string.
|
||||
|
@ -974,13 +974,14 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestReuseExpiredLease) {
|
||||
// We are going to configure a subnet with a pool that consists of
|
||||
// exactly one address. This address will be handed out to the
|
||||
// client, will get expired and then be reused.
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().clear();
|
||||
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1:1::"), 56, 1, 2,
|
||||
3, 4));
|
||||
subnet_->setIface("eth0");
|
||||
pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr));
|
||||
subnet_->addPool(pool_);
|
||||
CfgMgr::instance().addSubnet6(subnet_);
|
||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Allocate a lease.
|
||||
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
|
||||
|
@ -922,6 +922,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
|
||||
comment_ = parseAnswer(rcode_, status);
|
||||
ASSERT_EQ(0, rcode_);
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Prepare solicit packet. Server should select first subnet for it
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
@ -942,7 +944,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6_select) {
|
||||
// Check that pkt6 argument passing was successful and returned proper value
|
||||
EXPECT_TRUE(callback_pkt6_.get() == sol.get());
|
||||
|
||||
const Subnet6Collection* exp_subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* exp_subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
|
||||
// The server is supposed to pick the first subnet, because of matching
|
||||
// interface. Check that the value is reported properly.
|
||||
@ -990,6 +993,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
|
||||
comment_ = parseAnswer(rcode_, status);
|
||||
ASSERT_EQ(0, rcode_);
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Prepare solicit packet. Server should select first subnet for it
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
@ -1016,7 +1021,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet_select_change) {
|
||||
ASSERT_TRUE(addr_opt);
|
||||
|
||||
// Get all subnets and use second subnet for verification
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_EQ(2, subnets->size());
|
||||
|
||||
// Advertised address must belong to the second pool (in subnet's range,
|
||||
|
@ -106,7 +106,8 @@ TEST_F(JSONFileBackendTest, jsonFile) {
|
||||
EXPECT_NO_THROW(srv->init(TEST_FILE));
|
||||
|
||||
// Now check if the configuration has been applied correctly.
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(3, subnets->size()); // We expect 3 subnets.
|
||||
|
||||
@ -176,7 +177,8 @@ TEST_F(JSONFileBackendTest, comments) {
|
||||
EXPECT_NO_THROW(srv->init(TEST_FILE));
|
||||
|
||||
// Now check if the configuration has been applied correctly.
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
ASSERT_TRUE(subnets);
|
||||
ASSERT_EQ(1, subnets->size());
|
||||
|
||||
|
@ -223,8 +223,8 @@ TEST_F(RebindTest, directClient) {
|
||||
// subnets.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6 lease_client2 = client.getLease(0);
|
||||
ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
|
||||
ClientClasses()));
|
||||
ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
|
||||
selectSubnet(lease_client2.addr_, ClientClasses()));
|
||||
// The client's lease should have been extended. The client will
|
||||
// update the cltt to current time when the lease gets extended.
|
||||
ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
|
||||
@ -337,8 +337,8 @@ TEST_F(RebindTest, relayedClient) {
|
||||
// subnets.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6 lease_client2 = client.getLease(0);
|
||||
ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
|
||||
ClientClasses()));
|
||||
ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
|
||||
selectSubnet(lease_client2.addr_, ClientClasses()));
|
||||
// The client's lease should have been extended. The client will
|
||||
// update the cltt to current time when the lease gets extended.
|
||||
ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
|
||||
@ -498,8 +498,8 @@ TEST_F(RebindTest, directClientPD) {
|
||||
// subnets.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6 lease_client2 = client.getLease(0);
|
||||
ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
|
||||
ClientClasses()));
|
||||
ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
|
||||
selectSubnet(lease_client2.addr_, ClientClasses()));
|
||||
// The client's lease should have been extended. The client will
|
||||
// update the cltt to current time when the lease gets extended.
|
||||
ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
|
||||
@ -675,8 +675,8 @@ TEST_F(RebindTest, relayedUnicast) {
|
||||
// subnets.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6 lease_client2 = client.getLease(0);
|
||||
ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client2.addr_,
|
||||
ClientClasses()));
|
||||
ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
|
||||
selectSubnet(lease_client2.addr_, ClientClasses()));
|
||||
// The client's lease should have been extended. The client will
|
||||
// update the cltt to current time when the lease gets extended.
|
||||
ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000);
|
||||
|
@ -76,7 +76,8 @@ TEST_F(SARRTest, directClientPrefixHint) {
|
||||
client.usePD();
|
||||
configure(CONFIGS[0], *client.getServer());
|
||||
// Make sure we ended-up having expected number of subnets configured.
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
|
||||
const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
|
||||
getCfgSubnets6()->getAll();
|
||||
ASSERT_EQ(1, subnets->size());
|
||||
// Append IAPREFIX option to the client's message.
|
||||
ASSERT_NO_THROW(client.useHint(100, 200, 64, "2001:db8:3:33::33"));
|
||||
|
@ -49,7 +49,7 @@ CfgSubnets6::selectSubnet(const SubnetSelector& selector) const {
|
||||
}
|
||||
|
||||
// If interface name didn't match, try the client's address.
|
||||
if (!subnet && selector.remote_address_.isSpecified()) {
|
||||
if (!subnet && selector.remote_address_ != IOAddress("::")) {
|
||||
subnet = selectSubnet(selector.remote_address_,
|
||||
selector.client_classes_);
|
||||
}
|
||||
|
@ -62,114 +62,6 @@ CfgMgr::addOptionSpace6(const OptionSpacePtr& space) {
|
||||
spaces6_.insert(make_pair(space->getName(), space));
|
||||
}
|
||||
|
||||
Subnet6Ptr
|
||||
CfgMgr::getSubnet6(const std::string& iface,
|
||||
const isc::dhcp::ClientClasses& classes) {
|
||||
|
||||
if (!iface.length()) {
|
||||
return (Subnet6Ptr());
|
||||
}
|
||||
|
||||
// If there is more than one, we need to choose the proper one
|
||||
for (Subnet6Collection::iterator subnet = subnets6_.begin();
|
||||
subnet != subnets6_.end(); ++subnet) {
|
||||
|
||||
// If client is rejected because of not meeting client class criteria...
|
||||
if (!(*subnet)->clientSupported(classes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iface == (*subnet)->getIface()) {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
|
||||
DHCPSRV_CFGMGR_SUBNET6_IFACE)
|
||||
.arg((*subnet)->toText()).arg(iface);
|
||||
return (*subnet);
|
||||
}
|
||||
}
|
||||
return (Subnet6Ptr());
|
||||
}
|
||||
|
||||
Subnet6Ptr
|
||||
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint,
|
||||
const isc::dhcp::ClientClasses& classes,
|
||||
const bool relay) {
|
||||
|
||||
// If there is more than one, we need to choose the proper one
|
||||
for (Subnet6Collection::iterator subnet = subnets6_.begin();
|
||||
subnet != subnets6_.end(); ++subnet) {
|
||||
|
||||
// If client is rejected because of not meeting client class criteria...
|
||||
if (!(*subnet)->clientSupported(classes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the hint is a relay address, and there is relay info specified
|
||||
// for this subnet and those two match, then use this subnet.
|
||||
if (relay && ((*subnet)->getRelayInfo().addr_ == hint) ) {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
|
||||
DHCPSRV_CFGMGR_SUBNET6_RELAY)
|
||||
.arg((*subnet)->toText()).arg(hint.toText());
|
||||
return (*subnet);
|
||||
}
|
||||
|
||||
if ((*subnet)->inRange(hint)) {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_SUBNET6)
|
||||
.arg((*subnet)->toText()).arg(hint.toText());
|
||||
return (*subnet);
|
||||
}
|
||||
}
|
||||
|
||||
// sorry, we don't support that subnet
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_NO_SUBNET6)
|
||||
.arg(hint.toText());
|
||||
return (Subnet6Ptr());
|
||||
}
|
||||
|
||||
Subnet6Ptr CfgMgr::getSubnet6(OptionPtr iface_id_option,
|
||||
const isc::dhcp::ClientClasses& classes) {
|
||||
if (!iface_id_option) {
|
||||
return (Subnet6Ptr());
|
||||
}
|
||||
|
||||
// Let's iterate over all subnets and for those that have interface-id
|
||||
// defined, check if the interface-id is equal to what we are looking for
|
||||
for (Subnet6Collection::iterator subnet = subnets6_.begin();
|
||||
subnet != subnets6_.end(); ++subnet) {
|
||||
|
||||
// If client is rejected because of not meeting client class criteria...
|
||||
if (!(*subnet)->clientSupported(classes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( (*subnet)->getInterfaceId() &&
|
||||
((*subnet)->getInterfaceId()->equals(iface_id_option))) {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
|
||||
DHCPSRV_CFGMGR_SUBNET6_IFACE_ID)
|
||||
.arg((*subnet)->toText());
|
||||
return (*subnet);
|
||||
}
|
||||
}
|
||||
return (Subnet6Ptr());
|
||||
}
|
||||
|
||||
void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
|
||||
/// @todo: Check that this new subnet does not cross boundaries of any
|
||||
/// other already defined subnet.
|
||||
/// @todo: Check that there is no subnet with the same interface-id
|
||||
if (isDuplicate(*subnet)) {
|
||||
isc_throw(isc::dhcp::DuplicateSubnetID, "ID of the new IPv6 subnet '"
|
||||
<< subnet->getID() << "' is already in use");
|
||||
}
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET6)
|
||||
.arg(subnet->toText());
|
||||
subnets6_.push_back(subnet);
|
||||
}
|
||||
|
||||
void CfgMgr::deleteSubnets6() {
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DELETE_SUBNET6);
|
||||
subnets6_.clear();
|
||||
}
|
||||
|
||||
|
||||
std::string CfgMgr::getDataDir() {
|
||||
return (datadir_);
|
||||
|
@ -126,97 +126,6 @@ public:
|
||||
return (spaces6_);
|
||||
}
|
||||
|
||||
/// @brief get IPv6 subnet by address
|
||||
///
|
||||
/// Finds a matching subnet, based on an address. This can be used
|
||||
/// in two cases: when trying to find an appropriate lease based on
|
||||
/// a) relay link address (that must be the address that is on link)
|
||||
/// b) our global address on the interface the message was received on
|
||||
/// (for directly connected clients)
|
||||
///
|
||||
/// If there are any classes specified in a subnet, that subnet
|
||||
/// will be selected only if the client belongs to appropriate class.
|
||||
///
|
||||
/// @note The client classification is checked before any relay
|
||||
/// information checks are conducted.
|
||||
///
|
||||
/// If relay is true then relay info overrides (i.e. value the sysadmin
|
||||
/// can configure in Dhcp6/subnet6[X]/relay/ip-address) can be used.
|
||||
/// That is applicable only for relays. Those overrides must not be used
|
||||
/// for client address or for client hints. They are for link-addr field
|
||||
/// in the RELAY_FORW message only.
|
||||
///
|
||||
/// @param hint an address that belongs to a searched subnet
|
||||
/// @param classes classes the client belongs to
|
||||
/// @param relay true if address specified in hint is a relay
|
||||
///
|
||||
/// @return a subnet object (or NULL if no suitable match was fount)
|
||||
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint,
|
||||
const isc::dhcp::ClientClasses& classes,
|
||||
const bool relay = false);
|
||||
|
||||
/// @brief get IPv6 subnet by interface name
|
||||
///
|
||||
/// Finds a matching local subnet, based on interface name. This
|
||||
/// is used for selecting subnets that were explicitly marked by the
|
||||
/// user as reachable over specified network interface.
|
||||
///
|
||||
/// If there are any classes specified in a subnet, that subnet
|
||||
/// will be selected only if the client belongs to appropriate class.
|
||||
///
|
||||
/// @param iface_name interface name
|
||||
/// @param classes classes the client belongs to
|
||||
///
|
||||
/// @return a subnet object (or NULL if no suitable match was fount)
|
||||
Subnet6Ptr getSubnet6(const std::string& iface_name,
|
||||
const isc::dhcp::ClientClasses& classes);
|
||||
|
||||
/// @brief get IPv6 subnet by interface-id
|
||||
///
|
||||
/// Another possibility to find a subnet is based on interface-id.
|
||||
///
|
||||
/// If there are any classes specified in a subnet, that subnet
|
||||
/// will be selected only if the client belongs to appropriate class.
|
||||
///
|
||||
/// @param interface_id content of interface-id option returned by a relay
|
||||
/// @param classes classes the client belongs to
|
||||
///
|
||||
/// @return a subnet object
|
||||
Subnet6Ptr getSubnet6(OptionPtr interface_id,
|
||||
const isc::dhcp::ClientClasses& classes);
|
||||
|
||||
/// @brief adds an IPv6 subnet
|
||||
///
|
||||
/// @param subnet new subnet to be added.
|
||||
void addSubnet6(const Subnet6Ptr& subnet);
|
||||
|
||||
/// @todo: Add subnet6 removal routines. Currently it is not possible
|
||||
/// to remove subnets. The only case where subnet6 removal would be
|
||||
/// needed is a dynamic server reconfiguration - a use case that is not
|
||||
/// planned to be supported any time soon.
|
||||
|
||||
/// @brief removes all IPv6 subnets
|
||||
///
|
||||
/// This method removes all existing IPv6 subnets. It is used during
|
||||
/// reconfiguration - old configuration is wiped and new definitions
|
||||
/// are used to recreate subnets.
|
||||
///
|
||||
/// @todo Implement more intelligent approach. Note that comparison
|
||||
/// between old and new configuration is tricky. For example: is
|
||||
/// 2000::/64 and 2000::/48 the same subnet or is it something
|
||||
/// completely new?
|
||||
void deleteSubnets6();
|
||||
|
||||
/// @brief returns const reference to all subnets6
|
||||
///
|
||||
/// This is used in a hook (subnet6_select), where the hook is able
|
||||
/// to choose a different subnet. Server code has to offer a list
|
||||
/// of possible choices (i.e. all subnets).
|
||||
/// @return a pointer to const Subnet6 collection
|
||||
const Subnet6Collection* getSubnets6() {
|
||||
return (&subnets6_);
|
||||
}
|
||||
|
||||
/// @brief returns path do the data directory
|
||||
///
|
||||
/// This method returns a path to writeable directory that DHCP servers
|
||||
|
@ -51,7 +51,7 @@ SrvConfig::getConfigSummary(const uint32_t selection) const {
|
||||
}
|
||||
|
||||
if ((selection & CFGSEL_SUBNET6) == CFGSEL_SUBNET6) {
|
||||
subnets_num = CfgMgr::instance().getSubnets6()->size();
|
||||
subnets_num = getCfgSubnets6()->getAll()->size();
|
||||
if (subnets_num > 0) {
|
||||
s << "added IPv6 subnets: " << subnets_num;
|
||||
} else {
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/classify.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <util/optional_value.h>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
@ -47,9 +46,9 @@ struct SubnetSelector {
|
||||
//@}
|
||||
|
||||
/// @brief Address on which the message was received.
|
||||
util::OptionalValue<asiolink::IOAddress> local_address_;
|
||||
asiolink::IOAddress local_address_;
|
||||
/// @brief Source address of the message.
|
||||
util::OptionalValue<asiolink::IOAddress> remote_address_;
|
||||
asiolink::IOAddress remote_address_;
|
||||
/// @brief Classes that the client belongs to.
|
||||
ClientClasses client_classes_;
|
||||
/// @brief Name of the interface on which the message was received.
|
||||
@ -63,8 +62,8 @@ struct SubnetSelector {
|
||||
giaddr_(asiolink::IOAddress("0.0.0.0")),
|
||||
interface_id_(),
|
||||
first_relay_linkaddr_(asiolink::IOAddress("::")),
|
||||
local_address_(asiolink::IOAddress("0.0.0.0"), false),
|
||||
remote_address_(asiolink::IOAddress("0.0.0.0"), false),
|
||||
local_address_(asiolink::IOAddress("0.0.0.0")),
|
||||
remote_address_(asiolink::IOAddress("0.0.0.0")),
|
||||
client_classes_(), iface_name_(std::string()) {
|
||||
}
|
||||
};
|
||||
|
@ -91,6 +91,8 @@ public:
|
||||
/// in many tests, initializes cfg_mgr configuration and creates
|
||||
/// lease database.
|
||||
AllocEngine6Test() {
|
||||
CfgMgr::instance().clear();
|
||||
|
||||
duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
|
||||
iaid_ = 42;
|
||||
|
||||
@ -115,7 +117,6 @@ public:
|
||||
void initSubnet(const IOAddress& subnet, const IOAddress& pool_start,
|
||||
const IOAddress& pool_end) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
cfg_mgr.deleteSubnets6();
|
||||
|
||||
subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 1, 2, 3, 4));
|
||||
pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
|
||||
@ -125,7 +126,8 @@ public:
|
||||
pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, subnet, 56, 64));
|
||||
subnet_->addPool(pd_pool_);
|
||||
|
||||
cfg_mgr.addSubnet6(subnet_);
|
||||
cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
||||
cfg_mgr.commit();
|
||||
|
||||
}
|
||||
|
||||
@ -855,13 +857,13 @@ TEST_F(AllocEngine6Test, outOfAddresses6) {
|
||||
|
||||
IOAddress addr("2001:db8:1::ad");
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
|
||||
cfg_mgr.clear(); // Get rid of the default test configuration
|
||||
|
||||
// Create configuration similar to other tests, but with a single address pool
|
||||
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
|
||||
pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr)); // just a single address
|
||||
subnet_->addPool(pool_);
|
||||
cfg_mgr.addSubnet6(subnet_);
|
||||
cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
||||
|
||||
// Just a different duid
|
||||
DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
|
||||
@ -939,13 +941,14 @@ TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
|
||||
|
||||
IOAddress addr("2001:db8:1::ad");
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
|
||||
cfg_mgr.clear(); // Get rid of the default test configuration
|
||||
|
||||
// Create configuration similar to other tests, but with a single address pool
|
||||
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
|
||||
pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, addr, addr)); // just a single address
|
||||
subnet_->addPool(pool_);
|
||||
cfg_mgr.addSubnet6(subnet_);
|
||||
cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
||||
cfg_mgr.commit();
|
||||
|
||||
// Let's create an expired lease
|
||||
DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
|
||||
|
@ -283,7 +283,6 @@ public:
|
||||
|
||||
void clear() {
|
||||
CfgMgr::instance().setVerbose(false);
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
CfgMgr::instance().clear();
|
||||
}
|
||||
|
||||
@ -304,307 +303,6 @@ TEST_F(CfgMgrTest, configuration) {
|
||||
EXPECT_TRUE(configuration->getLoggingInfo().empty());
|
||||
}
|
||||
|
||||
// This test verifies if the configuration manager is able to hold v6 subnets
|
||||
// with their relay address information and return proper subnets, based on
|
||||
// those addresses.
|
||||
TEST_F(CfgMgrTest, subnet6RelayOverride) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
// Let's configure 3 subnets
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 48, 1, 2, 3, 4));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
// Check that without relay-info specified, subnets are not selected
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, true));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, true));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, true));
|
||||
|
||||
// Now specify relay info
|
||||
subnet1->setRelayInfo(IOAddress("2001:db8:ff::1"));
|
||||
subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
|
||||
subnet3->setRelayInfo(IOAddress("2001:db8:ff::3"));
|
||||
|
||||
// And try again. This time relay-info is there and should match.
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, true));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, true));
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, true));
|
||||
|
||||
// Finally, check that the relay works only if hint provided is relay address
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::1"), classify_, false));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::2"), classify_, false));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2001:db8:ff::3"), classify_, false));
|
||||
}
|
||||
|
||||
|
||||
// This test verifies if the configuration manager is able to hold and return
|
||||
// valid leases
|
||||
TEST_F(CfgMgrTest, classifySubnet6) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
// Let's configure 3 subnets
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
// Let's sanity check that we can use that configuration.
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
|
||||
|
||||
// Client now belongs to bar class.
|
||||
classify_.insert("bar");
|
||||
|
||||
// There are no class restrictions defined, so everything should work
|
||||
// as before
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
|
||||
|
||||
// Now let's add client class restrictions.
|
||||
subnet1->allowClientClass("foo"); // Serve here only clients from foo class
|
||||
subnet2->allowClientClass("bar"); // Serve here only clients from bar class
|
||||
subnet3->allowClientClass("baz"); // Serve here only clients from baz class
|
||||
|
||||
// The same check as above should result in client being served only in
|
||||
// bar class, i.e. subnet2
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
|
||||
|
||||
// Now let's check that client with wrong class is not supported
|
||||
classify_.clear();
|
||||
classify_.insert("some_other_class");
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
|
||||
|
||||
// Finally, let's check that client without any classes is not supported
|
||||
classify_.clear();
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::345"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::567"), classify_));
|
||||
}
|
||||
|
||||
// This test verifies if the configuration manager is able to hold, select
|
||||
// and return valid subnets, based on interface names along with client
|
||||
// classification.
|
||||
TEST_F(CfgMgrTest, classifySubnet6Interface) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
// Let's have an odd configuration: 3 shared subnets available on the
|
||||
// same direct link.
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
subnet1->setIface("foo");
|
||||
subnet2->setIface("foo");
|
||||
subnet3->setIface("foo");
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
|
||||
// Regular client should get the first subnet, because it meets all
|
||||
// criteria (matching interface name, no class restrictions.
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
|
||||
|
||||
// Now let's add class requirements for subnet1
|
||||
subnet1->allowClientClass("alpha");
|
||||
|
||||
// Client should now get the subnet2, because he no longer meets
|
||||
// requirements for subnet1 (belongs to wrong class)
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("foo", classify_));
|
||||
|
||||
// Now let's add (not matching) classes to the other two subnets
|
||||
subnet2->allowClientClass("beta");
|
||||
subnet3->allowClientClass("gamma");
|
||||
|
||||
// No subnets are suitable, so nothing will be selected
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
|
||||
|
||||
// Ok, let's add the client to gamme class, so he'll get a subnet
|
||||
classify_.insert("gamma");
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foo", classify_));
|
||||
}
|
||||
|
||||
// This test verifies if the configuration manager is able to hold, select
|
||||
// and return valid subnets, based on interface-id option inserted by relay,
|
||||
// along with client classification.
|
||||
TEST_F(CfgMgrTest, classifySubnet6InterfaceId) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
// Let's have an odd configuration: 3 shared subnets available via the
|
||||
// same remote relay with the same interface-id.
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
OptionPtr ifaceid = generateInterfaceId("relay1.eth0");
|
||||
subnet1->setInterfaceId(ifaceid);
|
||||
subnet2->setInterfaceId(ifaceid);
|
||||
subnet3->setInterfaceId(ifaceid);
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
// Regular client should get the first subnet, because it meets all
|
||||
// criteria (matching interface name, no class restrictions.
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid, classify_));
|
||||
|
||||
// Now let's add class requirements for subnet1
|
||||
subnet1->allowClientClass("alpha");
|
||||
|
||||
// Client should now get the subnet2, because he no longer meets
|
||||
// requirements for subnet1 (belongs to wrong class)
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid, classify_));
|
||||
|
||||
// Now let's add (not matching) classes to the other two subnets
|
||||
subnet2->allowClientClass("beta");
|
||||
subnet3->allowClientClass("gamma");
|
||||
|
||||
// No subnets are suitable, so nothing will be selected
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid, classify_));
|
||||
|
||||
// Ok, let's add the client to gamme class, so he'll get a subnet
|
||||
classify_.insert("gamma");
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid, classify_));
|
||||
}
|
||||
|
||||
// This test verifies if the configuration manager is able to hold and return
|
||||
// valid leases
|
||||
TEST_F(CfgMgrTest, subnet6) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
|
||||
// There shouldn't be any subnet configured at this stage
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
|
||||
// Now we have only one subnet, any request will be served from it
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1"), classify_));
|
||||
|
||||
// We used to allow getting a sole subnet if there was only one subnet
|
||||
// configured. That is no longer true. The code should not return
|
||||
// a subnet.
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef"),
|
||||
classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("5000::1"), classify_));
|
||||
|
||||
// Check that deletion of the subnets works.
|
||||
cfg_mgr.deleteSubnets6();
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::123"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::123"), classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::123"), classify_));
|
||||
}
|
||||
|
||||
// This test verifies if the configuration manager is able to hold, select
|
||||
// and return valid subnets, based on interface names.
|
||||
TEST_F(CfgMgrTest, subnet6Interface) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
subnet1->setIface("foo");
|
||||
subnet2->setIface("bar");
|
||||
subnet3->setIface("foobar");
|
||||
|
||||
// There shouldn't be any subnet configured at this stage
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
|
||||
// Now we have only one subnet, any request will be served from it
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6("foo", classify_));
|
||||
|
||||
// Check that the interface name is checked even when there is
|
||||
// only one subnet defined.
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
|
||||
|
||||
// We used to allow getting a sole subnet if there was only one subnet
|
||||
// configured. That is no longer true. The code should not return
|
||||
// a subnet.
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef"), classify_));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6("foobar", classify_));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6("bar", classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("xyzzy", classify_)); // no such interface
|
||||
|
||||
// Check that deletion of the subnets works.
|
||||
cfg_mgr.deleteSubnets6();
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("foo", classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("bar", classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6("foobar", classify_));
|
||||
}
|
||||
|
||||
// This test verifies if the configuration manager is able to hold, select
|
||||
// and return valid leases, based on interface-id option values
|
||||
TEST_F(CfgMgrTest, subnet6InterfaceId) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
|
||||
|
||||
// interface-id options used in subnets 1,2, and 3
|
||||
OptionPtr ifaceid1 = generateInterfaceId("relay1.eth0");
|
||||
OptionPtr ifaceid2 = generateInterfaceId("VL32");
|
||||
// That's a strange interface-id, but this is a real life example
|
||||
OptionPtr ifaceid3 = generateInterfaceId("ISAM144|299|ipv6|nt:vp:1:110");
|
||||
|
||||
// bogus interface-id
|
||||
OptionPtr ifaceid_bogus = generateInterfaceId("non-existent");
|
||||
|
||||
subnet1->setInterfaceId(ifaceid1);
|
||||
subnet2->setInterfaceId(ifaceid2);
|
||||
subnet3->setInterfaceId(ifaceid3);
|
||||
|
||||
// There shouldn't be any subnet configured at this stage
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid1, classify_));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet1);
|
||||
|
||||
// If we have only a single subnet and the request came from a local
|
||||
// address, let's use that subnet
|
||||
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(ifaceid1, classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid2, classify_));
|
||||
|
||||
cfg_mgr.addSubnet6(subnet2);
|
||||
cfg_mgr.addSubnet6(subnet3);
|
||||
|
||||
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(ifaceid3, classify_));
|
||||
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(ifaceid2, classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid_bogus, classify_));
|
||||
|
||||
// Check that deletion of the subnets works.
|
||||
cfg_mgr.deleteSubnets6();
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid1, classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid2, classify_));
|
||||
EXPECT_FALSE(cfg_mgr.getSubnet6(ifaceid3, classify_));
|
||||
}
|
||||
|
||||
|
||||
// This test verifies that new DHCPv4 option spaces can be added to
|
||||
// the configuration manager and that duplicated option space is
|
||||
// rejected.
|
||||
@ -731,26 +429,6 @@ TEST_F(CfgMgrTest, d2ClientConfig) {
|
||||
EXPECT_NE(*original_config, *updated_config);
|
||||
}
|
||||
|
||||
// Checks that detection of duplicated subnet IDs works as expected. It should
|
||||
// not be possible to add two IPv6 subnets holding the same ID to the config
|
||||
// manager.
|
||||
TEST_F(CfgMgrTest, subnet6Duplication) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3,
|
||||
4, 123));
|
||||
Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"), 64, 1, 2, 3,
|
||||
4, 124));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"), 64, 1, 2, 3,
|
||||
4, 123));
|
||||
|
||||
ASSERT_NO_THROW(cfg_mgr.addSubnet6(subnet1));
|
||||
EXPECT_NO_THROW(cfg_mgr.addSubnet6(subnet2));
|
||||
// Subnet 3 has the same ID as subnet 1. It shouldn't be able to add it.
|
||||
EXPECT_THROW(cfg_mgr.addSubnet6(subnet3), isc::dhcp::DuplicateSubnetID);
|
||||
}
|
||||
|
||||
|
||||
// This test verifies that the configuration staging, commit and rollback works
|
||||
// as expected.
|
||||
TEST_F(CfgMgrTest, staging) {
|
||||
|
@ -447,7 +447,6 @@ public:
|
||||
void reset_context(){
|
||||
// Note set context universe to V6 as it has to be something.
|
||||
CfgMgr::instance().clear();
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
parser_context_.reset(new ParserContext(Option::V6));
|
||||
|
||||
// Ensure no hooks libraries are loaded.
|
||||
|
@ -41,8 +41,6 @@ public:
|
||||
/// is @c TEST_SUBNETS_NUM for IPv4 and IPv6 each.
|
||||
SrvConfigTest()
|
||||
: iface_mgr_test_config_(true) {
|
||||
// Remove any subnets dangling from previous unit tests.
|
||||
clearSubnets();
|
||||
|
||||
// Disable DDNS.
|
||||
enableDDNS(false);
|
||||
@ -74,10 +72,7 @@ public:
|
||||
}
|
||||
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Removes any dangling configuration.
|
||||
virtual ~SrvConfigTest() {
|
||||
clearSubnets();
|
||||
}
|
||||
|
||||
/// @brief Convenience function which adds IPv4 subnet to the configuration.
|
||||
@ -108,12 +103,6 @@ public:
|
||||
/// @c conf_ object.
|
||||
void addSubnet6(const unsigned int index);
|
||||
|
||||
/// @brief Removes all subnets from the configuration.
|
||||
///
|
||||
/// @todo Modify this function once the subnet configuration is migrated
|
||||
/// from @c CfgMgr to @c SrvConfig.
|
||||
void clearSubnets();
|
||||
|
||||
/// @brief Enable/disable DDNS.
|
||||
///
|
||||
/// @param enable A boolean value indicating if the DDNS should be
|
||||
@ -146,12 +135,7 @@ SrvConfigTest::addSubnet6(const unsigned int index) {
|
||||
FAIL() << "Subnet index " << index << "out of range (0.."
|
||||
<< TEST_SUBNETS_NUM << "): " << "unable to add IPv6 subnet";
|
||||
}
|
||||
CfgMgr::instance().addSubnet6(test_subnets6_[index]);
|
||||
}
|
||||
|
||||
void
|
||||
SrvConfigTest::clearSubnets() {
|
||||
CfgMgr::instance().deleteSubnets6();
|
||||
conf_.getCfgSubnets6()->add(test_subnets6_[index]);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
x
Reference in New Issue
Block a user