]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#572] perfdhcp counting rejected leases
authorWlodek Wencel <wlodek@isc.org>
Tue, 19 Nov 2019 12:36:48 +0000 (19:36 +0700)
committerTomek Mrugalski <tomasz@isc.org>
Wed, 20 Nov 2019 06:52:57 +0000 (14:52 +0800)
src/bin/perfdhcp/stats_mgr.cc
src/bin/perfdhcp/stats_mgr.h
src/bin/perfdhcp/test_control.cc
src/bin/perfdhcp/test_control.h
src/bin/perfdhcp/tests/avalanche_scen_unittest.cc
src/bin/perfdhcp/tests/basic_scen_unittest.cc
src/bin/perfdhcp/tests/test_control_unittest.cc

index 056b9c045f2c03b704d77ad95c132ebf01237947..19109fc40d6ef2d812a507e58168c2b18a1578bd 100644 (file)
@@ -54,12 +54,12 @@ ExchangeStats::ExchangeStats(const ExchangeType xchg_type,
       ordered_lookups_(0),
       sent_packets_num_(0),
       rcvd_packets_num_(0),
+      rejected_leases_num_(0),
       boot_time_(boot_time)
 {
     next_sent_ = sent_packets_.begin();
 }
 
-
 void
 ExchangeStats::updateDelays(const dhcp::PktPtr& sent_packet,
                             const dhcp::PktPtr& rcvd_packet) {
index d4cba5787f2a8c019392ca0be30ce8869a225e79..efbd75c040fadee92c67ea27eaf2fee31dbfae8a 100644 (file)
@@ -459,6 +459,13 @@ public:
         return(drops);
     }
 
+    /// \brief Return total number of rejected leases.
+    ///
+    /// Method returns total number of rejected leases.
+    ///
+    /// \return number of rejected leases.
+    uint64_t getRejLeasesNum() const { return(rejected_leases_num_); }
+    void updateRejLeases() { ++rejected_leases_num_; }
     /// \brief Print main statistics for packet exchange.
     ///
     /// Method prints main statistics for particular exchange.
@@ -482,7 +489,8 @@ public:
              << "received packets: " << getRcvdPacketsNum() << endl
              << "drops: " << drops << endl
              << "drops ratio: " << drops_ratio << " %" << endl
-             << "orphans: " << getOrphans() << endl;
+             << "orphans: " << getOrphans() << endl
+             << "rejected leases: " << getRejLeasesNum() << endl;
     }
 
     /// \brief Print round trip time packets statistics.
@@ -619,6 +627,8 @@ private:
 
     uint64_t sent_packets_num_;    ///< Total number of sent packets.
     uint64_t rcvd_packets_num_;    ///< Total number of received packets.
+
+    uint64_t rejected_leases_num_;  ///< Total number of rejected leases (e.g. NoAddrAvail)
     boost::posix_time::ptime boot_time_; ///< Time when test is started.
 };
 
@@ -962,7 +972,21 @@ public:
         return(xchg_stats->getCollectedNum());
     }
 
-
+    /// \brief Return total number of rejected leases
+    ///
+    /// Method returns total number of rejected leases for specified
+    /// exchange type.
+    ///
+    /// \param xchg_type exchange type.
+    /// \throw isc::BadValue if invalid exchange type specified.
+    /// \return number of received packets.
+    uint64_t getRejLeasesNum(const ExchangeType xchg_type) const {
+        ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+        return(xchg_stats->getRejLeasesNum());
+    }
+    void updateRejLeases(const ExchangeType xchg_type) {
+    ExchangeStatsPtr xchg_stats = getExchangeStats(xchg_type);
+           xchg_stats->updateRejLeases(); }
     /// \brief Get time period since the start of test.
     ///
     /// Calculate dna return period since the test start. This
@@ -1017,6 +1041,7 @@ public:
         std::ostringstream stream_sent;
         std::ostringstream stream_rcvd;
         std::ostringstream stream_drops;
+        std::ostringstream stream_reject;
         std::string sep("");
         for (ExchangesMapIterator it = exchanges_.begin();
              it != exchanges_.end(); ++it) {
@@ -1027,10 +1052,12 @@ public:
             stream_sent << sep << it->second->getSentPacketsNum();
             stream_rcvd << sep << it->second->getRcvdPacketsNum();
             stream_drops << sep << it->second->getDroppedPacketsNum();
+            stream_reject << sep << it->second->getRejLeasesNum();
         }
         std::cout << "sent: " << stream_sent.str()
                   << "; received: " << stream_rcvd.str()
                   << "; drops: " << stream_drops.str()
