BIND 10 trac1959, updated. 6efd035f6178974adb48ace599f6d2335c0afd7e [1959] Added support for packet templates.

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Aug 29 16:01:53 UTC 2012


The branch, trac1959 has been updated
       via  6efd035f6178974adb48ace599f6d2335c0afd7e (commit)
      from  c47f7da793ecc7bb0486d6f78b9405803c2d2701 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 6efd035f6178974adb48ace599f6d2335c0afd7e
Author: Marcin Siodelski <marcin at isc.org>
Date:   Wed Aug 29 18:01:01 2012 +0200

    [1959] Added support for packet templates.

-----------------------------------------------------------------------

Summary of changes:
 tests/tools/perfdhcp/localized_option.h            |   60 +-
 tests/tools/perfdhcp/perf_pkt4.cc                  |   10 +-
 tests/tools/perfdhcp/perf_pkt4.h                   |   27 +
 tests/tools/perfdhcp/perf_pkt6.cc                  |    8 +
 tests/tools/perfdhcp/perf_pkt6.h                   |   26 +
 tests/tools/perfdhcp/pkt_transform.cc              |   13 +-
 tests/tools/perfdhcp/pkt_transform.h               |   28 +
 .../tools/perfdhcp/templates/discover-example.hex  |    1 +
 .../tools/perfdhcp/templates/request4-example.hex  |    1 +
 .../tools/perfdhcp/templates/request6-example.hex  |    1 +
 tests/tools/perfdhcp/templates/solicit-example.hex |    1 +
 tests/tools/perfdhcp/test_control.cc               |  623 +++++++++++++++++---
 tests/tools/perfdhcp/test_control.h                |  162 ++++-
 .../tools/perfdhcp/tests/test_control_unittest.cc  |   95 ++-
 14 files changed, 923 insertions(+), 133 deletions(-)
 create mode 100644 tests/tools/perfdhcp/templates/discover-example.hex
 create mode 100644 tests/tools/perfdhcp/templates/request4-example.hex
 create mode 100644 tests/tools/perfdhcp/templates/request6-example.hex
 create mode 100644 tests/tools/perfdhcp/templates/solicit-example.hex

-----------------------------------------------------------------------
diff --git a/tests/tools/perfdhcp/localized_option.h b/tests/tools/perfdhcp/localized_option.h
index 5374684..f93089f 100644
--- a/tests/tools/perfdhcp/localized_option.h
+++ b/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.
 };
 
 
diff --git a/tests/tools/perfdhcp/perf_pkt4.cc b/tests/tools/perfdhcp/perf_pkt4.cc
index 3f733af..3ccef94 100644
--- a/tests/tools/perfdhcp/perf_pkt4.cc
+++ b/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
diff --git a/tests/tools/perfdhcp/perf_pkt4.h b/tests/tools/perfdhcp/perf_pkt4.h
index f4cc440..1a19a08 100644
--- a/tests/tools/perfdhcp/perf_pkt4.h
+++ b/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
 
diff --git a/tests/tools/perfdhcp/perf_pkt6.cc b/tests/tools/perfdhcp/perf_pkt6.cc
index 24cfb93..56fe9df 100644
--- a/tests/tools/perfdhcp/perf_pkt6.cc
+++ b/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
diff --git a/tests/tools/perfdhcp/perf_pkt6.h b/tests/tools/perfdhcp/perf_pkt6.h
index 94fe47b..25fb4e5 100644
--- a/tests/tools/perfdhcp/perf_pkt6.h
+++ b/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
 
diff --git a/tests/tools/perfdhcp/pkt_transform.cc b/tests/tools/perfdhcp/pkt_transform.cc
index 5ed39bf..d87ca19 100644
--- a/tests/tools/perfdhcp/pkt_transform.cc
+++ b/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
diff --git a/tests/tools/perfdhcp/pkt_transform.h b/tests/tools/perfdhcp/pkt_transform.h
index 7fb19f4..e7665a2 100644
--- a/tests/tools/perfdhcp/pkt_transform.h
+++ b/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
diff --git a/tests/tools/perfdhcp/templates/discover-example.hex b/tests/tools/perfdhcp/templates/discover-example.hex
new file mode 100644
index 0000000..9a6e5ea
--- /dev/null
+++ b/tests/tools/perfdhcp/templates/discover-example.hex
@@ -0,0 +1 @@
+01010601008b45d200000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633501013707011c02030f060cff
\ No newline at end of file
diff --git a/tests/tools/perfdhcp/templates/request4-example.hex b/tests/tools/perfdhcp/templates/request4-example.hex
new file mode 100644
index 0000000..32447d6
--- /dev/null
+++ b/tests/tools/perfdhcp/templates/request4-example.hex
@@ -0,0 +1 @@
+01010601007b23f800000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633204ac1001813501033604ac1001013707011c02030f060cff
\ No newline at end of file
diff --git a/tests/tools/perfdhcp/templates/request6-example.hex b/tests/tools/perfdhcp/templates/request6-example.hex
new file mode 100644
index 0000000..1e3e76f
--- /dev/null
+++ b/tests/tools/perfdhcp/templates/request6-example.hex
@@ -0,0 +1 @@
+03da30c60001000e0001000117cf8e76000c010203060002000e0001000117cf8a5c080027a87b3400030028000000010000000a0000000e0005001820010db800010000000000000001b568000000be000000c8000800020000
\ No newline at end of file
diff --git a/tests/tools/perfdhcp/templates/solicit-example.hex b/tests/tools/perfdhcp/templates/solicit-example.hex
new file mode 100644
index 0000000..41c5ad3
--- /dev/null
+++ b/tests/tools/perfdhcp/templates/solicit-example.hex
@@ -0,0 +1 @@
+015f4e650001000e0001000117cf8e76000c010203040003000c0000000100000e01000015180006000400170018000800020000
\ No newline at end of file
diff --git a/tests/tools/perfdhcp/test_control.cc b/tests/tools/perfdhcp/test_control.cc
index c58631f..6da2549 100644
--- a/tests/tools/perfdhcp/test_control.cc
+++ b/tests/tools/perfdhcp/test_control.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+
+#include <fstream>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -25,8 +27,11 @@
 #include <dhcp/libdhcp++.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp/dhcp4.h>
