Browse Source

[1959] Added support for packet templates.

Marcin Siodelski 12 years ago
parent
commit
6efd035f61

+ 56 - 4
tests/tools/perfdhcp/localized_option.h

@@ -16,6 +16,8 @@
 #define __LOCALIZED_OPTION_H
 
 #include <dhcp/pkt6.h>
+#include <dhcp/option6_ia.h>
+#include <util/buffer.h>
 
 namespace isc {
 namespace perfdhcp {
@@ -51,7 +53,7 @@ public:
                     uint16_t type,
                     const dhcp::OptionBuffer& data) :
         dhcp::Option(u, type, data),
-        offset_(0) {
+        offset_(0), option_valid_(true) {
     }
 
 
@@ -66,7 +68,49 @@ public:
                     const dhcp::OptionBuffer& data,
                     const size_t offset) :
         dhcp::Option(u, type, data),
-        offset_(offset) {
+        offset_(offset), option_valid_(true) {
+    }
+
+    /// \brief Copy constructor, creates LocalizedOption from Option6IA.
+    ///
+    /// This copy constructor creates regular option from Option6IA.
+    /// The data from Option6IA data members are copied to
+    /// option buffer in appropriate sequence.
+    ///
+    /// \param opt_ia option to be copied.
+    /// \param offset location of the option in a packet.
+    LocalizedOption(const boost::shared_ptr<dhcp::Option6IA>& opt_ia,
+                    const size_t offset) :
+        dhcp::Option(Option::V6, 0, dhcp::OptionBuffer()),
+        offset_(offset), option_valid_(false) {
+        // If given option is NULL we will mark this new option
+        // as invalid. User may query if option is valid when
+        // object is created.
+        if (opt_ia) {
+            // Set universe and type.
+            universe_ = opt_ia->getUniverse();
+            type_ = opt_ia->getType();
+            util::OutputBuffer buf(opt_ia->len() - opt_ia->getHeaderLen());
+            try {
+                // Try to pack option data into the temporary buffer.
+                opt_ia->pack(buf);
+                if (buf.getLength() > 0) {
+                    const char* buf_data = static_cast<const char*>(buf.getData());
+                    // Option has been packed along with option type flag
+                    // and transaction id so we have to skip first 4 bytes
+                    // when copying temporary buffer option buffer.
+                    data_.assign(buf_data + 4, buf_data + buf.getLength());
+                }
+                option_valid_ = true;
+            } catch (const Exception&) {
+                // If there was an exception somewhere when packing
+                // the data into the buffer we assume that option is
+                // not valid and should not be used.
+                option_valid_ = false;
+            }
+        } else {
+            option_valid_ = false;
+        }
     }
 
     /// \brief Constructor, sets default (0) option offset
@@ -84,7 +128,7 @@ public:
                     dhcp::OptionBufferConstIter first,
                     dhcp::OptionBufferConstIter last) :
         dhcp::Option(u, type, first, last),
-        offset_(0) {
+        offset_(0), option_valid_(true) {
     }
 
 
@@ -104,7 +148,7 @@ public:
                     dhcp::OptionBufferConstIter first,
                     dhcp::OptionBufferConstIter last, const size_t offset) :
         dhcp::Option(u, type, first, last),
-        offset_(offset) {
+        offset_(offset), option_valid_(true) {
     }
 
     /// \brief Returns offset of an option in a DHCP packet.
@@ -112,8 +156,16 @@ public:
     /// \return option offset in a packet
     size_t getOffset() const { return offset_; };
 
+    /// \brief Checks if option is valid.
+    ///
+    /// \return true, if option is valid.
+    virtual bool valid() {
+        return (Option::valid() && option_valid_);
+    }
+
 private:
     size_t offset_;   ///< Offset of DHCP option in a packet
+    bool option_valid_; ///< Is option valid.
 };
 
 

+ 9 - 1
tests/tools/perfdhcp/perf_pkt4.cc

@@ -16,7 +16,6 @@
 #include <dhcp/dhcp6.h>
 
 #include "perf_pkt4.h"
-#include "pkt_transform.h"
 
 using namespace std;
 using namespace isc;
@@ -58,5 +57,14 @@ PerfPkt4::rawUnpack() {
     return (res);
 }
 
+void
+PerfPkt4::writeAt(size_t dest_pos,
+                  std::vector<uint8_t>::iterator first,
+                  std::vector<uint8_t>::iterator last) {
+    return (PktTransform::writeAt(data_, dest_pos, first, last));
+}
+
+
+
 } // namespace perfdhcp
 } // namespace isc

+ 27 - 0
tests/tools/perfdhcp/perf_pkt4.h

@@ -20,6 +20,7 @@
 #include <dhcp/pkt4.h>
 
 #include "localized_option.h"
+#include "pkt_transform.h"
 
 namespace isc {
 namespace perfdhcp {
@@ -102,11 +103,37 @@ public:
     /// \return false If unpack operation failed.
     bool rawUnpack();
 
+    /// \brief Replace contents of buffer with data.
+    ///
+    /// Function replaces part of the buffer with data from vector.
+    ///
+    /// \param dest_pos position in buffer where data is replaced.
+    /// \param first beginning of data range in source vector.
+    /// \param last end of data range in source vector.
+    void writeAt(size_t dest_pos,
+                 std::vector<uint8_t>::iterator first,
+                 std::vector<uint8_t>::iterator last);
+
+    
+    /// \brief Replace contents of buffer with value.
+    ///
+    /// Function replaces part of buffer with value.
+    ///
+    /// \param dest_pos position in buffer where value is
+    /// to be written.
+    /// \param val value to be written.
+    template<typename T>
+    void writeValueAt(size_t dest_pos, T val) {
+        PktTransform::writeValueAt<T>(data_, dest_pos, val);
+    }
+
 private:
     size_t transid_offset_;      ///< transaction id offset
 
 };
 
+typedef boost::shared_ptr<PerfPkt4> PerfPkt4Ptr;
+
 } // namespace perfdhcp
 } // namespace isc
 

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

@@ -60,5 +60,13 @@ PerfPkt6::rawUnpack() {
     return (res);
 }
 
+void
+PerfPkt6::writeAt(size_t dest_pos,
+                     std::vector<uint8_t>::iterator first,
+                     std::vector<uint8_t>::iterator last) {
+    return (PktTransform::writeAt(data_, dest_pos, first, last));
+}
+
+
 } // namespace perfdhcp
 } // namespace isc

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

@@ -20,6 +20,7 @@
 #include <dhcp/pkt6.h>
 
 #include "localized_option.h"
+#include "pkt_transform.h"
 
 namespace isc {
 namespace perfdhcp {
@@ -102,11 +103,36 @@ public:
     /// \return false if unpack operation failed.
     bool rawUnpack();
 
+    /// \brief Replace contents of buffer with data.
+    ///
+    /// Function replaces part of the buffer with data from vector.
+    ///
+    /// \param dest_pos position in buffer where data is replaced.
+    /// \param first beginning of data range in source vector.
+    /// \param last end of data range in source vector.
+    void writeAt(size_t dest_pos,
+                 std::vector<uint8_t>::iterator first,
+                 std::vector<uint8_t>::iterator last);
+
+    /// \brief Replace contents of buffer with value.
+    ///
+    /// Function replaces part of buffer with value.
+    ///
+    /// \param dest_pos position in buffer where value is
+    /// to be written.
+    /// \param val value to be written.
+    template<typename T>
+    void writeValueAt(size_t dest_pos, T val) {
+        PktTransform::writeValueAt<T>(data_, dest_pos, val);
+    }
+
 private:
     size_t transid_offset_;      ///< transaction id offset
 
 };
 
+typedef boost::shared_ptr<PerfPkt6> PerfPkt6Ptr;
+
 } // namespace perfdhcp
 } // namespace isc
 

+ 12 - 1
tests/tools/perfdhcp/pkt_transform.cc

@@ -216,7 +216,18 @@ PktTransform::unpackOptions(const OptionBuffer& in_buffer,
                         in_buffer.begin() + offset + opt_len);
     }
 }
-
+    
+void
+PktTransform::writeAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos,
+                      dhcp::OptionBuffer::iterator first,
+                      dhcp::OptionBuffer::iterator last) {
+    int i = 0;
+    for (std::vector<uint8_t>::iterator it = first;
+         it != last;
+         ++it, ++i) {
+        in_buffer[dest_pos + i] = *it;
+    }
+}
 
 } // namespace perfdhcp
 } // namespace isc

+ 28 - 0
tests/tools/perfdhcp/pkt_transform.h

@@ -92,6 +92,33 @@ public:
                        const size_t transid_offset,
                        uint32_t& transid);
 
+    /// \brief Replace contents of buffer with vector.
+    ///
+    /// Function replaces data of the buffer with data from vector.
+    ///
+    /// \param in_buffer destination buffer.
+    /// \param dest_pos position in destination buffer.
+    /// \param first beginning of data range in source vector.
+    /// \param last end of data range in source vector.
+    static void writeAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos,
+                        std::vector<uint8_t>::iterator first,
+                        std::vector<uint8_t>::iterator last);
+
+    /// \brief Replace contents of one vector with uint16 value.
+    ///
+    /// Function replaces data inside one vector with uint16_t value.
+    ///
+    /// \param in_buffer destination buffer.
+    /// \param dest_pos position in destination buffer.
+    /// \param val value to be written.
+    template<typename T>
+    static void writeValueAt(dhcp::OptionBuffer& in_buffer, size_t dest_pos,
+                        T val) {
+        for (int i = 0; i < sizeof(T); ++i) {
+            in_buffer[dest_pos + i] = (val >> (sizeof(T) - 8 * i - 1)) & 0xFF;
+        }
+    }
+
 private:
     /// \brief Replaces contents of options in a buffer.
     ///
@@ -131,6 +158,7 @@ private:
     /// \throw isc::Unexpected if options unpack failed.
     static void unpackOptions(const dhcp::OptionBuffer& in_buffer,
                               const dhcp::Option::OptionCollection& options);
+
 };
 
 } // namespace perfdhcp

File diff suppressed because it is too large
+ 1 - 0
tests/tools/perfdhcp/templates/discover-example.hex


File diff suppressed because it is too large
+ 1 - 0
tests/tools/perfdhcp/templates/request4-example.hex


+ 1 - 0
tests/tools/perfdhcp/templates/request6-example.hex

@@ -0,0 +1 @@
+03da30c60001000e0001000117cf8e76000c010203060002000e0001000117cf8a5c080027a87b3400030028000000010000000a0000000e0005001820010db800010000000000000001b568000000be000000c8000800020000

+ 1 - 0
tests/tools/perfdhcp/templates/solicit-example.hex

@@ -0,0 +1 @@
+015f4e650001000e0001000117cf8e76000c010203040003000c0000000100000e01000015180006000400170018000800020000

File diff suppressed because it is too large
+ 540 - 83
tests/tools/perfdhcp/test_control.cc


+ 139 - 23
tests/tools/perfdhcp/test_control.h

