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_);
57 return (is(ADDRESS_AND_PREFIX) || (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") {
74 type_ = 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)");
90 case ADDRESS_AND_PREFIX:
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);
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));
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) {
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);
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";
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) {
1143CommandOptions::initLeaseType() {
1144 std::string lease_type_arg(optarg ? optarg :
"");
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.
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.
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.