+#include <dhcp/option6_ia.h>
 #include "test_control.h"
 #include "command_options.h"
+#include "perf_pkt4.h"
+#include "perf_pkt6.h"
 
 using namespace std;
 using namespace boost;
@@ -91,13 +96,13 @@ TestControl::byte2Hex(const uint8_t b) const {
     const int b0 = b % 16;
     ostringstream stream;
     stream << std::hex << b1 << b0 << std::dec;
-    return stream.str();
+    return (stream.str());
 }
 
 bool
 TestControl::checkExitConditions() const {
     if (interrupted_) {
-        return(true);
+        return (true);
     }
     CommandOptions& options = CommandOptions::instance();
     bool test_period_reached = false;
@@ -117,9 +122,9 @@ TestControl::checkExitConditions() const {
     }
     if (test_period_reached) {
         if (testDiags('e')) {
-            std::cout << "Reached test period." << std::endl;
+            std::cout << "reached test-period." << std::endl;
         }
-        return(true);
+        return (true);
     }
 
     bool max_requests = false;
@@ -153,9 +158,9 @@ TestControl::checkExitConditions() const {
     }
     if (max_requests) {
         if (testDiags('e')) {
-            std::cout << "Reached test period." << std::endl;
+            std::cout << "Reached max requests limit." << std::endl;
         }
-        return(true);
+        return (true);
     }
 
     // Check if we reached maximum number of drops of OFFER/ADVERTISE packets.
@@ -191,7 +196,7 @@ TestControl::checkExitConditions() const {
         if (testDiags('e')) {
             std::cout << "Reached maximum drops number." << std::endl;
         }
-        return(true);
+        return (true);
     }
 
     // Check if we reached maximum drops percentage of OFFER/ADVERTISE packets.
@@ -236,20 +241,19 @@ TestControl::checkExitConditions() const {
         if (testDiags('e')) {
             std::cout << "Reached maximum percentage of drops." << std::endl;
         }
-        return(true);
+        return (true);
     }
-
-    return(false);
+    return (false);
 }
 
 OptionPtr
 TestControl::factoryElapsedTime6(Option::Universe, uint16_t,
                                  const OptionBuffer& buf) {
     if (buf.size() == 2) {
-        return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf));
+        return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf)));
     } else if (buf.size() == 0) {
-        return OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
-                                    OptionBuffer(2, 0)));
+        return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
+                                     OptionBuffer(2, 0))));
     }
     isc_throw(isc::BadValue,
               "elapsed time option buffer size has to be 0 or 2");
@@ -259,7 +263,7 @@ OptionPtr
 TestControl::factoryGeneric(Option::Universe u, uint16_t type,
                             const OptionBuffer& buf) {
     OptionPtr opt(new Option(u, type, buf));
-    return opt;
+    return (opt);
 }
 
 OptionPtr
@@ -274,13 +278,13 @@ TestControl::factoryIana6(Option::Universe, uint16_t,
     for (int i = 0;  i < buf.size(); ++i) {
         buf_ia_na.push_back(buf[i]);
     }
-    return OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na));
+    return (OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)));
 }
 
 OptionPtr
 TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
                                  const OptionBuffer&) {
-    return OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer()));
+    return (OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())));
 }
 
 OptionPtr
@@ -288,11 +292,11 @@ TestControl::factoryOptionRequestOption6(Option::Universe,
                                          uint16_t,
                                          const OptionBuffer&) {
     const uint8_t buf_array[] = {
-        D6O_NAME_SERVERS,
-        D6O_DOMAIN_SEARCH
+        0, D6O_NAME_SERVERS,
+        0, D6O_DOMAIN_SEARCH
     };
     OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
-    return OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options));
+    return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)));
 }
 
 
@@ -313,15 +317,15 @@ TestControl::factoryRequestList4(Option::Universe u,
     OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
     OptionPtr opt(new Option(u, type, buf));
     opt->setData(buf_with_options.begin(), buf_with_options.end());
-    return opt;
+    return (opt);
 }
 
 std::vector<uint8_t>
-TestControl::generateMacAddress() const {
+TestControl::generateMacAddress(uint8_t& randomized) const {
     CommandOptions& options = CommandOptions::instance();
     uint32_t clients_num = options.getClientsNum();
     if ((clients_num == 0) || (clients_num == 1)) {
-        return options.getMacPrefix();
+        return (options.getMacPrefix());
     }
     // Get the base MAC address. We are going to randomize part of it.
     std::vector<uint8_t> mac_addr(options.getMacPrefix());
@@ -333,12 +337,14 @@ TestControl::generateMacAddress() const {
     // will guarantee that every client has exactly one random MAC
     // address assigned.
     r %= clients_num;
+    randomized = 0;
     // Randomize MAC address octets.
     for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
          it >= mac_addr.begin();
          --it) {
         // Add the random value to the current octet.
         (*it) += r;
+        ++randomized;
         if (r < 256) {
             // If we are here it means that there is no sense
             // to randomize the remaining octets of MAC address
@@ -350,24 +356,24 @@ TestControl::generateMacAddress() const {
         // byte of random value.
         r >>= 8;
     }
-    return mac_addr;
+    return (mac_addr);
 }
 
 std::vector<uint8_t>
-TestControl::generateDuid() const {
+TestControl::generateDuid(uint8_t& randomized) const {
     CommandOptions& options = CommandOptions::instance();
     uint32_t clients_num = options.getClientsNum();
     if ((clients_num == 0) || (clients_num == 1)) {
-        return options.getDuidPrefix();
+        return (options.getDuidPrefix());
     }
     // Get the base DUID. We are going to randomize part of it.
     std::vector<uint8_t> duid(options.getDuidPrefix());
-    std::vector<uint8_t> mac_addr(generateMacAddress());
+    std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
     duid.resize(duid.size() - mac_addr.size());
     for (int i = 0; i < mac_addr.size(); ++i) {
         duid.push_back(mac_addr[i]);
     }
-    return duid;
+    return (duid);
 }
 
 uint64_t
@@ -413,20 +419,28 @@ uint64_t
 TestControl::getRcvdPacketsNum(const ExchangeType xchg_type) const {
     uint8_t ip_version = CommandOptions::instance().getIpVersion();
     if (ip_version == 4) {
-        return(stats_mgr4_->getRcvdPacketsNum(xchg_type));
+        return (stats_mgr4_->getRcvdPacketsNum(xchg_type));
     }
-    return(stats_mgr6_->
-           getRcvdPacketsNum(static_cast<StatsMgr6::ExchangeType>(xchg_type)));
+    return (stats_mgr6_->
+            getRcvdPacketsNum(static_cast<StatsMgr6::ExchangeType>(xchg_type)));
 }
 
 uint64_t
 TestControl::getSentPacketsNum(const ExchangeType xchg_type) const {
     uint8_t ip_version = CommandOptions::instance().getIpVersion();
     if (ip_version == 4) {
-        return(stats_mgr4_->getSentPacketsNum(xchg_type));
+        return (stats_mgr4_->getSentPacketsNum(xchg_type));
+    }
+    return (stats_mgr6_->
+            getSentPacketsNum(static_cast<StatsMgr6::ExchangeType>(xchg_type)));
+}
+
+TestControl::TemplateBuffer
+TestControl::getTemplateBuffer(const size_t idx) const {
+    if (template_buffers_.size() > idx) {
+        return (template_buffers_[idx]);
     }
-    return(stats_mgr6_->
-           getSentPacketsNum(static_cast<StatsMgr6::ExchangeType>(xchg_type)));
+    return (TemplateBuffer());
 }
 
 void
@@ -436,13 +450,13 @@ TestControl::handleInterrupt(int) {
 
 void
 TestControl::initPacketTemplates() {
+    template_buffers_.clear();
     CommandOptions& options = CommandOptions::instance();
     std::vector<std::string> template_files = options.getTemplateFiles();
     for (std::vector<std::string>::const_iterator it = template_files.begin();
          it != template_files.end();
          ++it) {
-
-        std::cout << "Open file " << *it << std::endl;
+        readPacketTemplate(*it);
     }
 }
 
@@ -565,7 +579,7 @@ TestControl::openSocket() const {
         }
     }
 
-    return(sock);
+    return (sock);
 }
 
 void
@@ -574,7 +588,6 @@ TestControl::printDiagnostics() const {
     if (testDiags('a')) {
         // Print all command line parameters.
         options.printCommandLine();
-        
         // Print MAC and DUID.
         std::cout << "Set MAC to " << vector2Hex(options.getMacPrefix(), "::")
                   << std::endl;
@@ -661,7 +674,38 @@ TestControl::vector2Hex(const std::vector<uint8_t>& vec,
             stream << separator << byte2Hex(*it);
         }
     }
-    return(stream.str());
+    return (stream.str());
+}
+
+void
+TestControl::readPacketTemplate(const std::string& file_name) {
+    std::ifstream temp_file;
+    temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate);
+    if (!temp_file.is_open()) {
+        isc_throw(BadValue, "unable to open template file " << file_name);
+    }
+    std::ifstream::pos_type temp_size = temp_file.tellg();
+    if (temp_size % 2 != 0) {
+        temp_file.close();
+        isc_throw(BadValue, "odd number of digits in template file");
+    }
+    temp_file.seekg(0, ios::beg);
+    std::vector<char> hex_digits(temp_size);
+    std::vector<uint8_t> binary_stream;
+    temp_file.read(&hex_digits[0], temp_size);
+    temp_file.close();
+    for (int i = 0; i < hex_digits.size(); i += 2) {
+        if (!isxdigit(hex_digits[i]) || !isxdigit(hex_digits[i+1])) {
+            isc_throw(BadValue, "the '" << hex_digits[i] << hex_digits[i+1]
+                      << "' is not hexadecimal digit");
+        }
+        stringstream s;
+        s << "0x" << hex_digits[i] << hex_digits[i+1];
+        int b;
+        s >> std::hex >> b;
+        binary_stream.push_back(static_cast<uint8_t>(b));
+    }
+    template_buffers_.push_back(binary_stream);
 }
 
 void
@@ -673,7 +717,11 @@ TestControl::receivePacket4(const TestControlSocket& socket,
         CommandOptions::ExchangeMode xchg_mode =
             CommandOptions::instance().getExchangeMode();
         if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
-            sendRequest4(socket, pkt4);
+            if (template_buffers_.size() < 2) {
+                sendRequest4(socket, discover_pkt4, pkt4);
+            } else {
+                sendRequest4(socket, template_buffers_[1], discover_pkt4, pkt4);
+            }
         }
     } else if (pkt4->getType() == DHCPACK) {
         stats_mgr4_->passRcvdPacket(StatsMgr4::XCHG_RA, pkt4);
@@ -690,7 +738,11 @@ TestControl::receivePacket6(const TestControlSocket& socket,
         CommandOptions::ExchangeMode xchg_mode =
             CommandOptions::instance().getExchangeMode();
         if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
-            sendRequest6(socket, solicit_pkt6, pkt6);
+            if (template_buffers_.size() < 2) {
+                sendRequest6(socket, solicit_pkt6, pkt6);
+            } else {
+                sendRequest6(socket, template_buffers_[1], solicit_pkt6, pkt6);
+            }
         }
     } else if (packet_type == DHCPV6_REPLY) {
         stats_mgr6_->passRcvdPacket(StatsMgr6::XCHG_RR, pkt6);
@@ -740,6 +792,7 @@ TestControl::registerOptionFactories4() const {
         LibDHCP::OptionFactoryRegister(Option::V4,
                                        DHO_DHCP_MESSAGE_TYPE,
                                        &TestControl::factoryGeneric);
+        // DHCP_SERVER_IDENTIFIER option factory.
         LibDHCP::OptionFactoryRegister(Option::V4,
                                        DHO_DHCP_SERVER_IDENTIFIER,
                                        &TestControl::factoryGeneric);
@@ -755,21 +808,27 @@ void
 TestControl::registerOptionFactories6() const {
     static bool factories_registered = false;
     if (!factories_registered) {
+        // D60_ELAPSED_TIME
         LibDHCP::OptionFactoryRegister(Option::V6,
                                        D6O_ELAPSED_TIME,
                                        &TestControl::factoryElapsedTime6);
+        // D6O_RAPID_COMMIT
         LibDHCP::OptionFactoryRegister(Option::V6,
                                        D6O_RAPID_COMMIT,
                                        &TestControl::factoryRapidCommit6);
+        // D6O_ORO (option request option) factory.
         LibDHCP::OptionFactoryRegister(Option::V6,
                                        D6O_ORO,
                                        &TestControl::factoryOptionRequestOption6);
+        // D6O_CLIENTID option factory.
         LibDHCP::OptionFactoryRegister(Option::V6,
                                        D6O_CLIENTID,
                                        &TestControl::factoryGeneric);
+        // D6O_SERVERID option factory.
         LibDHCP::OptionFactoryRegister(Option::V6,
                                        D6O_SERVERID,
                                        &TestControl::factoryGeneric);
+        // D6O_IA_NA option factory.
         LibDHCP::OptionFactoryRegister(Option::V6,
                                        D6O_IA_NA,
                                        &TestControl::factoryIana6);
@@ -821,39 +880,57 @@ TestControl::run() {
                   "command options must be parsed before running a test");
     }
 
+    // Diagnostics is command line options mainly.
     printDiagnostics();
-
+    // Option factories have to be registered.
     registerOptionFactories();
     TestControlSocket socket(openSocket());
-
     // Initialize packet templates.
     initPacketTemplates();
-
     // Initialize randomization seed.
     if (options.isSeeded()) {
         srandom(options.getSeed());
     }
-
     // If user interrupts the program we will exit gracefully.
     signal(SIGINT, TestControl::handleInterrupt);
-
     // Preload server with number of packets.
     const bool do_preload = true;
     for (int i = 0; i < options.getPreload(); ++i) {
         if (options.getIpVersion() == 4) {
-            sendDiscover4(socket, do_preload);
+            // No template buffer means no -T option specified.
+            // We will build packet ourselfs.
+            if (template_buffers_.size() == 0) {
+                sendDiscover4(socket, do_preload);
+            } else {
+                const uint8_t template_idx = 0;
+                sendDiscover4(socket, template_buffers_[template_idx],
+                              do_preload);
+            }
         } else if (options.getIpVersion() == 6) {
-            sendSolicit6(socket, do_preload);
+            // No template buffer means no -T option specified.
+            // We will build packet ourselfs.
+            if (template_buffers_.size() == 0) {
+                sendSolicit6(socket, do_preload);
+            } else {
+                const uint8_t template_idx = 0;
+                sendSolicit6(socket, template_buffers_[template_idx],
+                             do_preload);
+            }
         }
     }
-
+    // Initialize Statistics Manager. Release previous if any.
     initializeStatsMgr();
-
     for (;;) {
+        // Calculate send due based on when last exchange was initiated.
         updateSendDue();
+        // If test period finished, maximum number of packet drops
+        // has been reached or test has been interrupted we have to
+        // finish the test.
         if (checkExitConditions()) {
             break;
         }
+        // Calculate number of packets to be sent to stay
+        // catch up with rate.
         uint64_t packets_due = getNextExchangesNum();
         if ((packets_due == 0) && testDiags('i')) {
             if (options.getIpVersion() == 4) {
@@ -866,19 +943,36 @@ TestControl::run() {
         // @todo: set non-zero timeout for packets once we implement
         // microseconds timeout in IfaceMgr.
         receivePackets(socket);
-
+        // Send packets.
         for (uint64_t i = packets_due; i > 0; --i) {
             if (options.getIpVersion() == 4) {
-                sendDiscover4(socket);
+                // No template packets means that no -T option was specified.
+                // We have to build packets ourselfs.
+                if (template_buffers_.size() == 0) {
+                    sendDiscover4(socket);
+                } else {
+                    const uint8_t template_idx = 0;
+                    sendDiscover4(socket, template_buffers_[template_idx]);
+                }
             } else {
-                sendSolicit6(socket);
+                // No template packets means that no -T option was specified.
+                // We have to build packets ourselfs.
+                if (template_buffers_.size() == 0) {
+                    sendSolicit6(socket);
+                } else {
+                    const uint8_t template_idx = 0;
+                    sendSolicit6(socket, template_buffers_[template_idx]);
+                }
             }
         }
+        // Report delay means that user requested printing number
+        // of sent/received/dropped packets repeatedly.
         if (options.getReportDelay() > 0) {
             printIntermediateStats();
         }
     }
     printStats();
+    // Print server id.
     if (testDiags('s') && (first_packet_serverid_.size() > 0)) {
         std::cout << "Server id: " << vector2Hex(first_packet_serverid_) << std::endl;
     }
@@ -893,7 +987,8 @@ TestControl::sendDiscover4(const TestControlSocket& socket,
                            const bool preload /*= false*/) {
     last_sent_ = microsec_clock::universal_time();
     // Generate the MAC address to be passed in the packet.
-    std::vector<uint8_t> mac_address = generateMacAddress();
+    uint8_t randomized = 0;
+    std::vector<uint8_t> mac_address = generateMacAddress(randomized);
     // Generate trasnaction id to be set for the new exchange.
     const uint32_t transid = generateTransid();
     Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, transid));
@@ -911,6 +1006,10 @@ TestControl::sendDiscover4(const TestControlSocket& socket,
     // Set client's and server's ports as well as server's address,
     // and local (relay) address.
     setDefaults4(socket, pkt4);
+
+    // Set hardware address
+    pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address);
+
     pkt4->pack();
     IfaceMgr::instance().send(pkt4);
     if (!preload) {
@@ -923,7 +1022,69 @@ TestControl::sendDiscover4(const TestControlSocket& socket,
 }
 
 void
+TestControl::sendDiscover4(const TestControlSocket& socket,
+                           const std::vector<uint8_t>& template_buf,
+                           const bool preload /* = false */) {
+    // last_sent_ has to be updated for each function that initiates
+    // new transaction. The packet exchange synchronization relies on this.
+    last_sent_ = microsec_clock::universal_time();
+    CommandOptions& options = CommandOptions::instance();
+    // Get the first argument if mulitple the same arguments specified
+    // in the command line. First one refers to DISCOVER packets.
+    const uint8_t arg_idx = 0;
+    // Generate the MAC address to be passed in the packet.
+    uint8_t randomized = 0;
+    std::vector<uint8_t> mac_address = generateMacAddress(randomized);
+    // Generate trasnaction id to be set for the new exchange.
+    const uint32_t transid = generateTransid();
+    // Get transaction id offset.
+    size_t transid_offset = DHCPV4_TRANSID_OFFSET;
+    if (options.getTransactionIdOffset().size() > arg_idx) {
+        transid_offset = options.getTransactionIdOffset()[arg_idx];
+    }
+    // Calculate randomization offset.
+    size_t rand_offset = DHCPV4_RANDOMIZATION_OFFSET;
+    if (options.getRandomOffset().size() > arg_idx) {
+        rand_offset = options.getRandomOffset()[arg_idx];
+    }
+    // We need to go back by HW_ETHER_LEN (MAC address length)
+    // because this offset points to last octet of MAC address.
+    rand_offset -= HW_ETHER_LEN + 1;
+    // Create temporary buffer with template contents. We will
+    // modify this temporary buffer but we don't want to modify
+    // the original template.
+    std::vector<uint8_t> in_buf(template_buf.begin(),
+                                template_buf.end());
+    // Check if we are not going out of bounds.
+    if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
+        isc_throw(OutOfRange, "randomization offset is out of bounds");
+    }
+    PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
+                                  transid_offset,
+                                  transid));
+
+    // Replace MAC address in the template with actual MAC address.
+    pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
+    // Create a packet from the temporary buffer.
+    setDefaults4(socket, static_pointer_cast<Pkt4>(pkt4));
+    // Pack the input packet buffer to output buffer so as it can
+    // be sent to server.
+    pkt4->rawPack();
+    IfaceMgr::instance().send(static_pointer_cast<Pkt4>(pkt4));
+    if (!preload) {
+        if (!stats_mgr4_) {
+            isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
+                      "hasn't been initialized");
+        }
+        // Update packet stats.
+        stats_mgr4_->passSentPacket(StatsMgr4::XCHG_DO,
+                                    static_pointer_cast<Pkt4>(pkt4));
+    }
+}
+
+void
 TestControl::sendRequest4(const TestControlSocket& socket,
+                          const dhcp::Pkt4Ptr& discover_pkt4,
                           const dhcp::Pkt4Ptr& offer_pkt4) {
     const uint32_t transid = generateTransid();
     Pkt4Ptr pkt4(new Pkt4(DHCPREQUEST, transid));
@@ -958,7 +1119,7 @@ TestControl::sendRequest4(const TestControlSocket& socket,
     OptionPtr opt_requested_address =
         OptionPtr(new Option(Option::V4, DHO_DHCP_REQUESTED_ADDRESS,
                              OptionBuffer()));
-    opt_requested_address->setUint32(yiaddr);
+    opt_requested_address->setUint32(static_cast<uint32_t>(yiaddr));
     pkt4->addOption(opt_requested_address);
     OptionPtr opt_parameter_list =
         Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST);
@@ -966,6 +1127,15 @@ TestControl::sendRequest4(const TestControlSocket& socket,
     // Set client's and server's ports as well as server's address,
     // and local (relay) address.
     setDefaults4(socket, pkt4);
+
+    // Set hardware address
+    const uint8_t* chaddr = offer_pkt4->getChaddr();
+    std::vector<uint8_t> mac_address(chaddr, chaddr + HW_ETHER_LEN);
+    pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address);
+    // Set elapsed time.
+    uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
+    pkt4->setSecs(static_cast<uint16_t>(elapsed_time / 1000));
+    // Prepare on wire data to send.
     pkt4->pack();
     IfaceMgr::instance().send(pkt4);
     if (!stats_mgr4_) {
@@ -975,6 +1145,124 @@ TestControl::sendRequest4(const TestControlSocket& socket,
     stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA, pkt4);
 }
 
+void
+TestControl::sendRequest4(const TestControlSocket& socket,
+                          const std::vector<uint8_t>& template_buf,
+                          const dhcp::Pkt4Ptr& discover_pkt4,
+                          const dhcp::Pkt4Ptr& offer_pkt4) {
+    CommandOptions& options = CommandOptions::instance();
+    // Get the second argument if multiple the same arguments specified
+    // in the command line. Second one refers to REQUEST packets.
+    const uint8_t arg_idx = 1;
+    // Generate new transaction id.
+    const uint32_t transid = generateTransid();
+    // Get transaction id offset.
+    size_t transid_offset = DHCPV4_TRANSID_OFFSET;
+    if (options.getTransactionIdOffset().size() > arg_idx) {
+        transid_offset = options.getTransactionIdOffset()[arg_idx];
+    }
+    // Get the offset of MAC's last octet.
+    size_t rand_offset = DHCPV4_RANDOMIZATION_OFFSET;
+    if (options.getRandomOffset().size() > arg_idx) {
+        rand_offset = options.getRandomOffset()[arg_idx];
+    }
+    // We need to go back by HW_ETHER_LEN (MAC address length)
+    // because this offset points to last octet of MAC address.
+    rand_offset -= HW_ETHER_LEN + 1;
+    // Create temporaru buffer from the template.
+    std::vector<uint8_t> in_buf(template_buf.begin(),
+                                template_buf.end());
+    // Check if given randomization offset is not out of bounds.
+    if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
+        isc_throw(OutOfRange, "randomization offset is out of bounds");
+    }
+
+    // Create packet from the temporary buffer.
+    PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
+                                  transid_offset,
+                                  transid));
+
+     // Set hardware address from OFFER packet received.
+    const uint8_t* chaddr = offer_pkt4->getChaddr();
+    std::vector<uint8_t> mac_address(chaddr, chaddr + HW_ETHER_LEN);
+    pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
+
+   // Set elapsed time.
+    size_t elp_offset = 0;
+    if (options.getElapsedTimeOffset() > 0) {
+        elp_offset = options.getElapsedTimeOffset();
+    }
+    uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
+    pkt4->writeValueAt<uint16_t>(elp_offset,
+                                 static_cast<uint16_t>(elapsed_time / 1000));
+
+    // Get the actual server id offset.
+    size_t sid_offset = DHCPV4_SERVERID_OFFSET;
+    if (options.getServerIdOffset() > 0) {
+        sid_offset = options.getServerIdOffset();
+    }
+    if (CommandOptions::instance().isUseFirst() &&
+        (first_packet_serverid_.size() > 0)) {
+        boost::shared_ptr<LocalizedOption>
+            opt_serverid(new LocalizedOption(Option::V4,
+                                             DHO_DHCP_SERVER_IDENTIFIER,
+                                             first_packet_serverid_,
+                                             sid_offset));
+        pkt4->addOption(opt_serverid);
+    } else {
+        // Copy the contents of server identifier received in
+        // OFFER packet to put this into REQUEST.
+        OptionPtr opt_serverid_offer =
+            offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
+        if (!opt_serverid_offer) {
+            isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
+                      << "in OFFER message");
+        }
+        boost::shared_ptr<LocalizedOption>
+            opt_serverid(new LocalizedOption(Option::V4,
+                                             DHO_DHCP_SERVER_IDENTIFIER,
+                                             opt_serverid_offer->getData(),
+                                             sid_offset));
+        pkt4->addOption(opt_serverid);
+        if (stats_mgr4_->getRcvdPacketsNum(StatsMgr4::XCHG_DO) == 1) {
+            first_packet_serverid_ = opt_serverid_offer->getData();
+        }
+    }
+
+    /// Set client address.
+    asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
+    if (!yiaddr.getAddress().is_v4()) {
+        isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
+                  " IPv4 address");
+    }
+
+    // Get the actual offset of requested ip.
+    size_t rip_offset = DHCPV4_REQUESTED_IP_OFFSET;
+    if (options.getRequestedIpOffset() > 0) {
+        rip_offset = options.getRequestedIpOffset();
+    }
+    // Place requested IP option at specified position (rip_offset).
+    boost::shared_ptr<LocalizedOption>
+        opt_requested_ip(new LocalizedOption(Option::V4,
+                                             DHO_DHCP_REQUESTED_ADDRESS,
+                                             OptionBuffer(),
+                                             rip_offset));
+    // The IOAddress is castable to uint32_t and returns exactly what we need.
+    opt_requested_ip->setUint32(static_cast<uint32_t>(yiaddr));
+    pkt4->addOption(opt_requested_ip);
+
+    setDefaults4(socket, static_pointer_cast<Pkt4>(pkt4));
+    // Prepare on-wire data.
+    pkt4->rawPack();
+    IfaceMgr::instance().send(static_pointer_cast<Pkt4>(pkt4));
+    if (!stats_mgr4_) {
+        isc_throw(InvalidOperation, "Statistics Manager for DHCPv4 "
+                  "hasn't been initialized");
+    }
+    // Update packet stats.
+    stats_mgr4_->passSentPacket(StatsMgr4::XCHG_RA,
+                                static_pointer_cast<Pkt4>(pkt4));
+}
 
 void
 TestControl::sendRequest6(const TestControlSocket& socket,
@@ -982,31 +1270,22 @@ TestControl::sendRequest6(const TestControlSocket& socket,
                           const Pkt6Ptr& advertise_pkt6) {
     const uint32_t transid = generateTransid();
     Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid));