@@ -48,20 +48,41 @@ namespace perfdhcp {
 class TestControl : public boost::noncopyable {
 public:
 
-    // Statistics Manager for DHCPv4.
+    /// Default transaction id offset. 
+    static const size_t DHCPV4_TRANSID_OFFSET = 4;
+    /// Default offset of MAC's last octet.
+    static const size_t DHCPV4_RANDOMIZATION_OFFSET = 35;
+    /// Default elapsed time offset.
+    static const size_t DHCPV4_ELAPSED_TIME_OFFSET = 8;
+    /// Default server id offset.
+    static const size_t DHCPV4_SERVERID_OFFSET = 54;
+    /// Default requested ip offset.
+    static const size_t DHCPV4_REQUESTED_IP_OFFSET = 240;
+    /// Default DHCPV6 transaction id offset.
+    static const size_t DHCPV6_TRANSID_OFFSET = 1;
+    /// Default DHCPV6 randomization offset (last octet of DUID)
+    static const size_t DHCPV6_RANDOMIZATION_OFFSET = 21;
+    /// Default DHCPV6 elapsed time offset.
+    static const size_t DHCPV6_ELAPSED_TIME_OFFSET = 84;
+    /// Default DHCPV6 server id offset.
+    static const size_t DHCPV6_SERVERID_OFFSET = 22;
+    /// Default DHCPV6 IA_NA offset.
+    static const size_t DHCPV6_IA_NA_OFFSET = 40;
+
+    /// Statistics Manager for DHCPv4.
     typedef StatsMgr<dhcp::Pkt4> StatsMgr4;
-    // Pointer to Statistics Manager for DHCPv4;
+    /// Pointer to Statistics Manager for DHCPv4;
     typedef boost::shared_ptr<StatsMgr4> StatsMgr4Ptr;
-    // Statictics Manager for DHCPv6.
+    /// Statictics Manager for DHCPv6.
     typedef StatsMgr<dhcp::Pkt6> StatsMgr6;
-    // Pointer to Statistics Manager for DHCPv6.
+    /// Pointer to Statistics Manager for DHCPv6.
     typedef boost::shared_ptr<StatsMgr6> StatsMgr6Ptr;
-    // Packet exchange type.
+    /// Packet exchange type.
     typedef StatsMgr<>::ExchangeType ExchangeType;
-    // Packet template buffer.
+    /// Packet template buffer.
     typedef std::vector<uint8_t> TemplateBuffer;
-    //Packet template buffers list.
-    typedef std::list<TemplateBuffer> TemplateBufferList;
+    /// Packet template buffers list.
+    typedef std::vector<TemplateBuffer> TemplateBufferCollection;
 
     /// \brief Socket wrapper class.
     ///
@@ -302,9 +323,10 @@ protected:
     /// from the MAC address, this function uses \ref generateMacAddress
     /// internally to randomize the DUID.
     ///
+    /// \param randomized number of bytes randomized.
     /// \throw isc::BadValue if \ref generateMacAddress throws.
     /// \return vector representing DUID.
-    std::vector<uint8_t> generateDuid() const;
+    std::vector<uint8_t> generateDuid(uint8_t& randomized) const;
 
     /// \brief Generate MAC address.
     ///
@@ -315,10 +337,11 @@ protected:
     /// Based on this the random value is generated and added to
     /// the MAC address prefix (default MAC address).
     ///
+    /// \param randomized number of bytes randomized.
     /// \throw isc::BadValue if MAC address prefix (default or specified
     /// from the command line) has invalid size (expected 6 octets).
     /// \return generated MAC address.
-    std::vector<uint8_t> generateMacAddress() const;
+    std::vector<uint8_t> generateMacAddress(uint8_t& randomized) const;
 
     /// \brief generate transaction id.
     ///
@@ -337,6 +360,21 @@ protected:
     /// \return number of exchanges to be started immediatelly.
     uint64_t getNextExchangesNum() const;
 
+    /// \brief Return template buffer.
+    ///
+    /// Method returns template buffer at specified index.
+    ///
+    /// \param idx index of template buffer.
+    /// \return reference to template buffer or empty buffer if index
+    /// is out of bounds.
+    TemplateBuffer getTemplateBuffer(const size_t idx) const;
+
+    /// \brief Reads packet templates from files.
+    ///
+    /// Method iterates through all specified template files, reads
+    /// their content and stores it in class internal buffers
+    ///
+    /// \throw isc::BadValue if any of the template files does not exist
     void initPacketTemplates();
 
     /// \brief Initializes Statistics Manager.
@@ -448,9 +486,9 @@ protected:
     void registerOptionFactories() const;
 
 
-    /// \brief Resets internal state of the object. 
+    /// \brief Resets internal state of the object.
     ///
-    /// Method resets internal state of the object. It has to be 
+    /// Method resets internal state of the object. It has to be
     /// called before new test is started.
     void reset();
 
@@ -472,16 +510,46 @@ protected:
     void sendDiscover4(const TestControlSocket& socket,
                        const bool preload = false);
 
+    /// \brief Send DHCPv4 DISCOVER message from template.
+    ///
+    /// Method sends DHCPv4 DISCOVER message from template. The
+    /// template data is exepcted to be in binary format. Provided
+    /// buffer is copied and parts of it are replaced with actual
+    /// data (e.g. MAC address, transaction id etc.).
+    ///
+    /// \param socket socket to be used to send the message.
+    /// \param template_buf buffer holding template packet.
+    /// \param preload preload mode, packets not included in statistics.
+    /// \throw isc::OutOfRange if randomization offset is out of bounds.
+    void sendDiscover4(const TestControlSocket& socket,
+                       const std::vector<uint8_t>& template_buf,
+                       const bool preload = false);
+
     /// \brief Send DHCPv4 REQUEST message.
     ///
     /// Method creates and sends DHCPv4 REQUEST message to the server.
     ///
     /// \param socket socket to be used to send message.
+    /// \param discover_pkt4 DISCOVER packet sent.
     /// \param offer_pkt4 OFFER packet object.
     /// \throw isc::Unexpected if unexpected error occured.
     /// \throw isc::InvalidOperation if Statistics Manager has not been
     /// initialized.
     void sendRequest4(const TestControlSocket& socket,
+                      const dhcp::Pkt4Ptr& discover_pkt4,
+                      const dhcp::Pkt4Ptr& offer_pkt4);
+
+    /// \brief Send DHCPv4 REQUEST message from template.
+    ///
+    /// Method sends DHCPv4 REQUEST message from template.
+    ///
+    /// \param socket socket to be used to send message.
+    /// \param template_buf buffer holding template packet.
+    /// \param discover_pkt4 DISCOVER packet sent.
+    /// \param offer_pkt4 OFFER packet received.
+    void sendRequest4(const TestControlSocket& socket,
+                      const std::vector<uint8_t>& template_buf,
+                      const dhcp::Pkt4Ptr& discover_pkt4,
                       const dhcp::Pkt4Ptr& offer_pkt4);
 
     /// \brief Send DHCPv6 REQUEST message.
@@ -506,6 +574,19 @@ protected:
                       const dhcp::Pkt6Ptr& solicit_pkt6,
                       const dhcp::Pkt6Ptr& advertise_pkt6);
 
+    /// \brief Send DHCPv6 REQUEST message from template.
+    ///
+    /// Method sends DHCPv6 REQUEST message from template.
+    ///
+    /// \param socket socket to be used to send message.
+    /// \param template_buf packet template buffer.
+    /// \param solicit_pkt6 SOLICIT packet object.
+    /// \param advertise_pkt6 ADVERTISE packet object.
+    void sendRequest6(const TestControlSocket& socket,
+                      const std::vector<uint8_t>& template_buf,
+                      const dhcp::Pkt6Ptr& solicit_pkt6,
+                      const dhcp::Pkt6Ptr& advertise_pkt6);
+
     /// \brief Send DHCPv6 SOLICIT message.
     ///
     /// Method creates and sends DHCPv6 SOLICIT message to the server
@@ -522,6 +603,17 @@ protected:
     void sendSolicit6(const TestControlSocket& socket,
                       const bool preload = false);
 
+    /// \brief Send DHCPv6 SOLICIT message from template.
+    ///
+    /// Method sends DHCPv6 SOLICIT message from template.
+    ///
+    /// \param socket socket to be used to send the message.
+    /// \param template_buf packet template buffer.
+    /// \param preload mode, packets not included in statistics.
+    void sendSolicit6(const TestControlSocket& socket,
+                      const std::vector<uint8_t>& template_buf,
+                      const bool preload = false);
+
     /// \brief Set default DHCPv4 packet parameters.
     ///
     /// This method sets default parameters on the DHCPv4 packet:
@@ -573,10 +665,27 @@ private:
     /// \return hex string.
     std::string byte2Hex(const uint8_t b) const;
 
-    /// \brief Generate transaction id using random function.
-    ///
-    /// \return generated transaction id value.
-    static uint32_t generateTransidRandom();
+    /// \brief Calculate elapsed time between two packets.
+    ///
+    /// \param T Pkt4Ptr or Pkt6Ptr class.
+    /// \param pkt1 first packet.
+    /// \param pkt2 second packet.
+    /// \return elapsed time in milliseconds between pkt1 and pkt2.
+    template<class T>
+    uint32_t getElapsedTime(const T& pkt1, const T& pkt2) {
+        using namespace boost::posix_time;
+        ptime pkt1_time = pkt1->getTimestamp();
+        ptime pkt2_time = pkt2->getTimestamp();
+        if (pkt1_time.is_not_a_date_time() || 
+            pkt2_time.is_not_a_date_time()) {
+            return (0);
+        }
+        time_period elapsed_period(pkt1_time, pkt2_time);
+        if (elapsed_period.is_null()) {
+            return (0);
+        }
+        return(elapsed_period.length().total_milliseconds());
+    }
 
     /// \brief Get number of received packets.
     ///
@@ -604,6 +713,18 @@ private:
     /// \param sig signal (ignored)
     static void handleInterrupt(int sig);
 
+    /// \brief Print main diagnostics data.
+    ///
+    /// Method prints main diagnostics data.
+    void printDiagnostics() const;
+
+    /// \brief Read DHCP message template from file.
+    ///
+    /// Method reads DHCP message template from file and
+    /// converts it to binary format. Read data is appended
+    /// to template_buffers_ vector.
+    void readPacketTemplate(const std::string& file_name);
+
     /// \brief Convert vector in hexadecimal string.
     ///
     /// \param vec vector to be converted.
@@ -611,11 +732,6 @@ private:
     std::string vector2Hex(const std::vector<uint8_t>& vec,
                            const std::string& separator = "") const;
 
-    /// \brief Print main diagnostics data.
-    ///
-    /// Method prints main diagnostics data.
-    void printDiagnostics() const;
-
     boost::posix_time::ptime send_due_;    ///< Due time to initiate next chunk
                                            ///< of exchanges.
     boost::posix_time::ptime last_sent_;   ///< Indicates when the last exchange
@@ -629,10 +745,10 @@ private:
     TransidGeneratorPtr transid_gen_; ///< Transaction id generator.
 
     /// Buffer holiding server id received in first packet
-    dhcp::OptionBuffer first_packet_serverid_; 
+    dhcp::OptionBuffer first_packet_serverid_;
 
     /// Packet template buffers.
-    TemplateBufferList template_buffers_;
+    TemplateBufferCollection template_buffers_;
 
     static bool interrupted_;  ///< Is program interrupted.
 };

