2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-05 00:15:17 +00:00

[#991] added multi-threading unittests for v6 server

This commit is contained in:
Razvan Becheriu
2020-12-10 10:49:00 +02:00
parent a823c4d773
commit 0f0de1f6b4
7 changed files with 425 additions and 108 deletions

View File

@@ -2244,8 +2244,14 @@ TEST_F(Dhcpv4SrvTest, sanityCheck) {
RFCViolation);
}
// Checks if received relay agent info option is echoed back to the client
TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
} // end of anonymous namespace
namespace isc {
namespace dhcp {
namespace test {
void
Dhcpv4SrvTest::relayAgentInfoEcho() {
IfaceMgrTestConfig test_config(true);
NakedDhcpv4Srv srv(0);
@@ -2288,9 +2294,8 @@ TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
EXPECT_TRUE(rai_response->equals(rai_query));
}
// Checks if received bad relay agent info option is not echoed back
// to the client
TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEcho) {
void
Dhcpv4SrvTest::badRelayAgentInfoEcho() {
IfaceMgrTestConfig test_config(true);
NakedDhcpv4Srv srv(0);
@@ -2333,8 +2338,8 @@ TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEcho) {
ASSERT_FALSE(rai_response);
}
// Checks if client port can be overridden in packets being sent.
TEST_F(Dhcpv4SrvTest, portsClientPort) {
void
Dhcpv4SrvTest::portsClientPort() {
IfaceMgrTestConfig test_config(true);
NakedDhcpv4Srv srv(0);
@@ -2374,8 +2379,8 @@ TEST_F(Dhcpv4SrvTest, portsClientPort) {
EXPECT_EQ(srv.client_port_, offer->getRemotePort());
}
// Checks if server port can be overridden in packets being sent.
TEST_F(Dhcpv4SrvTest, portsServerPort) {
void
Dhcpv4SrvTest::portsServerPort() {
IfaceMgrTestConfig test_config(true);
// Do not use DHCP4_SERVER_PORT here as 0 means don't open sockets.
@@ -2415,6 +2420,52 @@ TEST_F(Dhcpv4SrvTest, portsServerPort) {
EXPECT_EQ(srv.server_port_, offer->getLocalPort());
}
} // end of isc::dhcp::test namespace
} // end of isc::dhcp namespace
} // end of isc namespace
namespace {
TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
Dhcpv4SrvMTTestGuard guard(*this, false);
relayAgentInfoEcho();
}
TEST_F(Dhcpv4SrvTest, relayAgentInfoEchoMultiThreading) {
Dhcpv4SrvMTTestGuard guard(*this, true);
relayAgentInfoEcho();
}
TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEcho) {
Dhcpv4SrvMTTestGuard guard(*this, false);
badRelayAgentInfoEcho();
}
TEST_F(Dhcpv4SrvTest, badRelayAgentInfoEchoMultiThreading) {
Dhcpv4SrvMTTestGuard guard(*this, true);
badRelayAgentInfoEcho();
}
TEST_F(Dhcpv4SrvTest, portsClientPort) {
Dhcpv4SrvMTTestGuard guard(*this, false);
portsClientPort();
}
TEST_F(Dhcpv4SrvTest, portsClientPortMultiThreading) {
Dhcpv4SrvMTTestGuard guard(*this, true);
portsClientPort();
}
TEST_F(Dhcpv4SrvTest, portsServerPort) {
Dhcpv4SrvMTTestGuard guard(*this, false);
portsServerPort();
}
TEST_F(Dhcpv4SrvTest, portsServerPortMultiTHreading) {
Dhcpv4SrvMTTestGuard guard(*this, true);
portsServerPort();
}
/// @todo Implement tests for subnetSelect See tests in dhcp6_srv_unittest.cc:
/// selectSubnetAddr, selectSubnetIface, selectSubnetRelayLinkaddr,
/// selectSubnetRelayInterfaceId. Note that the concept of interface-id is not

View File

@@ -456,8 +456,6 @@ Dhcpv4SrvTest::TearDown() {
<< " class after the test. Exception has been caught: "
<< ex.what();
}
setMultiThreading(false);
}
void

View File

@@ -170,6 +170,11 @@ public:
}
}
/// @brief fake receive packet from server
///
/// The client uses this packet as a reply from the server.
///
/// @return The received packet.
Pkt4Ptr receiveOneMsg() {
if (isc::util::MultiThreadingMgr::instance().getMode()) {
std::lock_guard<std::mutex> lk(mutex_);
@@ -179,6 +184,12 @@ public:
}
}
/// @brief fake receive packet from server
///
/// The client uses this packet as a reply from the server.
/// This function should be called in a thread safe context.
///
/// @return The received packet.
Pkt4Ptr receiveOneMsgInternal() {
// Return empty pointer if server hasn't responded.
if (fake_sent_.empty()) {
@@ -216,7 +227,7 @@ public:
processRelease(release, context);
}
/// @brief Runs processing DHCPDECLINE
/// @brief Runs processing DHCPDECLINE.
///
/// @param decline message received from client
void processDecline(Pkt4Ptr& decline) {
@@ -227,7 +238,7 @@ public:
/// @brief Dummy server identifier option used by various tests.
OptionPtr server_id_;
/// @brief packets we pretend to receive
/// @brief packets we pretend to receive.
///
/// Instead of setting up sockets on interfaces that change between OSes, it
/// is much easier to fake packet reception. This is a list of packets that
@@ -235,7 +246,7 @@ public:
/// using fakeReceive() and NakedDhcpv4Srv::receivePacket() methods.
std::list<Pkt4Ptr> fake_received_;
/// @brief packets we pretend to send
/// @brief packets we pretend to send.
std::list<Pkt4Ptr> fake_sent_;
using Dhcpv4Srv::adjustIfaceData;
@@ -556,9 +567,19 @@ public:
ExpectedResult expected_result);
/// @brief Checks if received relay agent info option is echoed back to the
/// client
/// client.
void relayAgentInfoEcho();
/// @brief Checks if received bad relay agent info option is not echoed back
/// to the client.
void badRelayAgentInfoEcho();
/// @brief Checks if client port can be overridden in packets being sent.
void portsClientPort();
/// @brief Checks if server port can be overridden in packets being sent.
void portsServerPort();
/// @brief This function cleans up after the test.
virtual void TearDown();
@@ -567,25 +588,25 @@ public:
multi_threading_ = enabled;
}
/// @brief A subnet used in most tests
/// @brief A subnet used in most tests.
Subnet4Ptr subnet_;
/// @brief A pool used in most tests
/// @brief A pool used in most tests.
Pool4Ptr pool_;
/// @brief A client-id used in most tests
/// @brief A client-id used in most tests.
ClientIdPtr client_id_;
/// @brief Return code
int rcode_;
/// @brief Comment
/// @brief Comment received from configuration.
isc::data::ConstElementPtr comment_;
/// @brief Server object under test.
NakedDhcpv4Srv srv_;
/// @brief The multi-threading flag
/// @brief The multi-threading flag.
bool multi_threading_;
};

