Browse Source

[1956] Created PerfPkt6 class

New class handles DHCPv6 messages in perfdhcp tool
Marcin Siodelski 13 years ago
parent
commit
908b273b78
3 changed files with 371 additions and 0 deletions
  1. 3 0
      tests/tools/perfdhcp/Makefile.am
  2. 144 0
      tests/tools/perfdhcp/perf_pkt6.cc
  3. 224 0
      tests/tools/perfdhcp/perf_pkt6.h

+ 3 - 0
tests/tools/perfdhcp/Makefile.am

@@ -26,5 +26,8 @@ endif
 pkglibexec_PROGRAMS  = perfdhcp
 perfdhcp_SOURCES  = perfdhcp.cc
 perfdhcp_SOURCES += command_options.cc command_options.h
+perfdhcp_SOURCES += perf_pkt6.cc perf_pkt6.h
 
 perfdhcp_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
+perfdhcp_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
+perfdhcp_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la

+ 144 - 0
tests/tools/perfdhcp/perf_pkt6.cc

@@ -0,0 +1,144 @@
+// Copyright (C) 2011  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 <boost/shared_ptr.hpp>
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/dhcp6.h>
+
+#include "perf_pkt6.h"
+
+using namespace std;
+using namespace isc;
+
+namespace isc {
+namespace perfdhcp {
+
+
+PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
+                                             uint16_t type,
+                                             const dhcp::OptionBuffer& data,
+                                             const OptionPosition& position) :
+    dhcp::Option(u, type, data),
+    position_(position) {
+}
+
+PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
+                                             uint16_t type,
+                                             dhcp::OptionBufferConstIter first,
+                                             dhcp::OptionBufferConstIter last,
+                                             const OptionPosition& position) :
+    dhcp::Option(u, type, first, last),
+    position_(position) {
+}
+
+PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, const OptionPosition& transid_offset) :
+    Pkt6(buf, len, dhcp::Pkt6::UDP),
+    transid_offset_(transid_offset) {
+
+    // Let's reset timestamp of the packet
+    memset(static_cast<void*>(&time_stamp_), 0, sizeof(time_stamp_));
+}
+
+void
+PerfPkt6::stampedPack() {
+    // This function simply wraps pack() function from parent class
+    // and then updates timestamp.
+    if (!pack()) {
+        isc_throw(isc::Unexpected, "Failed to prepare packet to send");
+    }
+    // Update pack time for RTT calculations.
+    updateTimestamp();
+}
+
+void
+PerfPkt6::stampedUnpack() {
+    // Update timestamp of the packet for RTT calculations.
+    // We do this before unpacking the packet so as unpack
+    // time will not affect the timestamp.
+    updateTimestamp();
+
+    // Unpack the incoming packet.
+    if (!unpack()) {
+        isc_throw(isc::Unexpected, "Failed to unpack incoming packet");
+    }
+}
+
+void
+PerfPkt6::stampedRawPack() {
+    try {
+        // Always override the packet if function is called.
+        bufferOut_.clear();
+        // Write whole buffer to output buffer.
+        bufferOut_.writeData(&data_[0], data_.size());
+        // We already have packet template stored in out buffer
+        // but still some options have to be updated if client
+        // specified them along with their offsets in the buffer.
+        updateOptions();
+    } catch (Exception& e) {
+        isc_throw(isc::Unexpected, "Failed to build packet from buffer");
+    }
+    // Update packet timestamp for RTT calculations - do not include pack time.
+    updateTimestamp();
+}
+
+void
+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_ = transid_ & 0xffffff;
+
+    // Get message type - assume it is first octet in the packet.
+    msg_type_ = data_[0];
+}
+
+void
+PerfPkt6::updateOptions() {
+    try {
+        // If there are any options on the list we will use provided options offsets
+        // to override them in the output buffer with new contents.
+        for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
+             it != options_.end(); ++it) {
+            // Get options with their position (offset).
+            boost::shared_ptr<PositionedOption> option = boost::dynamic_pointer_cast<PositionedOption>(it->second);
+            uint32_t position = option->getOptionPosition();
+            // If position is specified w need to seek to it.
+            if (position > 0) {
+                bufferOut_.clear();
+                bufferOut_.skip(position);
+            }
+            // Replace existing option with new value.
+            option->pack(bufferOut_);
+        }
+    }
+    catch (const Exception&) {
+        isc_throw(isc::Unexpected, "Failed to build packet (Option build failed");
+    }
+}
+
+void
+PerfPkt6::updateTimestamp() {
+    if (clock_gettime(CLOCK_REALTIME, &time_stamp_) < 0) {
+        isc_throw(isc::Unexpected, "Failed to get timestamp for packet");
+    }
+}
+
+} // namespace perfdhcp
+} // namespace isc

+ 224 - 0
tests/tools/perfdhcp/perf_pkt6.h

@@ -0,0 +1,224 @@
+// Copyright (C) 2011  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.
+
+#ifndef __PERF_PKT6_H
+#define __PERF_PKT6_H
+
+#include <time.h>
+
+#include <dhcp/pkt6.h>
+
+namespace isc {
+namespace perfdhcp {
+
+/// \brief PerfPkt6 (DHCPv6 packet)
+///
+/// This class extends functionality of \ref isc::dhcp::Pkt6 by
+/// adding ability to specify options offset in DHCP message
+/// and override options' contents with new option.
+/// This approach is useful when we create paket object from
+/// raw template buffer from file and we want to use it as
+/// a base to create test packets to be sent to DHCP server.
+///
+/// Some of the contents of such a template packets always
+/// have to be replaced e.g. transaction id, IA_NA. Other
+/// contents (options) may be changed e.g. elapsed time,
+/// server id.
+///
+/// In order to create packet from raw template buffer
+/// we have to pass this buffer along with transaction id
+/// offset. Class will read transaction id from the buffer.
+/// Next, in order to replace contents of selected options
+/// in a template packet, we need to add these selected options
+/// to packet object using addOption() method. Please note
+/// that options must be of the
+/// \ref isc::perfdhcp::PerfPkt6::PositionedOption type.
+///
+/// This class also records timestamps of last pack/unpack
+/// operation on the packet. This is to track DHCP server
+/// performance based on packet's send/receive duration.
+///
+/// \note: if you don't use template files simply use constructors
+/// inherited from parent class and isc::dhcp::Option type instead
+///
+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
+    /// offset in DHCPv6 message.
+    ///
+    class PositionedOption : public dhcp::Option {
+    public:
+        /// \brief Constructor, used to create positioned option from buffer
+        ///
+        ///
+        /// \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
+        /// \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);
+
+        /// \brief Constructor, used to create positioned option from buffer iterators
+        ///
+        /// 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, const OptionPosition& 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(); };
+
+    private:
+        OptionPosition position_;   ///< Absolute position of DHCPv6 option in a packet
+    };
+
+    /// Constructor, used in message transmission
+    ///
+    /// Creates new DHCPv6 message using provided buffer. New object
+    /// will keep copy of contents of provided buffer. If buffer contains
+    /// options at custom offsets (e.g. if packet was read from
+    /// template file) additional information about options'
+    /// offsets has to be provided - see
+    /// \ref isc::perfdhcp::PositionedOption for details.
+    ///
+    /// Transaction id is not considered DHCP option so
+    /// we pass it to constructor as extra argument. This is
+    /// required if transaction id offset differs from the
+    /// default one for DHCPv6 messages (ocets 2-4).
+    ///
+    /// \note use this constructor only in case you want to create
+    /// DHCPv6 message (incoming or outgoing) from the raw buffer
+    /// and you know options offsets. Options offsets are
+    /// specified from perfdhcp command line by the user.
+    ///
+    /// \param buf pointer to a buffer of received packet content
+    /// \param len size of buffer of packet content
+    /// \param xid_off transaction id offset in a packet
+    PerfPkt6(const uint8_t* buf,
+             uint32_t len,
+             const OptionPosition& transid_offset);
+
+    /// \brief Prepare on-wire packet format and record timestamp
+    ///
+    /// Prepares on-wire format of packet and all its options.
+    /// This method wraps dhcp::Pkt6::pack() function to
+    /// update packet timestamp.
+    ///
+    /// \note Use this function if you don't use template files
+    /// to construct DHCPv6 packets.
+    ///
+    /// \throw isc::Unexpected if pack and timestamp update failed
+    void stampedPack();
+
+    /// \brief Handles binary packet parsing and updates timestamp
+    ///
+    /// This method wraps dhcp::Pkt6::unpack() function to
+    /// update packet timestamp.
+    ///
+    /// \note Use this function if you don't use template files
+    /// and custom options offsets to construct DHCPv6 packets.
+    ///
+    /// \throw isc::Unexpected if function failed
+    void stampedUnpack();
+
+    /// \brief Prepares on-wire format from raw buffer
+    ///
+    /// The method copies user buffer to output buffer and
+    /// extracts transaction id from it based on transaction id
+    /// offset provided in constructor.
+    /// Eventually, this method updates packet timestamp.
+    ///
+    /// \note: Use this method to prepare on-wire DHCPv6 message
+    /// when you use template packets that require replacement
+    /// of selected options contents before sending.
+    ///
+    /// \throw isc::Unexepected if function failed
+    void stampedRawPack();
+
+    /// \brief Handles limited binary packet parsing for packets with
+    /// custom offsets of options and transaction id
+    ///
+    /// Function handles reception of packets that have non-default values
+    /// of options or transaction id offsets. Use
+    /// \ref isc::dhcp::Pkt6::addOption to specify which options to parse.
+    /// Each option should be of the: isc::perfdhcp::PerfPkt6::PositionedOption
+    /// type with offset value indicated.
+    ///
+    /// \throw isc::Unexpected if function failed
+    void stampedRawUnpack();
+
+private:
+
+    /// \brief Updates options in the output buffer
+    ///
+    /// This method updates options in the output buffer
+    /// with the ones provided with
+    /// \ref isc::dhcp::Pkt6::addOption. It is expected
+    /// that these options will be of the
+    /// \ref isc::perfdhcp::PerfPkt6::PositionedOption type
+    /// with their position (offset) specified.
+    ///
+    /// throw isc::Unexpected if options update fails
+    void updateOptions();
+
+    /// \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
+
+};
+
+} // namespace perfdhcp
+} // namespace isc
+
+#endif // __PERF_PKT6_H