25 #include <boost/date_time/posix_time/posix_time.hpp>
37 using namespace boost::posix_time;
45 bool TestControl::interrupted_ =
false;
48 TestControl::waitToExit() {
49 uint32_t
const wait_time = options_.getExitWaitTime();
52 if (wait_time && !haveAllPacketsBeenReceived()) {
53 const ptime now = microsec_clock::universal_time();
56 if (exit_time_.is_not_a_date_time()) {
57 exit_time_ = now + time_duration(microseconds(wait_time));
61 return (now < exit_time_);
69 TestControl::haveAllPacketsBeenReceived()
const {
70 const uint8_t& ipversion = options_.getIpVersion();
71 const std::vector<int>& num_request = options_.getNumRequests();
72 const size_t& num_request_size = num_request.size();
74 if (num_request_size == 0) {
78 uint32_t responses = 0;
79 uint32_t requests = num_request[0];
80 if (num_request_size >= 2) {
81 requests += num_request[1];
85 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) +
86 stats_mgr_.getRcvdPacketsNum(ExchangeType::RA);
88 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) +
89 stats_mgr_.getRcvdPacketsNum(ExchangeType::RR);
92 return (responses == requests);
96 TestControl::cleanCachedPackets() {
99 if (options_.getRenewRate() == 0) {
103 static boost::posix_time::ptime last_clean =
104 microsec_clock::universal_time();
107 time_period time_since_clean(last_clean,
108 microsec_clock::universal_time());
110 if (time_since_clean.length().total_seconds() >= 1) {
116 if (reply_storage_.size() > 5 * options_.getRenewRate()) {
117 reply_storage_.clear(reply_storage_.size() -
118 5 * options_.getRenewRate());
122 last_clean = microsec_clock::universal_time();
128 if (!pkt_from || !pkt_to) {
130 " for the copyIaOptions function");
133 if (options_.getLeaseType()
134 .includes(CommandOptions::LeaseType::ADDRESS)) {
138 " server's response");
140 pkt_to->addOption(option);
143 if (options_.getLeaseType()
144 .includes(CommandOptions::LeaseType::PREFIX)) {
148 " server's response");
150 pkt_to->addOption(option);
155 TestControl::byte2Hex(
const uint8_t b) {
156 const int b1 = b / 16;
157 const int b0 = b % 16;
158 ostringstream stream;
159 stream << std::hex << b1 << b0 << std::dec;
160 return (stream.str());
164 TestControl::createMessageFromAck(
const uint16_t msg_type,
169 <<
" to be created from Reply, expected DHCPREQUEST or"
175 auto msg_type_str = [=]() ->
const char* {
176 return (msg_type ==
DHCPREQUEST ?
"Request" :
"Release");
182 <<
" from a null DHCPACK message");
183 }
else if (ack->getYiaddr().isV4Zero()) {
187 <<
" from a DHCPACK message containing yiaddr of 0");
189 Pkt4Ptr msg(
new Pkt4(msg_type, generateTransid()));
190 msg->setCiaddr(ack->getYiaddr());
191 msg->setHWAddr(ack->getHWAddr());
192 msg->addOption(generateClientId(msg->getHWAddr()));
195 if (options_.isUseFirst()) {
197 if (first_packet_serverid_.empty()) {
201 <<
"from the first packet which lacks the server "
202 "identifier option");
204 msg->addOption(Option::factory(Option::V4,
206 first_packet_serverid_));
211 if (!server_identifier) {
215 <<
"from a DHCPACK message without the server "
216 "identifier option");
218 msg->addOption(server_identifier);
225 TestControl::createMessageFromReply(
const uint16_t msg_type,
230 <<
" to be created from Reply, expected DHCPV6_RENEW or"
236 auto msg_type_str = [=]() ->
const char* {
237 return (msg_type ==
DHCPV6_RENEW ?
"Renew" :
"Release");
243 <<
" message from the Reply message because the instance of"
244 " the Reply message is NULL");
247 Pkt6Ptr msg(
new Pkt6(msg_type, generateTransid()));
252 <<
" message because client id option has not been found"
253 " in the Reply message");
255 msg->addOption(opt_clientid);
260 <<
" because server id option has not been found in the"
263 msg->addOption(opt_serverid);
264 copyIaOptions(reply, msg);
271 if (buf.size() == 2) {
273 }
else if (buf.size() == 0) {
278 "elapsed time option buffer size has to be 0 or 2");
292 const uint8_t buf_array[] = {
294 0, 0, 3600 >> 8, 3600 & 0xff,
295 0, 0, 5400 >> 8, 5400 & 0xff,
297 OptionBuffer buf_ia_na(buf_array, buf_array +
sizeof(buf_array));
298 for (
size_t i = 0; i < buf.size(); ++i) {
299 buf_ia_na.push_back(buf[i]);
308 static const uint8_t buf_array[] = {
310 0, 0, 3600 >> 8, 3600 & 0xff,
311 0, 0, 5400 >> 8, 5400 & 0xff,
313 OptionBuffer buf_ia_pd(buf_array, buf_array +
sizeof(buf_array));
315 buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
330 const uint8_t buf_array[] = {
334 OptionBuffer buf_with_options(buf_array, buf_array +
sizeof(buf_array));
343 const uint8_t buf_array[] = {
353 OptionBuffer buf_with_options(buf_array, buf_array +
sizeof(buf_array));
355 opt->setData(buf_with_options.begin(), buf_with_options.end());
360 TestControl::generateMacAddress(uint8_t& randomized) {
363 if (macs.size() > 0) {
364 uint16_t r = number_generator_();
365 if (r >= macs.size()) {
372 uint32_t clients_num = options_.getClientsNum();
373 if (clients_num < 2) {
374 return (options_.getMacTemplate());
377 std::vector<uint8_t> mac_addr(options_.getMacTemplate());
378 if (mac_addr.size() != HW_ETHER_LEN) {
381 uint32_t r = macaddr_gen_->generate();
384 for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
385 it >= mac_addr.begin();
407 std::vector<uint8_t> client_id(1,
static_cast<uint8_t
>(hwaddr->htype_));
408 client_id.insert(client_id.end(), hwaddr->hwaddr_.begin(),
409 hwaddr->hwaddr_.end());
415 TestControl::generateDuid(uint8_t& randomized) {
416 std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
419 if (macs.size() > 0) {
420 uint16_t r = number_generator_();
421 if (r >= macs.size()) {
424 std::vector<uint8_t> mac = macs[r];
438 uint8_t duid_ll[] = {0, 3, 0, 1, 0, 0, 0, 0, 0, 0};
440 std::vector<uint8_t> duid(duid_ll,
441 duid_ll +
sizeof(duid_ll) /
sizeof(duid_ll[0]));
443 std::copy(mac.begin(), mac.end(), duid.begin() + 4);
446 uint32_t clients_num = options_.getClientsNum();
447 if ((clients_num == 0) || (clients_num == 1)) {
448 return (options_.getDuidTemplate());
451 std::vector<uint8_t> duid(options_.getDuidTemplate());
453 duid.resize(duid.size());
454 std::copy(mac_addr.begin(), mac_addr.end(),
455 duid.begin() + duid.size() - mac_addr.size());
461 TestControl::getElapsedTimeOffset()
const {
462 int elp_offset = options_.getIpVersion() == 4 ?
463 DHCPV4_ELAPSED_TIME_OFFSET : DHCPV6_ELAPSED_TIME_OFFSET;
464 if (options_.getElapsedTimeOffset() > 0) {
465 elp_offset = options_.getElapsedTimeOffset();
472 TestControl::getElapsedTime(
const T& pkt1,
const T& pkt2) {
473 using namespace boost::posix_time;
474 ptime pkt1_time = pkt1->getTimestamp();
475 ptime pkt2_time = pkt2->getTimestamp();
476 if (pkt1_time.is_not_a_date_time() ||
477 pkt2_time.is_not_a_date_time()) {
480 time_period elapsed_period(pkt1_time, pkt2_time);
481 return (elapsed_period.is_null() ? 0 :
482 elapsed_period.length().total_milliseconds());
486 TestControl::getRandomOffset(
const int arg_idx)
const {
487 int rand_offset = options_.getIpVersion() == 4 ?
488 DHCPV4_RANDOMIZATION_OFFSET : DHCPV6_RANDOMIZATION_OFFSET;
489 if (options_.getRandomOffset().size() > arg_idx) {
490 rand_offset = options_.getRandomOffset()[arg_idx];
492 return (rand_offset);
496 TestControl::getRequestedIpOffset()
const {
497 int rip_offset = options_.getIpVersion() == 4 ?
498 DHCPV4_REQUESTED_IP_OFFSET : DHCPV6_IA_NA_OFFSET;
499 if (options_.getRequestedIpOffset() > 0) {
500 rip_offset = options_.getRequestedIpOffset();
506 TestControl::getServerIdOffset()
const {
507 int srvid_offset = options_.getIpVersion() == 4 ?
508 DHCPV4_SERVERID_OFFSET : DHCPV6_SERVERID_OFFSET;
509 if (options_.getServerIdOffset() > 0) {
510 srvid_offset = options_.getServerIdOffset();
512 return (srvid_offset);
516 TestControl::getTemplateBuffer(
const size_t idx)
const {
517 if (template_buffers_.size() > idx) {
518 return (template_buffers_[idx]);
524 TestControl::getTransactionIdOffset(
const int arg_idx)
const {
525 int xid_offset = options_.getIpVersion() == 4 ?
526 DHCPV4_TRANSID_OFFSET : DHCPV6_TRANSID_OFFSET;
527 if (options_.getTransactionIdOffset().size() > arg_idx) {
528 xid_offset = options_.getTransactionIdOffset()[arg_idx];
534 TestControl::handleChild(
int) {
536 while (wait3(&status, WNOHANG, NULL) > 0) {
542 TestControl::handleInterrupt(
int) {
547 TestControl::initPacketTemplates() {
548 template_packets_v4_.clear();
549 template_packets_v6_.clear();
550 template_buffers_.clear();
551 std::vector<std::string> template_files = options_.getTemplateFiles();
552 for (std::vector<std::string>::const_iterator it = template_files.begin();
553 it != template_files.end(); ++it) {
554 readPacketTemplate(*it);
559 TestControl::sendPackets(
const uint64_t packets_num,
560 const bool preload ) {
561 for (uint64_t i = packets_num; i > 0; --i) {
562 if (options_.getIpVersion() == 4) {
565 if (template_buffers_.empty()) {
566 sendDiscover4(preload);
570 sendDiscover4(template_buffers_[0], preload);
575 if (template_buffers_.empty()) {
576 sendSolicit6(preload);
580 sendSolicit6(template_buffers_[0], preload);
587 TestControl::sendMultipleMessages4(
const uint32_t msg_type,
588 const uint64_t msg_num) {
589 for (uint64_t i = 0; i < msg_num; ++i) {
590 if (!sendMessageFromAck(msg_type)) {
598 TestControl::sendMultipleMessages6(
const uint32_t msg_type,
599 const uint64_t msg_num) {
600 for (uint64_t i = 0; i < msg_num; ++i) {
601 if (!sendMessageFromReply(msg_type)) {
609 TestControl::printDiagnostics()
const {
610 if (options_.testDiags(
'a')) {
612 options_.printCommandLine();
614 std::cout <<
"Set MAC to " << vector2Hex(options_.getMacTemplate(),
"::")
616 if (options_.getDuidTemplate().size() > 0) {
617 std::cout <<
"Set DUID to " << vector2Hex(options_.getDuidTemplate()) << std::endl;
623 TestControl::printTemplate(
const uint8_t packet_type)
const {
626 if (options_.getIpVersion() == 4) {
630 std::map<uint8_t, dhcp::Pkt4Ptr>::const_iterator pkt_it =
631 template_packets_v4_.find(packet_type);
632 if ((pkt_it != template_packets_v4_.end()) &&
635 const char* out_buf_data =
636 static_cast<const char*
>(out_buf.
getData());
637 std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.
getLength());
638 hex_buf = vector2Hex(buf);
640 }
else if (options_.getIpVersion() == 6) {
644 std::map<uint8_t, dhcp::Pkt6Ptr>::const_iterator pkt_it =
645 template_packets_v6_.find(packet_type);
646 if (pkt_it != template_packets_v6_.end() &&
649 const char* out_buf_data =
650 static_cast<const char*
>(out_buf.
getData());
651 std::vector<uint8_t> buf(out_buf_data, out_buf_data + out_buf.
getLength());
652 hex_buf = vector2Hex(buf);
655 std::cout <<
"xid-offset=" << getTransactionIdOffset(arg_idx) << std::endl;
656 std::cout <<
"random-offset=" << getRandomOffset(arg_idx) << std::endl;
658 std::cout <<
"srvid-offset=" << getServerIdOffset() << std::endl;
659 std::cout <<
"time-offset=" << getElapsedTimeOffset() << std::endl;
660 std::cout <<
"ip-offset=" << getRequestedIpOffset() << std::endl;
663 std::cout <<
"contents: " << std::endl;
666 while (line_len == 32) {
667 if (hex_buf.length() - i < 32) {
668 line_len = hex_buf.length() - i;
671 std::cout << setfill(
'0') << setw(4) << std::hex << i << std::dec
672 <<
" " << hex_buf.substr(i, line_len) << std::endl;
676 std::cout << std::endl;
680 TestControl::printTemplates()
const {
681 if (options_.getIpVersion() == 4) {
684 }
else if (options_.getIpVersion() == 6) {
691 TestControl::printRate()
const {
693 std::string exchange_name =
"4-way exchanges";
695 if (options_.getIpVersion() == 4) {
697 options_.getExchangeMode() == CommandOptions::DO_SA ?
698 ExchangeType::DO : ExchangeType::RA;
699 if (xchg_type == ExchangeType::DO) {
700 exchange_name =
"DISCOVER-OFFER";
702 }
else if (options_.getIpVersion() == 6) {
704 options_.getExchangeMode() == CommandOptions::DO_SA ?
705 ExchangeType::SA : ExchangeType::RR;
706 if (xchg_type == ExchangeType::SA) {
707 exchange_name = options_.isRapidCommit() ?
"Solicit-Reply" :
712 stats_mgr_.getTestPeriod().length().total_nanoseconds() / 1e9;
713 rate = stats_mgr_.getRcvdPacketsNum(xchg_type) / duration;
714 std::ostringstream s;
715 s <<
"***Rate statistics***" << std::endl;
716 s <<
"Rate: " << rate <<
" " << exchange_name <<
"/second";
717 if (options_.getRate() > 0) {
718 s <<
", expected rate: " << options_.getRate() << std::endl;
721 std::cout << s.str() << std::endl;
723 std::cout <<
"***Malformed Packets***" << std::endl
724 <<
"Malformed packets: " << ExchangeStats::malformed_pkts_
729 TestControl::printIntermediateStats() {
730 int delay = options_.getReportDelay();
731 ptime now = microsec_clock::universal_time();
732 time_period time_since_report(last_report_, now);
733 if (time_since_report.length().total_seconds() >= delay) {
734 stats_mgr_.printIntermediateStats(options_.getCleanReport(),
735 options_.getCleanReportSeparator());
741 TestControl::printStats()
const {
743 stats_mgr_.printStats();
744 if (options_.testDiags(
'i')) {
745 stats_mgr_.printCustomCounters();
750 TestControl::vector2Hex(
const std::vector<uint8_t>& vec,
751 const std::string& separator ) {
752 std::ostringstream stream;
753 for (std::vector<uint8_t>::const_iterator it = vec.begin();
756 if (it == vec.begin()) {
757 stream << byte2Hex(*it);
759 stream << separator << byte2Hex(*it);
762 return (stream.str());
766 TestControl::readPacketTemplate(
const std::string& file_name) {
767 std::ifstream temp_file;
768 temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate);
769 if (!temp_file.is_open()) {
773 std::streampos temp_size = temp_file.tellg();
774 if (temp_size == std::streampos(0)) {
778 temp_file.seekg(0, ios::beg);
779 std::vector<char> file_contents(temp_size);
780 temp_file.read(&file_contents[0], temp_size);
786 std::vector<char> hex_digits;
787 for (
size_t i = 0; i < file_contents.size(); ++i) {
788 if (isxdigit(file_contents[i])) {
789 hex_digits.push_back(file_contents[i]);
790 }
else if (!isxdigit(file_contents[i]) &&
791 !isspace(file_contents[i])) {
793 " hexadecimal digit");
797 if (hex_digits.size() % 2 != 0) {
799 }
else if (hex_digits.empty()) {
802 std::vector<uint8_t> binary_stream;
803 for (
size_t i = 0; i < hex_digits.size(); i += 2) {
805 s <<
"0x" << hex_digits[i] << hex_digits[i+1];
808 binary_stream.push_back(
static_cast<uint8_t
>(b));
810 template_buffers_.push_back(binary_stream);
814 TestControl::processReceivedPacket4(
const Pkt4Ptr& pkt4) {
816 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::DO, pkt4);
817 address4Uniqueness(pkt4, ExchangeType::DO);
818 Pkt4Ptr discover_pkt4(boost::dynamic_pointer_cast<Pkt4>(pkt));
820 if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
821 if (template_buffers_.size() < 2) {
822 sendRequest4(discover_pkt4, pkt4);
826 sendRequest4(template_buffers_[1], discover_pkt4, pkt4);
829 }
else if (pkt4->getType() ==
DHCPACK) {
833 if (stats_mgr_.passRcvdPacket(ExchangeType::RA, pkt4)) {
834 address4Uniqueness(pkt4, ExchangeType::RA);
839 if (stats_mgr_.hasExchangeStats(ExchangeType::RNA) ||
840 stats_mgr_.hasExchangeStats(ExchangeType::RLA)) {
844 ack_storage_.append(pkt4);
851 }
else if (stats_mgr_.hasExchangeStats(ExchangeType::RNA)) {
852 stats_mgr_.passRcvdPacket(ExchangeType::RNA, pkt4);
860 if (options_.getAddrUnique()) {
861 std::set<std::string> current;
864 for (
const auto& opt : pkt6->options_) {
865 switch (opt.second->getType()) {
869 auto ret = current.emplace(boost::dynamic_pointer_cast<
872 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
879 auto ret = current.emplace(boost::dynamic_pointer_cast<
882 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
891 addUniqeAddr(current, xchg_type);
898 if (options_.getAddrUnique()) {
901 std::set<std::string> current;
902 current.insert(pkt4->getYiaddr().toText());
904 addUniqeAddr(current, xchg_type);
909 TestControl::validateIA(
const Pkt6Ptr& pkt6) {
919 iapref = boost::dynamic_pointer_cast<
923 iaaddr = boost::dynamic_pointer_cast<
927 bool address_and_prefix = options_.getLeaseType().includes(
928 CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
929 bool prefix_only = options_.getLeaseType().includes(
930 CommandOptions::LeaseType::PREFIX);
931 bool address_only = options_.getLeaseType().includes(
932 CommandOptions::LeaseType::ADDRESS);
933 if ((address_and_prefix && iapref && iaaddr) ||
934 (prefix_only && iapref && !address_and_prefix) ||
935 (address_only && iaaddr && !address_and_prefix)) {
943 TestControl::processReceivedPacket6(
const Pkt6Ptr& pkt6) {
944 uint8_t packet_type = pkt6->
getType();
946 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::SA, pkt6);
947 Pkt6Ptr solicit_pkt6(boost::dynamic_pointer_cast<Pkt6>(pkt));
949 if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
950 if (validateIA(pkt6)) {
952 address6Uniqueness(pkt6, ExchangeType::SA);
953 if (template_buffers_.size() < 2) {
958 sendRequest6(template_buffers_[1], pkt6);
961 stats_mgr_.updateRejLeases(ExchangeType::SA);
969 if (stats_mgr_.passRcvdPacket(ExchangeType::RR, pkt6)) {
975 if (validateIA(pkt6)) {
977 address6Uniqueness(pkt6, ExchangeType::RR);
979 if (stats_mgr_.hasExchangeStats(ExchangeType::RN) ||
980 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
984 reply_storage_.append(pkt6);
987 stats_mgr_.updateRejLeases(ExchangeType::RR);
996 }
else if (!(stats_mgr_.hasExchangeStats(ExchangeType::RN) &&
997 stats_mgr_.passRcvdPacket(ExchangeType::RN, pkt6)) &&
998 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
1001 stats_mgr_.passRcvdPacket(ExchangeType::RL, pkt6);
1007 TestControl::consumeReceivedPackets() {
1008 unsigned int pkt_count = 0;
1010 while ((pkt = receiver_.getPkt())) {
1012 if (options_.getIpVersion() == 4) {
1013 Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
1014 processReceivedPacket4(pkt4);
1016 Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<Pkt6>(pkt);
1017 processReceivedPacket6(pkt6);
1023 TestControl::registerOptionFactories4()
const {
1024 static bool factories_registered =
false;
1025 if (!factories_registered) {
1027 LibDHCP::OptionFactoryRegister(Option::V4,
1029 &TestControl::factoryGeneric);
1031 LibDHCP::OptionFactoryRegister(Option::V4,
1033 &TestControl::factoryGeneric);
1035 LibDHCP::OptionFactoryRegister(Option::V4,
1037 &TestControl::factoryRequestList4);
1039 factories_registered =
true;
1043 TestControl::registerOptionFactories6()
const {
1044 static bool factories_registered =
false;
1045 if (!factories_registered) {
1047 LibDHCP::OptionFactoryRegister(Option::V6,
1049 &TestControl::factoryElapsedTime6);
1051 LibDHCP::OptionFactoryRegister(Option::V6,
1053 &TestControl::factoryRapidCommit6);
1055 LibDHCP::OptionFactoryRegister(Option::V6,
1057 &TestControl::factoryOptionRequestOption6);
1059 LibDHCP::OptionFactoryRegister(Option::V6,
1061 &TestControl::factoryGeneric);
1063 LibDHCP::OptionFactoryRegister(Option::V6,
1065 &TestControl::factoryGeneric);
1067 LibDHCP::OptionFactoryRegister(Option::V6,
1069 &TestControl::factoryIana6);
1072 LibDHCP::OptionFactoryRegister(Option::V6,
1074 &TestControl::factoryIapd6);
1078 factories_registered =
true;
1082 TestControl::registerOptionFactories()
const {
1083 switch(options_.getIpVersion()) {
1085 registerOptionFactories4();
1088 registerOptionFactories6();
1092 "before DHCP option factories can be registered");
1097 TestControl::reset() {
1098 transid_gen_.reset();
1099 last_report_ = microsec_clock::universal_time();
1104 first_packet_serverid_.clear();
1105 interrupted_ =
false;
1109 exit_time_(not_a_date_time),
1110 number_generator_(0, options.getMacsFromFile().size()),
1112 receiver_(socket, options.isSingleThreaded(), options.getIpVersion()),
1113 stats_mgr_(options),
1125 "command options must be parsed before running a test");
1128 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET,
data::ElementPtr());
1132 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6,
data::ElementPtr());
1151 time_period duration(from_iso_string(
"20111231T235959"),
1152 microsec_clock::universal_time());
1153 srandom(duration.length().total_seconds()
1154 + duration.length().fractional_seconds());
1168 }
else if (pid == 0) {
1195 uint8_t randomized = 0;
1212 pkt4->addOption(Option::factory(Option::V4,
1221 pkt4->setHWAddr(
HTYPE_ETHER, mac_address.size(), mac_address);
1238 pkt4->setSecs(
static_cast<uint16_t
>(val));
1255 const bool preload ) {
1258 const uint8_t arg_idx = 0;
1260 uint8_t randomized = 0;
1273 std::vector<uint8_t> in_buf(template_buf.begin(),
1274 template_buf.end());
1284 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1290 socket_.
send(boost::static_pointer_cast<Pkt4>(pkt4));
1294 boost::static_pointer_cast<Pkt4>(pkt4));
1305 "invalid message type "
1307 <<
" to be sent, expected DHCPREQUEST or DHCPRELEASE");
1321 msg->setGiaddr(ack->getGiaddr());
1344 <<
" to be sent, expected DHCPV6_RENEW or DHCPV6_RELEASE");
1374 const uint32_t transid = discover_pkt4->getTransid();
1386 if (!opt_serverid) {
1388 <<
"in OFFER message");
1393 pkt4->addOption(opt_serverid);
1398 if (!yiaddr.
isV4()) {
1405 opt_requested_address->setUint32(yiaddr.
toUint32());
1406 pkt4->addOption(opt_requested_address);
1409 pkt4->addOption(opt_parameter_list);
1413 pkt4->setGiaddr(offer_pkt4->getGiaddr());
1418 pkt4->setHWAddr(offer_pkt4->getHWAddr());
1422 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1423 pkt4->setSecs(
static_cast<uint16_t
>(elapsed_time / 1000));
1437 const uint8_t arg_idx = 1;
1439 const uint32_t transid = discover_pkt4->getTransid();
1447 std::vector<uint8_t> in_buf(template_buf.begin(),
1448 template_buf.end());
1460 HWAddrPtr hwaddr = offer_pkt4->getHWAddr();
1462 uint8_t hw_len = hwaddr->hwaddr_.size();
1464 memcpy(&mac_address[0], &hwaddr->hwaddr_[0],
1467 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1471 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1472 pkt4->writeValueAt<uint16_t>(elp_offset,
1473 static_cast<uint16_t
>(elapsed_time / 1000));
1481 boost::shared_ptr<LocalizedOption>
1486 pkt4->addOption(opt_serverid);
1492 if (!opt_serverid_offer) {
1494 <<
"in OFFER message");
1496 boost::shared_ptr<LocalizedOption>
1499 opt_serverid_offer->getData(),
1501 pkt4->addOption(opt_serverid);
1509 if (!yiaddr.
isV4()) {
1517 boost::shared_ptr<LocalizedOption>
1523 opt_requested_ip->setUint32(yiaddr.
toUint32());
1524 pkt4->addOption(opt_requested_ip);
1533 socket_.
send(boost::static_pointer_cast<Pkt4>(pkt4));
1536 boost::static_pointer_cast<Pkt4>(pkt4));
1547 pkt6->addOption(opt_elapsed_time);
1550 if (!opt_clientid) {
1553 pkt6->addOption(opt_clientid);
1559 pkt6->addOption(Option::factory(Option::V6,
D6O_SERVERID,
1563 if (!opt_serverid) {
1569 pkt6->addOption(opt_serverid);
1594 const Pkt6Ptr& advertise_pkt6) {
1597 const uint8_t arg_idx = 1;
1603 transid_offset, transid));
1606 boost::shared_ptr<LocalizedOption>
1609 pkt6->addOption(opt_elapsed_time);
1617 boost::shared_ptr<LocalizedOption>
1622 pkt6->addOption(opt_serverid);
1629 if (!opt_serverid_advertise) {
1631 <<
"in ADVERTISE message");
1633 boost::shared_ptr<LocalizedOption>
1636 opt_serverid_advertise->getData(),
1638 pkt6->addOption(opt_serverid);
1644 boost::shared_ptr<Option6IA> opt_ia_na_advertise =
1645 boost::static_pointer_cast<Option6IA>(advertise_pkt6->getOption(
D6O_IA_NA));
1646 if (!opt_ia_na_advertise) {
1651 boost::shared_ptr<LocalizedOption>
1653 if (!opt_ia_na->valid()) {
1656 pkt6->addOption(opt_ia_na);
1659 if (!opt_serverid_advertise) {
1664 boost::shared_ptr<LocalizedOption>
1666 opt_serverid_advertise->getData(),
1668 pkt6->addOption(opt_serverid);
1672 if (!opt_clientid_advertise) {
1675 rand_offset -= (opt_clientid_advertise->len() - 1);
1677 boost::shared_ptr<LocalizedOption>
1679 opt_clientid_advertise->getData(),
1681 pkt6->addOption(opt_clientid);
1709 uint8_t randomized = 0;
1732 pkt6->addOption(elapsed);
1740 pkt6->addOption(Option::factory(Option::V6,
D6O_CLIENTID, duid));
1741 pkt6->addOption(Option::factory(Option::V6,
D6O_ORO));
1749 pkt6->addOption(Option::factory(Option::V6,
D6O_IA_NA));
1753 pkt6->addOption(Option::factory(Option::V6,
D6O_IA_PD));
1772 const bool preload ) {
1773 const int arg_idx = 0;
1780 transid_offset, transid));
1788 uint8_t randomized = 0;
1790 if (rand_offset > template_buf.size()) {
1794 pkt6->writeAt(rand_offset - randomized + 1,
1795 duid.end() - randomized, duid.end());
1818 if (iface == NULL) {
1821 pkt->setIface(iface->getName());
1825 pkt->setLocalPort(DHCP4_CLIENT_PORT);
1830 pkt->setRemotePort(DHCP4_SERVER_PORT);
1851 if (iface == NULL) {
1854 pkt->setIface(iface->getName());
1858 pkt->setLocalPort(DHCP6_CLIENT_PORT);
1863 pkt->setRemotePort(DHCP6_SERVER_PORT);
1884 pkt->addRelayInfo(relay_info);
1893 result.insert(result.end(), a.begin(), a.end());
1894 result.insert(result.end(), b.begin(), b.end());
1898 static void mergeOptionIntoPacket(
Pkt4Ptr const& packet,
1900 uint16_t
const code(extra_option->getType());
1902 OptionPtr const& option(packet->getOption(code));
1907 packet->delOption(code);
1908 packet->addOption(boost::make_shared<Option>(
1910 concatenateBuffers(option->getData(),
1911 extra_option->getData())));
1919 packet->addOption(extra_option);
1928 for (
auto entry : extra_opts) {
1929 mergeOptionIntoPacket(pkt, entry.second);
1937 for (
auto entry : extra_opts) {
1938 pkt->addOption(entry.second);
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown when an object can not be found.
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)
std::string toText() const
Convert the address to a string.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
bool isV4() const
Convenience function to check for an IPv4 address.
isc::asiolink::IOAddress getAddress() const
Returns address contained within this option.
Class that represents IAPREFIX option in DHCPv6.
Forward declaration to OptionInt.
Universe
defines option universe DHCPv4 or DHCPv6
uint16_t getType() const
Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
Represents DHCPv4 packet.
Represents a DHCPv6 packet.
Socket wrapper structure.
virtual dhcp::IfacePtr getIface()=0
See description of this method in PerfSocket class below.
unsigned int ifindex_
Interface index.
virtual bool send(const dhcp::Pkt4Ptr &pkt)=0
See description of this method in PerfSocket class below.
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...
bool testDiags(const char diag)
Find if diagnostic flag has been set.
std::string getRandRelayAddr()
Returns random relay address.
int getIncreaseElapsedTime() const
Returns increased elapsed time.
std::string getWrapped() const
Returns wrapped command.
uint8_t getIpVersion() const
Returns IP version.
bool isRapidCommit() const
Check if rapid commit option used.
bool checkMultiSubnet()
Check if multi subnet mode is enabled.
bool isUseFirst() const
Check if server-ID to be taken from first package.
int getRemotePort() const
Returns remote port number.
const isc::dhcp::OptionCollection & getExtraOpts() const
Returns extra options to be inserted.
int getWaitForElapsedTime() const
Returns time to wait for elapsed time increase.
ExchangeMode
2-way (cmd line param -i) or 4-way exchanges
std::vector< std::vector< uint8_t > > MacAddrsVector
A vector holding MAC addresses.
std::string getServerName() const
Returns server name.
const isc::dhcp::OptionCollection & getRelayOpts(uint8_t encapsulation_level=1) const
Returns relay options to be inserted at given level of encapsulation.
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.
bool isSeeded() const
Checks if seed provided.
uint32_t getSeed() const
Returns random seed.
DHCP option at specific offset.
uint64_t getRcvdPacketsNum(const ExchangeType xchg_type) const
Return total number of received packets.
boost::posix_time::time_period getTestPeriod() const
Get time period since the start of test.
void passSentPacket(const ExchangeType xchg_type, const dhcp::PktPtr &packet)
Adds new packet to the sent packets list.
Sequential numbers generator class.
void saveFirstPacket(const dhcp::Pkt4Ptr &pkt)
Save the first DHCPv4 sent packet of the specified type.
void address6Uniqueness(const dhcp::Pkt6Ptr &pkt6, ExchangeType xchg_type)
Process received v6 addresses uniqueness.
static const uint8_t HW_ETHER_LEN
Length of the Ethernet HW address (MAC) in bytes.
std::map< uint8_t, dhcp::Pkt4Ptr > template_packets_v4_
First packets send.
bool sendMessageFromReply(const uint16_t msg_type)
Send DHCPv6 Renew or Release message.
void addExtraOpts(const dhcp::Pkt4Ptr &pkt4)
Inserts extra options specified by user.
void printDiagnostics() const
Print main diagnostics data.
static void handleChild(int sig)
Handle child signal.
int getRequestedIpOffset() const
Return requested ip offset in a packet.
boost::shared_ptr< NumberGenerator > NumberGeneratorPtr
The default generator pointer.
dhcp::Pkt4Ptr createMessageFromAck(const uint16_t msg_type, const dhcp::Pkt4Ptr &ack)
Creates DHCPREQUEST from a DHCPACK message.
std::vector< uint8_t > generateMacAddress(uint8_t &randomized)
Generate MAC address.
void setDefaults4(const dhcp::Pkt4Ptr &pkt)
Set default DHCPv4 packet parameters.
CommandOptions & options_
Command options.
void setMacAddrGenerator(const NumberGeneratorPtr &generator)
Set new MAC address generator.
void setDefaults6(const dhcp::Pkt6Ptr &pkt)
Set default DHCPv6 packet parameters.
void sendRequest6(const dhcp::Pkt6Ptr &advertise_pkt6)
Send DHCPv6 REQUEST message.
void sendSolicit6(const bool preload=false)
Send DHCPv6 SOLICIT message.
std::map< uint8_t, dhcp::Pkt6Ptr > template_packets_v6_
Template for v6.
PacketStorage< dhcp::Pkt6 > reply_storage_
Storage for reply messages.
void registerOptionFactories() const
Register option factory functions for DHCPv4 or DHCPv6.
std::vector< uint8_t > TemplateBuffer
Packet template buffer.
bool sendMessageFromAck(const uint16_t msg_type)
Send DHCPv4 renew (DHCPREQUEST).
void runWrapped(bool do_stop=false) const
Run wrapped command.
BasePerfSocket & socket_
Socket used for DHCP traffic.
void reset()
Resets internal state of the object.
void address4Uniqueness(const dhcp::Pkt4Ptr &pkt4, ExchangeType xchg_type)
Process received v4 addresses uniqueness.
int getRandomOffset(const int arg_idx) const
Return randomization offset in a packet.
dhcp::Pkt6Ptr createMessageFromReply(const uint16_t msg_type, const dhcp::Pkt6Ptr &reply)
Creates DHCPv6 message from the Reply packet.
int getElapsedTimeOffset() const
Return elapsed time offset in a packet.
void sendRequest4(const dhcp::Pkt4Ptr &discover_pkt4, const dhcp::Pkt4Ptr &offer_pkt4)
Send DHCPv4 REQUEST message.
StatsMgr stats_mgr_
Statistics Manager.
PacketStorage< dhcp::Pkt4 > ack_storage_
Storage for DHCPACK messages.
void copyIaOptions(const dhcp::Pkt6Ptr &pkt_from, dhcp::Pkt6Ptr &pkt_to)
Copies IA_NA or IA_PD option from one packet to another.
void setTransidGenerator(const NumberGeneratorPtr &generator)
Set new transaction id generator.
static void handleInterrupt(int sig)
Handle interrupt signal.
int getTransactionIdOffset(const int arg_idx) const
Return transaction id offset in a packet.
void initPacketTemplates()
Reads packet templates from files.
int getServerIdOffset() const
Return server id offset in a packet.
std::vector< uint8_t > generateDuid(uint8_t &randomized)
Generate DUID.
void sendDiscover4(const bool preload=false)
Send DHCPv4 DISCOVER message.
dhcp::OptionPtr generateClientId(const dhcp::HWAddrPtr &hwaddr) const
Generate DHCPv4 client identifier from HW address.
dhcp::OptionBuffer first_packet_serverid_
Buffer holding server id received in first packet.
uint32_t generateTransid()
generate transaction id.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
size_t getLength() const
Return the length of data written in the buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
boost::shared_ptr< Element > ElementPtr
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
@ DHO_DOMAIN_NAME_SERVERS
@ DHO_DHCP_SERVER_IDENTIFIER
@ DHO_DHCP_CLIENT_IDENTIFIER
@ DHO_DHCP_REQUESTED_ADDRESS
@ DHO_DHCP_PARAMETER_REQUEST_LIST
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
boost::shared_ptr< Option6IAPrefix > Option6IAPrefixPtr
Pointer to the Option6IAPrefix object.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
@ HTYPE_ETHER
Ethernet 10Mbps.
boost::shared_ptr< Option > OptionPtr
boost::shared_ptr< PerfPkt4 > PerfPkt4Ptr
ExchangeType
DHCP packet exchange types.
@ SA
DHCPv6 SOLICIT-ADVERTISE.
@ RNA
DHCPv4 REQUEST-ACK (renewal)
@ RL
DHCPv6 RELEASE-REPLY.
@ DO
DHCPv4 DISCOVER-OFFER.
@ RR
DHCPv6 REQUEST-REPLY.
boost::shared_ptr< PerfPkt6 > PerfPkt6Ptr
Defines the logger used by the top-level component of kea-lfc.
structure that describes a single relay information
isc::dhcp::OptionCollection options_
options received from a specified relay, except relay-msg option
uint8_t msg_type_
message type (RELAY-FORW oro RELAY-REPL)
isc::asiolink::IOAddress linkaddr_
fixed field in relay-forw/relay-reply
uint8_t hop_count_
number of traversed relays (up to 32)
isc::asiolink::IOAddress peeraddr_
fixed field in relay-forw/relay-reply
isc::asiolink::IOAddress addr_