+                  << "; rejected: " << stream_reject.str()
                   << std::endl;
     }
 
index 19ed5cbeab048cf10cec1ef7d3db8fd2c6dc7d84..7e0e9330e1a7c1249ade84c765ab1431631feef8 100644 (file)
@@ -17,6 +17,8 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaprefix.h>
 #include <util/unittests/check_valgrind.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
@@ -795,6 +797,41 @@ TestControl::processReceivedPacket4(const Pkt4Ptr& pkt4) {
     }
 }
 
+bool
+TestControl::validateIA(const Pkt6Ptr& pkt6) {
+    // check if iaaddr exists - if it does, we can continue sending request
+    // if not we will update statistics about rejected leases
+    // @todo it's checking just one iaaddress option for now it's ok
+    // but when perfdhcp will be extended to create message with multiple IA
+    // this will have to be iterate on:
+    // OptionCollection ias = pkt6->getOptions(D6O_IA_NA);
+    Option6IAPrefixPtr iapref;
+    Option6IAAddrPtr iaaddr;
+    if (pkt6->getOption(D6O_IA_PD)){
+        iapref = boost::dynamic_pointer_cast<
+                 Option6IAPrefix>(pkt6->getOption(D6O_IA_PD)->getOption(D6O_IAPREFIX));
+    }
+    if (pkt6->getOption(D6O_IA_NA)){
+        iaaddr = boost::dynamic_pointer_cast<
+                 Option6IAAddr>(pkt6->getOption(D6O_IA_NA)->getOption(D6O_IAADDR));
+    }
+    if ((options_.getLeaseType()
+         .includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX) && iapref && iaaddr)
+       || (options_.getLeaseType()
+           .includes(CommandOptions::LeaseType::PREFIX) && iapref
+           && !options_.getLeaseType()
+               .includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX))
+       || (options_.getLeaseType()
+           .includes(CommandOptions::LeaseType::ADDRESS) && iaaddr
+          && !options_.getLeaseType()
+             .includes(CommandOptions::LeaseType::ADDRESS_AND_PREFIX))) {
+       return true;
+    }
+    else {
+        return false;
+    }
+}
+
 void
 TestControl::processReceivedPacket6(const Pkt6Ptr& pkt6) {
     uint8_t packet_type = pkt6->getType();
@@ -803,15 +840,17 @@ TestControl::processReceivedPacket6(const Pkt6Ptr& pkt6) {
         Pkt6Ptr solicit_pkt6(boost::dynamic_pointer_cast<Pkt6>(pkt));
         CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
         if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
-            /// @todo check whether received ADVERTISE packet is sane.
-            /// We might want to check if STATUS_CODE option is non-zero
-            /// and if there is IAADR option in IA_NA.
-            if (template_buffers_.size() < 2) {
-                sendRequest6(pkt6);
-            } else {
-                /// @todo add defines for packet type index that can be
-                /// used to access template_buffers_.
-                sendRequest6(template_buffers_[1], pkt6);
+            if (validateIA(pkt6)) {
+               if (template_buffers_.size() < 2) {
+                    sendRequest6(pkt6);
+               } else {
+                    /// @todo add defines for packet type index that can be
+                    /// used to access template_buffers_.
+                    sendRequest6(template_buffers_[1], pkt6);
+               }
+            }
+            else {
+                stats_mgr_.updateRejLeases(ExchangeType::SA);
             }
         }
     } else if (packet_type == DHCPV6_REPLY) {
@@ -825,12 +864,18 @@ TestControl::processReceivedPacket6(const Pkt6Ptr& pkt6) {
             // being sent. Note that, Reply messages hold the information about
             // leases assigned. We use this information to construct Renew and
             // Release messages.
-            if (stats_mgr_.hasExchangeStats(ExchangeType::RN) ||
-                stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
-                // Renew or Release messages are sent, because StatsMgr has the
-                // specific exchange type specified. Let's append the Reply
-                // message to a storage.
-                reply_storage_.append(pkt6);
+            if (validateIA(pkt6)) {
+                // check if there is correct IA to continue with Renew/Release
+                if (stats_mgr_.hasExchangeStats(ExchangeType::RN) ||
+                    stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
+                    // Renew or Release messages are sent, because StatsMgr has the
+                    // specific exchange type specified. Let's append the Reply
+                    // message to a storage.
+                    reply_storage_.append(pkt6);
+                }
+            }
+            else {
+                stats_mgr_.updateRejLeases(ExchangeType::RR);
             }
         // The Reply message is not a server's response to the Request message
         // sent within the 4-way exchange. It may be a response to the Renew
index 0f75f72aacdc984aacada78bf85d454d97f7c3ce..9b05076a188dcdba27e48d939afb0d5b62d2c565 100644 (file)
@@ -536,6 +536,15 @@ protected:
     /// \throw isc::Unexpected if unexpected error occurred.
     void processReceivedPacket4(const dhcp::Pkt4Ptr& pkt4);
 
+    /// \brief Process IA in received DHCPv6 packet.
+    ///
+    /// Process IA in received message to check if it contain proper
+    /// address and/or prefix
+    ///
+    /// \param [in] pkt6 object representing DHCPv6 packet received.
+    /// \return true if the message include correct IA, false otherwise.
+    bool validateIA(const dhcp::Pkt6Ptr& pkt6);
+
     /// \brief Process received DHCPv6 packet.
     ///
     /// Method performs processing of the received DHCPv6 packet,
index cce3965b7b81185ea535b35bf94c07ff05147d14..7fcd4e67c6328418c195e012f96d089b36b4a9b1 100644 (file)
@@ -14,6 +14,8 @@
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaprefix.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/foreach.hpp>
@@ -114,11 +116,15 @@ public:
         // Add IA_NA if requested by the client.
         if (opt_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
             OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+            OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR, isc::asiolink::IOAddress("fe80::abcd"), 300, 500));
+            opt_ia_na->addOption(iaaddr);
             pkt->addOption(opt_ia_na);
         }
         // Add IA_PD if requested by the client.
         if (opt_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
             OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+            OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX, isc::asiolink::IOAddress("fe80::"), 64, 300, 500));
+            opt_ia_pd->addOption(iapref);
             pkt->addOption(opt_ia_pd);
         }
         OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