+ 74 - 21
tests/tools/perfdhcp/tests/test_control_unittest.cc

@@ -60,7 +60,7 @@ public:
         ///
         /// \return generated transaction id.
         virtual uint32_t generate() {
-            return ++transid_;
+            return (++transid_);
         }
     private:
         uint32_t transid_; ///< Last generated transaction id.
@@ -76,6 +76,8 @@ public:
     using TestControl::generateDuid;
     using TestControl::generateMacAddress;
     using TestControl::getNextExchangesNum;
+    using TestControl::getTemplateBuffer;
+    using TestControl::initPacketTemplates;
     using TestControl::initializeStatsMgr;
     using TestControl::openSocket;
     using TestControl::receivePacket4;
@@ -109,7 +111,7 @@ public:
 
     static uint32_t generateTransidIncremental() {
         static uint32_t transid(1);
-        return ++transid;
+        return (++transid);
     }
 
     /// \brief Get local loopback interface name.
@@ -134,11 +136,11 @@ public:
                  ++addr_it) {
                 if (asiolink::IOAddress("127.0.0.1").getAddress() ==
                     addr_it->getAddress()) {
-                    return iface->getName();
+                    return (iface->getName());
                 }
             }
         }
-        return("");
+        return ("");
     }
 
     /// \brief Match requested options in the buffer with given list.
@@ -163,7 +165,7 @@ public:
                 }
             }
         }
-        return matched_num;
+        return (matched_num);
     }
 
     /// \brief Calculate the maximum vectors' mismatch position.
@@ -193,7 +195,7 @@ public:
                 n %= 256;
             }
         }
-        return unequal_pos;
+        return (unequal_pos);
     }
 
     /// brief Test generation of mulitple DUIDs
@@ -235,7 +237,8 @@ public:
                 new_duid = old_duid;
             } else {
                 std::swap(old_duid, new_duid);
-                new_duid = tc.generateDuid();
+                uint8_t randomized = 0;
+                new_duid = tc.generateDuid(randomized);
             }
             // The DUID-LLT is expected to start with DUID_LLT value
             // of 1 and hardware ethernet type equal to 1 (HWETHER_TYPE).
@@ -309,10 +312,19 @@ public:
     /// \param iterations_performed actual number of iterations.
     void testPkt4Exchange(int iterations_num,
                           int receive_num,
+                          bool use_templates,
                           int& iterations_performed) const {
         int sock_handle = 0;
         NakedTestControl tc;
         tc.initializeStatsMgr();
+
+        // Use templates files to crate packets.
+        if (use_templates) {
+            tc.initPacketTemplates();
+            ASSERT_GT(tc.getTemplateBuffer(0).size(), 0);
+            ASSERT_GT(tc.getTemplateBuffer(1).size(), 0);
+        }
+
         // Incremental transaction id generator will generate
         // predictable values of transaction id for each iteration.
         // This is important because we need to simulate reponses
@@ -326,7 +338,11 @@ public:
         TestControl::TestControlSocket sock(sock_handle);
         uint32_t transid = 0;
         for (int i = 0; i < iterations_num; ++i) {
-            ASSERT_NO_THROW(tc.sendDiscover4(sock));
+            if (use_templates) {
+                ASSERT_NO_THROW(tc.sendDiscover4(sock, tc.getTemplateBuffer(0)));
+            } else {
+                ASSERT_NO_THROW(tc.sendDiscover4(sock));
+            }
             ++transid;
             // Do not simulate responses for packets later
             // that specified as receive_num. This simulates
@@ -359,10 +375,19 @@ public:
     /// \param iterations_performed actual number of iterations.
     void testPkt6Exchange(int iterations_num,
                           int receive_num,
+                          bool use_templates,
                           int& iterations_performed) const {
         int sock_handle = 0;
         NakedTestControl tc;
         tc.initializeStatsMgr();
+
+        // Use templates files to crate packets.
+        if (use_templates) {
+            tc.initPacketTemplates();
+            ASSERT_GT(tc.getTemplateBuffer(0).size(), 0);
+            ASSERT_GT(tc.getTemplateBuffer(1).size(), 0);
+        }
+
         // Incremental transaction id generator will generate
         // predictable values of transaction id for each iteration.
         // This is important because we need to simulate reponses
@@ -379,7 +404,11 @@ public:
             // Do not simulate responses for packets later
             // that specified as receive_num. This simulates
             // packet drops.
-            ASSERT_NO_THROW(tc.sendSolicit6(sock));
+            if (use_templates) {
+                ASSERT_NO_THROW(tc.sendSolicit6(sock, tc.getTemplateBuffer(0)));
+            } else {
+                ASSERT_NO_THROW(tc.sendSolicit6(sock));
+            }
             ++transid;
             if (i < receive_num) {
                 boost::shared_ptr<Pkt6>
@@ -423,7 +452,8 @@ public:
         // Do many iterations to generate and test MAC address values.
         for (int i = 0; i < clients_num * 10; ++i) {
             // Generate new MAC address.
-            MacAddress new_mac(tc.generateMacAddress());
+            uint8_t randomized = 0;
+            MacAddress new_mac(tc.generateMacAddress(randomized));
             // Get the mismatch position (counting from the end) of
             // mismatched octet between previously generated MAC address
             // and current.
@@ -471,7 +501,7 @@ private:
         offer->addOption(opt_msg_type);
         offer->addOption(opt_serverid);
         offer->updateTimestamp();
-        return(offer);
+        return (offer);
     }
 
     boost::shared_ptr<Pkt6>
@@ -479,14 +509,15 @@ private:
         OptionPtr opt_ia_na = Option::factory(Option::V6, D6O_IA_NA);
         OptionPtr opt_serverid(new Option(Option::V6, D6O_SERVERID));
         NakedTestControl tc;
-        std::vector<uint8_t> duid(tc.generateDuid());
+        uint8_t randomized = 0;
+        std::vector<uint8_t> duid(tc.generateDuid(randomized));
         OptionPtr opt_clientid(Option::factory(Option::V6, D6O_CLIENTID, duid));
         boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE, transid));
         advertise->addOption(opt_ia_na);
         advertise->addOption(opt_serverid);
         advertise->addOption(opt_clientid);
         advertise->updateTimestamp();
-        return(advertise);
+        return (advertise);
     }
 
 };
