From: Tomek Mrugalski Date: Tue, 24 Apr 2018 08:02:04 +0000 (+0100) Subject: [github77] -o code,hexstring is now supported in perfdhcp X-Git-Tag: trac5382a_base~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7c70e7783650cc6cf250e53c3c82fe96faf2a6ea;p=thirdparty%2Fkea.git [github77] -o code,hexstring is now supported in perfdhcp --- diff --git a/src/bin/perfdhcp/command_options.cc b/src/bin/perfdhcp/command_options.cc index 50d9f1f606..154deabc17 100644 --- a/src/bin/perfdhcp/command_options.cc +++ b/src/bin/perfdhcp/command_options.cc @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include @@ -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(opt); if (optarg) { stream << " " << optarg; @@ -400,7 +404,46 @@ CommandOptions::initialize(int argc, char** argv, bool print_cmd_line) { " -O 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(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,"); + } + + // Now try to interpret the hexstring + opt_text = opt_text.substr(coma_loc + 1); + std::vector 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 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) { diff --git a/src/bin/perfdhcp/command_options.h b/src/bin/perfdhcp/command_options.h index cb29ce37f9..2ef5533593 100644 --- a/src/bin/perfdhcp/command_options.h +++ b/src/bin/perfdhcp/command_options.h @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -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 diff --git a/src/bin/perfdhcp/perfdhcp.xml b/src/bin/perfdhcp/perfdhcp.xml index 95d47a828a..c7d489548b 100644 --- a/src/bin/perfdhcp/perfdhcp.xml +++ b/src/bin/perfdhcp/perfdhcp.xml @@ -65,6 +65,7 @@ + @@ -415,6 +416,28 @@ + + + + + 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 may be used + multiple times. It is necessary to specify protocol family + (either or ) before + using . + + + + diff --git a/src/bin/perfdhcp/test_control.cc b/src/bin/perfdhcp/test_control.cc index d58bf63615..c1dc0c044a 100644 --- a/src/bin/perfdhcp/test_control.cc +++ b/src/bin/perfdhcp/test_control.cc @@ -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)); + + // 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)); @@ -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()); diff --git a/src/bin/perfdhcp/test_control.h b/src/bin/perfdhcp/test_control.h index bf954c0647..e38fee17a8 100644 --- a/src/bin/perfdhcp/test_control.h +++ b/src/bin/perfdhcp/test_control.h @@ -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).