19#include <boost/lexical_cast.hpp>
20#include <boost/date_time/posix_time/posix_time.hpp>
51 return (lease_type == type_);
56 return (is(ADDRESS_AND_PREFIX) || (lease_type == type_));
66 if (cmd_line_arg ==
"address-only") {
69 }
else if (cmd_line_arg ==
"prefix-only") {
72 }
else if (cmd_line_arg ==
"address-and-prefix") {
73 type_ = ADDRESS_AND_PREFIX;
77 " must be one of the following: 'address-only' or"
86 return (
"address-only (IA_NA option added to the client's request)");
88 return (
"prefix-only (IA_PD option added to the client's request)");
89 case ADDRESS_AND_PREFIX:
90 return (
"address-and-prefix (Both IA_NA and IA_PD options added to the"
91 " client's request)");
94 " returning textual representation of the lease type");
102 uint8_t mac[6] = { 0x0, 0xC, 0x1, 0x2, 0x3, 0x4 };
106 double dt[2] = { 1., 1. };
117 clean_report_ =
false;
118 clean_report_separator_ =
"";
120 mac_template_.assign(mac, mac + 6);
121 duid_template_.clear();
123 addr_unique_ =
false;
124 mac_list_file_.clear();
126 relay_addr_list_file_.clear();
127 relay_addr_list_.clear();
128 multi_subnet_ =
false;
129 num_request_.clear();
132 wait_for_elapsed_time_ = -1;
133 increased_elapsed_time_ = -1;
135 drop_time_.assign(dt, dt + 2);
139 is_interface_ =
false;
146 rapid_commit_ =
false;
148 template_file_.clear();
156 server_name_.clear();
157 v6_relay_encapsulation_level_ = 0;
158 generateDuidTemplate();
160 if (std::thread::hardware_concurrency() == 1) {
161 single_thread_mode_ =
true;
163 single_thread_mode_ =
false;
168 relay_opts_[i] = option_collection;
211 bool help_or_version_mode = initialize(argc, argv, print_cmd_line);
212 if (!help_or_version_mode) {
215 return (help_or_version_mode);
222CommandOptions::initialize(
int argc,
char** argv,
bool print_cmd_line) {
224 int opt_long_index = 0;
225 std::string drop_arg;
226 size_t percent_loc = 0;
227 double drop_percent = 0;
234 std::ostringstream stream;
235 stream <<
"perfdhcp";
236 int num_mac_list_files = 0;
237 int num_subnet_list_files = 0;
239 struct option long_options[] = {
247 while((opt = getopt_long(argc, argv,
248 "huv46A:r:t:R:b:n:p:d:D:l:P:a:L:N:M:s:iBc1"
249 "J:T:X:O:o:E:S:I:x:W:w:e:f:F:g:C:y:Y:",
250 long_options, &opt_long_index)) != -1) {
252 opt <= 'z' ? stream << static_cast<char>(opt) :
253 stream <<
"-" << long_options[opt_long_index].name;
255 stream <<
" " << optarg;
267 v6_relay_encapsulation_level_ =
268 static_cast<uint8_t
>(positiveInteger(
"-A<encapsulation-level> must"
269 " be a positive integer"));
270 if (v6_relay_encapsulation_level_ != 1) {
280 check(ipversion_ == 6,
"IP version already set to 6");
285 check(ipversion_ == 4,
"IP version already set to 4");
290 check(base_.size() > 3,
"-b<value> already specified,"
291 " unexpected occurrence of 5th -b<value>");
292 base_.push_back(optarg ? optarg :
"");
293 decodeBase(base_.back());
301 rapid_commit_ =
true;
305 clean_report_ =
true;
306 clean_report_separator_ = optarg ? optarg :
"";
310 check(drop_time_set_ > 1,
311 "maximum number of drops already specified, "
312 "unexpected 3rd occurrence of -d<value>");
314 drop_time_[drop_time_set_] =
315 boost::lexical_cast<double>(optarg ? optarg :
"");
316 }
catch (
const boost::bad_lexical_cast&) {
318 "value of drop time: -d<value>"
319 " must be positive number");
321 check(drop_time_[drop_time_set_] <= 0.,
322 "drop-time must be a positive number");
323 drop_time_set_ =
true;
327 drop_arg = std::string(optarg ? optarg :
"");
328 percent_loc = drop_arg.find(
'%');
329 check(max_pdrop_.size() > 1 || max_drop_.size() > 1,
330 "values of maximum drops: -D<value> already "
331 "specified, unexpected 3rd occurrence of -D<value>");
332 if ((percent_loc) != std::string::npos) {
335 boost::lexical_cast<double>(drop_arg.substr(0, percent_loc));
336 }
catch (
const boost::bad_lexical_cast&) {
338 "value of drop percentage: -D<value%>"
341 check((drop_percent <= 0) || (drop_percent >= 100),
342 "value of drop percentage: -D<value%> must be 0..100");
343 max_pdrop_.push_back(drop_percent);
345 num_drops = positiveInteger(
"value of max drops number:"
346 " -D<value> must be a positive integer");
347 max_drop_.push_back(num_drops);
356 elp_offset_ = nonNegativeInteger(
"value of time-offset: -E<value>"
357 " must not be a negative integer");
361 renew_rate_ = positiveInteger(
"value of the renew rate: -f<renew-rate>"
362 " must be a positive integer");
366 release_rate_ = positiveInteger(
"value of the release rate:"
367 " -F<release-rate> must be a"
368 " positive integer");
372 std::string optarg_text(optarg ? optarg :
"");
373 if (optarg_text ==
"single") {
374 single_thread_mode_ =
true;
375 }
else if (optarg_text ==
"multi") {
376 single_thread_mode_ =
false;
379 isc_throw(
InvalidParameter,
"value of thread mode (-g) '" << optarg <<
"' is wrong - should be '-g single' or '-g multi'");
391 exchange_mode_ =
DO_SA;
395 rip_offset_ = positiveInteger(
"value of ip address offset:"
396 " -I<value> must be a"
397 " positive integer");
401 check(num_subnet_list_files >= 1,
"only one -J option can be specified");
402 num_subnet_list_files++;
403 relay_addr_list_file_ = std::string(optarg ? optarg :
"");
408 localname_ = std::string(optarg ? optarg :
"");
413 local_port_ = nonNegativeInteger(
"value of local port:"
414 " -L<value> must not be a"
415 " negative integer");
417 static_cast<int>(std::numeric_limits<uint16_t>::max()),
418 "local-port must be lower than " +
419 boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
423 remote_port_ = nonNegativeInteger(
"value of remote port:"
424 " -L<value> must not be a"
425 " negative integer");
427 static_cast<int>(std::numeric_limits<uint16_t>::max()),
428 "remote-port must be lower than " +
429 boost::lexical_cast<std::string>(std::numeric_limits<uint16_t>::max()));
433 check(num_mac_list_files >= 1,
"only one -M option can be specified");
434 num_mac_list_files++;
435 mac_list_file_ = std::string(optarg ? optarg :
"");
440 exit_wait_time_ = nonNegativeInteger(
"value of exist wait time: "
441 "-W<value> must not be a "
446 num_req = positiveInteger(
"value of num-request:"
447 " -n<value> must be a positive integer");
448 if (num_request_.size() >= 2) {
450 "value of maximum number of requests: -n<value> "
451 "already specified, unexpected 3rd occurrence"
454 num_request_.push_back(num_req);
458 if (rnd_offset_.size() < 2) {
459 offset_arg = positiveInteger(
"value of random offset: "
460 "-O<value> must be greater than 3");
463 "random offsets already specified,"
464 " unexpected 3rd occurrence of -O<value>");
466 check(offset_arg < 3,
"value of random random-offset:"
467 " -O<value> must be greater than 3 ");
468 rnd_offset_.push_back(offset_arg);
473 check( (ipversion_ != 4) && (ipversion_ != 6),
474 "-4 or -6 must be explicitly specified before -o is used.");
477 std::string opt_text(optarg ? optarg :
"");
478 size_t comma_loc = opt_text.find(
',');
479 check(comma_loc == std::string::npos,
480 "-o option must provide option code, a comma and hexstring for"
481 " the option content, e.g. -o60,646f63736973 for sending option"
482 " 60 (class-id) with the value 'docsis'");
487 code = boost::lexical_cast<int>(opt_text.substr(0, comma_loc));
488 check(code <= 0,
"Option code can't be negative");
489 }
catch (
const boost::bad_lexical_cast&) {
491 "-o option, expected format: -o<integer>,<hexstring>");
495 opt_text = opt_text.substr(comma_loc + 1);
496 std::vector<uint8_t> bin;
507 extra_opts_.insert(make_pair(code, opt));
511 period_ = positiveInteger(
"value of test period:"
512 " -p<value> must be a positive integer");
516 preload_ = nonNegativeInteger(
"number of preload packets:"
517 " -P<value> must not be "
518 "a negative integer");
522 rate_ = positiveInteger(
"value of rate:"
523 " -r<value> must be a positive integer");
531 seed_ =
static_cast<unsigned int>
532 (nonNegativeInteger(
"value of seed:"
533 " -s <seed> must be non-negative integer"));
534 seeded_ = seed_ > 0 ? true :
false;
538 sid_offset_ = positiveInteger(
"value of server id offset:"
539 " -S<value> must be a"
540 " positive integer");
544 report_delay_ = positiveInteger(
"value of report delay:"
545 " -t<value> must be a"
546 " positive integer");
550 if (template_file_.size() < 2) {
551 sarg = nonEmptyString(
"template file name not specified,"
552 " expected -T<filename>");
553 template_file_.push_back(sarg);
556 "template files are already specified,"
557 " unexpected 3rd -T<filename> occurrence");
566 wrapped_ = nonEmptyString(
"command for wrapped mode:"
567 " -w<command> must be specified");
571 diags_ = nonEmptyString(
"value of diagnostics selectors:"
572 " -x<value> must be specified");
576 if (xid_offset_.size() < 2) {
577 offset_arg = positiveInteger(
"value of transaction id:"
578 " -X<value> must be a"
579 " positive integer");
582 "transaction ids already specified,"
583 " unexpected 3rd -X<value> occurrence");
585 xid_offset_.push_back(offset_arg);
589 wait_for_elapsed_time_ = nonNegativeInteger(
"value of time:"
590 " -Y<value> must be a non negative integer");
594 increased_elapsed_time_ = positiveInteger(
"value of time:"
595 " -y<value> must be a positive integer");
599 std::string optarg_text(optarg ? optarg :
"");
600 if (optarg_text ==
"basic") {
602 }
else if (optarg_text ==
"avalanche") {
613 check((ipversion_ != 6),
614 "-6 must be explicitly specified before --or is used.");
615 check(v6_relay_encapsulation_level_ <= 0,
616 "-A must be explicitly specified before --or is used.");
619 std::string opt_text(optarg ? optarg :
"");
620 size_t colon_loc = opt_text.find(
':');
621 size_t comma_loc = opt_text.find(
',');
624 uint8_t option_encapsulation_level = 1;
625 if (colon_loc == std::string::npos) {
632 option_encapsulation_level =
633 boost::lexical_cast<int>(opt_text.substr(0, colon_loc));
634 check(option_encapsulation_level != 1,
"Relayed option encapsulation level "
635 "supports only value 1 at the moment.");
636 }
catch (
const boost::bad_lexical_cast&) {
638 "Invalid relayed option encapsulation level specified for "
639 "--or option, expected format: --or <integer>:<integer>,<hexstring>");
643 check(comma_loc == std::string::npos,
644 "--or option must provide encapsulation level, a colon, option code, a comma and "
645 "hexstring for the option content, e.g. --or 1:38,31323334 for sending option"
646 " 38 (subscriber-id) with the value 1234 at first level of encapsulation");
651 code = boost::lexical_cast<int>(
652 opt_text.substr(colon_loc + 1, comma_loc - colon_loc - 1));
653 check(code <= 0,
"Option code can't be negative or zero");
654 }
catch (
const boost::bad_lexical_cast&) {
656 "Invalid option code specified for "
657 "--or option, expected format: --or <integer>:<integer>,<hexstring>");
661 opt_text = opt_text.substr(comma_loc + 1);
662 std::vector<uint8_t> bin;
671 auto relay_opts = relay_opts_.find(option_encapsulation_level);
672 relay_opts->second.insert(make_pair(code, option));
682 if (ipversion_ == 0) {
691 if (template_file_.size() > 1) {
692 if (xid_offset_.size() == 1) {
693 xid_offset_.push_back(xid_offset_[0]);
695 if (rnd_offset_.size() == 1) {
696 rnd_offset_.push_back(rnd_offset_[0]);
704 check(optind < argc -1,
"extra arguments?");
705 if (optind == argc - 1) {
706 server_name_ = argv[optind];
707 stream <<
" " << server_name_;
709 if ((ipversion_ == 4) && (server_name_.compare(
"all") == 0)) {
713 }
else if ((ipversion_ == 6) && (server_name_.compare(
"all") == 0)) {
715 }
else if ((ipversion_ == 6) &&
716 (server_name_.compare(
"servers") == 0)) {
721 if (print_cmd_line) {
722 std::cout <<
"Running: " << stream.str() << std::endl;
726 std::cout <<
"Scenario: basic." << std::endl;
728 std::cout <<
"Scenario: avalanche." << std::endl;
732 std::cout <<
"Multi-thread mode enabled." << std::endl;
737 if (!localname_.empty()) {
738 if (server_name_.empty()) {
739 if (is_interface_ && (ipversion_ == 4)) {
742 }
else if (is_interface_ && (ipversion_ == 6)) {
747 if (server_name_.empty()) {
749 "without an interface, server is required");
754 if (duid_template_.empty()) {
755 generateDuidTemplate();
761CommandOptions::initClientsNum() {
762 const std::string errmsg =
763 "value of -R <value> must be non-negative integer";
770 long long clients_num = boost::lexical_cast<long long>(optarg ? optarg :
"");
771 check(clients_num < 0, errmsg);
772 clients_num_ = boost::lexical_cast<uint32_t>(optarg ? optarg :
"");
773 }
catch (
const boost::bad_lexical_cast&) {
779CommandOptions::initIsInterface() {
780 is_interface_ =
false;
781 if (!localname_.empty()) {
783 if (iface_mgr.
getIface(localname_) != NULL) {
784 is_interface_ =
true;
790CommandOptions::decodeBase(
const std::string& base) {
792 boost::algorithm::to_lower(b);
795 if ((b.substr(0, 4) ==
"mac=") || (b.substr(0, 6) ==
"ether=")) {
797 }
else if (b.substr(0, 5) ==
"duid=") {
801 "base value not provided as -b<value>,"
802 " expected -b mac=<mac> or -b duid=<duid>");
807CommandOptions::decodeMacBase(
const std::string& base) {
809 size_t found = base.find(
'=');
810 static const char* errmsg =
"expected -b<base> format for"
811 " mac address is -b mac=00::0C::01::02::03::04 or"
812 " -b mac=00:0C:01:02:03:04";
813 check(found == std::string::npos, errmsg);
816 std::istringstream s1(base.substr(found + 1));
818 mac_template_.clear();
820 while (std::getline(s1, token,
':')) {
822 if (token.length() > 0) {
826 ui = convertHexString(token);
829 "invalid characters in MAC provided");
833 mac_template_.push_back(ui);
837 check(mac_template_.size() != 6, errmsg);
841CommandOptions::decodeDuid(
const std::string& base) {
843 std::vector<uint8_t> duid_template;
844 size_t found = base.find(
'=');
845 check(found == std::string::npos,
"expected -b<base>"
846 " format for duid is -b duid=<duid>");
847 std::string b = base.substr(found + 1);
850 check(b.length() & 1,
"odd number of hexadecimal digits in duid");
851 check(b.length() > 128,
"duid too large");
852 check(b.length() == 0,
"no duid specified");
855 for (
size_t i = 0; i < b.length(); i += 2) {
859 ui = convertHexString(b.substr(i, 2));
862 "invalid characters in DUID provided,"
863 " expected hex digits");
865 duid_template.push_back(
static_cast<uint8_t
>(ui));
870 check(duid_template.size() < 6,
"DUID must be at least 6 octets long");
872 std::swap(duid_template, duid_template_);
876CommandOptions::generateDuidTemplate() {
877 using namespace boost::posix_time;
881 duid_template_.clear();
882 const uint8_t duid_template_len = 14;
883 duid_template_.resize(duid_template_len);
887 duid_template_[2] = HWTYPE_ETHERNET >> 8;
888 duid_template_[3] = HWTYPE_ETHERNET & 0xff;
893 ptime now = microsec_clock::universal_time();
894 ptime duid_epoch(from_iso_string(
"20000101T000000"));
895 time_period period(duid_epoch, now);
896 uint32_t duration_sec = htonl(period.length().total_seconds());
897 memcpy(&duid_template_[4], &duration_sec, 4);
902 memcpy(&duid_template_[8], &mac_template_[0], 6);
909 "Trying to access relay options at encapsulation level that doesn't exist");
912 return relay_opts_.find(encapsulation_level)->second;
916CommandOptions::convertHexString(
const std::string& text)
const {
919 for (
size_t i = 0; i < text.length(); ++i) {
920 if (!std::isxdigit(text[i])) {
922 "The following digit: " << text[i] <<
" in "
923 << text <<
"is not hexadecimal");
927 std::istringstream text_stream(text);
928 text_stream >> std::hex >> ui >> std::dec;
932 " two hex digits to byte");
937bool CommandOptions::validateIP(
const std::string& line) {
947 relay_addr_list_.push_back(line);
948 multi_subnet_ =
true;
952void CommandOptions::loadRelayAddr() {
954 std::ifstream infile(relay_addr_list_file_.c_str());
956 while (std::getline(infile, line)) {
959 tmp <<
"invalid address or wrong address version in line: " << cnt;
960 check(validateIP(line), tmp.str());
962 check(cnt == 0,
"file with addresses is empty!");
965void CommandOptions::loadMacs() {
967 std::ifstream infile(mac_list_file_.c_str());
969 while (std::getline(infile, line)) {
972 tmp <<
"invalid mac in input line " << cnt;
974 check(decodeMacString(line), tmp.str());
978bool CommandOptions::decodeMacString(
const std::string& line) {
980 std::istringstream s(line);
982 std::vector<uint8_t> mac;
983 while(std::getline(s, token,
':')) {
985 if (token.length() > 0) {
989 ui = convertHexString(token);
997 mac_list_.push_back(mac);
1002CommandOptions::validate() {
1004 "-B is not compatible with IPv6 (-6)");
1006 "-6 (IPv6) must be set to use -c");
1008 "Can't use -4 with -A, it's a V6 only option.");
1010 "second -n<num-request> is not compatible with -i");
1012 "-6 option must be used if lease type other than '-e address-only'"
1016 "template files may be only used with '-e address-only'");
1018 "second -d<drop-time> is not compatible with -i");
1021 "second -D<max-drop> is not compatible with -i");
1023 "-1 is not compatible with -i");
1025 "second -T<template-file> is not compatible with -i");
1027 "second -X<xid-offset> is not compatible with -i");
1029 "second -O<random-offset is not compatible with -i");
1031 "-E<time-offset> is not compatible with -i");
1033 "-S<srvid-offset> is not compatible with -i");
1035 "-I<ip-offset> is not compatible with -i");
1037 "-f<renew-rate> is not compatible with -i");
1039 "-F<release-rate> is not compatible with -i");
1041 "-i must be set to use -c");
1043 "The sum of Renew rate (-f<renew-rate>) and Release rate"
1044 " (-F<release-rate>) must not be greater than the exchange"
1045 " rate specified as -r<rate>");
1047 "Renew rate specified as -f<renew-rate> must not be specified"
1048 " when -r<rate> parameter is not specified");
1050 "Release rate specified as -F<release-rate> must not be specified"
1051 " when -r<rate> parameter is not specified");
1053 "-T<template-file> must be set to use -X<xid-offset>");
1055 "-T<template-file> must be set to use -O<random-offset>");
1057 "second/request -T<template-file> must be set to use -E<time-offset>");
1059 "second/request -T<template-file> must be set to "
1060 "use -S<srvid-offset>");
1062 "second/request -T<template-file> must be set to "
1063 "use -I<ip-offset>");
1065 "Can't use -b with -M option");
1067 "Option -y can't be used without -Y");
1069 "Option -Y can't be used without -y");
1070 auto nthreads = std::thread::hardware_concurrency();
1072 std::cout <<
"WARNING: Currently system can run only 1 thread in parallel." << std::endl
1073 <<
"WARNING: Better results are achieved when run in single-threaded mode." << std::endl
1074 <<
"WARNING: To switch use -g single option." << std::endl;
1076 std::cout <<
"WARNING: Currently system can run more than 1 thread in parallel." << std::endl
1077 <<
"WARNING: Better results are achieved when run in multi-threaded mode." << std::endl
1078 <<
"WARNING: To switch use -g multi option." << std::endl;
1083 "in case of avalanche scenario number\nof clients must be specified"
1084 " using -R option explicitly");
1087 double dt[2] = { 1000.0, 1000.0 };
1088 drop_time_.assign(dt, dt + 2);
1089 if (drop_time_set_) {
1090 std::cout <<
"INFO: in avalanche scenario drop time is ignored" << std::endl;
1096CommandOptions::check(
bool condition,
const std::string& errmsg)
const {
1099 std::ostringstream stream;
1100 stream << errmsg <<
"\n";
1107CommandOptions::positiveInteger(
const std::string& errmsg)
const {
1109 int value = boost::lexical_cast<int>(optarg ? optarg :
"");
1110 check(value <= 0, errmsg);
1112 }
catch (
const boost::bad_lexical_cast&) {
1118CommandOptions::nonNegativeInteger(
const std::string& errmsg)
const {
1120 int value = boost::lexical_cast<int>(optarg ? optarg :
"");
1121 check(value < 0, errmsg);
1123 }
catch (
const boost::bad_lexical_cast&) {
1129CommandOptions::nonEmptyString(
const std::string& errmsg)
const {
1130 std::string sarg(optarg ? optarg :
"");
1131 if (sarg.length() == 0) {
1138CommandOptions::initLeaseType() {
1139 std::string lease_type_arg(optarg ? optarg :
"");
1145 std::cout <<
"IPv" <<
static_cast<int>(ipversion_) << std::endl;
1146 if (exchange_mode_ ==
DO_SA) {
1147 if (ipversion_ == 4) {
1148 std::cout <<
"DISCOVER-OFFER only" << std::endl;
1150 std::cout <<
"SOLICIT-ADVERTISE only" << std::endl;
1155 std::cout <<
"rate[1/s]=" << rate_ << std::endl;
1158 std::cout <<
"renew-rate[1/s]=" <<
getRenewRate() << std::endl;
1161 std::cout <<
"release-rate[1/s]=" <<
getReleaseRate() << std::endl;
1163 if (report_delay_ != 0) {
1164 std::cout <<
"report[s]=" << report_delay_ << std::endl;
1166 if (clients_num_ != 0) {
1167 std::cout <<
"clients=" << clients_num_ << std::endl;
1169 for (
size_t i = 0; i < base_.size(); ++i) {
1170 std::cout <<
"base[" << i <<
"]=" << base_[i] << std::endl;
1172 for (
size_t i = 0; i < num_request_.size(); ++i) {
1173 std::cout <<
"num-request[" << i <<
"]=" << num_request_[i] << std::endl;
1176 std::cout <<
"test-period=" << period_ << std::endl;
1178 for (
size_t i = 0; i < drop_time_.size(); ++i) {
1179 std::cout <<
"drop-time[" << i <<
"]=" << drop_time_[i] << std::endl;
1181 for (
size_t i = 0; i < max_drop_.size(); ++i) {
1182 std::cout <<
"max-drop{" << i <<
"]=" << max_drop_[i] << std::endl;
1184 for (
size_t i = 0; i < max_pdrop_.size(); ++i) {
1185 std::cout <<
"max-pdrop{" << i <<
"]=" << max_pdrop_[i] << std::endl;
1187 if (preload_ != 0) {
1188 std::cout <<
"preload=" << preload_ << std::endl;
1191 std::cout <<
"local-port=" << local_port_ << std::endl;
1194 std::cout <<
"remote-port=" << remote_port_ << std::endl;
1197 std::cout <<
"seed=" << seed_ << std::endl;
1200 std::cout <<
"broadcast" << std::endl;
1202 if (rapid_commit_) {
1203 std::cout <<
"rapid-commit" << std::endl;
1206 std::cout <<
"use-first" << std::endl;
1208 if (!mac_list_file_.empty()) {
1209 std::cout <<
"mac-list-file=" << mac_list_file_ << std::endl;
1211 for (
size_t i = 0; i < template_file_.size(); ++i) {
1212 std::cout <<
"template-file[" << i <<
"]=" << template_file_[i] << std::endl;
1214 for (
size_t i = 0; i < xid_offset_.size(); ++i) {
1215 std::cout <<
"xid-offset[" << i <<
"]=" << xid_offset_[i] << std::endl;
1217 if (elp_offset_ != 0) {
1218 std::cout <<
"elp-offset=" << elp_offset_ << std::endl;
1220 for (
size_t i = 0; i < rnd_offset_.size(); ++i) {
1221 std::cout <<
"rnd-offset[" << i <<
"]=" << rnd_offset_[i] << std::endl;
1223 if (sid_offset_ != 0) {
1224 std::cout <<
"sid-offset=" << sid_offset_ << std::endl;
1226 if (rip_offset_ != 0) {
1227 std::cout <<
"rip-offset=" << rip_offset_ << std::endl;
1229 if (!diags_.empty()) {
1230 std::cout <<
"diagnostic-selectors=" << diags_ << std::endl;
1232 if (!wrapped_.empty()) {
1233 std::cout <<
"wrapped=" << wrapped_ << std::endl;
1235 if (!localname_.empty()) {
1236 if (is_interface_) {
1237 std::cout <<
"interface=" << localname_ << std::endl;
1239 std::cout <<
"local-addr=" << localname_ << std::endl;
1242 if (!server_name_.empty()) {
1243 std::cout <<
"server=" << server_name_ << std::endl;
1245 if (single_thread_mode_) {
1246 std::cout <<
"single-thread-mode" << std::endl;
1248 std::cout <<
"multi-thread-mode" << std::endl;
1255R
"(perfdhcp [-1] [-4 | -6] [-A encapsulation-level] [-b base] [-B] [-c]
1256 [-C separator] [-d drop-time] [-D max-drop] [-e lease-type]
1257 [-E time-offset] [-f renew-rate] [-F release-rate] [-g thread-mode]
1258 [-h] [-i] [-I ip-offset] [-J remote-address-list-file]
1259 [-l local-address|interface] [-L local-port] [-M mac-list-file]
1260 [-n num-request] [-N remote-port] [-O random-offset]
1261 [-o code,hexstring] [--or encapsulation-level:code,hexstring]
1262 [-p test-period] [-P preload] [-r rate]
1263 [-R num-clients] [-s seed] [-S srvid-offset] [--scenario name]
1264 [-t report] [-T template-file] [-u] [-v] [-W exit-wait-time]
1265 [-w script_name] [-x diagnostic-selector] [-X xid-offset] [server]
1267The [server] argument is the name/address of the DHCP server to
1268contact. For DHCPv4 operation, exchanges are initiated by
1269transmitting a DHCP DISCOVER to this address.
1271For DHCPv6 operation, exchanges are initiated by transmitting a DHCP
1272SOLICIT to this address. In the DHCPv6 case, the special name 'all'
1273can be used to refer to All_DHCP_Relay_Agents_and_Servers (the
1274multicast address FF02::1:2), or the special name 'servers' to refer
1275to All_DHCP_Servers (the multicast address FF05::1:3). The [server]
1276argument is optional only in the case that -l is used to specify an
1277interface, in which case [server] defaults to 'all'.
1279The default is to perform a single 4-way exchange, effectively pinging
1281The -r option is used to set up a performance test, without
1282it exchanges are initiated as fast as possible.
1283The other scenario is an avalanche which is selected by
1284--scenario avalanche. It first sends as many Discovery or Solicit
1285messages as request in -R option then back off mechanism is used for
1286each simulated client until all requests are answered. At the end
1287time of whole scenario is reported.
1290-1: Take the server-ID option from the first received message.
1291-4: DHCPv4 operation (default). This is incompatible with the -6 option.
1292-6: DHCPv6 operation. This is incompatible with the -4 option.
1293-b<base>: The base mac, duid, IP, etc, used to simulate different
1294 clients. This can be specified multiple times, each instance is
1295 in the <type>=<value> form, for instance:
1296 (and default) mac=00:0c:01:02:03:04.
1297-d<drop-time>: Specify the time after which a request is treated as
1298 having been lost. The value is given in seconds and may contain a
1299 fractional component. The default is 1 second.
1300-e<lease-type>: A type of lease being requested from the server. It
1301 may be one of the following: address-only, prefix-only or
1302 address-and-prefix. The address-only indicates that the regular
1303 address (v4 or v6) will be requested. The prefix-only indicates
1304 that the IPv6 prefix will be requested. The address-and-prefix
1305 indicates that both IPv6 address and prefix will be requested.
1306 The '-e prefix-only' and -'e address-and-prefix' must not be
1308-E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)
1309 elapsed-time option in the (second/request) template.
1310 The value 0 disables it.
1311-F<release-rate>: Rate at which Release requests are sent to
1312 a server. This value is only valid when used in conjunction with
1313 the exchange rate (given by -r<rate>). Furthermore the sum of
1314 this value and the renew-rate (given by -f<rate>) must be equal
1315 to or less than the exchange rate.
1316-f<renew-rate>: Rate at which DHCPv4 or DHCPv6 renew requests are sent
1317 to a server. This value is only valid when used in conjunction
1318 with the exchange rate (given by -r<rate>). Furthermore the sum of
1319 this value and the release-rate (given by -F<rate>) must be equal
1320 to or less than the exchange rate.
1321-g<thread-mode>: 'single' or 'multi'. In multi-thread mode packets
1322 are received in separate thread. This allows better utilisation of CPUs.
1323 If more than 1 CPU is present then multi-thread mode is the default,
1324 otherwise single-thread is the default.
1326-i: Do only the initial part of an exchange: DO or SA, depending on
1327 whether -6 is given.
1328-I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP
1329 option / (DHCPv6) IA_NA option in the (second/request) template.
1330-J<remote-address-list-file>: Text file that include multiple addresses.
1331 If provided perfdhcp will choose randomly one of addresses for each
1333-l<local-addr|interface>: For DHCPv4 operation, specify the local
1334 hostname/address to use when communicating with the server. By
1335 default, the interface address through which traffic would
1336 normally be routed to the server is used.
1337 For DHCPv6 operation, specify the name of the network interface
1338 via which exchanges are initiated.
1339-L<local-port>: Specify the local port to use
1340 (the value 0 means to use the default).
1341-M<mac-list-file>: A text file containing a list of MAC addresses,
1342 one per line. If provided, a MAC address will be chosen randomly
1343 from this list for every new exchange. In the DHCPv6 case, MAC
1344 addresses are used to generate DUID-LLs. This parameter must not be
1345 used in conjunction with the -b parameter.
1346-N<remote-port>: Specify the remote port to use
1347 (the value 0 means to use the default).
1348-o<code,hexstring>: Send custom option with the specified code and the
1349 specified buffer in hexstring format.
1350-O<random-offset>: Offset of the last octet to randomize in the template.
1351-P<preload>: Initiate first <preload> exchanges back to back at startup.
1352-r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)
1353 exchanges per second. A periodic report is generated showing the
1354 number of exchanges which were not completed, as well as the
1355 average response latency. The program continues until
1356 interrupted, at which point a final report is generated.
1357-R<range>: Specify how many different clients are used. With 1
1358 (the default), all requests seem to come from the same client.
1359-s<seed>: Specify the seed for randomization, making it repeatable.
1360--scenario <name>: where name is 'basic' (default) or 'avalanche'.
1361-S<srvid-offset>: Offset of the server-ID option in the
1362 (second/request) template.
1363-T<template-file>: The name of a file containing the template to use
1364 as a stream of hexadecimal digits.
1365-u: Enable checking address uniqueness. Lease valid lifetime should not be
1366 shorter than test duration and clients should not request address more than
1367 once without releasing it first.
1368-v: Report the version number of this program.
1369-W<time>: Specifies exit-wait-time parameter, that makes perfdhcp wait
1370 for <time> us after an exit condition has been met to receive all
1371 packets without sending any new packets. Expressed in microseconds.
1372-w<wrapped>: Command to call with start/stop at the beginning/end of
1374-x<diagnostic-selector>: Include extended diagnostics in the output.
1375 <diagnostic-selector> is a string of single-keywords specifying
1376 the operations for which verbose output is desired. The selector
1378 * 'a': print the decoded command line arguments
1379 * 'e': print the exit reason
1380 * 'i': print rate processing details
1381 * 'l': print received leases
1382 * 's': print first server-id
1383 * 't': when finished, print timers of all successful exchanges
1384 * 'T': when finished, print templates
1385-X<xid-offset>: Transaction ID (aka. xid) offset in the template.
1386-Y<time>: time in seconds after which perfdhcp will start sending
1387 messages with increased elapsed time option.
1388-y<time>: period of time in seconds in which perfdhcp will be sending
1389 messages with increased elapsed time option.
1391-B: Force broadcast handling.
1394-c: Add a rapid commit option (exchanges will be SA).
1395-A<encapsulation-level>: Specifies that relayed traffic must be
1396 generated. The argument specifies the level of encapsulation, i.e.
1397 how many relay agents are simulated. Currently the only supported
1398 <encapsulation-level> value is 1, which means that the generated
1399 traffic is an equivalent of the traffic passing through a single
1401--or encapsulation-level:<code,hexstring>: Send given option included
1402 to simulated DHCPv6 relayed traffic at given level of encapsulation
1403 with the specified code and the specified buffer in hexstring format.
1404 Currently the only supported encapsulation-level value is 1.
1405 Must be used together with -A.
1407The remaining options are typically used in conjunction with -r:
1409-D<max-drop>: Abort the test immediately if max-drop requests have
1410 been dropped. max-drop must be a positive integer. If max-drop
1411 includes the suffix '%', it specifies a maximum percentage of
1412 requests that may be dropped before abort. In this case, testing
1413 of the threshold begins after 10 requests have been expected to
1415-n<num-request>: Initiate <num-request> transactions. No report is
1416 generated until all transactions have been initiated/waited-for,
1417 after which a report is generated and the program terminates.
1418-p<test-period>: Send requests for the given test period, which is
1419 specified in the same manner as -d. This can be used as an
1420 alternative to -n, or both options can be given, in which case the
1421 testing is completed when either limit is reached.
1422-t<report>: Delay in seconds between two periodic reports.
1423-C<separator>: Output reduced, an argument is a separator for periodic
1424 (-t) reports generated in easy parsable mode. Data output won't be
1425 changed, remain identical as in -t option.
1428- tooshort: received a too short message
1429- orphans: received a message which doesn't match an exchange
1430 (duplicate, late or not related)
1431- locallimit: reached to local system limits when sending a message.
14350 on complete success.
14361 for a general error.
14372 if an error is found in the command line arguments.
14383 if there are no general failures in operation, but one or more
1439 exchanges are not successfully completed.
1445 std::cout <<
"VERSION: " << VERSION << std::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.
The IOAddress class represents an IP addresses (version agnostic)
An exception that is thrown if an error occurs within the IO module.
@ DUID_LLT
link-layer + time, see RFC3315, section 11.2
Handles network interfaces, transmission and reception.
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.
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 &input, vector< uint8_t > &result)
Decode a text encoded in the base16 ('hex') format into the original data.
Defines the logger used by the top-level component of kea-lfc.