View File

@@ -21,6 +21,7 @@
#include <dhcpsrv/pool.h>
#include <dhcp6/tests/dhcp6_client.h>
#include <util/buffer.h>
#include <util/multi_threading_mgr.h>
#include <boost/foreach.hpp>
#include <boost/pointer_cast.hpp>
#include <algorithm>
@@ -31,6 +32,7 @@
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::util;
namespace {
@@ -618,7 +620,6 @@ Dhcp6Client::doRelease() {
}
}
void
Dhcp6Client::generateIAFromLeases(const Pkt6Ptr& query,
const bool include_address) {
@@ -778,8 +779,7 @@ Dhcp6Client::hasLeaseForAddressRange(const asiolink::IOAddress& first,
}
bool
Dhcp6Client::
hasLeaseWithZeroLifetimeForAddress(const asiolink::IOAddress& address) const {
Dhcp6Client::hasLeaseWithZeroLifetimeForAddress(const asiolink::IOAddress& address) const {
std::vector<Lease6> leases = getLeasesByAddress(address);
BOOST_FOREACH(const Lease6& lease, leases) {
if ((lease.preferred_lft_ == 0) && (lease.valid_lft_ == 0)) {
@@ -919,13 +919,7 @@ Dhcp6Client::modifyDUID() {
Pkt6Ptr
Dhcp6Client::receiveOneMsg() {
// Return empty pointer if server hasn't responded.
if (srv_->fake_sent_.empty()) {
return (Pkt6Ptr());
}
Pkt6Ptr msg = srv_->fake_sent_.front();
srv_->fake_sent_.pop_front();
return (msg);
return (srv_->receiveOneMsg());
}
void
@@ -991,6 +985,9 @@ Dhcp6Client::sendMsg(const Pkt6Ptr& msg) {
} catch (...) {
// Suppress errors, as the DHCPv6 server does.
}
// Make sure the server processed all packets in MT.
isc::util::MultiThreadingMgr::instance().getThreadPool().wait();
}
void

View File

@@ -6,13 +6,14 @@
#include <config.h>
#include <gtest/gtest.h>
#include <cc/command_interpreter.h>
#include <dhcp/option6_status_code.h>
#include <dhcp6/tests/dhcp6_test_utils.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp/tests/pkt_captures.h>
#include <log/logger_support.h>
#include <dhcpsrv/cfg_multi_threading.h>
#include <util/pointer_util.h>
#include <cc/command_interpreter.h>
#include <stats/stats_mgr.h>
#include <cstdio>
#include <sstream>
@@ -22,6 +23,7 @@ using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::asiolink;
using namespace isc::stats;
using namespace isc::util;
namespace isc {
namespace dhcp {
@@ -53,16 +55,14 @@ BaseServerTest::~BaseServerTest() {
}
Dhcpv6SrvTest::Dhcpv6SrvTest()
: NakedDhcpv6SrvTest(), srv_(0) {
subnet_ = isc::dhcp::Subnet6Ptr
(new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
48, 1000, 2000, 3000, 4000));
: NakedDhcpv6SrvTest(), srv_(0), multi_threading_(false) {
subnet_ = isc::dhcp::Subnet6Ptr(new isc::dhcp::Subnet6(isc::asiolink::IOAddress("2001:db8:1::"),
48, 1000, 2000, 3000, 4000));
subnet_->setIface("eth0");
pool_ = isc::dhcp::Pool6Ptr
(new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
isc::asiolink::IOAddress("2001:db8:1:1::"),
64));
pool_ = isc::dhcp::Pool6Ptr(new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_NA,
isc::asiolink::IOAddress("2001:db8:1:1::"),
64));
subnet_->addPool(pool_);
isc::dhcp::CfgMgr::instance().clear();
@@ -71,10 +71,9 @@ Dhcpv6SrvTest::Dhcpv6SrvTest()
isc::dhcp::CfgMgr::instance().commit();
// configure PD pool
pd_pool_ = isc::dhcp::Pool6Ptr
(new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
isc::asiolink::IOAddress("2001:db8:1:2::"),
64, 80));
pd_pool_ = isc::dhcp::Pool6Ptr(new isc::dhcp::Pool6(isc::dhcp::Lease::TYPE_PD,
isc::asiolink::IOAddress("2001:db8:1:2::"),
64, 80));
subnet_->addPool(pd_pool_);
}
@@ -809,6 +808,7 @@ Dhcpv6SrvTest::configure(const std::string& config) {
void
Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
MultiThreadingCriticalSection cs;
ConstElementPtr json;
try {
json = parseJSON(config);
@@ -822,6 +822,9 @@ Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
// Disable the re-detect flag
disableIfacesReDetect(json);
// Set up multi-threading
configureMultiThreading(multi_threading_, json);
// Configure the server and make sure the config is accepted
EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
ASSERT_TRUE(status);
@@ -830,11 +833,18 @@ Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
ASSERT_EQ(0, rcode) << "configuration failed, test is broken: "
<< comment->str();
try {
CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
} catch (const std::exception& ex) {
ADD_FAILURE() << "Error applying multi threading settings: "
<< ex.what();
}
CfgMgr::instance().commit();
}
NakedDhcpv6SrvTest::NakedDhcpv6SrvTest()
: rcode_(-1) {
: rcode_(-1) {
// it's ok if that fails. There should not be such a file anyway
static_cast<void>(remove(DUID_FILE));

View File

@@ -29,6 +29,7 @@
#include <dhcp6/dhcp6_srv.h>
#include <dhcp6/parser_context.h>
#include <hooks/hooks_manager.h>
#include <util/multi_threading_mgr.h>
#include <list>
@@ -157,6 +158,9 @@ public:
return (pkt);
}
// Make sure the server processed all packets in MT.
isc::util::MultiThreadingMgr::instance().getThreadPool().wait();
// If not, just trigger shutdown and
// return immediately
shutdown();
@@ -169,7 +173,42 @@ public:
/// it in fake_send_ list where test can later inspect
/// server's response.
virtual void sendPacket(const isc::dhcp::Pkt6Ptr& pkt) {
fake_sent_.push_back(pkt);
if (isc::util::MultiThreadingMgr::instance().getMode()) {
std::lock_guard<std::mutex> lk(mutex_);
fake_sent_.push_back(pkt);
} else {
fake_sent_.push_back(pkt);
}
}
/// @brief fake receive packet from server
///
/// The client uses this packet as a reply from the server.
///
/// @return The received packet.
Pkt6Ptr receiveOneMsg() {
if (isc::util::MultiThreadingMgr::instance().getMode()) {
std::lock_guard<std::mutex> lk(mutex_);
return (receiveOneMsgInternal());
} else {
return (receiveOneMsgInternal());
}
}
/// @brief fake receive packet from server
///
/// The client uses this packet as a reply from the server.
/// This function should be called in a thread safe context.
///
/// @return The received packet.
Pkt6Ptr receiveOneMsgInternal() {
// Return empty pointer if server hasn't responded.
if (fake_sent_.empty()) {
return (Pkt6Ptr());
}
Pkt6Ptr msg = fake_sent_.front();
fake_sent_.pop_front();
return (msg);
}
/// @brief adds a packet to fake receive queue
@@ -276,7 +315,7 @@ public:
using Dhcpv6Srv::server_port_;
using Dhcpv6Srv::client_port_;
/// @brief packets we pretend to receive
/// @brief packets we pretend to receive.
///
/// Instead of setting up sockets on interfaces that change between
/// OSes, it is much easier to fake packet reception. This is a list
@@ -285,7 +324,11 @@ public:
/// NakedDhcpv6Srv::receivePacket() methods.
std::list<isc::dhcp::Pkt6Ptr> fake_received_;
/// @brief packets we pretend to send.
std::list<isc::dhcp::Pkt6Ptr> fake_sent_;
/// @brief Mutex to protect the packet buffers.
std::mutex mutex_;
};
/// @brief Test fixture for any tests requiring blank/empty configuration
@@ -497,6 +540,17 @@ public:
NO_IA // Client will not send IA_NA at all
};
class Dhcpv6SrvMTTestGuard {
public:
Dhcpv6SrvMTTestGuard(Dhcpv6SrvTest& test, bool mt_enabled) : test_(test) {
test_.setMultiThreading(mt_enabled);
}
~Dhcpv6SrvMTTestGuard() {
test_.setMultiThreading(false);
}
Dhcpv6SrvTest& test_;
};
/// @brief Constructor that initializes a simple default configuration
///
/// Sets up a single subnet6 with one pool for addresses and second
@@ -587,9 +641,10 @@ public:
// Checks if the lease sent to client is present in the database
// and is valid when checked against the configured subnet
isc::dhcp::Lease6Ptr checkLease
(const isc::dhcp::DuidPtr& duid, const isc::dhcp::OptionPtr& ia_na,
boost::shared_ptr<isc::dhcp::Option6IAAddr> addr);
isc::dhcp::Lease6Ptr
checkLease(const isc::dhcp::DuidPtr& duid,
const isc::dhcp::OptionPtr& ia_na,
boost::shared_ptr<isc::dhcp::Option6IAAddr> addr);
/// @brief Check if the specified lease is present in the data base.
///
@@ -606,9 +661,10 @@ public:
/// @param ia_pd IA_PD option that contains the IAPRefix option
/// @param prefix pointer to the IAPREFIX option
/// @return corresponding IPv6 lease (if found)
isc::dhcp::Lease6Ptr checkPdLease
(const isc::dhcp::DuidPtr& duid, const isc::dhcp::OptionPtr& ia_pd,
boost::shared_ptr<isc::dhcp::Option6IAPrefix> prefix);
isc::dhcp::Lease6Ptr
checkPdLease(const isc::dhcp::DuidPtr& duid,
const isc::dhcp::OptionPtr& ia_pd,
boost::shared_ptr<isc::dhcp::Option6IAPrefix> prefix);
/// @brief Creates a message with specified IA
///
@@ -761,18 +817,25 @@ public:
/// @param stat_name this statistic is expected to be set to 1
void testReceiveStats(uint8_t pkt_type, const std::string& stat_name);
/// @brief Set multi-threading mode.
void setMultiThreading(bool enabled) {
multi_threading_ = enabled;
}
/// A subnet used in most tests
/// A subnet used in most tests.
isc::dhcp::Subnet6Ptr subnet_;
/// A normal, non-temporary pool used in most tests
/// A normal, non-temporary pool used in most tests.
isc::dhcp::Pool6Ptr pool_;
/// A prefix pool used in most tests
/// A prefix pool used in most tests.
isc::dhcp::Pool6Ptr pd_pool_;
/// @brief Server object under test.
NakedDhcpv6Srv srv_;
/// @brief The multi-threading flag.
bool multi_threading_;
};
/// @brief Patch the server config to add interface-config/re-detect=false
@@ -787,13 +850,35 @@ disableIfacesReDetect(isc::data::ConstElementPtr json) {
}
}
/// @brief Patch the server config to add multi-threading/enable-multi-threading
/// @param json the server config
inline void
configureMultiThreading(bool enabled, isc::data::ConstElementPtr json) {
isc::data::ConstElementPtr multi_threading = json->get("multi-threading");
if (!multi_threading) {
isc::data::ElementPtr mutable_cfg =
boost::const_pointer_cast<isc::data::Element>(json);
multi_threading = isc::data::Element::createMap();
mutable_cfg->set("multi-threading", multi_threading);
}
isc::data::ElementPtr mutable_cfg =
boost::const_pointer_cast<isc::data::Element>(multi_threading);
if (enabled) {
mutable_cfg->set("enable-multi-threading", isc::data::Element::create(true));
mutable_cfg->set("thread-pool-size", isc::data::Element::create(4));
mutable_cfg->set("packet-queue-size", isc::data::Element::create(4));
} else {
mutable_cfg->set("enable-multi-threading", isc::data::Element::create(false));
}
}
/// @brief Runs parser in JSON mode, useful for parser testing
///
/// @param in string to be parsed
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ElementPtr
parseJSON(const std::string& in)
{
parseJSON(const std::string& in) {
isc::dhcp::Parser6Context ctx;
return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_JSON));
}
@@ -807,8 +892,7 @@ parseJSON(const std::string& in)
/// @param verbose display the exception message when it fails
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ElementPtr
parseDHCP6(const std::string& in, bool verbose = false)
{
parseDHCP6(const std::string& in, bool verbose = false) {
try {
isc::dhcp::Parser6Context ctx;
isc::data::ElementPtr json;
@@ -832,8 +916,7 @@ parseDHCP6(const std::string& in, bool verbose = false)
/// @param verbose display the exception message when it fails
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ElementPtr
parseOPTION_DEFS(const std::string& in, bool verbose = false)
{
parseOPTION_DEFS(const std::string& in, bool verbose = false) {
try {
isc::dhcp::Parser6Context ctx;
return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEFS));
@@ -846,8 +929,8 @@ parseOPTION_DEFS(const std::string& in, bool verbose = false)
}
}
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace
} // end of isc::dhcp::test namespace
} // end of isc::dhcp namespace
} // end of isc namespace
#endif // DHCP6_TEST_UTILS_H

