From: Andrei Pavel Date: Mon, 15 Feb 2021 12:06:25 +0000 (+0200) Subject: [#1703] perfdhcp -x l: printLeases() X-Git-Tag: Kea-1.9.5~102 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=387ab7ea3db77ff69a5f6560442ecf342f410a47;p=thirdparty%2Fkea.git [#1703] perfdhcp -x l: printLeases() --- diff --git a/src/bin/perfdhcp/avalanche_scen.cc b/src/bin/perfdhcp/avalanche_scen.cc index 11a793f8a4..a4b187869a 100644 --- a/src/bin/perfdhcp/avalanche_scen.cc +++ b/src/bin/perfdhcp/avalanche_scen.cc @@ -171,6 +171,11 @@ AvalancheScen::run() { std::cout << "Interrupted" << std::endl; } + // Print any received leases. + if (options_.testDiags('l')) { + stats_mgr.printLeases(); + } + // Calculate total stats. int total_sent_pkts = total_resent_; // This holds sent + resent packets counts. int total_rcvd_pkts = 0; // This holds received packets count. @@ -193,5 +198,5 @@ AvalancheScen::run() { return (0); } -} -} +} // namespace perfdhcp +} // namespace isc diff --git a/src/bin/perfdhcp/basic_scen.cc b/src/bin/perfdhcp/basic_scen.cc index 6b7bcc23dd..5469310db4 100644 --- a/src/bin/perfdhcp/basic_scen.cc +++ b/src/bin/perfdhcp/basic_scen.cc @@ -237,12 +237,16 @@ BasicScen::run() { tc_.printTemplates(); } + // Print any received leases. + if (options_.testDiags('l')) { + stats_mgr.printLeases(); + } + int ret_code = 0; // Check if any packet drops occurred. ret_code = stats_mgr.droppedPackets() ? 3 : 0; return (ret_code); } - -} -} +} // namespace perfdhcp +} // namespace isc diff --git a/src/bin/perfdhcp/command_options.cc b/src/bin/perfdhcp/command_options.cc index 02e1573b94..31053f22f8 100644 --- a/src/bin/perfdhcp/command_options.cc +++ b/src/bin/perfdhcp/command_options.cc @@ -1281,10 +1281,11 @@ CommandOptions::usage() const { "-x: Include extended diagnostics in the output.\n" " is a string of single-keywords specifying\n" " the operations for which verbose output is desired. The selector\n" - " keyletters are:\n" + " key letters are:\n" " * 'a': print the decoded command line arguments\n" " * 'e': print the exit reason\n" " * 'i': print rate processing details\n" + " * 'l': print received leases\n" " * 's': print first server-id\n" " * 't': when finished, print timers of all successful exchanges\n" " * 'T': when finished, print templates\n" diff --git a/src/bin/perfdhcp/stats_mgr.cc b/src/bin/perfdhcp/stats_mgr.cc index 899686c49d..4d312de6b6 100644 --- a/src/bin/perfdhcp/stats_mgr.cc +++ b/src/bin/perfdhcp/stats_mgr.cc @@ -6,12 +6,46 @@ #include +#include +#include +#include +#include +#include +#include #include +#include +using isc::dhcp::DHO_DHCP_CLIENT_IDENTIFIER; +using isc::dhcp::DUID; +using isc::dhcp::Option6IAAddr; +using isc::dhcp::Option6IAAddrPtr; +using isc::dhcp::Option6IAPrefix; +using isc::dhcp::Option6IAPrefixPtr; +using isc::dhcp::OptionPtr; +using isc::dhcp::Pkt4; +using isc::dhcp::Pkt4Ptr; +using isc::dhcp::PktPtr; namespace isc { namespace perfdhcp { +int dhcpVersion(ExchangeType const exchange_type) { + switch (exchange_type) { + case ExchangeType::DO: + case ExchangeType::RA: + case ExchangeType::RNA: + return 4; + case ExchangeType::SA: + case ExchangeType::RR: + case ExchangeType::RN: + case ExchangeType::RL: + return 6; + default: + isc_throw(BadValue, + "unrecognized exchange type '" << exchange_type << "'"); + } +} + std::ostream& operator<<(std::ostream& os, ExchangeType xchg_type) { switch(xchg_type) { @@ -64,8 +98,8 @@ ExchangeStats::ExchangeStats(const ExchangeType xchg_type, } void -ExchangeStats::updateDelays(const dhcp::PktPtr& sent_packet, - const dhcp::PktPtr& rcvd_packet) { +ExchangeStats::updateDelays(const PktPtr& sent_packet, + const PktPtr& rcvd_packet) { if (!sent_packet) { isc_throw(BadValue, "Sent packet is null"); } @@ -114,8 +148,8 @@ ExchangeStats::updateDelays(const dhcp::PktPtr& sent_packet, sum_delay_squared_ += delta * delta; } -dhcp::PktPtr -ExchangeStats::matchPackets(const dhcp::PktPtr& rcvd_packet) { +PktPtr +ExchangeStats::matchPackets(const PktPtr& rcvd_packet) { using namespace boost::posix_time; if (!rcvd_packet) { @@ -128,7 +162,7 @@ ExchangeStats::matchPackets(const dhcp::PktPtr& rcvd_packet) { // that the received packet we got has no corresponding // sent packet so orphans counter has to be updated. ++orphans_; - return(dhcp::PktPtr()); + return(PktPtr()); } else if (next_sent_ == sent_packets_.end()) { // Even if there are still many unmatched packets on the // list we might hit the end of it because of unordered @@ -246,13 +280,13 @@ ExchangeStats::matchPackets(const dhcp::PktPtr& rcvd_packet) { // If we are here, it means that both ordered lookup and // unordered lookup failed. Searched packet is not on the list. ++orphans_; - return(dhcp::PktPtr()); + return(PktPtr()); } // Packet is matched so we count it. We don't count unmatched packets // as they are counted as orphans with a separate counter. ++rcvd_packets_num_; - dhcp::PktPtr sent_packet(*next_sent_); + PktPtr sent_packet(*next_sent_); // If packet was found, we assume it will be never searched // again. We want to delete this packet from the list to // improve performance of future searches. @@ -279,7 +313,7 @@ ExchangeStats::printTimestamps() { for (PktListIterator it = rcvd_packets_.begin(); it != rcvd_packets_.end(); ++it) { - dhcp::PktPtr rcvd_packet = *it; + PktPtr rcvd_packet = *it; PktListTransidHashIndex& idx = archived_packets_.template get<1>(); std::pairgetTransid() == rcvd_packet->getTransid()) { - dhcp::PktPtr sent_packet = *it_archived; + PktPtr sent_packet = *it_archived; // Get sent and received packet times. ptime sent_time = sent_packet->getTimestamp(); ptime rcvd_time = rcvd_packet->getTimestamp(); @@ -322,9 +356,9 @@ StatsMgr::StatsMgr(CommandOptions& options) : boot_time_(boost::posix_time::microsec_clock::universal_time()) { // Check if packet archive mode is required. If user - // requested diagnostics option -x t we have to enable + // requested diagnostics option -x l or -x t we have to enable // it so as StatsMgr preserves all packets. - archive_enabled_ = options.testDiags('t') ? true : false; + archive_enabled_ = options.testDiags('l') || options.testDiags('t'); if (options.getIpVersion() == 4) { addExchangeStats(ExchangeType::DO, options.getDropTime()[0]); @@ -351,7 +385,84 @@ StatsMgr::StatsMgr(CommandOptions& options) : addCustomCounter("shortwait", "Short waits for packets"); } } -int ExchangeStats::malformed_pkts_{0}; +std::string +ExchangeStats::receivedLeases() const { + // Get DHCP version. + int const v(dhcpVersion(xchg_type_)); + + std::stringstream result; + // Iterate through all received packets. + for (PktPtr const& packet : rcvd_packets_) { + + // Get client identifier. + if (v == 4) { + OptionPtr const& client_id_option( + packet->getOption(DHO_DHCP_CLIENT_IDENTIFIER)); + if (client_id_option) { + result << TestControl::vector2Hex(client_id_option->getData()); + } + } else if (v == 6) { + OptionPtr const& client_id_option(packet->getOption(D6O_CLIENTID)); + if (client_id_option) { + result << DUID(client_id_option->getData()).toText(); + } + } else { + isc_throw(BadValue, "unrecognized DHCP version '" << v << "'"); + } + result << ','; + + // Get address. + if (v == 4) { + Pkt4Ptr const& packet4(boost::dynamic_pointer_cast(packet)); + if (packet4) { + result << packet4->getYiaddr().toText(); + } + } else if (v == 6) { + OptionPtr const& option(packet->getOption(D6O_IA_NA)); + if (option) { + Option6IAAddrPtr const& iaaddr( + boost::dynamic_pointer_cast( + option->getOption(D6O_IAADDR))); + if (iaaddr) { + result << iaaddr->getAddress().toText(); + } + } + } + result << ','; + + // Get prefix. + OptionPtr const& option(packet->getOption(D6O_IA_PD)); + if (option) { + Option6IAPrefixPtr const& iaprefix( + boost::dynamic_pointer_cast( + option->getOption(D6O_IAPREFIX))); + if (iaprefix) { + result << iaprefix->getAddress().toText(); + } + } + + result << std::endl; + } + + return result.str(); } + +void +ExchangeStats::printLeases() const { + std::cout << receivedLeases() << std::endl; } + +void StatsMgr::printLeases() const { + for (auto const& exchange : exchanges_) { + std::cout << "***Leases for " << exchange.first << "***" << std::endl; + std::cout << "client_id,adrress,prefix" << std::endl; + exchange.second->printLeases(); + std::cout << std::endl; + } +} + +int ExchangeStats::malformed_pkts_{0}; + +} // namespace perfdhcp +} // namespace isc diff --git a/src/bin/perfdhcp/stats_mgr.h b/src/bin/perfdhcp/stats_mgr.h index 03741c633c..b7a7d0fec4 100644 --- a/src/bin/perfdhcp/stats_mgr.h +++ b/src/bin/perfdhcp/stats_mgr.h @@ -39,6 +39,13 @@ enum class ExchangeType { RL ///< DHCPv6 RELEASE-REPLY }; +/// \brief Get the DHCP version that fits the exchange type. +/// +/// \param exchange_type exchange type that will determine the version +/// \throw isc::BadValue exchange type is unrecognized +/// \return DHCP version: 4 or 6 +int dhcpVersion(ExchangeType const exchange_type); + /// \brief Return name of the exchange. /// /// Function returns name of the specified exchange type. @@ -555,6 +562,19 @@ public: return(std::make_tuple(sent_packets_.begin(), sent_packets_.end())); } + /// \brief Return the list of received leases in CSV format as string. + /// + /// Depending exchange type, it can apply to + /// potential leases received in offers and advertisements, + /// committed leases received in acknowledgements and replies, + /// renewed or released leases. + /// + /// \return multiline string of received leases in CSV format + std::string receivedLeases() const; + + /// \brief Print the list of received leases. + void printLeases() const; + static int malformed_pkts_; // Private stuff of ExchangeStats class @@ -1159,6 +1179,9 @@ public: } } + /// \brief Delegate to all exchanges to print their leases. + void printLeases() const; + /// \brief Print names and values of custom counters. /// /// Method prints names and values of custom counters. Custom counters diff --git a/src/bin/perfdhcp/test_control.cc b/src/bin/perfdhcp/test_control.cc index 6f4ca935ff..cb973e4cc0 100644 --- a/src/bin/perfdhcp/test_control.cc +++ b/src/bin/perfdhcp/test_control.cc @@ -698,7 +698,7 @@ TestControl::printStats() const { std::string TestControl::vector2Hex(const std::vector& vec, - const std::string& separator /* ="" */) { + const std::string& separator /* = "" */) { std::ostringstream stream; for (std::vector::const_iterator it = vec.begin(); it != vec.end();