Commit 6efd035f authored by Marcin Siodelski's avatar Marcin Siodelski

[1959] Added support for packet templates.

parent c47f7da7
......@@ -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.
};
......
......@@ -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
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -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
......@@ -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
......
01010601008b45d200000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633501013707011c02030f060cff
\ No newline at end of file
01010601007b23f800000000000000000000000000000000ac100102000c0102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000638253633204ac1001813501033604ac1001013707011c02030f060cff
\ No newline at end of file
03da30c60001000e0001000117cf8e76000c010203060002000e0001000117cf8a5c080027a87b3400030028000000010000000a0000000e0005001820010db800010000000000000001b568000000be000000c8000800020000
\ No newline at end of file
015f4e650001000e0001000117cf8e76000c010203040003000c0000000100000e01000015180006000400170018000800020000
\ No newline at end of file
This diff is collapsed.
......@@ -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.
};
......
......@@ -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: