Commit 7c70e778 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[github77] -o code,hexstring is now supported in perfdhcp

parent 8461ee4f
......@@ -10,7 +10,9 @@
#include <exceptions/exceptions.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/duid.h>
#include <dhcp/option.h>
#include <cfgrpt/config_report.h>
#include <util/encode/hex.h>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
......@@ -28,6 +30,7 @@ extern int optreset;
using namespace std;
using namespace isc;
using namespace isc::dhcp;
namespace isc {
namespace perfdhcp {
......@@ -151,6 +154,7 @@ CommandOptions::reset() {
server_name_.clear();
v6_relay_encapsulation_level_ = 0;
generateDuidTemplate();
extra_opts_.clear();
}
bool
......@@ -218,7 +222,7 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
// In this section we collect argument values from command line
// they will be tuned and validated elsewhere
while((opt = getopt(argc, argv, "hv46A:r:t:R:b:n:p:d:D:l:P:a:L:M:"
"s:iBc1T:X:O:E:S:I:x:W:w:e:f:F:")) != -1) {
"s:iBc1T:X:O:o:E:S:I:x:W:w:e:f:F:")) != -1) {
stream << " -" << static_cast<char>(opt);
if (optarg) {
stream << " " << optarg;
......@@ -400,7 +404,46 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) {
" -O<value> must be greater than 3 ");
rnd_offset_.push_back(offset_arg);
break;
case 'o': {
// we must know how to contruct the option: whether it's v4 or v6.
check( (ipversion_ != 4) && (ipversion_ != 6),
"-4 or -6 must be explicitly specified before -o is used.");
// custom option (expected format: code,hexstring)
std::string opt_text = std::string(optarg);
size_t coma_loc = opt_text.find(',');
check(coma_loc == std::string::npos,
"-o option must provide option code, a coma and hexstring for"
" the option content, e.g. -o60,646f63736973 for sending option"
" 60 (class-id) with the value 'docsis'");
int code = 0;
// Try to parse the option code
try {
code = boost::lexical_cast<int>(opt_text.substr(0,coma_loc));
check(code <= 0, "Option code can't be negative");
} catch (boost::bad_lexical_cast&) {
isc_throw(InvalidParameter, "Invalid option code specified for "
"-o option, expected format: -o<integer>,<hexstring>");
}
// Now try to interpret the hexstring
opt_text = opt_text.substr(coma_loc + 1);
std::vector<uint8_t> bin;
try {
isc::util::encode::decodeHex(opt_text, bin);
} catch (BadValue& e) {
isc_throw(InvalidParameter, "Error during encoding option -o:"
<< e.what());
}
// Create and remember the option.
OptionPtr opt(new Option(ipversion_ == 4 ? Option::V4 : Option::V6,
code, bin));
extra_opts_.insert(make_pair(code, opt));
break;
}
case 'p':
period_ = positiveInteger("value of test period:"
" -p<value> must be a positive integer");
......@@ -721,11 +764,16 @@ CommandOptions::convertHexString(const std::string& text) const {
}
void CommandOptions::loadMacs() {
std::string line;
std::ifstream infile(mac_list_file_.c_str());
while (std::getline(infile, line)) {
check(decodeMacString(line), "invalid mac in input");
}
std::string line;
std::ifstream infile(mac_list_file_.c_str());
size_t cnt = 0;
while (std::getline(infile, line)) {
cnt++;
stringstream tmp;
tmp << "invalid mac in input line " << cnt;
// Let's print more meaningful error that contains line with error.
check(decodeMacString(line), tmp.str());
}
}
bool CommandOptions::decodeMacString(const std::string& line) {
......
......@@ -9,6 +9,7 @@
#include <boost/noncopyable.hpp>
#include <dhcp/option.h>
#include <stdint.h>
#include <string>
#include <vector>
......@@ -337,6 +338,11 @@ public:
/// \return wrapped command (start/stop).
std::string getWrapped() const { return wrapped_; }
/// @brief Returns extra options to be inserted.
///
/// @return container with options
const isc::dhcp::OptionCollection& getExtraOpts() const { return extra_opts_; }
/// \brief Returns server name.
///
/// \return server name.
......@@ -637,6 +643,9 @@ private:
/// Indicates how many DHCPv6 relay agents are simulated.
uint8_t v6_relay_encapsulation_level_;
/// @brief Extra options to be sent in each packet.
isc::dhcp::OptionCollection extra_opts_;
};
} // namespace perfdhcp
......
......@@ -65,6 +65,7 @@
<arg choice="opt" rep="norepeat"><option>-M <replaceable class="parameter">mac-list-file</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-n <replaceable class="parameter">num-request</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-O <replaceable class="parameter">random-offset</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-o <replaceable class="parameter">code,hexstring</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-p <replaceable class="parameter">test-period</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-P <replaceable class="parameter">preload</replaceable></option></arg>
<arg choice="opt" rep="norepeat"><option>-r <replaceable class="parameter">rate</replaceable></option></arg>
......@@ -415,6 +416,28 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>-o <replaceable class="parameter">code,hexstring</replaceable></option></term>
<listitem>
<para>
This forces perfdhcp to insert specified extra option (or
options if used several times) into packets being
transmitted. The code specifies option code and the
hexstring is a hexadecimal string that defines the content
of the option. Care should be taken as perfdhcp does not
offer any kind of logic behind those options. They're
simply inserted into packets being sent as is. Be careful
not to insert options that are already inserted. For
example, to insert client class identifier (option code
60) with a string 'docsis', you can use -o
60,646f63736973. The <option>-o</option> may be used
multiple times. It is necessary to specify protocol family
(either <option>-4</option> or <option>-6</option>) before
using <option>-o</option>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-P <replaceable class="parameter">preload</replaceable></option></term>
<listitem>
......
......@@ -1706,6 +1706,9 @@ TestControl::sendDiscover4(const TestControlSocket& socket,
// Set client identifier
pkt4->addOption(generateClientId(pkt4->getHWAddr()));
// Add any extra options that user may have specified.
addExtraOpts(pkt4);
pkt4->pack();
IfaceMgr::instance().send(pkt4);
if (!preload) {
......@@ -1784,6 +1787,10 @@ TestControl::sendRequestFromAck(const TestControlSocket& socket) {
// Create message of the specified type.
Pkt4Ptr msg = createRequestFromAck(ack);
setDefaults4(socket, msg);
// Add any extra options that user may have specified.
addExtraOpts(msg);
msg->pack();
// And send it.
IfaceMgr::instance().send(msg);
......@@ -1817,6 +1824,10 @@ TestControl::sendMessageFromReply(const uint16_t msg_type,
// Prepare the message of the specified type.
Pkt6Ptr msg = createMessageFromReply(msg_type, reply);
setDefaults6(socket, msg);
// Add any extra options that user may have specified.
addExtraOpts(msg);
msg->pack();
// And send it.
IfaceMgr::instance().send(msg);
......@@ -1874,6 +1885,9 @@ TestControl::sendRequest4(const TestControlSocket& socket,
// and local (relay) address.
setDefaults4(socket, pkt4);
// Add any extra options that user may have specified.
addExtraOpts(pkt4);
// Set hardware address
pkt4->setHWAddr(offer_pkt4->getHWAddr());
// Set client id.
......@@ -1989,6 +2003,10 @@ TestControl::sendRequest4(const TestControlSocket& socket,
pkt4->addOption(opt_requested_ip);
setDefaults4(socket, boost::static_pointer_cast<Pkt4>(pkt4));
// Add any extra options that user may have specified.
addExtraOpts(pkt4);
// Prepare on-wire data.
pkt4->rawPack();
IfaceMgr::instance().send(boost::static_pointer_cast<Pkt4>(pkt4));
......@@ -2044,6 +2062,10 @@ TestControl::sendRequest6(const TestControlSocket& socket,
// Set default packet data.
setDefaults6(socket, pkt6);
// Add any extra options that user may have specified.
addExtraOpts(pkt6);
// Prepare on-wire data.
pkt6->pack();
IfaceMgr::instance().send(pkt6);
......@@ -2148,6 +2170,10 @@ TestControl::sendRequest6(const TestControlSocket& socket,
pkt6->addOption(opt_clientid);
// Set default packet data.
setDefaults6(socket, pkt6);
// Add any extra options that user may have specified.
addExtraOpts(pkt6);
// Prepare on wire data.
pkt6->rawPack();
// Send packet.
......@@ -2205,6 +2231,10 @@ TestControl::sendSolicit6(const TestControlSocket& socket,
}
setDefaults6(socket, pkt6);
// Add any extra options that user may have specified.
addExtraOpts(pkt6);
pkt6->pack();
IfaceMgr::instance().send(pkt6);
if (!preload) {
......@@ -2250,6 +2280,10 @@ TestControl::sendSolicit6(const TestControlSocket& socket,
// Prepare on-wire data.
pkt6->rawPack();
setDefaults6(socket, pkt6);
// Add any extra options that user may have specified.
addExtraOpts(pkt6);
// Send solicit packet.
IfaceMgr::instance().send(pkt6);
if (!preload) {
......@@ -2324,6 +2358,26 @@ TestControl::setDefaults6(const TestControlSocket& socket,
}
}
void
TestControl::addExtraOpts(const Pkt4Ptr& pkt) {
// All all extra options that the user may have specified
CommandOptions& options = CommandOptions::instance();
const dhcp::OptionCollection& extra_opts = options.getExtraOpts();
for (auto entry : extra_opts) {
pkt->addOption(entry.second);
}
}
void
TestControl::addExtraOpts(const Pkt6Ptr& pkt) {
// All all extra options that the user may have specified
CommandOptions& options = CommandOptions::instance();
const dhcp::OptionCollection& extra_opts = options.getExtraOpts();
for (auto entry : extra_opts) {
pkt->addOption(entry.second);
}
}
bool
TestControl::testDiags(const char diag) const {
std::string diags(CommandOptions::instance().getDiags());
......
......@@ -939,6 +939,26 @@ protected:
void setDefaults6(const TestControlSocket& socket,
const dhcp::Pkt6Ptr& pkt);
/// @brief Inserts extra options specified by user.
///
/// Note: addExtraOpts for v4 and v6 could easily be turned into a template.
/// However, this would require putting code here that uses CommandOptions,
/// and that would create dependency between test_control.h and
/// command_options.h.
///
/// @param pkt4 options will be added here
void addExtraOpts(const dhcp::Pkt4Ptr& pkt4);
/// @brief Inserts extra options specified by user.
///
/// Note: addExtraOpts for v4 and v6 could easily be turned into a template.
/// However, this would require putting code here that uses CommandOptions,
/// and that would create dependency between test_control.h and
/// command_options.h.
///
/// @param pkt6 options will be added here
void addExtraOpts(const dhcp::Pkt6Ptr& pkt6);
/// \brief Find if diagnostic flag has been set.
///
/// \param diag diagnostic flag (a,e,i,s,r,t,T).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment