8#include <kea_version.h> 
   20#include <boost/lexical_cast.hpp> 
   21#include <boost/date_time/posix_time/posix_time.hpp> 
   52    return (lease_type == type_);
 
 
   67    if (cmd_line_arg == 
"address-only") {
 
   70    } 
else if (cmd_line_arg == 
"prefix-only") {
 
   73    } 
else if (cmd_line_arg == 
"address-and-prefix") {
 
   78                  " must be one of the following: 'address-only' or" 
 
   87        return (
"address-only (IA_NA option added to the client's request)");
 
   89        return (
"prefix-only (IA_PD option added to the client's request)");
 
   91        return (
"address-and-prefix (Both IA_NA and IA_PD options added to the" 
   92                " client's request)");
 
   95                  " returning textual representation of the lease type");
 
 
  103    uint8_t mac[6] = { 0x0, 0xC, 0x1, 0x2, 0x3, 0x4 };
 
  107    double dt[2] = { 1., 1. };
 
  118    clean_report_ = 
false;
 
  119    clean_report_separator_ = 
"";
 
  121    mac_template_.assign(mac, mac + 6);
 
  122    duid_template_.clear();
 
  124    addr_unique_ = 
false;
 
  125    mac_list_file_.clear();
 
  127    relay_addr_list_file_.clear();
 
  128    relay_addr_list_.clear();
 
  129    multi_subnet_ = 
false;
 
  130    num_request_.clear();
 
  133    wait_for_elapsed_time_ = -1;
 
  134    increased_elapsed_time_ = -1;
 
  136    drop_time_.assign(dt, dt + 2);
 
  140    is_interface_ = 
false;
 
  147    rapid_commit_ = 
false;
 
  149    template_file_.clear();
 
  157    server_name_.clear();
 
  158    v6_relay_encapsulation_level_ = 0;
 
  159    generateDuidTemplate();
 
  161    if (std::thread::hardware_concurrency() == 1) {
 
  162        single_thread_mode_ = 
true;
 
  164        single_thread_mode_ = 
false;
 
  169        relay_opts_[i] = option_collection;
 
 
  212    bool help_or_version_mode = initialize(argc, argv, print_cmd_line);
 
  213    if (!help_or_version_mode) {
 
  216    return (help_or_version_mode);
 
 
  223CommandOptions::initialize(
int argc, 
char** argv, 
bool print_cmd_line) {
 
  225    int opt_long_index = 0;     
 
  226    std::string drop_arg;       
 
  227    size_t percent_loc = 0;     
 
  228    double drop_percent = 0;    
 
  235    std::ostringstream stream;
 
  236    stream << 
"perfdhcp";
 
  237    int num_mac_list_files = 0;
 
  238    int num_subnet_list_files = 0;
 
  240    struct option long_options[] = {
 
  248    while((opt = getopt_long(argc, argv,
 
  249                             "huvV46A:r:t:R:b:n:p:d:D:l:P:a:L:N:M:s:iBc1" 
  250                             "J:T:X:O:o:E:S:I:x:W:w:e:f:F:g:C:y:Y:",
 
  251                             long_options, &opt_long_index)) != -1) {
 
  253        opt <= 'z' ? stream << static_cast<char>(opt) :
 
  254                     stream << 
"-" << long_options[opt_long_index].name;
 
  256            stream << 
" " << optarg;
 
  268            v6_relay_encapsulation_level_ =
 
  269                static_cast<uint8_t
>(positiveInteger(
"-A<encapsulation-level> must" 
  270                                                     " be a positive integer"));
 
  271            if (v6_relay_encapsulation_level_ != 1) {
 
  281            check(ipversion_ == 6, 
"IP version already set to 6");
 
  286            check(ipversion_ == 4, 
"IP version already set to 4");
 
  291            check(base_.size() > 3, 
"-b<value> already specified," 
  292                  " unexpected occurrence of 5th -b<value>");
 
  293            base_.push_back(optarg ? optarg : 
"");
 
  294            decodeBase(base_.back());
 
  302            rapid_commit_ = 
true;
 
  306            clean_report_ = 
true;
 
  307            clean_report_separator_ = optarg ? optarg : 
"";
 
  311            check(drop_time_set_ > 1,
 
  312                  "maximum number of drops already specified, " 
  313                  "unexpected 3rd occurrence of -d<value>");
 
  315                drop_time_[drop_time_set_] =
 
  316                    boost::lexical_cast<double>(optarg ? optarg : 
"");
 
  317            } 
catch (
const boost::bad_lexical_cast&) {
 
  319                          "value of drop time: -d<value>" 
  320                          " must be positive number");
 
  322            check(drop_time_[drop_time_set_] <= 0.,
 
  323                  "drop-time must be a positive number");
 
  324            drop_time_set_ = 
true;
 
  328            drop_arg = std::string(optarg ? optarg : 
"");
 
  329            percent_loc = drop_arg.find(
'%');
 
  330            check(max_pdrop_.size() > 1 || max_drop_.size() > 1,
 
  331                  "values of maximum drops: -D<value> already " 
  332                  "specified, unexpected 3rd occurrence of -D<value>");
 
  333            if ((percent_loc) != std::string::npos) {
 
  336                        boost::lexical_cast<double>(drop_arg.substr(0, percent_loc));
 
  337                } 
catch (
const boost::bad_lexical_cast&) {
 
  339                              "value of drop percentage: -D<value%>" 
  342                check((drop_percent <= 0) || (drop_percent >= 100),
 
  343                  "value of drop percentage: -D<value%> must be 0..100");
 
  344                max_pdrop_.push_back(drop_percent);
 
  346                num_drops = positiveInteger(
"value of max drops number:" 
  347                                            " -D<value> must be a positive integer");
 
  348                max_drop_.push_back(num_drops);
 
  357            elp_offset_ = nonNegativeInteger(
"value of time-offset: -E<value>" 
  358                                             " must not be a negative integer");
 
  362            renew_rate_ = positiveInteger(
"value of the renew rate: -f<renew-rate>" 
  363                                          " must be a positive integer");
 
  367            release_rate_ = positiveInteger(
"value of the release rate:" 
  368                                            " -F<release-rate> must be a" 
  369                                            " positive integer");
 
  373            std::string optarg_text(optarg ? optarg : 
"");
 
  374            if (optarg_text == 
"single") {
 
  375                single_thread_mode_ = 
true;
 
  376            } 
else if (optarg_text == 
"multi") {
 
  377                single_thread_mode_ = 
false;
 
  380                    isc_throw(
InvalidParameter, 
"value of thread mode (-g) '" << optarg << 
"' is wrong - should be '-g single' or '-g multi'");
 
  392            exchange_mode_ = 
DO_SA;
 
  396            rip_offset_ = positiveInteger(
"value of ip address offset:" 
  397                                          " -I<value> must be a" 
  398                                          " positive integer");
 
  402            check(num_subnet_list_files >= 1, 
"only one -J option can be specified");
 
  403            num_subnet_list_files++;
 
  404            relay_addr_list_file_ = std::string(optarg ? optarg : 
"");
 
  409            localname_ = std::string(optarg ? optarg : 
"");
 
  414             local_port_ = nonNegativeInteger(
"value of local port:" 
  415                                              " -L<value> must not be a" 
  416                                              " negative integer");
 
  418                   static_cast<int>(std::numeric_limits<uint16_t>::max()),
 
  419                   "local-port must be lower than " +
 
  420                   boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
 
  424             remote_port_ = nonNegativeInteger(
"value of remote port:" 
  425                                               " -L<value> must not be a" 
  426                                               " negative integer");
 
  428                   static_cast<int>(std::numeric_limits<uint16_t>::max()),
 
  429                   "remote-port must be lower than " +
 
  430                   boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
 
  434            check(num_mac_list_files >= 1, 
"only one -M option can be specified");
 
  435            num_mac_list_files++;
 
  436            mac_list_file_ = std::string(optarg ? optarg : 
"");
 
  441            exit_wait_time_ = nonNegativeInteger(
"value of exist wait time: " 
  442                                                  "-W<value> must not be a " 
  447            num_req = positiveInteger(
"value of num-request:" 
  448                                      " -n<value> must be a positive integer");
 
  449            if (num_request_.size() >= 2) {
 
  451                          "value of maximum number of requests: -n<value> " 
  452                          "already specified, unexpected 3rd occurrence" 
  455            num_request_.push_back(num_req);
 
  459            if (rnd_offset_.size() < 2) {
 
  460                offset_arg = positiveInteger(
"value of random offset: " 
  461                                             "-O<value> must be greater than 3");
 
  464                          "random offsets already specified," 
  465                          " unexpected 3rd occurrence of -O<value>");
 
  467            check(offset_arg < 3, 
"value of random random-offset:" 
  468                  " -O<value> must be greater than 3 ");
 
  469            rnd_offset_.push_back(offset_arg);
 
  474            check( (ipversion_ != 4) && (ipversion_ != 6),
 
  475                   "-4 or -6 must be explicitly specified before -o is used.");
 
  478            std::string opt_text(optarg ? optarg : 
"");
 
  479            size_t comma_loc = opt_text.find(
',');
 
  480            check(comma_loc == std::string::npos,
 
  481                  "-o option must provide option code, a comma and hexstring for" 
  482                  " the option content, e.g. -o60,646f63736973 for sending option" 
  483                  " 60 (class-id) with the value 'docsis'");
 
  488                code = boost::lexical_cast<int>(opt_text.substr(0, comma_loc));
 
  489                check(code <= 0, 
"Option code can't be negative");
 
  490            } 
catch (
const boost::bad_lexical_cast&) {
 
  492                          "-o option, expected format: -o<integer>,<hexstring>");
 
  496            opt_text = opt_text.substr(comma_loc + 1);
 
  497            std::vector<uint8_t> bin;
 
  508            extra_opts_.insert(make_pair(code, option));
 
  512            period_ = positiveInteger(
"value of test period:" 
  513                                      " -p<value> must be a positive integer");
 
  517            preload_ = nonNegativeInteger(
"number of preload packets:" 
  518                                          " -P<value> must not be " 
  519                                          "a negative integer");
 
  523            rate_ = positiveInteger(
"value of rate:" 
  524                                    " -r<value> must be a positive integer");
 
  532            seed_ = 
static_cast<unsigned int> 
  533                (nonNegativeInteger(
"value of seed:" 
  534                                    " -s <seed> must be non-negative integer"));
 
  535            seeded_ = seed_ > 0 ? true : 
false;
 
  539            sid_offset_ = positiveInteger(
"value of server id offset:" 
  540                                          " -S<value> must be a" 
  541                                          " positive integer");
 
  545            report_delay_ = positiveInteger(
"value of report delay:" 
  546                                            " -t<value> must be a" 
  547                                            " positive integer");
 
  551            if (template_file_.size() < 2) {
 
  552                sarg = nonEmptyString(
"template file name not specified," 
  553                                      " expected -T<filename>");
 
  554                template_file_.push_back(sarg);
 
  557                          "template files are already specified," 
  558                          " unexpected 3rd -T<filename> occurrence");
 
  571            wrapped_ = nonEmptyString(
"command for wrapped mode:" 
  572                                      " -w<command> must be specified");
 
  576            diags_ = nonEmptyString(
"value of diagnostics selectors:" 
  577                                    " -x<value> must be specified");
 
  581            if (xid_offset_.size() < 2) {
 
  582                offset_arg = positiveInteger(
"value of transaction id:" 
  583                                             " -X<value> must be a" 
  584                                             " positive integer");
 
  587                          "transaction ids already specified," 
  588                          " unexpected 3rd -X<value> occurrence");
 
  590            xid_offset_.push_back(offset_arg);
 
  594            wait_for_elapsed_time_ = nonNegativeInteger(
"value of time:" 
  595                                     " -Y<value> must be a non negative integer");
 
  599            increased_elapsed_time_ = positiveInteger(
"value of time:" 
  600                                      " -y<value> must be a positive integer");
 
  604            std::string optarg_text(optarg ? optarg : 
"");
 
  605            if (optarg_text == 
"basic") {
 
  607            } 
else if (optarg_text == 
"avalanche") {
 
  618            check((ipversion_ != 6),
 
  619                  "-6 must be explicitly specified before --or is used.");
 
  620            check(v6_relay_encapsulation_level_ <= 0,
 
  621                  "-A must be explicitly specified before --or is used.");
 
  624            std::string opt_text(optarg ? optarg : 
"");
 
  625            size_t colon_loc = opt_text.find(
':');
 
  626            size_t comma_loc = opt_text.find(
',');
 
  629            uint8_t option_encapsulation_level = 1;
 
  630            if (colon_loc == std::string::npos) {
 
  637                    option_encapsulation_level =
 
  638                        boost::lexical_cast<int>(opt_text.substr(0, colon_loc));
 
  639                    check(option_encapsulation_level != 1, 
"Relayed option encapsulation level " 
  640                                                           "supports only value 1 at the moment.");
 
  641                } 
catch (
const boost::bad_lexical_cast&) {
 
  643                              "Invalid relayed option encapsulation level specified for " 
  644                              "--or option, expected format: --or <integer>:<integer>,<hexstring>");
 
  648            check(comma_loc == std::string::npos,
 
  649                  "--or option must provide encapsulation level, a colon, option code, a comma and " 
  650                  "hexstring for the option content, e.g. --or 1:38,31323334 for sending option" 
  651                  " 38 (subscriber-id) with the value 1234 at first level of encapsulation");
 
  656                code = boost::lexical_cast<int>(
 
  657                    opt_text.substr(colon_loc + 1, comma_loc - colon_loc - 1));
 
  658                check(code <= 0, 
"Option code can't be negative or zero");
 
  659            } 
catch (
const boost::bad_lexical_cast&) {
 
  661                          "Invalid option code specified for " 
  662                          "--or option, expected format: --or <integer>:<integer>,<hexstring>");
 
  666            opt_text = opt_text.substr(comma_loc + 1);
 
  667            std::vector<uint8_t> bin;
 
  676            auto relay_opts = relay_opts_.find(option_encapsulation_level);
 
  677            relay_opts->second.insert(make_pair(code, option));
 
  687    if (ipversion_ == 0) {
 
  696    if (template_file_.size() > 1) {
 
  697        if (xid_offset_.size() == 1) {
 
  698            xid_offset_.push_back(xid_offset_[0]);
 
  700        if (rnd_offset_.size() == 1) {
 
  701            rnd_offset_.push_back(rnd_offset_[0]);
 
  709    check(optind < argc -1, 
"extra arguments?");
 
  710    if (optind == argc - 1) {
 
  711        server_name_ = argv[optind];
 
  712        stream << 
" " << server_name_;
 
  714        if ((ipversion_ == 4) && (server_name_.compare(
"all") == 0)) {
 
  718        } 
else if ((ipversion_ == 6) && (server_name_.compare(
"all") == 0)) {
 
  720        } 
else if ((ipversion_ == 6) &&
 
  721                   (server_name_.compare(
"servers") == 0)) {
 
  726        if (print_cmd_line) {
 
  727            std::cout << 
"Running: " << stream.str() << std::endl;
 
  731            std::cout << 
"Scenario: basic." << std::endl;
 
  733            std::cout << 
"Scenario: avalanche." << std::endl;
 
  737            std::cout << 
"Multi-thread mode enabled." << std::endl;
 
  742    if (!localname_.empty()) {
 
  743        if (server_name_.empty()) {
 
  744            if (is_interface_ && (ipversion_ == 4)) {
 
  747            } 
else if (is_interface_ && (ipversion_ == 6)) {
 
  752    if (server_name_.empty()) {
 
  754                  "without an interface, server is required");
 
  759    if (duid_template_.empty()) {
 
  760        generateDuidTemplate();
 
  766CommandOptions::initClientsNum() {
 
  767    const std::string errmsg =
 
  768        "value of -R <value> must be non-negative integer";
 
  775        long long clients_num = boost::lexical_cast<long long>(optarg ? optarg : 
"");
 
  776        check(clients_num < 0, errmsg);
 
  777        clients_num_ = boost::lexical_cast<uint32_t>(optarg ? optarg : 
"");
 
  778    } 
catch (
const boost::bad_lexical_cast&) {
 
  784CommandOptions::initIsInterface() {
 
  785    is_interface_ = 
false;
 
  786    if (!localname_.empty()) {
 
  788        if (iface_mgr.
getIface(localname_) != NULL)  {
 
  789            is_interface_ = 
true;
 
  795CommandOptions::decodeBase(
const std::string& base) {
 
  797    boost::algorithm::to_lower(b);
 
  800    if ((b.substr(0, 4) == 
"mac=") || (b.substr(0, 6) == 
"ether=")) {
 
  802    } 
else if (b.substr(0, 5) == 
"duid=") {
 
  806                  "base value not provided as -b<value>," 
  807                  " expected -b mac=<mac> or -b duid=<duid>");
 
  812CommandOptions::decodeMacBase(
const std::string& base) {
 
  814    size_t found = base.find(
'=');
 
  815    static const char* errmsg = 
"expected -b<base> format for" 
  816        " mac address is -b mac=00::0C::01::02::03::04 or" 
  817        " -b mac=00:0C:01:02:03:04";
 
  818    check(found == std::string::npos, errmsg);
 
  821    std::istringstream s1(base.substr(found + 1));
 
  823    mac_template_.clear();
 
  825    while (std::getline(s1, token, 
':')) {
 
  827        if (token.length() > 0) {
 
  831                ui = convertHexString(token);
 
  832            } 
catch (
const isc::InvalidParameter&) {
 
  834                          "invalid characters in MAC provided");
 
  838            mac_template_.push_back(ui);
 
  842    check(mac_template_.size() != 6, errmsg);
 
  846CommandOptions::decodeDuid(
const std::string& base) {
 
  848    std::vector<uint8_t> duid_template;
 
  849    size_t found = base.find(
'=');
 
  850    check(found == std::string::npos, 
"expected -b<base>" 
  851          " format for duid is -b duid=<duid>");
 
  852    std::string b = base.substr(found + 1);
 
  855    check(b.length() & 1, 
"odd number of hexadecimal digits in duid");
 
  856    check(b.length() > 128, 
"duid too large");
 
  857    check(b.length() == 0, 
"no duid specified");
 
  860    for (
size_t i = 0; i < b.length(); i += 2) {
 
  864            ui = convertHexString(b.substr(i, 2));
 
  865        } 
catch (
const isc::InvalidParameter&) {
 
  867                      "invalid characters in DUID provided," 
  868                      " expected hex digits");
 
  870        duid_template.push_back(
static_cast<uint8_t
>(ui));
 
  875    check(duid_template.size() < 6, 
"DUID must be at least 6 octets long");
 
  877    std::swap(duid_template, duid_template_);
 
  881CommandOptions::generateDuidTemplate() {
 
  882    using namespace boost::posix_time;
 
  886    duid_template_.clear();
 
  887    const uint8_t duid_template_len = 14;
 
  888    duid_template_.resize(duid_template_len);
 
  892    duid_template_[2] = HWTYPE_ETHERNET >> 8;
 
  893    duid_template_[3] = HWTYPE_ETHERNET & 0xff;
 
  898    ptime now = microsec_clock::universal_time();
 
  899    ptime duid_epoch(from_iso_string(
"20000101T000000"));
 
  900    time_period period(duid_epoch, now);
 
  901    uint32_t duration_sec = htonl(period.length().total_seconds());
 
  902    memcpy(&duid_template_[4], &duration_sec, 4);
 
  907    memcpy(&duid_template_[8], &mac_template_[0], 6);
 
  914                  "Trying to access relay options at encapsulation level that doesn't exist");
 
  917    return relay_opts_.find(encapsulation_level)->second;
 
 
  921CommandOptions::convertHexString(
const std::string& text)
 const {
 
  924    for (
size_t i = 0; i < text.length(); ++i) {
 
  925        if (!std::isxdigit(text[i])) {
 
  927                      "The following digit: " << text[i] << 
" in " 
  928                      << text << 
"is not hexadecimal");
 
  932    std::istringstream text_stream(text);
 
  933    text_stream >> std::hex >> ui >> std::dec;
 
  937                  " two hex digits to byte");
 
  942bool CommandOptions::validateIP(
const std::string& line) {
 
  944        isc::asiolink::IOAddress ip_address(line);
 
  949    } 
catch (
const isc::asiolink::IOError& e) {
 
  952    relay_addr_list_.push_back(line);
 
  953    multi_subnet_ = 
true;
 
  957void CommandOptions::loadRelayAddr() {
 
  959    std::ifstream infile(relay_addr_list_file_.c_str());
 
  961    while (std::getline(infile, line)) {
 
  964        tmp << 
"invalid address or wrong address version in line: " << cnt;
 
  965        check(validateIP(line), tmp.str());
 
  967    check(cnt == 0, 
"file with addresses is empty!");
 
  970void CommandOptions::loadMacs() {
 
  972    std::ifstream infile(mac_list_file_.c_str());
 
  974    while (std::getline(infile, line)) {
 
  977        tmp << 
"invalid mac in input line " << cnt;
 
  979        check(decodeMacString(line), tmp.str());
 
  983bool CommandOptions::decodeMacString(
const std::string& line) {
 
  985  std::istringstream s(line);
 
  987  std::vector<uint8_t> mac;
 
  988  while(std::getline(s, token, 
':')) {
 
  990    if (token.length() > 0) {
 
  994        ui = convertHexString(token);
 
  995      } 
catch (
const isc::InvalidParameter&) {
 
 1002  mac_list_.push_back(mac);
 
 1007CommandOptions::validate() {
 
 1009          "-B is not compatible with IPv6 (-6)");
 
 1011          "-6 (IPv6) must be set to use -c");
 
 1013          "Can't use -4 with -A, it's a V6 only option.");
 
 1015          "second -n<num-request> is not compatible with -i");
 
 1017          "-6 option must be used if lease type other than '-e address-only'" 
 1021          "template files may be only used with '-e address-only'");
 
 1023          "second -d<drop-time> is not compatible with -i");
 
 1026          "second -D<max-drop> is not compatible with -i");
 
 1028          "-1 is not compatible with -i");
 
 1030          "second -T<template-file> is not compatible with -i");
 
 1032          "second -X<xid-offset> is not compatible with -i");
 
 1034          "second -O<random-offset is not compatible with -i");
 
 1036          "-E<time-offset> is not compatible with -i");
 
 1038          "-S<srvid-offset> is not compatible with -i");
 
 1040          "-I<ip-offset> is not compatible with -i");
 
 1042          "-f<renew-rate> is not compatible with -i");
 
 1044          "-F<release-rate> is not compatible with -i");
 
 1046          "-i must be set to use -c");
 
 1048          "The sum of Renew rate (-f<renew-rate>) and Release rate" 
 1049          " (-F<release-rate>) must not be greater than the exchange" 
 1050          " rate specified as -r<rate>");
 
 1052          "Renew rate specified as -f<renew-rate> must not be specified" 
 1053          " when -r<rate> parameter is not specified");
 
 1055          "Release rate specified as -F<release-rate> must not be specified" 
 1056          " when -r<rate> parameter is not specified");
 
 1058          "-T<template-file> must be set to use -X<xid-offset>");
 
 1060          "-T<template-file> must be set to use -O<random-offset>");
 
 1062          "second/request -T<template-file> must be set to use -E<time-offset>");
 
 1064          "second/request -T<template-file> must be set to " 
 1065          "use -S<srvid-offset>");
 
 1067          "second/request -T<template-file> must be set to " 
 1068          "use -I<ip-offset>");
 
 1070          "Can't use -b with -M option");
 
 1072      "Option -y can't be used without -Y");
 
 1074      "Option -Y can't be used without -y");
 
 1075    auto nthreads = std::thread::hardware_concurrency();
 
 1077        std::cout << 
"WARNING: Currently system can run only 1 thread in parallel." << std::endl
 
 1078                  << 
"WARNING: Better results are achieved when run in single-threaded mode." << std::endl
 
 1079                  << 
"WARNING: To switch use -g single option." << std::endl;
 
 1081        std::cout << 
"WARNING: Currently system can run more than 1 thread in parallel." << std::endl
 
 1082                  << 
"WARNING: Better results are achieved when run in multi-threaded mode." << std::endl
 
 1083                  << 
"WARNING: To switch use -g multi option." << std::endl;
 
 1088              "in case of avalanche scenario number\nof clients must be specified" 
 1089              " using -R option explicitly");
 
 1092        double dt[2] = { 1000.0, 1000.0 };
 
 1093        drop_time_.assign(dt, dt + 2);
 
 1094        if (drop_time_set_) {
 
 1095            std::cout << 
"INFO: in avalanche scenario drop time is ignored" << std::endl;
 
 1101CommandOptions::check(
bool condition, 
const std::string& errmsg)
 const {
 
 1104    std::ostringstream stream;
 
 1105    stream << errmsg << 
"\n";
 
 1107        isc_throw(isc::InvalidParameter, errmsg);
 
 1112CommandOptions::positiveInteger(
const std::string& errmsg)
 const {
 
 1114        int value = boost::lexical_cast<int>(optarg ? optarg : 
"");
 
 1115        check(value <= 0, errmsg);
 
 1117    } 
catch (
const boost::bad_lexical_cast&) {
 
 1123CommandOptions::nonNegativeInteger(
const std::string& errmsg)
 const {
 
 1125        int value = boost::lexical_cast<int>(optarg ? optarg : 
"");
 
 1126        check(value < 0, errmsg);
 
 1128    } 
catch (
const boost::bad_lexical_cast&) {
 
 1134CommandOptions::nonEmptyString(
const std::string& errmsg)
 const {
 
 1135    std::string sarg(optarg ? optarg : 
"");
 
 1136    if (sarg.length() == 0) {
 
 1137        isc_throw(isc::InvalidParameter, errmsg);
 
 1143CommandOptions::initLeaseType() {
 
 1144    std::string lease_type_arg(optarg ? optarg : 
"");
 
 1145    lease_type_.fromCommandLine(lease_type_arg);
 
 1150    std::cout << 
"IPv" << 
static_cast<int>(ipversion_) << std::endl;
 
 1151    if (exchange_mode_ == 
DO_SA) {
 
 1152        if (ipversion_ == 4) {
 
 1153            std::cout << 
"DISCOVER-OFFER only" << std::endl;
 
 1155            std::cout << 
"SOLICIT-ADVERTISE only" << std::endl;
 
 1160        std::cout << 
"rate[1/s]=" << rate_ <<  std::endl;
 
 1163        std::cout << 
"renew-rate[1/s]=" << 
getRenewRate() << std::endl;
 
 1166        std::cout << 
"release-rate[1/s]=" << 
getReleaseRate() << std::endl;
 
 1168    if (report_delay_ != 0) {
 
 1169        std::cout << 
"report[s]=" << report_delay_ << std::endl;
 
 1171    if (clients_num_ != 0) {
 
 1172        std::cout << 
"clients=" << clients_num_ << std::endl;
 
 1174    for (
size_t i = 0; i < base_.size(); ++i) {
 
 1175        std::cout << 
"base[" << i << 
"]=" << base_[i] <<  std::endl;
 
 1177    for (
size_t i = 0; i < num_request_.size(); ++i) {
 
 1178        std::cout << 
"num-request[" << i << 
"]=" << num_request_[i] << std::endl;
 
 1181        std::cout << 
"test-period=" << period_ << std::endl;
 
 1183    for (
size_t i = 0; i < drop_time_.size(); ++i) {
 
 1184        std::cout << 
"drop-time[" << i << 
"]=" << drop_time_[i] << std::endl;
 
 1186    for (
size_t i = 0; i < max_drop_.size(); ++i) {
 
 1187        std::cout << 
"max-drop{" << i << 
"]=" << max_drop_[i] << std::endl;
 
 1189    for (
size_t i = 0; i < max_pdrop_.size(); ++i) {
 
 1190        std::cout << 
"max-pdrop{" << i << 
"]=" << max_pdrop_[i] << std::endl;
 
 1192    if (preload_ != 0) {
 
 1193        std::cout << 
"preload=" << preload_ <<  std::endl;
 
 1196        std::cout << 
"local-port=" << local_port_ <<  std::endl;
 
 1199        std::cout << 
"remote-port=" << remote_port_ <<  std::endl;
 
 1202        std::cout << 
"seed=" << seed_ << std::endl;
 
 1205        std::cout << 
"broadcast" << std::endl;
 
 1207    if (rapid_commit_) {
 
 1208        std::cout << 
"rapid-commit" << std::endl;
 
 1211        std::cout << 
"use-first" << std::endl;
 
 1213    if (!mac_list_file_.empty()) {
 
 1214        std::cout << 
"mac-list-file=" << mac_list_file_ << std::endl;
 
 1216    for (
size_t i = 0; i < template_file_.size(); ++i) {
 
 1217        std::cout << 
"template-file[" << i << 
"]=" << template_file_[i] << std::endl;
 
 1219    for (
size_t i = 0; i < xid_offset_.size(); ++i) {
 
 1220        std::cout << 
"xid-offset[" << i << 
"]=" << xid_offset_[i] << std::endl;
 
 1222    if (elp_offset_ != 0) {
 
 1223        std::cout << 
"elp-offset=" << elp_offset_ << std::endl;
 
 1225    for (
size_t i = 0; i < rnd_offset_.size(); ++i) {
 
 1226        std::cout << 
"rnd-offset[" << i << 
"]=" << rnd_offset_[i] << std::endl;
 
 1228    if (sid_offset_ != 0) {
 
 1229        std::cout << 
"sid-offset=" << sid_offset_ << std::endl;
 
 1231    if (rip_offset_ != 0) {
 
 1232        std::cout << 
"rip-offset=" << rip_offset_ << std::endl;
 
 1234    if (!diags_.empty()) {
 
 1235        std::cout << 
"diagnostic-selectors=" << diags_ <<  std::endl;
 
 1237    if (!wrapped_.empty()) {
 
 1238        std::cout << 
"wrapped=" << wrapped_ << std::endl;
 
 1240    if (!localname_.empty()) {
 
 1241        if (is_interface_) {
 
 1242            std::cout << 
"interface=" << localname_ << std::endl;
 
 1244            std::cout << 
"local-addr=" << localname_ << std::endl;
 
 1247    if (!server_name_.empty()) {
 
 1248        std::cout << 
"server=" << server_name_ << std::endl;
 
 1250    if (single_thread_mode_) {
 
 1251        std::cout << 
"single-thread-mode" << std::endl;
 
 1253        std::cout << 
"multi-thread-mode" << std::endl;
 
 
 1260R
"(perfdhcp [-1] [-4 | -6] [-A encapsulation-level] [-b base] [-B] [-c] 
 1261         [-C separator] [-d drop-time] [-D max-drop] [-e lease-type] 
 
 1262         [-E time-offset] [-f renew-rate] [-F release-rate] [-g thread-mode] 
 1263         [-h] [-i] [-I ip-offset] [-J remote-address-list-file] 
 1264         [-l local-address|interface] [-L local-port] [-M mac-list-file] 
 1265         [-n num-request] [-N remote-port] [-O random-offset] 
 1266         [-o code,hexstring] [--or encapsulation-level:code,hexstring] 
 
 1267         [-p test-period] [-P preload] [-r rate] 
 1268         [-R num-clients] [-s seed] [-S srvid-offset] [--scenario name] 
 1269         [-t report] [-T template-file] [-u] [-v] [-W exit-wait-time] 
 1270         [-w script_name] [-x diagnostic-selector] [-X xid-offset] [server] 
 
 1272The [server] argument is the name/address of the DHCP server to 
 1273contact.  For DHCPv4 operation, exchanges are initiated by 
 1274transmitting a DHCP DISCOVER to this address. 
 1276For DHCPv6 operation, exchanges are initiated by transmitting a DHCP 
 1277SOLICIT to this address.  In the DHCPv6 case, the special name 'all' 
 1278can be used to refer to All_DHCP_Relay_Agents_and_Servers (the 
 1279multicast address FF02::1:2), or the special name 'servers' to refer 
 1280to All_DHCP_Servers (the multicast address FF05::1:3).  The [server] 
 1281argument is optional only in the case that -l is used to specify an 
 1282interface, in which case [server] defaults to 'all'. 
 1284The default is to perform a single 4-way exchange, effectively pinging 
 1286The -r option is used to set up a performance test, without 
 1287it exchanges are initiated as fast as possible. 
 1288The other scenario is an avalanche which is selected by 
 1289--scenario avalanche. It first sends as many Discovery or Solicit 
 1290messages as request in -R option then back off mechanism is used for 
 1291each simulated client until all requests are answered. At the end 
 1292time of whole scenario is reported. 
 1295-1: Take the server-ID option from the first received message. 
 1296-4: DHCPv4 operation (default). This is incompatible with the -6 option. 
 1297-6: DHCPv6 operation. This is incompatible with the -4 option. 
 1298-b<base>: The base mac, duid, IP, etc, used to simulate different 
 1299    clients.  This can be specified multiple times, each instance is 
 1300    in the <type>=<value> form, for instance: 
 1301    (and default) mac=00:0c:01:02:03:04. 
 1302-d<drop-time>: Specify the time after which a request is treated as 
 1303    having been lost.  The value is given in seconds and may contain a 
 1304    fractional component.  The default is 1 second. 
 1305-e<lease-type>: A type of lease being requested from the server. It 
 1306    may be one of the following: address-only, prefix-only or 
 1307    address-and-prefix. The address-only indicates that the regular 
 1308    address (v4 or v6) will be requested. The prefix-only indicates 
 1309    that the IPv6 prefix will be requested. The address-and-prefix 
 1310    indicates that both IPv6 address and prefix will be requested. 
 1311    The '-e prefix-only' and -'e address-and-prefix' must not be 
 1313-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6) 
 1314    elapsed-time option in the (second/request) template. 
 1315    The value 0 disables it. 
 1316-F<release-rate>: Rate at which Release requests are sent to 
 1317    a server. This value is only valid when used in conjunction with 
 1318    the exchange rate (given by -r<rate>).  Furthermore the sum of 
 1319    this value and the renew-rate (given by -f<rate>) must be equal 
 1320    to or less than the exchange rate. 
 1321-f<renew-rate>: Rate at which DHCPv4 or DHCPv6 renew requests are sent 
 1322    to a server. This value is only valid when used in conjunction 
 1323    with the exchange rate (given by -r<rate>).  Furthermore the sum of 
 1324    this value and the release-rate (given by -F<rate>) must be equal 
 1325    to or less than the exchange rate. 
 1326-g<thread-mode>: 'single' or 'multi'. In multi-thread mode packets 
 1327    are received in separate thread. This allows better utilisation of CPUs. 
 1328    If more than 1 CPU is present then multi-thread mode is the default, 
 1329    otherwise single-thread is the default. 
 1331-i: Do only the initial part of an exchange: DO or SA, depending on 
 1332    whether -6 is given. 
 1333-I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP 
 1334    option / (DHCPv6) IA_NA option in the (second/request) template. 
 1335-J<remote-address-list-file>: Text file that include multiple addresses. 
 1336    If provided perfdhcp will choose randomly one of addresses for each 
 1338-l<local-addr|interface>: For DHCPv4 operation, specify the local 
 1339    hostname/address to use when communicating with the server.  By 
 1340    default, the interface address through which traffic would 
 1341    normally be routed to the server is used. 
 1342    For DHCPv6 operation, specify the name of the network interface 
 1343    via which exchanges are initiated. 
 1344-L<local-port>: Specify the local port to use 
 1345    (the value 0 means to use the default). 
 1346-M<mac-list-file>: A text file containing a list of MAC addresses, 
 1347   one per line. If provided, a MAC address will be chosen randomly 
 1348   from this list for every new exchange. In the DHCPv6 case, MAC 
 1349   addresses are used to generate DUID-LLs. This parameter must not be 
 1350   used in conjunction with the -b parameter. 
 1351-N<remote-port>: Specify the remote port to use 
 1352    (the value 0 means to use the default). 
 1353-o<code,hexstring>: Send custom option with the specified code and the 
 1354    specified buffer in hexstring format. 
 1355-O<random-offset>: Offset of the last octet to randomize in the template. 
 1356-P<preload>: Initiate first <preload> exchanges back to back at startup. 
 1357-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA) 
 1358    exchanges per second.  A periodic report is generated showing the 
 1359    number of exchanges which were not completed, as well as the 
 1360    average response latency.  The program continues until 
 1361    interrupted, at which point a final report is generated. 
 1362-R<range>: Specify how many different clients are used. With 1 
 1363    (the default), all requests seem to come from the same client. 
 1364-s<seed>: Specify the seed for randomization, making it repeatable. 
 1365--scenario <name>: where name is 'basic' (default) or 'avalanche'. 
 1366-S<srvid-offset>: Offset of the server-ID option in the 
 1367    (second/request) template. 
 1368-T<template-file>: The name of a file containing the template to use 
 1369    as a stream of hexadecimal digits. 
 1370-u: Enable checking address uniqueness. Lease valid lifetime should not be 
 1371    shorter than test duration and clients should not request address more than 
 1372    once without releasing it first. 
 1373-v: Display the Kea version. 
 1374-V: Display the extended Kea version. 
 1375-W<time>: Specifies exit-wait-time parameter, that makes perfdhcp wait 
 1376    for <time> us after an exit condition has been met to receive all 
 1377    packets without sending any new packets. Expressed in microseconds. 
 1378-w<wrapped>: Command to call with start/stop at the beginning/end of 
 1380-x<diagnostic-selector>: Include extended diagnostics in the output. 
 1381    <diagnostic-selector> is a string of single-keywords specifying 
 1382    the operations for which verbose output is desired.  The selector 
 1384   * 'a': print the decoded command line arguments 
 1385   * 'e': print the exit reason 
 1386   * 'i': print rate processing details 
 1387   * 'l': print received leases 
 1388   * 's': print first server-id 
 1389   * 't': when finished, print timers of all successful exchanges 
 1390   * 'T': when finished, print templates 
 1391-X<xid-offset>: Transaction ID (aka. xid) offset in the template. 
 1392-Y<time>: time in seconds after which perfdhcp will start sending 
 1393    messages with increased elapsed time option. 
 1394-y<time>: period of time in seconds in which perfdhcp will be sending 
 1395    messages with increased elapsed time option. 
 1397-B: Force broadcast handling. 
 1400-c: Add a rapid commit option (exchanges will be SA). 
 1401-A<encapsulation-level>: Specifies that relayed traffic must be 
 1402    generated. The argument specifies the level of encapsulation, i.e. 
 1403    how many relay agents are simulated. Currently the only supported 
 1404    <encapsulation-level> value is 1, which means that the generated 
 1405    traffic is an equivalent of the traffic passing through a single 
 1407--or encapsulation-level:<code,hexstring>: Send given option included 
 1408    to simulated DHCPv6 relayed traffic at given level of encapsulation 
 1409    with the specified code and the specified buffer in hexstring format. 
 1410    Currently the only supported encapsulation-level value is 1. 
 1411    Must be used together with -A. 
 1413The remaining options are typically used in conjunction with -r: 
 1415-D<max-drop>: Abort the test immediately if max-drop requests have 
 1416    been dropped.  max-drop must be a positive integer. If max-drop 
 1417    includes the suffix '%', it specifies a maximum percentage of 
 1418    requests that may be dropped before abort. In this case, testing 
 1419    of the threshold begins after 10 requests have been expected to 
 1421-n<num-request>: Initiate <num-request> transactions.  No report is 
 1422    generated until all transactions have been initiated/waited-for, 
 1423    after which a report is generated and the program terminates. 
 1424-p<test-period>: Send requests for the given test period, which is 
 1425    specified in the same manner as -d.  This can be used as an 
 1426    alternative to -n, or both options can be given, in which case the 
 1427    testing is completed when either limit is reached. 
 1428-t<report>: Delay in seconds between two periodic reports. 
 1429-C<separator>: Output reduced, an argument is a separator for periodic 
 1430    (-t) reports generated in easy parsable mode. Data output won't be 
 1431    changed, remain identical as in -t option. 
 1434- tooshort: received a too short message 
 1435- orphans: received a message which doesn't match an exchange 
 1436   (duplicate, late or not related) 
 1437- locallimit: reached to local system limits when sending a message. 
 14410 on complete success. 
 14421 for a general error. 
 14432 if an error is found in the command line arguments. 
 14443 if there are no general failures in operation, but one or more 
 1445  exchanges are not successfully completed. 
 1451    std::cout << VERSION << std::endl;
 
 1456    cout << VERSION << 
" (" << EXTENDED_VERSION << 
")" << endl;
 
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
@ DUID_LLT
link-layer + time, see RFC3315, section 11.2
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
void set(const Type lease_type)
Sets the lease type code.
void fromCommandLine(const std::string &cmd_line_arg)
Sets the lease type from the command line argument.
bool is(const Type lease_type) const
Checks if lease type has the specified code.
std::string toText() const
Return textual representation of the lease type.
bool includes(const Type lease_type) const
Checks if lease type implies request for the address, prefix (or both) as specified by the function a...
int getIncreaseElapsedTime() const
Returns increased elapsed time.
int getServerIdOffset() const
Returns template offset for server-ID.
bool isSingleThreaded() const
Check if single-threaded mode is enabled.
int getRenewRate() const
Returns a rate at which DHCPv6 Renew messages are sent.
uint8_t getIpVersion() const
Returns IP version.
int getRate() const
Returns exchange rate.
void version() const
Print program version.
bool isRapidCommit() const
Check if rapid commit option used.
bool isUseFirst() const
Check if server-ID to be taken from first package.
int getLocalPort() const
Returns local port number.
void extendedVersion() const
Print extended program version.
std::string getMacListFile() const
Returns location of the file containing list of MAC addresses.
std::vector< int > getRandomOffset() const
Returns template offsets for rnd.
std::vector< double > getMaxDropPercentage() const
Returns maximal percentage of drops.
int getRemotePort() const
Returns remote port number.
static const uint8_t RELAY_OPTIONS_MAX_ENCAPSULATION
Maximum allowed level of encapsulation of added relay options.
int getWaitForElapsedTime() const
Returns time to wait for elapsed time increase.
bool isBroadcast() const
Checks if broadcast address is to be used.
std::vector< std::string > getTemplateFiles() const
Returns template file names.
std::vector< int > getTransactionIdOffset() const
brief Returns template offsets for xid.
int getElapsedTimeOffset() const
Returns template offset for elapsed time.
const isc::dhcp::OptionCollection & getRelayOpts(uint8_t encapsulation_level=1) const
Returns relay options to be inserted at given level of encapsulation.
std::vector< int > getNumRequests() const
Returns maximum number of exchanges.
LeaseType getLeaseType() const
\ brief Returns the type of lease being requested.
bool isUseRelayedV6() const
Check if generated DHCPv6 messages should appear as relayed.
uint32_t getClientsNum() const
Returns number of simulated clients.
void reset()
Reset to defaults.
std::vector< double > getDropTime() const
Returns drop time.
std::vector< int > getMaxDrop() const
Returns maximum drops number.
static void usage()
Print usage.
bool parse(int argc, char **const argv, bool print_cmd_line=false)
Parse command line.
int getReleaseRate() const
Returns a rate at which DHCPv6 Release messages are sent.
ExchangeMode getExchangeMode() const
Returns packet exchange mode.
void printCommandLine() const
Print command line arguments.
int getCleanReport() const
Returns clean report mode.
int getRequestedIpOffset() const
Returns template offset for requested IP.
#define DHCP_IPV4_BROADCAST_ADDRESS
#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
boost::shared_ptr< Option > OptionPtr
const int LONG_OPT_RELAY_OPTION
const int LONG_OPT_SCENARIO
void decodeHex(const string &encoded_str, vector< uint8_t > &output)
Decode a base16 encoded string into binary data.
Defines the logger used by the top-level component of kea-lfc.