Browse Source

[1956] Basic unit tests added for PerfPkt6 class.

Marcin Siodelski 13 years ago
parent
commit
a6a3d1b172

+ 12 - 0
src/lib/dhcp/option.cc

@@ -270,6 +270,18 @@ void Option::setUint32(uint32_t value) {
   writeUint32(value, &data_[0]);
 }
 
+void Option::setData(const OptionBufferConstIter first,
+                     const OptionBufferConstIter last) {
+    // We will copy entire option buffer, so we have to resize data_.
+    data_.resize(last - first);
+    OptionBufferConstIter x = first;
+    while (x != last) {
+        data_[x - first] = *x;
+        ++x;
+    }
+}
+
+
 Option::~Option() {
 
 }

+ 9 - 0
src/lib/dhcp/option.h

@@ -244,6 +244,15 @@ public:
     /// @param value value to be set
     void setUint32(uint32_t value);
 
+    /// @brief Sets content of this option from buffer.
+    ///
+    /// Option will be resized to length of buffer.
+    ///
+    /// @param first iterator pointing begining of buffer to copy.
+    /// @param last iterator pointing to end of buffer to copy.
+    void setData(OptionBufferConstIter first,
+                 OptionBufferConstIter last);
+
     /// just to force that every option has virtual dtor
     virtual ~Option();
 

+ 54 - 9
tests/tools/perfdhcp/perf_pkt6.cc

@@ -12,8 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <boost/shared_ptr.hpp>
-
+#include <exceptions/exceptions.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/dhcp6.h>
 
@@ -28,8 +27,15 @@ namespace perfdhcp {
 
 PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
                                              uint16_t type,
+                                             const dhcp::OptionBuffer& data) :
+    dhcp::Option(u, type, data),
+    position_(0) {
+}
+
+PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
+                                             uint16_t type,
                                              const dhcp::OptionBuffer& data,
-                                             const OptionPosition& position) :
+                                             const size_t position) :
     dhcp::Option(u, type, data),
     position_(position) {
 }
@@ -37,13 +43,21 @@ PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
 PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
                                              uint16_t type,
                                              dhcp::OptionBufferConstIter first,
+                                             dhcp::OptionBufferConstIter last) :
+    dhcp::Option(u, type, first, last),
+    position_(0) {
+}
+
+PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
+                                             uint16_t type,
+                                             dhcp::OptionBufferConstIter first,
                                              dhcp::OptionBufferConstIter last,
-                                             const OptionPosition& position) :
+                                             const size_t position) :
     dhcp::Option(u, type, first, last),
     position_(position) {
 }
 
-PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, const OptionPosition& transid_offset) :
+PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, size_t transid_offset) :
     Pkt6(buf, len, dhcp::Pkt6::UDP),
     transid_offset_(transid_offset) {
 
@@ -98,17 +112,18 @@ PerfPkt6::stampedRawUnpack() {
     // Update packet timestamp for RTT calculations but do not include unpack time.
     updateTimestamp();
 
-    // Get transaction id offset.
-    int transid_offset = transid_offset_.get();
     // Read transaction id from the packet at the given offset.
-    transid_ = ( (data_[transid_offset]) << 16 ) +
-        ((data_[transid_offset + 1]) << 8) + (data_[transid_offset + 2]);
+    transid_ = ( (data_[transid_offset_]) << 16 ) +
+        ((data_[transid_offset_ + 1]) << 8) + (data_[transid_offset_ + 2]);
     transid_ = transid_ & 0xffffff;
 
     // Get message type - assume it is first octet in the packet.
     msg_type_ = data_[0];
+
+    rawUnpackOptions();
 }
 
+
 void
 PerfPkt6::updateOptions() {
     try {
@@ -134,6 +149,36 @@ PerfPkt6::updateOptions() {
 }
 
 void
+PerfPkt6::rawUnpackOptions() {
+    for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
+         it != options_.end(); ++it) {
+
+        PositionedOptionPtr option = boost::dynamic_pointer_cast<PositionedOption>(it->second);
+        size_t opt_pos = option->getOptionPosition();
+
+        if (opt_pos == 0) {
+            isc_throw(isc::BadValue, "Failed to unpack packet from raw buffer "
+                      "(Option position not specified)");
+        } else if (opt_pos + 4 > data_.size()) {
+            isc_throw(isc::BadValue, "Failed to unpack options from from raw buffer "
+                      "(Option position out of bounds)");
+        }
+
+        size_t offset = opt_pos;
+        //        uint16_t opt_type = data_[offset] * 256 + data_[offset + 1];
+        offset += 2;
+        uint16_t opt_len = data_[offset] * 256 + data_[offset + 1];
+        offset += 2;
+
+        if (offset + opt_len > data_.size()) {
+            isc_throw(isc::BadValue,
+                      "Failed to unpack option from raw buffer (Option truncated)");
+        }
+        option->setData(data_.begin() + offset, data_.begin() + offset + opt_len);
+    }
+}
+
+void
 PerfPkt6::updateTimestamp() {
     if (clock_gettime(CLOCK_REALTIME, &time_stamp_) < 0) {
         isc_throw(isc::Unexpected, "Failed to get timestamp for packet");

+ 46 - 30
tests/tools/perfdhcp/perf_pkt6.h

@@ -16,7 +16,7 @@
 #define __PERF_PKT6_H
 
 #include <time.h>
-
+#include <boost/shared_ptr.hpp>
 #include <dhcp/pkt6.h>
 
 namespace isc {
@@ -55,28 +55,6 @@ namespace perfdhcp {
 class PerfPkt6 : public dhcp::Pkt6 {
 public:
 
-    /// \brief Class represents position of DHCP option in a packet
-    class OptionPosition {
-    public:
-        /// \brief Class constructor
-        ///
-        /// Applies default value of option position
-        explicit OptionPosition() : position_(0) { };
-
-        /// \brief Class constructor
-        ///
-        /// \param position position of option in DHCP packet
-        explicit OptionPosition(size_t position) : position_(position)  { };
-
-        /// \brief Returns position of DHCP option in a packet
-        ///
-        /// \return position of DHCP option in packet
-        size_t get() const { return position_; }
-    private:
-        size_t position_;    ///< position of option in a packet
-                               ///< Zero is default position
-    };
-
     /// \brief DHCPv6 option at specific offset
     ///
     /// This class represents DHCPv6 option at specified
@@ -84,6 +62,16 @@ public:
     ///
     class PositionedOption : public dhcp::Option {
     public:
+
+        /// \brief Constructor, sets default (0) option position
+        ///
+        ///
+        /// \param u specifies universe (V4 or V6)
+        /// \param type option type (0-255 for V4 and 0-65535 for V6)
+        /// \param data content of the option
+        PositionedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data);
+
+
         /// \brief Constructor, used to create positioned option from buffer
         ///
         ///
@@ -92,7 +80,21 @@ public:
         /// \param data content of the option
         /// \param position absolute position of option in a packet (zero is default)
         PositionedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data,
-                         const OptionPosition& position);
+                         const size_t position);
+
+        /// \brief Constructor, sets default (0) option position
+        ///
+        /// This contructor is similar to the previous one, but it does not take
+        /// the whole vector<uint8_t>, but rather subset of it.
+        ///
+        /// \param u specifies universe (V4 or V6)
+        /// \param type option type (0-255 for V4 and 0-65535 for V6)
+        /// \param first iterator to the first element that should be copied
+        /// \param last iterator to the next element after the last one
+        ///        to be copied.
+        /// \param position absolute position of option in a packet (zero is default)
+        PositionedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
+                         dhcp::OptionBufferConstIter last);
 
         /// \brief Constructor, used to create positioned option from buffer iterators
         ///
@@ -106,19 +108,21 @@ public:
         ///        to be copied.
         /// \param position absolute position of option in a packet (zero is default)
         PositionedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
-                         dhcp::OptionBufferConstIter last, const OptionPosition& position);
+                         dhcp::OptionBufferConstIter last, const size_t position);
 
 
         /// \brief Returns absolute position (offset) of an option in a
         /// DHCPv6 packet.
         ///
         /// \return absolute position (offset) of an option in a packet
-        size_t getOptionPosition() const { return position_.get(); };
+        size_t getOptionPosition() const { return position_; };
 
     private:
-        OptionPosition position_;   ///< Absolute position of DHCPv6 option in a packet
+        size_t position_;   ///< Absolute position of DHCPv6 option in a packet
     };
 
+    typedef boost::shared_ptr<PositionedOption> PositionedOptionPtr;
+
     /// Constructor, used in message transmission
     ///
     /// Creates new DHCPv6 message using provided buffer. New object
@@ -143,7 +147,17 @@ public:
     /// \param xid_off transaction id offset in a packet
     PerfPkt6(const uint8_t* buf,
              uint32_t len,
-             const OptionPosition& transid_offset);
+             size_t transid_offset_);
+
+    /// \brief Returns transaction id offset in packet buffer
+    ///
+    /// return transaction id offset in packet buffer
+    size_t getTransIdOffset() const { return transid_offset_; };
+
+    /// \brief Returns current packet timestamp
+    ///
+    /// \return current packet timestamp
+    timespec getTimestamp() const { return time_stamp_; }
 
     /// \brief Prepare on-wire packet format and record timestamp
     ///