-    // Calculate elapsed time
-    ptime solicit_time = solicit_pkt6->getTimestamp();
-    ptime advertise_time = advertise_pkt6->getTimestamp();
-    if (solicit_time.is_not_a_date_time()) {
-        isc_throw(Unexpected, "timestamp was not set for SOLICIT packet");
-    }
-    if (advertise_time.is_not_a_date_time()) {
-        isc_throw(Unexpected, "timestamp was not set for ADVERTISE packet");
-    }
-    time_period period(solicit_time, advertise_time);
-    if (period.is_null()) {
-        pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
-    } else {
-        OptionBuffer buf();
-        const uint32_t elapsed_time = period.length().total_seconds();
-        OptionPtr opt_elapsed_time =
-            Option::factory(Option::V6, D6O_ELAPSED_TIME);
-        opt_elapsed_time->setUint16(static_cast<uint16_t>(elapsed_time));
-        pkt6->addOption(opt_elapsed_time);
-    }
+    // Set elapsed time.
+    const uint32_t elapsed_time =
+        getElapsedTime<Pkt6Ptr>(solicit_pkt6, advertise_pkt6);
+    OptionPtr opt_elapsed_time =
+        Option::factory(Option::V6, D6O_ELAPSED_TIME);
+    opt_elapsed_time->setUint16(static_cast<uint16_t>(elapsed_time / 10));
+    pkt6->addOption(opt_elapsed_time);
+    // Set client id.
     OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID);
     if (!opt_clientid) {
         isc_throw(Unexpected, "client id not found in received packet");
     }
     pkt6->addOption(opt_clientid);
+
+    // Use first flags indicates that we want to use the server
+    // id captured in fisrt packet.
     if (CommandOptions::instance().isUseFirst() &&
         (first_packet_serverid_.size() > 0)) {
         pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID,
@@ -1021,14 +1300,17 @@ TestControl::sendRequest6(const TestControlSocket& socket,
         }
         pkt6->addOption(opt_serverid);
     }
+    // Set IA_NA option.
     OptionPtr opt_ia_na = advertise_pkt6->getOption(D6O_IA_NA);
     if (!opt_ia_na) {
         isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
                   "packet");
     }
     pkt6->addOption(opt_ia_na);
-    setDefaults6(socket, pkt6);
 
+    // Set default packet data.
+    setDefaults6(socket, pkt6);
+    // Prepare on-wire data.
     pkt6->pack();
     IfaceMgr::instance().send(pkt6);
     if (!stats_mgr6_) {
@@ -1039,13 +1321,139 @@ TestControl::sendRequest6(const TestControlSocket& socket,
 }
 
 void
+TestControl::sendRequest6(const TestControlSocket& socket,
+                          const std::vector<uint8_t>& template_buf,
+                          const Pkt6Ptr& solicit_pkt6,
+                          const Pkt6Ptr& advertise_pkt6) {
+    CommandOptions& options = CommandOptions::instance();
+    // Get the second argument if multiple the same arguments specified
+    // in the command line. Second one refers to REQUEST packets.
+    const uint8_t arg_idx = 1;
+    // Generate transaction id.
+    const uint32_t transid = generateTransid();
+    // Get transaction id offset.
+    size_t transid_offset = DHCPV6_TRANSID_OFFSET;
+    if (options.getTransactionIdOffset().size() > arg_idx) {
+        transid_offset = options.getTransactionIdOffset()[arg_idx];
+    }
+    PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
+                                  transid_offset, transid));
+    // Set elapsed time.
+    size_t elp_offset = DHCPV6_ELAPSED_TIME_OFFSET;
+    if (options.getElapsedTimeOffset() > 0) {
+        elp_offset = options.getElapsedTimeOffset();
+    }
+    uint32_t elapsed_time =
+        getElapsedTime<Pkt6Ptr>(solicit_pkt6, advertise_pkt6);
+    boost::shared_ptr<LocalizedOption>
+        opt_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME,
+                                             OptionBuffer(), elp_offset));
+    opt_elapsed_time->setUint16(static_cast<uint16_t>(elapsed_time / 10));
+    pkt6->addOption(opt_elapsed_time);
+
+    // Get the actual server id offset.
+    size_t sid_offset = DHCPV6_SERVERID_OFFSET;
+    if (options.getServerIdOffset() > 0) {
+        sid_offset = options.getServerIdOffset();
+    }
+    if (CommandOptions::instance().isUseFirst() &&
+        (first_packet_serverid_.size() > 0)) {
+        boost::shared_ptr<LocalizedOption>
+            opt_serverid(new LocalizedOption(Option::V6,
+                                             D6O_SERVERID,
+                                             first_packet_serverid_,
+                                             sid_offset));
+        pkt6->addOption(opt_serverid);
+
+    } else {
+        // Copy the contents of server identifier received in
+        // ADVERTISE packet to put this into REQUEST.
+        OptionPtr opt_serverid_advertise =
+            advertise_pkt6->getOption(D6O_SERVERID);
+        if (!opt_serverid_advertise) {
+            isc_throw(BadValue, "there is no SERVERID option "
+                      << "in ADVERTISE message");
+        }
+        boost::shared_ptr<LocalizedOption>
+            opt_serverid(new LocalizedOption(Option::V6,
+                                             D6O_SERVERID,
+                                             opt_serverid_advertise->getData(),
+                                             sid_offset));
+        pkt6->addOption(opt_serverid);
+        if (stats_mgr6_->getRcvdPacketsNum(StatsMgr6::XCHG_SA) == 1) {
+            first_packet_serverid_ = opt_serverid_advertise->getData();
+        }
+    }
+    // Set IA_NA
+    boost::shared_ptr<Option6IA> opt_ia_na_advertise =
+       static_pointer_cast<Option6IA>(advertise_pkt6->getOption(D6O_IA_NA));
+    if (!opt_ia_na_advertise) {
+        isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
+                  "packet");
+    }
+    size_t addr_offset = DHCPV6_IA_NA_OFFSET;
+    if (options.getRequestedIpOffset() > 0) {
+        addr_offset = options.getRequestedIpOffset();
+    }
+    boost::shared_ptr<LocalizedOption>
+        opt_ia_na(new LocalizedOption(opt_ia_na_advertise, addr_offset));
+    if (!opt_ia_na->valid()) {
+        isc_throw(BadValue, "Option IA_NA in advertise packet is invalid");
+    }
+    pkt6->addOption(opt_ia_na);
+    // Set server id.
+    OptionPtr opt_serverid_advertise = advertise_pkt6->getOption(D6O_SERVERID);
+    if (!opt_serverid_advertise) {
+        isc_throw(Unexpected, "DHCPV6 SERVERID option not found in received "
+                  "packet");
+    }
+    size_t srvid_offset = DHCPV6_SERVERID_OFFSET;
+    if (options.getServerIdOffset() > 0) {
+        srvid_offset = options.getServerIdOffset();
+    }
+    boost::shared_ptr<LocalizedOption>
+        opt_serverid(new LocalizedOption(Option::V6, D6O_SERVERID,
+                                         opt_serverid_advertise->getData(),
+                                         srvid_offset));
+    pkt6->addOption(opt_serverid);
+    // Get randomization offset.
+    size_t rand_offset = DHCPV6_RANDOMIZATION_OFFSET;
+    if (options.getRandomOffset().size() > arg_idx) {
+        rand_offset = options.getRandomOffset()[arg_idx];
+    }
+    OptionPtr opt_clientid_advertise = advertise_pkt6->getOption(D6O_CLIENTID);
+    if (!opt_clientid_advertise) {
+        isc_throw(Unexpected, "DHCPV6 CLIENTID option not found in received packet");
+    }
+    rand_offset -= (opt_clientid_advertise->len() - 1);
+    // Set client id.
+    boost::shared_ptr<LocalizedOption>
+        opt_clientid(new LocalizedOption(Option::V6, D6O_CLIENTID,
+                                         opt_clientid_advertise->getData(),
+                                         rand_offset));
+    pkt6->addOption(opt_clientid);
+    // Set default packet data.
+    setDefaults6(socket, pkt6);
+    // Prepare on wire data.
+    pkt6->rawPack();
+    // Send packet.
+    IfaceMgr::instance().send(pkt6);
+    if (!stats_mgr6_) {
+        isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
+                  "hasn't been initialized");
+    }
+    // Update packet stats.
+    stats_mgr6_->passSentPacket(StatsMgr6::XCHG_RR, pkt6);
+
+}
+
+void
 TestControl::sendSolicit6(const TestControlSocket& socket,
                           const bool preload /*= false*/) {
     last_sent_ = microsec_clock::universal_time();
-    // Generate the MAC address to be passed in the packet.
-    std::vector<uint8_t> mac_address = generateMacAddress();
     // Generate DUID to be passed to the packet
-    std::vector<uint8_t> duid = generateDuid();
+    uint8_t randomized = 0;
+    std::vector<uint8_t> duid = generateDuid(randomized);
     // Generate trasnaction id to be set for the new exchange.
     const uint32_t transid = generateTransid();
     Pkt6Ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
@@ -1073,6 +1481,58 @@ TestControl::sendSolicit6(const TestControlSocket& socket,
 }
 
 void
+TestControl::sendSolicit6(const TestControlSocket& socket,
+                          const std::vector<uint8_t>& template_buf,
+                          const bool preload /*= false*/) {
+    last_sent_ = microsec_clock::universal_time();
+    CommandOptions& options = CommandOptions::instance();
+    const int arg_idx = 0;
+    // Get transaction id offset.
+    size_t transid_offset = DHCPV6_TRANSID_OFFSET;
+    if (options.getTransactionIdOffset().size() > arg_idx) {
+        transid_offset = options.getTransactionIdOffset()[arg_idx];
+    }
+    // Generate trasnaction id to be set for the new exchange.
+    const uint32_t transid = generateTransid();
+    // Create packet.
+    PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
+                                  transid_offset, transid));
+    if (!pkt6) {
+        isc_throw(Unexpected, "failed to create SOLICIT packet");
+    }
+    size_t rand_offset = DHCPV6_RANDOMIZATION_OFFSET;
+    if (options.getRandomOffset().size() > arg_idx) {
+        rand_offset = options.getRandomOffset()[arg_idx];
+    }
+    // randomized will pick number of bytes randomized so we can
+    // just use part of the generated duid and substitude a few bytes
+    /// in template.
+    uint8_t randomized = 0;
+    std::vector<uint8_t> duid = generateDuid(randomized);
+    if (rand_offset > template_buf.size()) {
+        isc_throw(OutOfRange, "randomization offset is out of bounds");
+    }
+    // Store random part of the DUID into the packet.
+    pkt6->writeAt(rand_offset - randomized + 1,
+                  duid.end() - randomized, duid.end());
+
+    // Prepare on-wire data.
+    pkt6->rawPack();
+    setDefaults6(socket, pkt6);
+    // Send solicit packet.
+    IfaceMgr::instance().send(pkt6);
+    if (!preload) {
+        if (!stats_mgr6_) {
+            isc_throw(InvalidOperation, "Statistics Manager for DHCPv6 "
+                      "hasn't been initialized");
+        }
+        // Update packet stats.
+        stats_mgr6_->passSentPacket(StatsMgr6::XCHG_SA, pkt6);
+    }
+}
+
+
+void
 TestControl::setDefaults4(const TestControlSocket& socket,
                           const Pkt4Ptr& pkt) {
     CommandOptions& options = CommandOptions::instance();
@@ -1090,9 +1550,6 @@ TestControl::setDefaults4(const TestControlSocket& socket,
     pkt->setLocalAddr(IOAddress(socket.getAddress()));
     // Set relay (GIADDR) address to local address.
     pkt->setGiaddr(IOAddress(socket.getAddress()));
-    std::vector<uint8_t> mac = generateMacAddress();
-    // Set hardware address
-    pkt->setHWAddr(HTYPE_ETHER, mac.size(), mac);
     // Pretend that we have one relay (which is us).
     pkt->setHops(1);
 }
@@ -1119,9 +1576,9 @@ bool
 TestControl::testDiags(const char diag) const {
     std::string diags(CommandOptions::instance().getDiags());
     if (diags.find(diag) != std::string::npos) {
-        return true;
+        return (true);
     }
-    return false;
+    return (false);
 }
 
 void
diff --git a/tests/tools/perfdhcp/test_control.h b/tests/tools/perfdhcp/test_control.h
index 9b634ce..2bace3a 100644
--- a/tests/tools/perfdhcp/test_control.h
+++ b/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.
 };
diff --git a/tests/tools/perfdhcp/tests/test_control_unittest.cc b/tests/tools/perfdhcp/tests/test_control_unittest.cc
index 2284042..d72cd0f 100644
--- a/tests/tools/perfdhcp/tests/test_control_unittest.cc
+++ b/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



More information about the bind10-changes mailing list