@@ -634,8 +665,8 @@ TEST_F(TestControlTest, Options6) {
     OptionPtr opt_oro(Option::factory(Option::V6, D6O_ORO));
     // Prepare the reference buffer with requested options.
     const uint8_t requested_options[] = {
-        D6O_NAME_SERVERS,
-        D6O_DOMAIN_SEARCH
+        0, D6O_NAME_SERVERS,
+        0, D6O_DOMAIN_SEARCH
     };
     OptionBuffer
         requested_options_ref(requested_options,
@@ -751,22 +782,28 @@ TEST_F(TestControlTest, Packet4Exchange) {
     // The actual number of iterations will be stored in the
     // following variable.
     int iterations_performed = 0;
-    testPkt4Exchange(iterations_num, iterations_num, iterations_performed);
+    bool use_templates = false;
+    testPkt4Exchange(iterations_num, iterations_num, use_templates, iterations_performed);
     // The command line restricts the number of iterations to 10
     // with -n 10 parameter.
     EXPECT_EQ(10, iterations_performed);
 
     // With the following command line we restrict the maximum
     // number of dropped packets to 20% of all.
+    // Use templates for this test.
     processCmdLine("perfdhcp -l " + loopback_iface
-                   + " -r 100 -R 20 -n 20 -D 10% -L 10547 127.0.0.1");
+                   + " -r 100 -R 20 -n 20 -D 10% -L 10547"
+                   + " -T ../templates/discover-example.hex"
+                   + " -T ../templates/request4-example.hex"
+                   + " 127.0.0.1");
     // The number iterations is restricted by the percentage of
     // dropped packets (-D 10%). We also have to bump up the number
     // of iterations because the percentage limitation checks starts
     // at packet #10. We expect that at packet #12 the 10% threshold
     // will be reached.
     const int received_num = 10;
-    testPkt4Exchange(iterations_num, received_num, iterations_performed);
+    use_templates = true;
+    testPkt4Exchange(iterations_num, received_num, use_templates, iterations_performed);
     EXPECT_EQ(12, iterations_performed);
 }
 
@@ -788,22 +825,38 @@ TEST_F(TestControlTest, Packet6Exchange) {
     int iterations_performed = 0;
     // Set number of received packets equal to number of iterations.
     // This simulates no packet drops.
-    testPkt6Exchange(iterations_num, iterations_num, iterations_performed);
+    bool use_templates = false;
+    testPkt6Exchange(iterations_num, iterations_num, use_templates, iterations_performed);
     // Actual number of iterations should be 10.
     EXPECT_EQ(10, iterations_performed);
 
     // The maximum number of dropped packets is 3 (because of -D 3).
+    use_templates = true;
     processCmdLine("perfdhcp -l " + loopback_iface
-                   + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547 ::1");
+                   + " -6 -r 100 -n 10 -R 20 -D 3 -L 10547"
+                   + " -T ../templates/solicit-example.hex"
+                   + " -T ../templates/request6-example.hex ::1");
     // For the first 3 packets we are simulating responses from server.
     // For other packets we don't so packet as 4,5,6 will be dropped and
     // then test should be interrupted and actual number of iterations will
     // be 6.
     const int received_num = 3;
-    testPkt6Exchange(iterations_num, received_num, iterations_performed);
+    testPkt6Exchange(iterations_num, received_num, use_templates, iterations_performed);
     EXPECT_EQ(6, iterations_performed);
 }
 
+TEST_F(TestControlTest, PacketTemplates) {
+    CommandOptions& options = CommandOptions::instance();
+    NakedTestControl tc;
+
+    ASSERT_NO_THROW(
+        processCmdLine("perfdhcp -l 127.0.0.1"
+                       " -T ../templates/discover-example.hex"
+                       " -T ../templates/request4-example.hex all")
+    );
+    ASSERT_NO_THROW(tc.initPacketTemplates());
+}
+
 TEST_F(TestControlTest, RateControl) {
     // We don't specify the exchange rate here so the aggressivity
     // value will determine how many packets are to be send each