mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 13:07:50 +00:00
[4254] perfdhcp sends DHCPv4 renews when -f option is specified.
This commit is contained in:
parent
9328124027
commit
c6a38e4e7c
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -315,6 +315,14 @@ TestControl::checkExitConditions() const {
|
||||
return (false);
|
||||
}
|
||||
|
||||
Pkt4Ptr
|
||||
TestControl::createRequestFromAck(const dhcp::Pkt4Ptr& ack) {
|
||||
Pkt4Ptr msg(new Pkt4(DHCPREQUEST, generateTransid()));
|
||||
msg->setCiaddr(ack->getYiaddr());
|
||||
msg->setHWAddr(ack->getHWAddr());
|
||||
return (msg);
|
||||
}
|
||||
|
||||
Pkt6Ptr
|
||||
TestControl::createMessageFromReply(const uint16_t msg_type,
|
||||
const dhcp::Pkt6Ptr& reply) {
|
||||
@ -663,6 +671,9 @@ TestControl::initializeStatsMgr() {
|
||||
stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RA,
|
||||
options.getDropTime()[1]);
|
||||
}
|
||||
if (options.getRenewRate() != 0) {
|
||||
stats_mgr4_->addExchangeStats(StatsMgr4::XCHG_RN);
|
||||
}
|
||||
|
||||
} else if (options.getIpVersion() == 6) {
|
||||
stats_mgr6_.reset();
|
||||
@ -831,6 +842,17 @@ TestControl::sendPackets(const TestControlSocket& socket,
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
TestControl::sendMultipleRequests(const TestControlSocket& socket,
|
||||
const uint64_t msg_num) {
|
||||
for (uint64_t i = 0; i < msg_num; ++i) {
|
||||
if (!sendRequestFromAck(socket)) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
return (msg_num);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
TestControl::sendMultipleMessages6(const TestControlSocket& socket,
|
||||
const uint32_t msg_type,
|
||||
@ -1072,7 +1094,28 @@ TestControl::processReceivedPacket4(const TestControlSocket& socket,
|
||||
}
|
||||
}
|
||||
} else if (pkt4->getType() == DHCPACK) {
|
||||
stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4);
|
||||
// If received message is DHCPACK, we have to check if this is a response
|
||||
// to 4-way exchange. We'll match this packet with a DHCPREQUESTs sent
|
||||
// as part of the 4-way exchages.
|
||||
if (stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4)) {
|
||||
// The DHCPACK belongs to DHCPREQUEST-DHCPACK exchange type. So, we
|
||||
// may need to keep this DHCPACK in the storage if renews. Note that,
|
||||
// DHCPACK messages hold the information about leases assigned.
|
||||
// We use this information to renew.
|
||||
if (stats_mgr4_->hasExchangeStats(StatsMgr4::XCHG_RN)) {
|
||||
// Renew messages are sent, because StatsMgr has the
|
||||
// specific exchange type specified. Let's append the DHCPACK.
|
||||
// message to a storage
|
||||
ack_storage_.append(pkt4);
|
||||
}
|
||||
// The DHCPACK message is not a server's response to the DHCPREQUEST
|
||||
// message sent within the 4-way exchange. It may be a response to a
|
||||
// renewal. In this case we first check if StatsMgr has exchange type
|
||||
// for renew specified, and if it has, if there is a corresponding
|
||||
// renew message for the received DHCPACK.
|
||||
} else if (stats_mgr4_->hasExchangeStats(StatsMgr4::XCHG_RN)) {
|
||||
stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RN, pkt4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1364,13 +1407,18 @@ TestControl::run() {
|
||||
|
||||
// If -f<renew-rate> option was specified we have to check how many
|
||||
// Renew packets should be sent to catch up with a desired rate.
|
||||
if ((options.getIpVersion() == 6) && (options.getRenewRate() != 0)) {
|
||||
if (options.getRenewRate() != 0) {
|
||||
uint64_t renew_packets_due =
|
||||
renew_rate_control_.getOutboundMessageCount();
|
||||
checkLateMessages(renew_rate_control_);
|
||||
// Send Renew messages.
|
||||
|
||||
// Send multiple renews to satify the desired rate.
|
||||
if (options.getIpVersion() == 4) {
|
||||
sendMultipleRequests(socket, renew_packets_due);
|
||||
} else {
|
||||
sendMultipleMessages6(socket, DHCPV6_RENEW, renew_packets_due);
|
||||
}
|
||||
}
|
||||
|
||||
// If -F<release-rate> option was specified we have to check how many
|
||||
// Release messages should be sent to catch up with a desired rate.
|
||||
@ -1568,6 +1616,32 @@ TestControl::sendDiscover4(const TestControlSocket& socket,
|
||||
saveFirstPacket(pkt4);
|
||||
}
|
||||
|
||||
bool
|
||||
TestControl::sendRequestFromAck(const TestControlSocket& socket) {
|
||||
// Update timestamp of last sent renewal.
|
||||
renew_rate_control_.updateSendTime();
|
||||
|
||||
// Get one of the recorded DHCPACK messages.
|
||||
Pkt4Ptr ack = ack_storage_.getRandom();
|
||||
if (!ack) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create message of the specified type.
|
||||
Pkt4Ptr msg = createRequestFromAck(ack);
|
||||
setDefaults4(socket, msg);
|
||||
msg->pack();
|
||||
// And send it.
|
||||
IfaceMgr::instance().send(msg);
|
||||
if (!stats_mgr4_) {
|
||||
isc_throw(Unexpected, "Statistics Manager for DHCPv4 "
|
||||
"hasn't been initialized");
|
||||
}
|
||||
stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RN, msg);
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TestControl::sendMessageFromReply(const uint16_t msg_type,
|
||||
const TestControlSocket& socket) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -306,13 +306,21 @@ protected:
|
||||
/// has been reached.
|
||||
void cleanCachedPackets();
|
||||
|
||||
/// \brief Creates DHCPREQUEST from a DHCPACK message.
|
||||
///
|
||||
/// \param ack An instance of the DHCPACK message to be used to
|
||||
/// create a new message.
|
||||
///
|
||||
/// \return Pointer to the created message.
|
||||
dhcp::Pkt4Ptr createRequestFromAck(const dhcp::Pkt4Ptr& ack);
|
||||
|
||||
/// \brief Creates DHCPv6 message from the Reply packet.
|
||||
///
|
||||
/// This function creates DHCPv6 Renew or Release message using the
|
||||
/// data from the Reply message by copying options from the Reply
|
||||
/// message.
|
||||
///
|
||||
/// \param msg_type A type of the message to be createad.
|
||||
/// \param msg_type A type of the message to be created.
|
||||
/// \param reply An instance of the Reply packet which contents should
|
||||
/// be used to create an instance of the new message.
|
||||
///
|
||||
@ -726,6 +734,15 @@ protected:
|
||||
const uint64_t packets_num,
|
||||
const bool preload = false);
|
||||
|
||||
/// \brief Send number of DHCPREQUEST (renew) messages to a server.
|
||||
///
|
||||
/// \param socket An object representing socket to be used to send packets.
|
||||
/// \param msg_num A number of messages to be sent.
|
||||
///
|
||||
/// \return A number of messages actually sent.
|
||||
uint64_t sendMultipleRequests(const TestControlSocket& socket,
|
||||
const uint64_t msg_num);
|
||||
|
||||
/// \brief Send number of DHCPv6 Renew or Release messages to the server.
|
||||
///
|
||||
/// \param socket An object representing socket to be used to send packets.
|
||||
@ -738,6 +755,14 @@ protected:
|
||||
const uint32_t msg_type,
|
||||
const uint64_t msg_num);
|
||||
|
||||
/// \brief Send DHCPv4 renew (DHCPREQUEST) using specified socket.
|
||||
///
|
||||
/// \param socket An object encapsulating socket to be used to send
|
||||
/// a packet.
|
||||
///
|
||||
/// \return true if the message has been sent, false otherwise.
|
||||
bool sendRequestFromAck(const TestControlSocket& socket);
|
||||
|
||||
/// \brief Send DHCPv6 Renew or Release message using specified socket.
|
||||
///
|
||||
/// This method will select an existing lease from the Reply packet cache
|
||||
@ -1077,6 +1102,7 @@ protected:
|
||||
StatsMgr4Ptr stats_mgr4_; ///< Statistics Manager 4.
|
||||
StatsMgr6Ptr stats_mgr6_; ///< Statistics Manager 6.
|
||||
|
||||
PacketStorage<dhcp::Pkt4> ack_storage_; ///< A storage for DHCPACK messages.
|
||||
PacketStorage<dhcp::Pkt6> reply_storage_; ///< A storage for reply messages.
|
||||
|
||||
NumberGeneratorPtr transid_gen_; ///< Transaction id generator.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -95,6 +95,7 @@ public:
|
||||
|
||||
using TestControl::checkExitConditions;
|
||||
using TestControl::createMessageFromReply;
|
||||
using TestControl::createRequestFromAck;
|
||||
using TestControl::factoryElapsedTime6;
|
||||
using TestControl::factoryGeneric;
|
||||
using TestControl::factoryIana6;
|
||||
@ -114,6 +115,7 @@ public:
|
||||
using TestControl::reset;
|
||||
using TestControl::sendDiscover4;
|
||||
using TestControl::sendPackets;
|
||||
using TestControl::sendMultipleRequests;
|
||||
using TestControl::sendMultipleMessages6;
|
||||
using TestControl::sendRequest6;
|
||||
using TestControl::sendSolicit6;
|
||||
@ -650,7 +652,134 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test that the DHCPv4 Release or Renew message is created
|
||||
/// \brief Test sending DHCPv4 renews.
|
||||
///
|
||||
/// This function simulates acquiring 10 leases from the server. Returned
|
||||
/// DHCPACK messages are cached and used to send renew messages.
|
||||
/// The maxmimal number of messages which can be sent is equal to the
|
||||
/// number of leases acquired (10). This function also checks that an
|
||||
/// attempt to send more renew messages than the number of leases acquired
|
||||
/// will fail.
|
||||
void testSendRenew4() {
|
||||
std::string loopback_iface(getLocalLoopback());
|
||||
if (loopback_iface.empty()) {
|
||||
std::cout << "Skipping the test because loopback interface could"
|
||||
" not be detected" << std::endl;
|
||||
return;
|
||||
}
|
||||
// Build a command line. Depending on the message type, we will use
|
||||
// -f<renew-rate> or -F<release-rate> parameter.
|
||||
std::ostringstream s;
|
||||
s << "perfdhcp -4 -l " << loopback_iface << " -r 10 -f";
|
||||
s << " 10 -R 10 -L 10067 -n 10 127.0.0.1";
|
||||
ASSERT_NO_THROW(processCmdLine(s.str()));
|
||||
// Create a test controller class.
|
||||
NakedTestControl tc;
|
||||
tc.initializeStatsMgr();
|
||||
// Set the transaction id generator to sequential to control to
|
||||
// guarantee that transaction ids are predictable.
|
||||
boost::shared_ptr<NakedTestControl::IncrementalGenerator>
|
||||
generator(new NakedTestControl::IncrementalGenerator());
|
||||
tc.setTransidGenerator(generator);
|
||||
// Socket has to be created so as we can actually send packets.
|
||||
int sock_handle = 0;
|
||||
ASSERT_NO_THROW(sock_handle = tc.openSocket());
|
||||
TestControl::TestControlSocket sock(sock_handle);
|
||||
|
||||
// Send a number of DHCPDISCOVER messages. Each generated message will
|
||||
// be assigned a different transaction id, starting from 1 to 10.
|
||||
tc.sendPackets(sock, 10);
|
||||
|
||||
// Simulate DHCPOFFER responses from the server. Each DHCPOFFER is
|
||||
// assigned a transaction id from the range of 1 to 10, so as they
|
||||
// match the transaction ids from the DHCPDISCOVER messages.
|
||||
for (unsigned i = generator->getNext() - 10;
|
||||
i < generator->getNext(); ++i) {
|
||||
Pkt4Ptr offer(createOfferPkt4(i));
|
||||
// If DHCPOFFER is matched with the DHCPDISCOVER the call below
|
||||
// will trigger a corresponding DHCPREQUEST. They will be assigned
|
||||
// transaction ids from the range from 11 to 20 (the range of
|
||||
// 1 to 10 has been used by DHCPDISCOVER-DHCPOFFER).
|
||||
ASSERT_NO_THROW(tc.processReceivedPacket4(sock, offer));
|
||||
}
|
||||
|
||||
// Requests have been sent, so now let's simulate responses from the
|
||||
// server. Generate corresponding DHCPACK messages with the transaction
|
||||
// ids from the range from 11 to 20.
|
||||
for (unsigned i = generator->getNext() - 10;
|
||||
i < generator->getNext(); ++i) {
|
||||
Pkt4Ptr ack(createAckPkt4(i));
|
||||
// Each DHCPACK packet corresponds to the new lease acquired. Since
|
||||
// -f<renew-rate> option has been specified, received Reply
|
||||
// messages are held so as renew messages can be sent for
|
||||
// existing leases.
|
||||
ASSERT_NO_THROW(tc.processReceivedPacket4(sock, ack));
|
||||
}
|
||||
|
||||
uint64_t msg_num;
|
||||
// Try to send 5 messages. It should be successful because 10
|
||||
// DHCPREQUEST messages has been received. For each of them we
|
||||
// should be able to send renewal.
|
||||
ASSERT_NO_THROW(
|
||||
msg_num = tc.sendMultipleRequests(sock, 5)
|
||||
);
|
||||
// Make sure that we have sent 5 messages.
|
||||
EXPECT_EQ(5, msg_num);
|
||||
|
||||
// Try to do it again. We should still have 5 Reply packets for
|
||||
// which renews haven't been sent yet.
|
||||
ASSERT_NO_THROW(
|
||||
msg_num = tc.sendMultipleRequests(sock, 5)
|
||||
);
|
||||
EXPECT_EQ(5, msg_num);
|
||||
|
||||
// We used all the DHCPACK packets (we sent renew or release for each of
|
||||
// them already). Therefore, no further renew messages should be sent
|
||||
// before we acquire new leases.
|
||||
ASSERT_NO_THROW(
|
||||
msg_num = tc.sendMultipleRequests(sock, 5)
|
||||
);
|
||||
// Make sure that no message has been sent.
|
||||
EXPECT_EQ(0, msg_num);
|
||||
}
|
||||
|
||||
/// \brief Test that the DHCPREQUEST message is created correctly and
|
||||
/// comprises expected values.
|
||||
void testCreateRequest() {
|
||||
// This command line specifies that the Release/Renew messages should
|
||||
// be sent with the same rate as the Solicit messages.
|
||||
std::ostringstream s;
|
||||
s << "perfdhcp -4 -l lo -r 10 -f 10";
|
||||
s << " -R 10 -L 10067 -n 10 127.0.0.1";
|
||||
ASSERT_NO_THROW(processCmdLine(s.str()));
|
||||
// Create a test controller class.
|
||||
NakedTestControl tc;
|
||||
// Set the transaction id generator which will be used by the
|
||||
// createRenew or createRelease function to generate transaction id.
|
||||
boost::shared_ptr<NakedTestControl::IncrementalGenerator>
|
||||
generator(new NakedTestControl::IncrementalGenerator());
|
||||
tc.setTransidGenerator(generator);
|
||||
|
||||
Pkt4Ptr ack = createAckPkt4(1);
|
||||
|
||||
// Create DHCPREQUST from DHCPACK.
|
||||
Pkt4Ptr request;
|
||||
ASSERT_NO_THROW(request = tc.createRequestFromAck(ack));
|
||||
|
||||
// Make sure that the DHCPACK has been successfully created and that
|
||||
// it holds expected data.
|
||||
ASSERT_TRUE(request);
|
||||
EXPECT_EQ("127.0.0.1", request->getCiaddr().toText());
|
||||
|
||||
// HW address.
|
||||
HWAddrPtr hwaddr_ack = ack->getHWAddr();
|
||||
ASSERT_TRUE(hwaddr_ack);
|
||||
HWAddrPtr hwaddr_req = request->getHWAddr();
|
||||
ASSERT_TRUE(hwaddr_req);
|
||||
EXPECT_TRUE(hwaddr_ack->hwaddr_ == hwaddr_req->hwaddr_);
|
||||
}
|
||||
|
||||
/// \brief Test that the DHCPv6 Release or Renew message is created
|
||||
/// correctly and comprises expected options.
|
||||
///
|
||||
/// \param msg_type A type of the message to be tested: DHCPV6_RELEASE
|
||||
@ -822,20 +951,41 @@ public:
|
||||
CommandOptionsHelper::process(cmdline);
|
||||
}
|
||||
|
||||
/// \brief Create DHCPOFFER or DHCPACK packet.
|
||||
///
|
||||
/// \param pkt_type DHCPOFFER or DHCPACK.
|
||||
/// \param transid Transaction id.
|
||||
///
|
||||
/// \return Instance of the packet.
|
||||
Pkt4Ptr
|
||||
createResponsePkt4(const uint8_t pkt_type,
|
||||
const uint32_t transid) const {
|
||||
Pkt4Ptr pkt(new Pkt4(pkt_type, transid));
|
||||
OptionPtr opt_serverid = Option::factory(Option::V4,
|
||||
DHO_DHCP_SERVER_IDENTIFIER,
|
||||
OptionBuffer(4, 1));
|
||||
pkt->setYiaddr(asiolink::IOAddress("127.0.0.1"));
|
||||
pkt->addOption(opt_serverid);
|
||||
pkt->updateTimestamp();
|
||||
return (pkt);
|
||||
}
|
||||
|
||||
/// \brief Create DHCPv4 OFFER packet.
|
||||
///
|
||||
/// \param transid transaction id.
|
||||
/// \return instance of the packet.
|
||||
boost::shared_ptr<Pkt4>
|
||||
Pkt4Ptr
|
||||
createOfferPkt4(uint32_t transid) const {
|
||||
boost::shared_ptr<Pkt4> offer(new Pkt4(DHCPOFFER, transid));
|
||||
OptionPtr opt_serverid = Option::factory(Option::V4,
|
||||
DHO_DHCP_SERVER_IDENTIFIER,
|
||||
OptionBuffer(4, 1));
|
||||
offer->setYiaddr(asiolink::IOAddress("127.0.0.1"));
|
||||
offer->addOption(opt_serverid);
|
||||
offer->updateTimestamp();
|
||||
return (offer);
|
||||
return (createResponsePkt4(DHCPOFFER, transid));
|
||||
}
|
||||
|
||||
/// \brief Create DHCPACK packet.
|
||||
///
|
||||
/// \param transid transaction id.
|
||||
/// \return instance of the packet.
|
||||
Pkt4Ptr
|
||||
createAckPkt4(const uint32_t transid) const {
|
||||
return (createResponsePkt4(DHCPACK, transid));
|
||||
}
|
||||
|
||||
/// \brief Create DHCPv6 ADVERTISE packet.
|
||||
@ -1432,14 +1582,30 @@ TEST_F(TestControlTest, PacketTemplates) {
|
||||
EXPECT_THROW(tc.initPacketTemplates(), isc::BadValue);
|
||||
}
|
||||
|
||||
TEST_F(TestControlTest, processRenew) {
|
||||
// This test verifies that DHCPv4 renew (DHCPREQUEST) messages can be
|
||||
// sent for acquired leases.
|
||||
TEST_F(TestControlTest, processRenew4) {
|
||||
testSendRenew4();
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv6 Renew messages can be sent for acquired
|
||||
// leases.
|
||||
TEST_F(TestControlTest, processRenew6) {
|
||||
testSendRenewRelease(DHCPV6_RENEW);
|
||||
}
|
||||
|
||||
TEST_F(TestControlTest, processRelease) {
|
||||
// This test verifies that DHCPv6 Release messages can be sent for acquired
|
||||
// leases.
|
||||
TEST_F(TestControlTest, processRelease6) {
|
||||
testSendRenewRelease(DHCPV6_RELEASE);
|
||||
}
|
||||
|
||||
// This test verifies that DHCPREQUEST is created correctly from the
|
||||
// DHCPACK message.
|
||||
TEST_F(TestControlTest, createRequest) {
|
||||
testCreateRequest();
|
||||
}
|
||||
|
||||
// This test verifies that the DHCPV6 Renew message is created correctly
|
||||
// and that it comprises all required options.
|
||||
TEST_F(TestControlTest, createRenew) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user