@@ -208,13 +222,15 @@ private:
     /// throw isc::Unexpected if options update fails
     void updateOptions();
 
+    void rawUnpackOptions();
+
     /// \brief Update packet timestamp with current time
     ///
     /// \throw isc::Unexpected if timestamp update failed
     void updateTimestamp();
 
-    OptionPosition transid_offset_;  ///< transaction id offset
-    timespec time_stamp_;            ///< time stamp of last pack or unpack
+    size_t transid_offset_;      ///< transaction id offset
+    timespec time_stamp_;        ///< time stamp of last pack or unpack
 
 };
 

+ 5 - 1
tests/tools/perfdhcp/tests/Makefile.am

@@ -4,8 +4,9 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
+AM_LDFLAGS = $(CLOCK_GETTIME_LDFLAGS)
 if USE_STATIC_LINK
-AM_LDFLAGS = -static
+AM_LDFLAGS += -static
 endif
 
 CLEANFILES = *.gcno *.gcda
@@ -15,7 +16,9 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += command_options_unittest.cc
+run_unittests_SOURCES += perf_pkt6_unittest.cc
 run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/command_options.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt6.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
@@ -23,6 +26,7 @@ run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 endif
 

+ 140 - 0
tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc

@@ -0,0 +1,140 @@
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <sstream>
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+#include <dhcp/dhcp6.h>
+
+#include "../perf_pkt6.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::perfdhcp;
+
+typedef PerfPkt6::PositionedOptionPtr PositionedOptionPtr;
+typedef PerfPkt6::PositionedOption PositionedOption;
+
+namespace {
+class PerfPkt6Test : public ::testing::Test {
+public:
+    PerfPkt6Test() {
+    }
+
+/// @brief returns captured actual SOLICIT packet
+///
+/// Captured SOLICIT packet with transid=0x3d79fb and options: client-id,
+/// in_na, dns-server, elapsed-time, option-request
+/// This code was autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
+/// but we spent some time to make is less ugly than it used to be.
+///
+/// @return pointer to Pkt6 that represents received SOLICIT
+PerfPkt6* capture1() {
+    uint8_t data[98];
+    data[0]  = 1;
+    data[1]  = 1;       data[2]  = 2;     data[3] = 3;      data[4]  = 0;
+    data[5]  = 1;       data[6]  = 0;     data[7] = 14;     data[8]  = 0;
+    data[9]  = 1;       data[10] = 0;     data[11] = 1;     data[12] = 21;
+    data[13] = 158;     data[14] = 60;    data[15] = 22;    data[16] = 0;
+    data[17] = 30;      data[18] = 140;   data[19] = 155;   data[20] = 115;
+    data[21] = 73;      data[22] = 0;     data[23] = 3;     data[24] = 0;
+    data[25] = 40;      data[26] = 0;     data[27] = 0;     data[28] = 0;
+    data[29] = 1;       data[30] = 255;   data[31] = 255;   data[32] = 255;
+    data[33] = 255;     data[34] = 255;   data[35] = 255;   data[36] = 255;
+    data[37] = 255;     data[38] = 0;     data[39] = 5;     data[40] = 0;
+    data[41] = 24;      data[42] = 32;    data[43] = 1;     data[44] = 13;
+    data[45] = 184;     data[46] = 0;     data[47] = 1;     data[48] = 0;
+    data[49] = 0;       data[50] = 0;     data[51] = 0;     data[52] = 0;
+    data[53] = 0;       data[54] = 0;     data[55] = 0;     data[56] = 18;
+    data[57] = 52;      data[58] = 255;   data[59] = 255;   data[60] = 255;
+    data[61] = 255;     data[62] = 255;   data[63] = 255;   data[64] = 255;
+    data[65] = 255;     data[66] = 0;     data[67] = 23;    data[68] = 0;
+    data[69] = 16;      data[70] = 32;    data[71] = 1;     data[72] = 13;
+    data[73] = 184;     data[74] = 0;     data[75] = 1;     data[76] = 0;
+    data[77] = 0;       data[78] = 0;     data[79] = 0;     data[80] = 0;
+    data[81] = 0;       data[82] = 0;     data[83] = 0;     data[84] = 221;
+    data[85] = 221;     data[86] = 0;     data[87] = 8;     data[88] = 0;
+    data[89] = 2;       data[90] = 0;     data[91] = 100;   data[92] = 0;
+    data[93] = 6;       data[94] = 0;     data[95] = 2;     data[96] = 0;
+    data[97] = 23;
+
+    PerfPkt6* pkt = new PerfPkt6(data, sizeof(data), 0);
+
+    /*    pkt->setRemotePort(546);
+    pkt->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
+    pkt->setLocalPort(0);
+    pkt->setLocalAddr(IOAddress("ff02::1:2"));
+    pkt->setIndex(2);
+    pkt->setIface("eth0");*/
+
+    return (pkt);
+}
+
+};
+
+TEST_F(PerfPkt6Test, constructor) {
+    uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
+    timespec zero_t_spec;
+    memset(&zero_t_spec, 0, sizeof(zero_t_spec));
+
+    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data), 1));
+    timespec packet_t_spec = pkt1->getTimestamp();
+
+    EXPECT_EQ(6, pkt1->getData().size());
+    EXPECT_EQ(0, memcmp( &pkt1->getData()[0], data, sizeof(data)));
+    EXPECT_EQ(1, pkt1->getTransIdOffset());
+    EXPECT_EQ(0, memcmp(&packet_t_spec, &zero_t_spec, sizeof(zero_t_spec)));
+}
+
+TEST_F(PerfPkt6Test, UnpackRawSolicit) {
+    // Create packetPositionedOptionPtr
+    boost::scoped_ptr<PerfPkt6> pkt1(capture1());
+    // Create some input buffer to initialize options.
+    uint8_t buf_elapsed_time[] = { 8, 2, 4, 5 };
+    // Create options.
+    dhcp::OptionBuffer buf(buf_elapsed_time, buf_elapsed_time + 4);
+    PositionedOptionPtr pkt1_elapsed_time(new PositionedOption(Option::V6, 8, buf, 86));
+
+    // Add option to packet and create on-wire format from added options.
+    // Contents of options will override contents of packet buffer.
+    ASSERT_NO_THROW(pkt1->addOption(pkt1_elapsed_time));
+    ASSERT_NO_THROW(pkt1->stampedRawPack());
+
+    // Let's create another packet using packed data stored in first packet.
+    // We will try to unpack data into option objects.
+    buf.clear();
+    OptionBuffer pkt1_output = pkt1->getData();
+    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(&pkt1_output[0], pkt1_output.size(), 1));
+
+    // Create partial options to specify offsets of certain options in packet.
+    PositionedOptionPtr pkt2_elapsed_time(new PositionedOption(Option::V6, D6O_ELAPSED_TIME, buf, 86));
+    // Add partial options.
+    pkt2->addOption(pkt2_elapsed_time);
+    // Get relevant parts of buffer data into option objects.
+    ASSERT_NO_THROW(pkt2->stampedRawUnpack());
+    // Once option data is updated we pull it out.
+    pkt2_elapsed_time = boost::dynamic_pointer_cast<PositionedOption>(pkt2->getOption(D6O_ELAPSED_TIME));
+    ASSERT_TRUE(pkt2_elapsed_time);
+    // Expecting option contents be the same as original.
+    OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData();
+    ASSERT_EQ(100, pkt2_elapsed_time->getUint16());
+}
+
+}