View File

@@ -242,17 +242,69 @@ public:
isc::stats::StatsMgr::instance().removeAll();
}
/// @brief Check that server processes correctly a prefix hint sent by the
/// client. This test checks that the server doesn't allocate colliding
/// prefixes as a result of receiving hints from two clients which set the
/// non-significant bytes of the prefix in their hints. The server should
/// zero the non-significant bytes of the hint and allocate the prefix of
/// the correct (configured) length.
void directClientPrefixHint();
/// @brief This test verifies that the same options can be specified on the
/// global level, subnet level and pool level. The options associated with
/// pools are used when the lease is handed out from these pools.
void optionsInheritance();
/// @brief This test verifies that it is possible to specify an excluded
/// prefix (RFC 6603) and send it back to the client requesting prefix
/// delegation.
void directClientExcludedPrefix();
/// @brief Check that when the client includes the Rapid Commit option in
/// its Solicit, the server responds with Reply and commits the lease.
void rapidCommitEnable();
/// @brief Check that the server responds with Advertise if the client
/// hasn't included the Rapid Commit option in the Solicit.
void rapidCommitNoOption();
/// @brief Check that when the Rapid Commit support is disabled for the
/// subnet the server replies with an Advertise and ignores the Rapid Commit
/// option sent by the client.
void rapidCommitDisable();
/// @brief This test verifies that regular Solicit/Adv/Request/Reply
/// exchange will result in appropriately set statistics.
void sarrStats();
/// @brief This test verifies that pkt6-receive-drop is increased properly
/// when the client's packet is rejected due to mismatched server-id value.
void pkt6ReceiveDropStat1();
/// @brief This test verifies that pkt6-receive-drop is increased properly
/// when the client's packet is rejected due to being unicast communication.
void pkt6ReceiveDropStat2();
/// @brief This test verifies that pkt6-receive-drop is increased properly
/// when the client's packet is rejected due to having too many client-id
/// options (exactly one is expected).
void pkt6ReceiveDropStat3();
/// @brief This test verifies that in pool reservations are ignored when the
/// reservations-out-of-pool flag is set to true.
void reservationModeOutOfPool();
/// @brief This test verifies that the in-pool reservation can be assigned
/// to a client not owning this reservation when the
/// reservations-out-of-pool flag is set to true.
void reservationIgnoredInOutOfPoolMode();
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig iface_mgr_test_config_;
};
/// Check that server processes correctly a prefix hint sent by the client.
/// This test checks that the server doesn't allocate colliding prefixes
/// as a result of receiving hints from two clients which set the
/// non-significant bytes of the prefix in their hints. The server should zero
/// the non-significant bytes of the hint and allocate the prefix of the
/// correct (configured) length.
TEST_F(SARRTest, directClientPrefixHint) {
void
SARRTest::directClientPrefixHint() {
Dhcp6Client client;
// Configure client to request IA_PD.
client.requestPrefix();
@@ -306,10 +358,18 @@ TEST_F(SARRTest, directClientPrefixHint) {
ASSERT_TRUE(lease_server);
}
// This test verifies that the same options can be specified on the global
// level, subnet level and pool level. The options associated with pools
// are used when the lease is handed out from these pools.
TEST_F(SARRTest, optionsInheritance) {
TEST_F(SARRTest, directClientPrefixHint) {
Dhcpv6SrvMTTestGuard guard(*this, false);
directClientPrefixHint();
}
TEST_F(SARRTest, directClientPrefixHintMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
directClientPrefixHint();
}
void
SARRTest::optionsInheritance() {
Dhcp6Client client;
// Request a single address and single prefix.
ASSERT_NO_THROW(client.requestPrefix(0xabac, 64, IOAddress("2001:db8:4::")));
@@ -367,9 +427,18 @@ TEST_F(SARRTest, optionsInheritance) {
ASSERT_TRUE(client.hasOptionWithAddress(D6O_SNTP_SERVERS, "3000:2::2"));
}
/// This test verifies that it is possible to specify an excluded prefix
/// (RFC 6603) and send it back to the client requesting prefix delegation.
TEST_F(SARRTest, directClientExcludedPrefix) {
TEST_F(SARRTest, optionsInheritance) {
Dhcpv6SrvMTTestGuard guard(*this, false);
optionsInheritance();
}
TEST_F(SARRTest, optionsInheritanceMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
optionsInheritance();
}
void
SARRTest::directClientExcludedPrefix() {
Dhcp6Client client;
// Configure client to request IA_PD.
client.requestPrefix();
@@ -408,9 +477,18 @@ TEST_F(SARRTest, directClientExcludedPrefix) {
EXPECT_EQ(120, static_cast<unsigned>(pd_exclude->getExcludedPrefixLength()));
}
// Check that when the client includes the Rapid Commit option in its
// Solicit, the server responds with Reply and commits the lease.
TEST_F(SARRTest, rapidCommitEnable) {
TEST_F(SARRTest, directClientExcludedPrefix) {
Dhcpv6SrvMTTestGuard guard(*this, false);
directClientExcludedPrefix();
}
TEST_F(SARRTest, directClientExcludedPrefixMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
directClientExcludedPrefix();
}
void
SARRTest::rapidCommitEnable() {
Dhcp6Client client;
// Configure client to request IA_NA
client.requestAddress();
@@ -446,9 +524,18 @@ TEST_F(SARRTest, rapidCommitEnable) {
EXPECT_EQ(1, CfgMgr::instance().getD2ClientMgr().getQueueSize());
}
// Check that the server responds with Advertise if the client hasn't
// included the Rapid Commit option in the Solicit.
TEST_F(SARRTest, rapidCommitNoOption) {
TEST_F(SARRTest, rapidCommitEnable) {
Dhcpv6SrvMTTestGuard guard(*this, false);
rapidCommitEnable();
}
TEST_F(SARRTest, rapidCommitEnableMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
rapidCommitEnable();
}
void
SARRTest::rapidCommitNoOption() {
Dhcp6Client client;
// Configure client to request IA_NA
client.requestAddress();
@@ -476,10 +563,18 @@ TEST_F(SARRTest, rapidCommitNoOption) {
EXPECT_EQ(0, CfgMgr::instance().getD2ClientMgr().getQueueSize());
}
// Check that when the Rapid Commit support is disabled for the subnet
// the server replies with an Advertise and ignores the Rapid Commit
// option sent by the client.
TEST_F(SARRTest, rapidCommitDisable) {
TEST_F(SARRTest, rapidCommitNoOption) {
Dhcpv6SrvMTTestGuard guard(*this, false);
rapidCommitNoOption();
}
TEST_F(SARRTest, rapidCommitNoOptionMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
rapidCommitNoOption();
}
void
SARRTest::rapidCommitDisable() {
Dhcp6Client client;
// The subnet assigned to eth1 has Rapid Commit disabled.
client.setInterface("eth1");
@@ -511,9 +606,18 @@ TEST_F(SARRTest, rapidCommitDisable) {
EXPECT_EQ(0, CfgMgr::instance().getD2ClientMgr().getQueueSize());
}
// This test verifies that regular Solicit/Adv/Request/Reply exchange will
// result in appropriately set statistics.
TEST_F(SARRTest, sarrStats) {
TEST_F(SARRTest, rapidCommitDisable) {
Dhcpv6SrvMTTestGuard guard(*this, false);
rapidCommitDisable();
}
TEST_F(SARRTest, rapidCommitDisableMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
rapidCommitDisable();
}
void
SARRTest::sarrStats() {
// Let's use one of the existing configurations and tell the client to
// ask for an address.
@@ -577,9 +681,18 @@ TEST_F(SARRTest, sarrStats) {
EXPECT_EQ(2, pkt6_sent->getInteger().first);
}
// This test verifies that pkt6-receive-drop is increased properly when the
// client's packet is rejected due to mismatched server-id value.
TEST_F(SARRTest, pkt6ReceiveDropStat1) {
TEST_F(SARRTest, sarrStats) {
Dhcpv6SrvMTTestGuard guard(*this, false);
sarrStats();
}
TEST_F(SARRTest, sarrStatsMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
sarrStats();
}
void
SARRTest::pkt6ReceiveDropStat1() {
// Dummy server-id (0xff repeated 10 times)
std::vector<uint8_t> data(10, 0xff);
@@ -606,9 +719,18 @@ TEST_F(SARRTest, pkt6ReceiveDropStat1) {
EXPECT_EQ(1, pkt6_recv_drop->getInteger().first);
}
// This test verifies that pkt6-receive-drop is increased properly when the
// client's packet is rejected due to being unicast communication.
TEST_F(SARRTest, pkt6ReceiveDropStat2) {
TEST_F(SARRTest, pkt6ReceiveDropStat1) {
Dhcpv6SrvMTTestGuard guard(*this, false);
pkt6ReceiveDropStat1();
}
TEST_F(SARRTest, pkt6ReceiveDropStat1MultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
pkt6ReceiveDropStat1();
}
void
SARRTest::pkt6ReceiveDropStat2() {
// Let's use one of the existing configurations and tell the client to
// ask for an address.
@@ -630,10 +752,18 @@ TEST_F(SARRTest, pkt6ReceiveDropStat2) {
EXPECT_EQ(1, pkt6_recv_drop->getInteger().first);
}
// This test verifies that pkt6-receive-drop is increased properly when the
// client's packet is rejected due to having too many client-id options
// (exactly one is expected).
TEST_F(SARRTest, pkt6ReceiveDropStat3) {
TEST_F(SARRTest, pkt6ReceiveDropStat2) {
Dhcpv6SrvMTTestGuard guard(*this, false);
pkt6ReceiveDropStat2();
}
TEST_F(SARRTest, pkt6ReceiveDropStat2MultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
pkt6ReceiveDropStat2();
}
void
SARRTest::pkt6ReceiveDropStat3() {
// Let's use one of the existing configurations and tell the client to
// ask for an address.
@@ -658,9 +788,18 @@ TEST_F(SARRTest, pkt6ReceiveDropStat3) {
EXPECT_EQ(1, pkt6_recv_drop->getInteger().first);
}
// This test verifies that in pool reservations are ignored when the
// reservations-out-of-pool flag is set to true.
TEST_F(SARRTest, reservationModeOutOfPool) {
TEST_F(SARRTest, pkt6ReceiveDropStat3) {
Dhcpv6SrvMTTestGuard guard(*this, false);
pkt6ReceiveDropStat3();
}
TEST_F(SARRTest, pkt6ReceiveDropStat3MultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
pkt6ReceiveDropStat3();
}
void
SARRTest::reservationModeOutOfPool() {
// Create the first client for which we have a reservation out of the
// dynamic pool.
Dhcp6Client client;
@@ -694,10 +833,18 @@ TEST_F(SARRTest, reservationModeOutOfPool) {
ASSERT_EQ("2001:db8:1::3", lease.addr_.toText());
}
// This test verifies that the in-pool reservation can be assigned to a client
// not owning this reservation when the reservations-out-of-pool flag is set to
// true.
TEST_F(SARRTest, reservationIgnoredInOutOfPoolMode) {
TEST_F(SARRTest, reservationModeOutOfPool) {
Dhcpv6SrvMTTestGuard guard(*this, false);
reservationModeOutOfPool();
}
TEST_F(SARRTest, reservationModeOutOfPoolMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
reservationModeOutOfPool();
}
void
SARRTest::reservationIgnoredInOutOfPoolMode() {
// Create the first client for which we have a reservation out of the
// dynamic pool.
Dhcp6Client client;
@@ -716,4 +863,14 @@ TEST_F(SARRTest, reservationIgnoredInOutOfPoolMode) {
ASSERT_EQ("2001:db8:1::5", lease.addr_.toText());
}
TEST_F(SARRTest, reservationIgnoredInOutOfPoolMode) {
Dhcpv6SrvMTTestGuard guard(*this, false);
reservationIgnoredInOutOfPoolMode();
}
TEST_F(SARRTest, reservationIgnoredInOutOfPoolModeMultiThreading) {
Dhcpv6SrvMTTestGuard guard(*this, true);
reservationIgnoredInOutOfPoolMode();
}
} // end of anonymous namespace