]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[github77] -o code,hexstring is now supported in perfdhcp
authorTomek Mrugalski <tomasz@isc.org>
Tue, 24 Apr 2018 08:02:04 +0000 (09:02 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Thu, 24 May 2018 13:15:46 +0000 (15:15 +0200)
src/bin/perfdhcp/command_options.cc
src/bin/perfdhcp/command_options.h
src/bin/perfdhcp/perfdhcp.xml
src/bin/perfdhcp/test_control.cc
src/bin/perfdhcp/test_control.h

index 50d9f1f606c0035ea73f0a32827390b0983aeac5..154deabc17beeea89a8b9440ab26c3c266fce74f 100644 (file)
@@ -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) {
index cb29ce37f90345f1c29dc3f734b4782dc4056b56..2ef5533593e1f9c8468b02c7e3cf6058634c2bf0 100644 (file)
@@ -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
index 95d47a828afdc63e87a4200b7a1b36bc0b9c4cf8..c7d489548b1882e3110f41874c988ec03531d7f7 100644 (file)
@@ -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>
                 </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>
index d58bf6361548b5fbb72ed96f63894a86ffa16389..c1dc0c044aaa0c2e6fc12def7b16bc6d2a1ac6da 100644 (file)
@@ -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());
index bf954c0647bc7737fab6fdb783b8ee703ab230c1..e38fee17a882b78e8c4c91f541a42ccd60296b93 100644 (file)
@@ -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).