index 24b743c79163fc0c5db48f47dab543ccf17dcb02..a5bde10d7d697c3c5041654da5e3b924beead71e 100644 (file)
@@ -14,7 +14,8 @@
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/iface_mgr.h>
-
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaprefix.h>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/foreach.hpp>
 
@@ -99,11 +100,17 @@ public:
         // Add IA_NA if requested by the client.
         if (opt_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
             OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+            OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR,
+                             isc::asiolink::IOAddress("fe80::abcd"), 300, 500));
+            opt_ia_na->addOption(iaaddr);
             pkt->addOption(opt_ia_na);
         }
         // Add IA_PD if requested by the client.
         if (opt_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
             OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+            OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX,
+                             isc::asiolink::IOAddress("fe80::"), 64, 300, 500));
+            opt_ia_pd->addOption(iapref);
             pkt->addOption(opt_ia_pd);
         }
         OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
index aef88599c8287c602c1f4082b9ca5c74f354453d..4a31f98b783949383934d2a4270736c51202cd60 100644 (file)
@@ -14,6 +14,8 @@
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/iface_mgr.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaprefix.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/foreach.hpp>
@@ -887,7 +889,7 @@ public:
             // transaction ids from the range from 11 to 20 (the range of
             // 1 to 10 has been used by Solicit-Advertise).
             tc.processReceivedPacket6(advertise);
-    }
+        }
 
         // Requests have been sent, so now let's simulate responses from the
         // server. Generate corresponding Reply messages with the transaction
@@ -924,6 +926,49 @@ public:
 
     }
 
+    /// \brief Test counting rejected leases in Solicit-Advertise.
+    ///
+    /// This function simulates acquiring 4 leases from the server and
+    /// rejecting allocating of 6 leases
+
+    void testCountRejectedLeasesSolAdv() {
+        // Build a command line.
+        CommandOptions opt;
+        std::ostringstream s;
+        s << "perfdhcp -6 -l fake -r 10 -R 10 -L 10547 -n 10 ::1";
+        processCmdLine(opt, s.str());
+        // Create a test controller class.
+        NakedTestControl tc(opt);
+        // 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);
+
+        // Send a number of Solicit messages. Each generated Solicit will be
+        // assigned a different transaction id, starting from 1 to 10.
+        tc.sendPackets(10);
+
+        // Simulate Advertise responses from the server. Each advertise is
+        // assigned a transaction id from the range of 1 to 6 with incorrect IA
+        // included in the message
+        for (unsigned i = generator->getNext() - 10; i < 7; ++i) {
+            Pkt6Ptr advertise(createAdvertisePkt6(tc, i, false));
+            tc.processReceivedPacket6(advertise);
+        }
+        // counter of rejected leases has to be 6
+        EXPECT_EQ(tc.stats_mgr_.getRejLeasesNum(ExchangeType::SA), 6);
+        // Simulate Advertise responses from the server. Each advertise is
+        // assigned a transaction id from the range of 7 to 10 with correct IA
+        // included in the message
+        for (unsigned i = generator->getNext() - 7; i < 11; ++i) {
+            Pkt6Ptr advertise(createAdvertisePkt6(tc, i));
+            tc.processReceivedPacket6(advertise);
+        }
+        // counter of rejected leases can't change at this point
+        EXPECT_EQ(tc.stats_mgr_.getRejLeasesNum(ExchangeType::SA), 6);
+    }
+
     /// \brief Parse command line string with CommandOptions.
     ///
     /// \param cmdline command line string to be parsed.
@@ -975,16 +1020,27 @@ public:
     /// \param transid transaction id.
     /// \return instance of the packet.
     Pkt6Ptr
-    createAdvertisePkt6(NakedTestControl &tc, const uint32_t transid) const {
+    createAdvertisePkt6(NakedTestControl &tc, const uint32_t transid,
+                        const bool validIA = true) const {
         boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
         // Add IA_NA if requested by the client.
         if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
             OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+            if (validIA) {
+                OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR,
+                                 isc::asiolink::IOAddress("fe80::abcd"), 300, 500));
+                opt_ia_na->addOption(iaaddr);
+            }
             advertise->addOption(opt_ia_na);
         }
         // Add IA_PD if requested by the client.
         if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
             OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+            if (validIA) {
+                OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX,
+                                 isc::asiolink::IOAddress("fe80::"), 64, 300, 500));
+                opt_ia_pd->addOption(iapref);
+            }
             advertise->addOption(opt_ia_pd);
         }
         OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
@@ -998,16 +1054,27 @@ public:
     }
 
     Pkt6Ptr
-    createReplyPkt6(NakedTestControl &tc, const uint32_t transid) const {
+    createReplyPkt6(NakedTestControl &tc, const uint32_t transid,
+                    const bool validIA = true) const {
         Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, transid));
         // Add IA_NA if requested by the client.
         if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
             OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
+            if (validIA) {
+                OptionPtr iaaddr(new Option6IAAddr(D6O_IAADDR,
+                                 isc::asiolink::IOAddress("fe80::abcd"), 300, 500));
+                opt_ia_na->addOption(iaaddr);
+            }
             reply->addOption(opt_ia_na);
         }
         // Add IA_PD if requested by the client.
         if (tc.options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
             OptionPtr opt_ia_pd = Option::factory(Option::V6, D6O_IA_PD);
+            if (validIA) {
+                OptionPtr iapref(new Option6IAPrefix(D6O_IAPREFIX,
+                                 isc::asiolink::IOAddress("fe80::"), 64, 300, 500));
+                opt_ia_pd->addOption(iapref);
+            }
             reply->addOption(opt_ia_pd);
         }
         OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
@@ -1623,6 +1690,12 @@ TEST_F(TestControlTest, createRenew) {
     testCreateRenewRelease(DHCPV6_RENEW);
 }
 
+// This test verifies that the counter of rejected leases in
+// Solicit-Advertise message exchange works correctly
+TEST_F(TestControlTest, rejectedLeasesAdv) {
+    testCountRejectedLeasesSolAdv();
+}
+
 // This test verifies that the DHCPv6 Release message is created correctly
 // and that it comprises all required options.
 TEST_F(TestControlTest, createRelease) {