Kea: test_control.cc Source File

| Kea 3.2.0-git

test_control.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <perfdhcp/test_control.h>
10#include <perfdhcp/receiver.h>
11#include <perfdhcp/command_options.h>
12#include <perfdhcp/perf_pkt4.h>
13#include <perfdhcp/perf_pkt6.h>
14
15#include <exceptions/exceptions.h>
16#include <dhcp/libdhcp++.h>
17#include <dhcp/iface_mgr.h>
18#include <dhcp/dhcp4.h>
19#include <dhcp/option6_ia.h>
20#include <dhcp/option6_iaaddr.h>
21#include <dhcp/option6_iaprefix.h>
22#include <dhcp/option_int.h>
23#include <util/unittests/check_valgrind.h>
24
25#include <boost/date_time/posix_time/posix_time.hpp>
26#include <algorithm>
27#include <fstream>
28#include <stdio.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <unistd.h>
32#include <signal.h>
33#include <sstream>
34#include <sys/wait.h>
35
36using namespace std;
37using namespace boost::posix_time;
38using namespace isc;
39using namespace isc::dhcp;
40using namespace isc::asiolink;
41
42namespace isc {
43namespace perfdhcp {
44
45bool TestControl::interrupted_ = false;
46
47bool
48TestControl::waitToExit() {
49 uint32_t const wait_time = options_.getExitWaitTime();
50
51 // If we care and not all packets are in yet
52 if (wait_time && !haveAllPacketsBeenReceived()) {
53 const ptime now = microsec_clock::universal_time();
54
55 // Init the end time if it hasn't started yet
56 if (exit_time_.is_not_a_date_time()) {
57 exit_time_ = now + time_duration(microseconds(wait_time));
58 }
59
60 // If we're not at end time yet, return true
61 return (now < exit_time_);
62 }
63
64 // No need to wait, return false;
65 return (false);
66}
67
68bool
69TestControl::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();
73
74 if (num_request_size == 0) {
75 return (false);
76 }
77
78 uint32_t responses = 0;
79 uint32_t requests = num_request[0];
80 if (num_request_size >= 2) {
81 requests += num_request[1];
82 }
83
84 if (ipversion == 4) {
85 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) +
86 stats_mgr_.getRcvdPacketsNum(ExchangeType::RA);
87 } else {
88 responses = stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) +
89 stats_mgr_.getRcvdPacketsNum(ExchangeType::RR);
90 }
91
92 return (responses == requests);
93}
94
95void
96TestControl::cleanCachedPackets() {
97 // When Renews are not sent, Reply packets are not cached so there
98 // is nothing to do.
99 if (options_.getRenewRate() == 0) {
100 return;
101 }
102
103 static boost::posix_time::ptime last_clean =
104 microsec_clock::universal_time();
105
106 // Check how much time has passed since last cleanup.
107 time_period time_since_clean(last_clean,
108 microsec_clock::universal_time());
109 // Cleanup every 1 second.
110 if (time_since_clean.length().total_seconds() >= 1) {
111 // Calculate how many cached packets to remove. Actually we could
112 // just leave enough packets to handle Renews for 1 second but
113 // since we want to randomize leases to be renewed so leave 5
114 // times more packets to randomize from.
116 if (reply_storage_.size() > 5 * size_t(options_.getRenewRate())) {
117 reply_storage_.clear(reply_storage_.size() -
118 5 * options_.getRenewRate());
119 }
120 // Remember when we performed a cleanup for the last time.
121 // We want to do the next cleanup not earlier than in one second.
122 last_clean = microsec_clock::universal_time();
123 }
124}
125
126void
127TestControl::copyIaOptions(const Pkt6Ptr& pkt_from, Pkt6Ptr& pkt_to) {
128 if (!pkt_from || !pkt_to) {
129 isc_throw(BadValue, "NULL pointers must not be specified as arguments"
130 " for the copyIaOptions function");
131 }
132 // IA_NA
133 if (options_.getLeaseType()
134 .includes(CommandOptions::LeaseType::ADDRESS)) {
135 OptionPtr option = pkt_from->getOption(D6O_IA_NA);
136 if (!option) {
137 isc_throw(NotFound, "IA_NA option not found in the"
138 " server's response");
139 }
140 pkt_to->addOption(option);
141 }
142 // IA_PD
143 if (options_.getLeaseType()
144 .includes(CommandOptions::LeaseType::PREFIX)) {
145 OptionPtr option = pkt_from->getOption(D6O_IA_PD);
146 if (!option) {
147 isc_throw(NotFound, "IA_PD option not found in the"
148 " server's response");
149 }
150 pkt_to->addOption(option);
151 }
152}
153
154std::string
155TestControl::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());
161}
162
163 Pkt4Ptr
164TestControl::createMessageFromAck(const uint16_t msg_type,
165 const dhcp::Pkt4Ptr& ack) {
166 // Restrict messages to Release and Renew.
167 if (msg_type != DHCPREQUEST && msg_type != DHCPRELEASE) {
168 isc_throw(isc::BadValue, "invalid message type " << msg_type
169 << " to be created from Reply, expected DHCPREQUEST or"
170 " DHCPRELEASE");
171 }
172
173 // Get the string representation of the message - to be used for error
174 // logging purposes.
175 auto msg_type_str = [=]() -> const char* {
176 return (msg_type == DHCPREQUEST ? "Request" : "Release");
177 };
178
179 if (!ack) {
180 isc_throw(isc::BadValue, "Unable to create "
181 << msg_type_str()
182 << " from a null DHCPACK message");
183 } else if (ack->getYiaddr().isV4Zero()) {
184 isc_throw(isc::BadValue,
185 "Unable to create "
186 << msg_type_str()
187 << " from a DHCPACK message containing yiaddr of 0");
188 }
189 Pkt4Ptr msg(new Pkt4(msg_type, generateTransid()));
190 msg->setCiaddr(ack->getYiaddr());
191 msg->setHWAddr(ack->getHWAddr());
192 msg->addOption(generateClientId(msg->getHWAddr()));
193 if (msg_type == DHCPRELEASE) {
194 // RFC 2132: DHCPRELEASE MUST include server ID.
195 if (options_.isUseFirst()) {
196 // Honor the '-1' flag if it exists.
197 if (first_packet_serverid_.empty()) {
198 isc_throw(isc::BadValue,
199 "Unable to create "
200 << msg_type_str()
201 << "from the first packet which lacks the server "
202 "identifier option");
203 }
204 msg->addOption(Option::factory(Option::V4,
205 DHO_DHCP_SERVER_IDENTIFIER,
206 first_packet_serverid_));
207 } else {
208 // Otherwise take it from the DHCPACK message.
209 OptionPtr server_identifier(
210 ack->getOption(DHO_DHCP_SERVER_IDENTIFIER));
211 if (!server_identifier) {
212 isc_throw(isc::BadValue,
213 "Unable to create "
214 << msg_type_str()
215 << "from a DHCPACK message without the server "
216 "identifier option");
217 }
218 msg->addOption(server_identifier);
219 }
220 }
221 return (msg);
222}
223
224 Pkt6Ptr
225TestControl::createMessageFromReply(const uint16_t msg_type,
226 const dhcp::Pkt6Ptr& reply) {
227 // Restrict messages to Release and Renew.
228 if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
229 isc_throw(isc::BadValue, "invalid message type " << msg_type
230 << " to be created from Reply, expected DHCPV6_RENEW or"
231 " DHCPV6_RELEASE");
232 }
233
234 // Get the string representation of the message - to be used for error
235 // logging purposes.
236 auto msg_type_str = [=]() -> const char* {
237 return (msg_type == DHCPV6_RENEW ? "Renew" : "Release");
238 };
239
240 // Reply message must be specified.
241 if (!reply) {
242 isc_throw(isc::BadValue, "Unable to create " << msg_type_str()
243 << " message from the Reply message because the instance of"
244 " the Reply message is NULL");
245 }
246
247 Pkt6Ptr msg(new Pkt6(msg_type, generateTransid()));
248 // Client id.
249 OptionPtr opt_clientid = reply->getOption(D6O_CLIENTID);
250 if (!opt_clientid) {
251 isc_throw(isc::Unexpected, "failed to create " << msg_type_str()
252 << " message because client id option has not been found"
253 " in the Reply message");
254 }
255 msg->addOption(opt_clientid);
256 // Server id.
257 OptionPtr opt_serverid = reply->getOption(D6O_SERVERID);
258 if (!opt_serverid) {
259 isc_throw(isc::Unexpected, "failed to create " << msg_type_str()
260 << " because server id option has not been found in the"
261 " Reply message");
262 }
263 msg->addOption(opt_serverid);
264 copyIaOptions(reply, msg);
265 return (msg);
266}
267
268 OptionPtr
269TestControl::factoryElapsedTime6(Option::Universe, uint16_t,
270 const OptionBuffer& buf) {
271 if (buf.size() == 2) {
272 return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME, buf)));
273 } else if (buf.size() == 0) {
274 return (OptionPtr(new Option(Option::V6, D6O_ELAPSED_TIME,
275 OptionBuffer(2, 0))));
276 }
277 isc_throw(isc::BadValue,
278 "elapsed time option buffer size has to be 0 or 2");
279}
280
281 OptionPtr
282TestControl::factoryGeneric(Option::Universe u, uint16_t type,
283 const OptionBuffer& buf) {
284 OptionPtr opt(new Option(u, type, buf));
285 return (opt);
286}
287
288 OptionPtr
289TestControl::factoryIana6(Option::Universe, uint16_t,
290 const OptionBuffer& buf) {
292 const uint8_t buf_array[] = {
293 0, 0, 0, 1, // IAID = 1
294 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
295 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
296 };
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]);
300 }
301 return (OptionPtr(new Option(Option::V6, D6O_IA_NA, buf_ia_na)));
302}
303
304 OptionPtr
305TestControl::factoryIapd6(Option::Universe, uint16_t,
306 const OptionBuffer& buf) {
308 static const uint8_t buf_array[] = {
309 0, 0, 0, 1, // IAID = 1
310 0, 0, 3600 >> 8, 3600 & 0xff, // T1 = 3600
311 0, 0, 5400 >> 8, 5400 & 0xff, // T2 = 5400
312 };
313 OptionBuffer buf_ia_pd(buf_array, buf_array + sizeof(buf_array));
314 // Append sub-options to IA_PD.
315 buf_ia_pd.insert(buf_ia_pd.end(), buf.begin(), buf.end());
316 return (OptionPtr(new Option(Option::V6, D6O_IA_PD, buf_ia_pd)));
317}
318
319
320 OptionPtr
321TestControl::factoryRapidCommit6(Option::Universe, uint16_t,
322 const OptionBuffer&) {
323 return (OptionPtr(new Option(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())));
324}
325
326 OptionPtr
327TestControl::factoryOptionRequestOption6(Option::Universe,
328 uint16_t,
329 const OptionBuffer&) {
330 const uint8_t buf_array[] = {
331 0, D6O_NAME_SERVERS,
332 0, D6O_DOMAIN_SEARCH,
333 };
334 OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
335 return (OptionPtr(new Option(Option::V6, D6O_ORO, buf_with_options)));
336}
337
338
339 OptionPtr
340TestControl::factoryRequestList4(Option::Universe u,
341 uint16_t type,
342 const OptionBuffer& buf) {
343 const uint8_t buf_array[] = {
344 DHO_SUBNET_MASK,
345 DHO_BROADCAST_ADDRESS,
346 DHO_TIME_OFFSET,
347 DHO_ROUTERS,
348 DHO_DOMAIN_NAME,
349 DHO_DOMAIN_NAME_SERVERS,
350 DHO_HOST_NAME
351 };
352
353 OptionBuffer buf_with_options(buf_array, buf_array + sizeof(buf_array));
354 OptionPtr opt(new Option(u, type, buf));
355 opt->setData(buf_with_options.begin(), buf_with_options.end());
356 return (opt);
357}
358
359std::vector<uint8_t>
360TestControl::generateMacAddress(uint8_t& randomized) {
361 const CommandOptions::MacAddrsVector& macs = options_.getMacsFromFile();
362 // if we are using the -M option return a random one from the list...
363 if (macs.size() > 0) {
364 uint16_t r = random_generator_->generate();
365 if (r >= macs.size()) {
366 r = 0;
367 }
368 return (macs[r]);
369
370 } else {
371 // ... otherwise use the standard behavior
372 uint32_t clients_num = options_.getClientsNum();
373 if (clients_num < 2) {
374 return (options_.getMacTemplate());
375 }
376 // Get the base MAC address. We are going to randomize part of it.
377 std::vector<uint8_t> mac_addr(options_.getMacTemplate());
378 if (mac_addr.size() != HW_ETHER_LEN) {
379 isc_throw(BadValue, "invalid MAC address template specified");
380 }
381 uint32_t r = macaddr_gen_->generate();
382 randomized = 0;
383 // Randomize MAC address octets.
384 for (std::vector<uint8_t>::iterator it = mac_addr.end() - 1;
385 it >= mac_addr.begin();
386 --it) {
387 // Add the random value to the current octet.
388 (*it) += r;
389 ++randomized;
390 if (r < 256) {
391 // If we are here it means that there is no sense
392 // to randomize the remaining octets of MAC address
393 // because the following bytes of random value
394 // are zero and it will have no effect.
395 break;
396 }
397 // Randomize the next octet with the following
398 // byte of random value.
399 r >>= 8;
400 }
401 return (mac_addr);
402 }
403}
404
405 OptionPtr
406TestControl::generateClientId(const dhcp::HWAddrPtr& hwaddr) const {
407 vector<uint8_t> client_id;
408 client_id.push_back(static_cast<uint8_t>(hwaddr->htype_));
409 for (uint8_t const& byte : hwaddr->hwaddr_) {
410 client_id.push_back(byte);
411 }
412 return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
413 client_id)));
414}
415
416std::vector<uint8_t>
417TestControl::generateDuid(uint8_t& randomized) {
418 std::vector<uint8_t> mac_addr(generateMacAddress(randomized));
419 const CommandOptions::MacAddrsVector& macs = options_.getMacsFromFile();
420 // pick a random mac address if we are using option -M..
421 if (macs.size() > 0) {
422 uint16_t r = random_generator_->generate();
423 if (r >= macs.size()) {
424 r = 0;
425 }
426 std::vector<uint8_t> mac = macs[r];
427 // DUID_LL is in this format
428 // 0 1 2 3
429 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
430 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
431 // | 3 | hardware type (16 bits) |
432 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433 // . .
434 // . link-layer address (variable length) .
435 // . .
436 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437
438 // No C++11 so initializer list support, building a vector<uint8_t> is a
439 // pain...
440 uint8_t duid_ll[] = {0, 3, 0, 1, 0, 0, 0, 0, 0, 0};
441 // copy duid_ll array into the vector
442 std::vector<uint8_t> duid(duid_ll,
443 duid_ll + sizeof(duid_ll) / sizeof(duid_ll[0]));
444 // put the mac address bytes at the end
445 std::copy(mac.begin(), mac.end(), duid.begin() + 4);
446 return (duid);
447 } else {
448 uint32_t clients_num = options_.getClientsNum();
449 if ((clients_num == 0) || (clients_num == 1)) {
450 return (options_.getDuidTemplate());
451 }
452 // Get the base DUID. We are going to randomize part of it.
453 std::vector<uint8_t> duid(options_.getDuidTemplate());
455 duid.resize(duid.size());
456 std::copy(mac_addr.begin(), mac_addr.end(),
457 duid.begin() + duid.size() - mac_addr.size());
458 return (duid);
459 }
460}
461
462int
463TestControl::getElapsedTimeOffset() const {
464 int elp_offset = options_.getIpVersion() == 4 ?
465 DHCPV4_ELAPSED_TIME_OFFSET : DHCPV6_ELAPSED_TIME_OFFSET;
466 if (options_.getElapsedTimeOffset() > 0) {
467 elp_offset = options_.getElapsedTimeOffset();
468 }
469 return (elp_offset);
470}
471
472template<class T>
473uint32_t
474TestControl::getElapsedTime(const T& pkt1, const T& pkt2) {
475 using namespace boost::posix_time;
476 ptime pkt1_time = pkt1->getTimestamp();
477 ptime pkt2_time = pkt2->getTimestamp();
478 if (pkt1_time.is_not_a_date_time() ||
479 pkt2_time.is_not_a_date_time()) {
480 isc_throw(InvalidOperation, "packet timestamp not set");;
481 }
482 time_period elapsed_period(pkt1_time, pkt2_time);
483 return (elapsed_period.is_null() ? 0 :
484 elapsed_period.length().total_milliseconds());
485}
486
487int
488TestControl::getRandomOffset(const int arg_idx) const {
489 int rand_offset = options_.getIpVersion() == 4 ?
490 DHCPV4_RANDOMIZATION_OFFSET : DHCPV6_RANDOMIZATION_OFFSET;
491 if (options_.getRandomOffset().size() > size_t(arg_idx)) {
492 rand_offset = options_.getRandomOffset()[arg_idx];
493 }
494 return (rand_offset);
495}
496
497int
498TestControl::getRequestedIpOffset() const {
499 int rip_offset = options_.getIpVersion() == 4 ?
500 DHCPV4_REQUESTED_IP_OFFSET : DHCPV6_IA_NA_OFFSET;
501 if (options_.getRequestedIpOffset() > 0) {
502 rip_offset = options_.getRequestedIpOffset();
503 }
504 return (rip_offset);
505}
506
507int
508TestControl::getServerIdOffset() const {
509 int srvid_offset = options_.getIpVersion() == 4 ?
510 DHCPV4_SERVERID_OFFSET : DHCPV6_SERVERID_OFFSET;
511 if (options_.getServerIdOffset() > 0) {
512 srvid_offset = options_.getServerIdOffset();
513 }
514 return (srvid_offset);
515}
516
517 TestControl::TemplateBuffer
518TestControl::getTemplateBuffer(const size_t idx) const {
519 if (template_buffers_.size() > idx) {
520 return (template_buffers_[idx]);
521 }
522 isc_throw(OutOfRange, "invalid buffer index");
523}
524
525int
526TestControl::getTransactionIdOffset(const int arg_idx) const {
527 int xid_offset = options_.getIpVersion() == 4 ?
528 DHCPV4_TRANSID_OFFSET : DHCPV6_TRANSID_OFFSET;
529 if (options_.getTransactionIdOffset().size() > size_t(arg_idx)) {
530 xid_offset = options_.getTransactionIdOffset()[arg_idx];
531 }
532 return (xid_offset);
533}
534
535void
536TestControl::handleChild(int) {
537 int status = 0;
538 while (wait3(&status, WNOHANG, NULL) > 0) {
539 // continue
540 }
541}
542
543void
544TestControl::handleInterrupt(int) {
545 interrupted_ = true;
546}
547
548void
549TestControl::initPacketTemplates() {
550 template_packets_v4_.clear();
551 template_packets_v6_.clear();
552 template_buffers_.clear();
553 std::vector<std::string> template_files = options_.getTemplateFiles();
554 for (auto const& it : template_files) {
555 readPacketTemplate(it);
556 }
557}
558
559void
560TestControl::sendPackets(const uint64_t packets_num,
561 const bool preload /* = false */) {
562 for (uint64_t i = packets_num; i > 0; --i) {
563 if (options_.getIpVersion() == 4) {
564 // No template packets means that no -T option was specified.
565 // We have to build packets ourselves.
566 if (template_buffers_.empty()) {
567 sendDiscover4(preload);
568 } else {
571 sendDiscover4(template_buffers_[0], preload);
572 }
573 } else {
574 // No template packets means that no -T option was specified.
575 // We have to build packets ourselves.
576 if (template_buffers_.empty()) {
577 sendSolicit6(preload);
578 } else {
581 sendSolicit6(template_buffers_[0], preload);
582 }
583 }
584 }
585}
586
587uint64_t
588TestControl::sendMultipleMessages4(const uint32_t msg_type,
589 const uint64_t msg_num) {
590 for (uint64_t i = 0; i < msg_num; ++i) {
591 if (!sendMessageFromAck(msg_type)) {
592 return (i);
593 }
594 }
595 return (msg_num);
596}
597
598uint64_t
599TestControl::sendMultipleMessages6(const uint32_t msg_type,
600 const uint64_t msg_num) {
601 for (uint64_t i = 0; i < msg_num; ++i) {
602 if (!sendMessageFromReply(msg_type)) {
603 return (i);
604 }
605 }
606 return (msg_num);
607}
608
609void
610TestControl::printDiagnostics() const {
611 if (options_.testDiags('a')) {
612 // Print all command line parameters.
613 options_.printCommandLine();
614 // Print MAC and DUID.
615 std::cout << "Set MAC to " << vector2Hex(options_.getMacTemplate(), "::")
616 << std::endl;
617 if (options_.getDuidTemplate().size() > 0) {
618 std::cout << "Set DUID to " << vector2Hex(options_.getDuidTemplate()) << std::endl;
619 }
620 }
621}
622
623void
624TestControl::printTemplate(const uint8_t packet_type) const {
625 std::string hex_buf;
626 int arg_idx = 0;
627 if (options_.getIpVersion() == 4) {
628 if (packet_type == DHCPREQUEST) {
629 arg_idx = 1;
630 }
631 std::map<uint8_t, dhcp::Pkt4Ptr>::const_iterator pkt_it =
632 template_packets_v4_.find(packet_type);
633 if ((pkt_it != template_packets_v4_.end()) &&
634 pkt_it->second) {
635 hex_buf = vector2Hex(pkt_it->second->getBuffer().getVector());
636 }
637 } else if (options_.getIpVersion() == 6) {
638 if (packet_type == DHCPV6_REQUEST) {
639 arg_idx = 1;
640 }
641 std::map<uint8_t, dhcp::Pkt6Ptr>::const_iterator pkt_it =
642 template_packets_v6_.find(packet_type);
643 if (pkt_it != template_packets_v6_.end() &&
644 pkt_it->second) {
645 hex_buf = vector2Hex(pkt_it->second->getBuffer().getVector());
646 }
647 }
648 std::cout << "xid-offset=" << getTransactionIdOffset(arg_idx) << std::endl;
649 std::cout << "random-offset=" << getRandomOffset(arg_idx) << std::endl;
650 if (arg_idx > 0) {
651 std::cout << "srvid-offset=" << getServerIdOffset() << std::endl;
652 std::cout << "time-offset=" << getElapsedTimeOffset() << std::endl;
653 std::cout << "ip-offset=" << getRequestedIpOffset() << std::endl;
654 }
655
656 std::cout << "contents: " << std::endl;
657 int line_len = 32;
658 int i = 0;
659 // Save cout fmtflags.
660 auto flags(std::cout.flags());
661 while (line_len == 32) {
662 if (hex_buf.length() - i < 32) {
663 line_len = hex_buf.length() - i;
664 };
665 if (line_len > 0) {
666 std::cout << setfill('0') << setw(4) << std::hex << i << std::dec
667 << " " << hex_buf.substr(i, line_len) << std::endl;
668 }
669 i += 32;
670 }
671 // Restore cout fmtflags.
672 std::cout.flags(flags);
673 std::cout << std::endl;
674}
675
676void
677TestControl::printTemplates() const {
678 if (options_.getIpVersion() == 4) {
679 printTemplate(DHCPDISCOVER);
680 printTemplate(DHCPREQUEST);
681 } else if (options_.getIpVersion() == 6) {
682 printTemplate(DHCPV6_SOLICIT);
683 printTemplate(DHCPV6_REQUEST);
684 }
685}
686
687void
688TestControl::printRate() const {
689 double rate = 0;
690 std::string exchange_name = "4-way exchanges";
691 ExchangeType xchg_type = ExchangeType::DO;
692 if (options_.getIpVersion() == 4) {
693 xchg_type =
694 options_.getExchangeMode() == CommandOptions::DO_SA ?
695 ExchangeType::DO : ExchangeType::RA;
696 if (xchg_type == ExchangeType::DO) {
697 exchange_name = "DISCOVER-OFFER";
698 }
699 } else if (options_.getIpVersion() == 6) {
700 xchg_type =
701 options_.getExchangeMode() == CommandOptions::DO_SA ?
702 ExchangeType::SA : ExchangeType::RR;
703 if (xchg_type == ExchangeType::SA) {
704 exchange_name = options_.isRapidCommit() ? "Solicit-Reply" :
705 "Solicit-Advertise";
706 }
707 }
708 double duration =
709 stats_mgr_.getTestPeriod().length().total_nanoseconds() / 1e9;
710 rate = stats_mgr_.getRcvdPacketsNum(xchg_type) / duration;
711 std::ostringstream s;
712 s << "***Rate statistics***" << std::endl;
713 s << "Rate: " << rate << " " << exchange_name << "/second";
714 if (options_.getRate() > 0) {
715 s << ", expected rate: " << options_.getRate() << std::endl;
716 }
717
718 std::cout << s.str() << std::endl;
719
720 std::cout <<"***Malformed Packets***" << std::endl
721 << "Malformed packets: " << ExchangeStats::malformed_pkts_
722 << std::endl;
723}
724
725void
726TestControl::printIntermediateStats() {
727 int delay = options_.getReportDelay();
728 ptime now = microsec_clock::universal_time();
729 time_period time_since_report(last_report_, now);
730 if (time_since_report.length().total_seconds() >= delay) {
731 stats_mgr_.printIntermediateStats(options_.getCleanReport(),
732 options_.getCleanReportSeparator());
733 last_report_ = now;
734 }
735}
736
737void
738TestControl::printStats() const {
739 printRate();
740 stats_mgr_.printStats();
741 if (options_.testDiags('i')) {
742 stats_mgr_.printCustomCounters();
743 }
744}
745
746std::string
747TestControl::vector2Hex(const std::vector<uint8_t>& vec,
748 const std::string& separator /* = "" */) {
749 std::ostringstream stream;
750 bool first = true;
751 for (auto const& it : vec) {
752 if (first) {
753 stream << byte2Hex(it);
754 first = false;
755 } else {
756 stream << separator << byte2Hex(it);
757 }
758 }
759 return (stream.str());
760}
761
762void
763TestControl::readPacketTemplate(const std::string& file_name) {
764 std::ifstream temp_file;
765 temp_file.open(file_name.c_str(), ios::in | ios::binary | ios::ate);
766 if (!temp_file.is_open()) {
767 isc_throw(BadValue, "unable to open template file " << file_name);
768 }
769 // Read template file contents.
770 std::streampos temp_size = temp_file.tellg();
771 if (temp_size == std::streampos(0)) {
772 temp_file.close();
773 isc_throw(OutOfRange, "the template file " << file_name << " is empty");
774 }
775 temp_file.seekg(0, ios::beg);
776 std::vector<char> file_contents(temp_size);
777 temp_file.read(&file_contents[0], temp_size);
778 temp_file.close();
779 // Spaces are allowed so we have to strip the contents
780 // from them. In the same time we want to make sure that
781 // apart from spaces the file contains hexadecimal digits
782 // only.
783 std::vector<char> hex_digits;
784 for (size_t i = 0; i < file_contents.size(); ++i) {
785 if (isxdigit(file_contents[i])) {
786 hex_digits.push_back(file_contents[i]);
787 } else if (!isxdigit(file_contents[i]) &&
788 !isspace(file_contents[i])) {
789 isc_throw(BadValue, "'" << file_contents[i] << "' is not a"
790 " hexadecimal digit");
791 }
792 }
793 // Expect even number of digits.
794 if (hex_digits.size() % 2 != 0) {
795 isc_throw(OutOfRange, "odd number of digits in template file");
796 } else if (hex_digits.empty()) {
797 isc_throw(OutOfRange, "template file " << file_name << " is empty");
798 }
799 std::vector<uint8_t> binary_stream;
800 for (size_t i = 0; i < hex_digits.size(); i += 2) {
801 stringstream s;
802 s << "0x" << hex_digits[i] << hex_digits[i+1];
803 int b;
804 s >> std::hex >> b;
805 binary_stream.push_back(static_cast<uint8_t>(b));
806 }
807 template_buffers_.push_back(binary_stream);
808}
809
810void
811TestControl::processReceivedPacket4(const Pkt4Ptr& pkt4) {
812 if (pkt4->getType() == DHCPOFFER) {
813 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::DO, pkt4);
814 address4Uniqueness(pkt4, ExchangeType::DO);
815 Pkt4Ptr discover_pkt4(boost::dynamic_pointer_cast<Pkt4>(pkt));
816 CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
817 if ((xchg_mode == CommandOptions::DORA_SARR) && discover_pkt4) {
818 if (template_buffers_.size() < 2) {
819 sendRequest4(discover_pkt4, pkt4);
820 } else {
823 sendRequest4(template_buffers_[1], discover_pkt4, pkt4);
824 }
825 }
826 } else if (pkt4->getType() == DHCPACK) {
827 // If received message is DHCPACK, we have to check if this is
828 // a response to 4-way exchange. We'll match this packet with
829 // a DHCPREQUEST sent as part of the 4-way exchanges.
830 if (stats_mgr_.passRcvdPacket(ExchangeType::RA, pkt4)) {
831 address4Uniqueness(pkt4, ExchangeType::RA);
832 // The DHCPACK belongs to DHCPREQUEST-DHCPACK exchange type.
833 // So, we may need to keep this DHCPACK in the storage if renews.
834 // Note that, DHCPACK messages hold the information about
835 // leases assigned. We use this information to renew.
836 if (stats_mgr_.hasExchangeStats(ExchangeType::RNA) ||
837 stats_mgr_.hasExchangeStats(ExchangeType::RLA)) {
838 // Renew or release messages are sent, because StatsMgr has the
839 // specific exchange type specified. Let's append the DHCPACK
840 // message to a storage.
841 ack_storage_.append(pkt4);
842 }
843 // The DHCPACK message is not a server's response to the DHCPREQUEST
844 // message sent within the 4-way exchange. It may be a response to a
845 // renewal. In this case we first check if StatsMgr has exchange type
846 // for renew specified, and if it has, if there is a corresponding
847 // renew message for the received DHCPACK.
848 } else if (stats_mgr_.hasExchangeStats(ExchangeType::RNA)) {
849 stats_mgr_.passRcvdPacket(ExchangeType::RNA, pkt4);
850 }
851 }
852}
853
854void
855TestControl::address6Uniqueness(const Pkt6Ptr& pkt6, ExchangeType xchg_type) {
856 // check if received address is unique
857 if (options_.getAddrUnique()) {
858 std::set<std::string> current;
859 // addresses were already checked in validateIA
860 // we can safely assume that those are correct
861 for (auto const& opt : pkt6->options_) {
862 switch (opt.second->getType()) {
863 case D6O_IA_PD: {
864 // add address and check if it has not been already assigned
865 // addresses should be unique cross options of the packet
866 auto ret = current.emplace(boost::dynamic_pointer_cast<
867 Option6IAPrefix>(opt.second->getOption(D6O_IAPREFIX))->getAddress().toText());
868 if (!ret.second) {
869 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
870 }
871 break;
872 }
873 case D6O_IA_NA: {
874 // add address and check if it has not been already assigned
875 // addresses should be unique cross options of the packet
876 auto ret = current.emplace(boost::dynamic_pointer_cast<
877 Option6IAAddr>(opt.second->getOption(D6O_IAADDR))->getAddress().toText());
878 if (!ret.second) {
879 stats_mgr_.updateNonUniqueAddrNum(xchg_type);
880 }
881 break;
882 }
883 default:
884 break;
885 }
886 }
887 // addresses should be unique cross packets
888 addUniqeAddr(current, xchg_type);
889 }
890}
891
892void
893TestControl::address4Uniqueness(const Pkt4Ptr& pkt4, ExchangeType xchg_type) {
894 // check if received address is unique
895 if (options_.getAddrUnique()) {
896 // addresses were already checked in validateIA
897 // we can safely assume that those are correct
898 std::set<std::string> current;
899 current.insert(pkt4->getYiaddr().toText());
900 // addresses should be unique cross packets
901 addUniqeAddr(current, xchg_type);
902 }
903}
904
905bool
906TestControl::validateIA(const Pkt6Ptr& pkt6) {
907 // check if iaaddr exists - if it does, we can continue sending request
908 // if not we will update statistics about rejected leases
909 // @todo it's checking just one iaaddress option for now it's ok
910 // but when perfdhcp will be extended to create message with multiple IA
911 // this will have to be iterate on:
912 // OptionCollection ias = pkt6->getOptions(D6O_IA_NA);
913 Option6IAPrefixPtr iapref;
914 Option6IAAddrPtr iaaddr;
915 if (pkt6->getOption(D6O_IA_PD)) {
916 iapref = boost::dynamic_pointer_cast<
917 Option6IAPrefix>(pkt6->getOption(D6O_IA_PD)->getOption(D6O_IAPREFIX));
918 }
919 if (pkt6->getOption(D6O_IA_NA)) {
920 iaaddr = boost::dynamic_pointer_cast<
921 Option6IAAddr>(pkt6->getOption(D6O_IA_NA)->getOption(D6O_IAADDR));
922 }
923
924 bool address_and_prefix = options_.getLeaseType().includes(
925 CommandOptions::LeaseType::ADDRESS_AND_PREFIX);
926 bool prefix_only = options_.getLeaseType().includes(
927 CommandOptions::LeaseType::PREFIX);
928 bool address_only = options_.getLeaseType().includes(
929 CommandOptions::LeaseType::ADDRESS);
930 if ((address_and_prefix && iapref && iaaddr) ||
931 (prefix_only && iapref && !address_and_prefix) ||
932 (address_only && iaaddr && !address_and_prefix)) {
933 return (true);
934 } else {
935 return (false);
936 }
937}
938
939void
940TestControl::processReceivedPacket6(const Pkt6Ptr& pkt6) {
941 uint8_t packet_type = pkt6->getType();
942 if (packet_type == DHCPV6_ADVERTISE) {
943 PktPtr pkt = stats_mgr_.passRcvdPacket(ExchangeType::SA, pkt6);
944 Pkt6Ptr solicit_pkt6(boost::dynamic_pointer_cast<Pkt6>(pkt));
945 CommandOptions::ExchangeMode xchg_mode = options_.getExchangeMode();
946 if ((xchg_mode == CommandOptions::DORA_SARR) && solicit_pkt6) {
947 if (validateIA(pkt6)) {
948 // if address is correct - check uniqueness
949 address6Uniqueness(pkt6, ExchangeType::SA);
950 if (template_buffers_.size() < 2) {
951 sendRequest6(pkt6);
952 } else {
955 sendRequest6(template_buffers_[1], pkt6);
956 }
957 } else {
958 stats_mgr_.updateRejLeases(ExchangeType::SA);
959 }
960 }
961 } else if (packet_type == DHCPV6_REPLY) {
962 // If the received message is Reply, we have to find out which exchange
963 // type the Reply message belongs to. It is doable by matching the Reply
964 // transaction id with the transaction id of the sent Request, Renew
965 // or Release. First we start with the Request.
966 if (stats_mgr_.passRcvdPacket(ExchangeType::RR, pkt6)) {
967 // The Reply belongs to Request-Reply exchange type. So, we may need
968 // to keep this Reply in the storage if Renews or/and Releases are
969 // being sent. Note that, Reply messages hold the information about
970 // leases assigned. We use this information to construct Renew and
971 // Release messages.
972 if (validateIA(pkt6)) {
973 // if address is correct - check uniqueness
974 address6Uniqueness(pkt6, ExchangeType::RR);
975 // check if there is correct IA to continue with Renew/Release
976 if (stats_mgr_.hasExchangeStats(ExchangeType::RN) ||
977 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
978 // Renew or Release messages are sent, because StatsMgr has the
979 // specific exchange type specified. Let's append the Reply
980 // message to a storage.
981 reply_storage_.append(pkt6);
982 }
983 } else {
984 stats_mgr_.updateRejLeases(ExchangeType::RR);
985 }
986 // The Reply message is not a server's response to the Request message
987 // sent within the 4-way exchange. It may be a response to the Renew
988 // or Release message. In the if clause we first check if StatsMgr
989 // has exchange type for Renew specified, and if it has, if there is
990 // a corresponding Renew message for the received Reply. If not,
991 // we check that StatsMgr has exchange type for Release specified,
992 // as possibly the Reply has been sent in response to Release.
993 } else if (!(stats_mgr_.hasExchangeStats(ExchangeType::RN) &&
994 stats_mgr_.passRcvdPacket(ExchangeType::RN, pkt6)) &&
995 stats_mgr_.hasExchangeStats(ExchangeType::RL)) {
996 // At this point, it is only possible that the Reply has been sent
997 // in response to a Release. Try to match the Reply with Release.
998 stats_mgr_.passRcvdPacket(ExchangeType::RL, pkt6);
999 }
1000 }
1001}
1002
1003unsigned int
1004TestControl::consumeReceivedPackets() {
1005 unsigned int pkt_count = 0;
1006 PktPtr pkt;
1007 while ((pkt = receiver_.getPkt())) {
1008 pkt_count += 1;
1009 if (options_.getIpVersion() == 4) {
1010 Pkt4Ptr pkt4 = boost::dynamic_pointer_cast<Pkt4>(pkt);
1011 processReceivedPacket4(pkt4);
1012 } else {
1013 Pkt6Ptr pkt6 = boost::dynamic_pointer_cast<Pkt6>(pkt);
1014 processReceivedPacket6(pkt6);
1015 }
1016 }
1017 return pkt_count;
1018}
1019void
1020TestControl::registerOptionFactories4() const {
1021 static bool factories_registered = false;
1022 if (!factories_registered) {
1023 // DHCP_MESSAGE_TYPE option factory.
1024 LibDHCP::OptionFactoryRegister(Option::V4,
1025 DHO_DHCP_MESSAGE_TYPE,
1026 &TestControl::factoryGeneric);
1027 // DHCP_SERVER_IDENTIFIER option factory.
1028 LibDHCP::OptionFactoryRegister(Option::V4,
1029 DHO_DHCP_SERVER_IDENTIFIER,
1030 &TestControl::factoryGeneric);
1031 // DHCP_PARAMETER_REQUEST_LIST option factory.
1032 LibDHCP::OptionFactoryRegister(Option::V4,
1033 DHO_DHCP_PARAMETER_REQUEST_LIST,
1034 &TestControl::factoryRequestList4);
1035 }
1036 factories_registered = true;
1037}
1038
1039void
1040TestControl::registerOptionFactories6() const {
1041 static bool factories_registered = false;
1042 if (!factories_registered) {
1043 // D6O_ELAPSED_TIME
1044 LibDHCP::OptionFactoryRegister(Option::V6,
1045 D6O_ELAPSED_TIME,
1046 &TestControl::factoryElapsedTime6);
1047 // D6O_RAPID_COMMIT
1048 LibDHCP::OptionFactoryRegister(Option::V6,
1049 D6O_RAPID_COMMIT,
1050 &TestControl::factoryRapidCommit6);
1051 // D6O_ORO (option request option) factory.
1052 LibDHCP::OptionFactoryRegister(Option::V6,
1053 D6O_ORO,
1054 &TestControl::factoryOptionRequestOption6);
1055 // D6O_CLIENTID option factory.
1056 LibDHCP::OptionFactoryRegister(Option::V6,
1057 D6O_CLIENTID,
1058 &TestControl::factoryGeneric);
1059 // D6O_SERVERID option factory.
1060 LibDHCP::OptionFactoryRegister(Option::V6,
1061 D6O_SERVERID,
1062 &TestControl::factoryGeneric);
1063 // D6O_IA_NA option factory.
1064 LibDHCP::OptionFactoryRegister(Option::V6,
1065 D6O_IA_NA,
1066 &TestControl::factoryIana6);
1067
1068 // D6O_IA_PD option factory.
1069 LibDHCP::OptionFactoryRegister(Option::V6,
1070 D6O_IA_PD,
1071 &TestControl::factoryIapd6);
1072
1073
1074 }
1075 factories_registered = true;
1076}
1077
1078void
1079TestControl::registerOptionFactories() const {
1080 switch(options_.getIpVersion()) {
1081 case 4:
1082 registerOptionFactories4();
1083 break;
1084 case 6:
1085 registerOptionFactories6();
1086 break;
1087 default:
1088 isc_throw(InvalidOperation, "command line options have to be parsed "
1089 "before DHCP option factories can be registered");
1090 }
1091}
1092
1093void
1094TestControl::reset() {
1095 transid_gen_.reset();
1096 last_report_ = microsec_clock::universal_time();
1097 // Actual generators will have to be set later on because we need to
1098 // get command line parameters first.
1099 setTransidGenerator(NumberGeneratorPtr());
1100 setMacAddrGenerator(NumberGeneratorPtr());
1101 first_packet_serverid_.clear();
1102 interrupted_ = false;
1103}
1104
1105TestControl::TestControl(CommandOptions& options, BasePerfSocket &socket) :
1106 exit_time_(not_a_date_time),
1107 socket_(socket),
1108 receiver_(socket, options.isSingleThreaded(), options.getIpVersion()),
1109 stats_mgr_(options),
1110 random_generator_(new RandomGenerator(0, options.getMacsFromFile().size())),
1111 options_(options) {
1112 // Reset singleton state before test starts.
1113 reset();
1114
1115 // Ip version is not set ONLY in case the command options
1116 // were not parsed. This surely means that parse() function
1117 // was not called prior to starting the test. This is fatal
1118 // error.
1119 if (options_.getIpVersion() == 0) {
1120 isc_throw(InvalidOperation,
1121 "command options must be parsed before running a test");
1122 } else if (options_.getIpVersion() == 4) {
1123 // Turn off packet queueing.
1124 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET, data::ElementPtr());
1125 setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator()));
1126 } else {
1127 // Turn off packet queueing.
1128 IfaceMgr::instance().configureDHCPPacketQueue(AF_INET6, data::ElementPtr());
1129 setTransidGenerator(NumberGeneratorPtr(new SequentialGenerator(0x00FFFFFF)));
1130 }
1131
1132 uint32_t clients_num = options_.getClientsNum() == 0 ?
1133 1 : options_.getClientsNum();
1134 setMacAddrGenerator(NumberGeneratorPtr(new SequentialGenerator(clients_num)));
1135
1136 // Diagnostics are command line options mainly.
1137 printDiagnostics();
1138 // Option factories have to be registered.
1139 registerOptionFactories();
1140 // Initialize packet templates.
1141 initPacketTemplates();
1142 // Initialize randomization seed.
1143 if (options_.isSeeded()) {
1144 srandom(options_.getSeed());
1145 } else {
1146 // Seed with current time.
1147 time_period duration(from_iso_string("20111231T235959"),
1148 microsec_clock::universal_time());
1149 srandom(duration.length().total_seconds()
1150 + duration.length().fractional_seconds());
1151 }
1152 // If user interrupts the program we will exit gracefully.
1153 signal(SIGINT, TestControl::handleInterrupt);
1154}
1155
1156void
1157TestControl::runWrapped(bool do_stop /*= false */) const {
1158 if (!options_.getWrapped().empty()) {
1159 pid_t pid = 0;
1160 signal(SIGCHLD, handleChild);
1161 pid = fork();
1162 if (pid < 0) {
1163 isc_throw(Unexpected, "unable to fork");
1164 } else if (pid == 0) {
1165 execlp(options_.getWrapped().c_str(), do_stop ? "stop" : "start", (void*)0);
1166 }
1167 }
1168}
1169
1170void
1171TestControl::saveFirstPacket(const Pkt4Ptr& pkt) {
1172 if (options_.testDiags('T')) {
1173 if (template_packets_v4_.find(pkt->getType()) == template_packets_v4_.end()) {
1174 template_packets_v4_[pkt->getType()] = pkt;
1175 }
1176 }
1177}
1178
1179void
1180 TestControl::saveFirstPacket(const Pkt6Ptr& pkt) {
1181 if (options_.testDiags('T')) {
1182 if (template_packets_v6_.find(pkt->getType()) == template_packets_v6_.end()) {
1183 template_packets_v6_[pkt->getType()] = pkt;
1184 }
1185 }
1186}
1187
1188void
1189TestControl::sendDiscover4(const bool preload /*= false*/) {
1190 // Generate the MAC address to be passed in the packet.
1191 uint8_t randomized = 0;
1192 std::vector<uint8_t> mac_address = generateMacAddress(randomized);
1193 // Generate transaction id to be set for the new exchange.
1194 const uint32_t transid = generateTransid();
1195 Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, transid));
1196 if (!pkt4) {
1197 isc_throw(Unexpected, "failed to create DISCOVER packet");
1198 }
1199
1200 // Delete the default Message Type option set by Pkt4
1201 pkt4->delOption(DHO_DHCP_MESSAGE_TYPE);
1202
1203 // Set options: DHCP_MESSAGE_TYPE and DHCP_PARAMETER_REQUEST_LIST
1204 OptionBuffer buf_msg_type;
1205 buf_msg_type.push_back(DHCPDISCOVER);
1206 pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_MESSAGE_TYPE,
1207 buf_msg_type));
1208 pkt4->addOption(Option::factory(Option::V4,
1209 DHO_DHCP_PARAMETER_REQUEST_LIST));
1210
1211
1212 // Set client's and server's ports as well as server's address,
1213 // and local (relay) address.
1214 setDefaults4(pkt4);
1215
1216 // Set hardware address
1217 pkt4->setHWAddr(HTYPE_ETHER, mac_address.size(), mac_address);
1218
1219 // Set client identifier
1220 pkt4->addOption(generateClientId(pkt4->getHWAddr()));
1221
1222 // Check if we need to simulate HA failures by pretending no responses were received.
1223 // The DHCP protocol signals that by increasing secs field (seconds since the configuration attempt started).
1224 if (options_.getIncreaseElapsedTime() &&
1225 stats_mgr_.getTestPeriod().length().total_seconds() >= options_.getWaitForElapsedTime() &&
1226 stats_mgr_.getTestPeriod().length().total_seconds() < options_.getWaitForElapsedTime() +
1227 options_.getIncreaseElapsedTime()) {
1228
1229 // Keep increasing elapsed time. The value should start increasing steadily.
1230 uint32_t val = stats_mgr_.getTestPeriod().length().total_seconds() - options_.getWaitForElapsedTime() + 1;
1231 if (val > 65535) {
1232 val = 65535;
1233 }
1234 pkt4->setSecs(static_cast<uint16_t>(val));
1235 }
1236
1237 // Add any extra options that user may have specified.
1238 addExtraOpts(pkt4);
1239
1240 pkt4->pack();
1241 socket_.send(pkt4);
1242 if (!preload) {
1243 stats_mgr_.passSentPacket(ExchangeType::DO, pkt4);
1244 }
1245
1246 saveFirstPacket(pkt4);
1247}
1248
1249void
1250 TestControl::sendDiscover4(const std::vector<uint8_t>& template_buf,
1251 const bool preload /* = false */) {
1252 // Get the first argument if multiple the same arguments specified
1253 // in the command line. First one refers to DISCOVER packets.
1254 const uint8_t arg_idx = 0;
1255 // Generate the MAC address to be passed in the packet.
1256 uint8_t randomized = 0;
1257 std::vector<uint8_t> mac_address = generateMacAddress(randomized);
1258 // Generate transaction id to be set for the new exchange.
1259 const uint32_t transid = generateTransid();
1260 // Get transaction id offset.
1261 size_t transid_offset = getTransactionIdOffset(arg_idx);
1262 // Get randomization offset.
1263 // We need to go back by HW_ETHER_LEN (MAC address length)
1264 // because this offset points to last octet of MAC address.
1265 size_t rand_offset = getRandomOffset(arg_idx) - HW_ETHER_LEN + 1;
1266 // Create temporary buffer with template contents. We will
1267 // modify this temporary buffer but we don't want to modify
1268 // the original template.
1269 std::vector<uint8_t> in_buf(template_buf.begin(),
1270 template_buf.end());
1271 // Check if we are not going out of bounds.
1272 if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
1273 isc_throw(OutOfRange, "randomization offset is out of bounds");
1274 }
1275 PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
1276 transid_offset,
1277 transid));
1278
1279 // Replace MAC address in the template with actual MAC address.
1280 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1281 // Create a packet from the temporary buffer.
1282 setDefaults4(boost::static_pointer_cast<Pkt4>(pkt4));
1283 // Pack the input packet buffer to output buffer so as it can
1284 // be sent to server.
1285 pkt4->rawPack();
1286 socket_.send(boost::static_pointer_cast<Pkt4>(pkt4));
1287 if (!preload) {
1288 // Update packet stats.
1289 stats_mgr_.passSentPacket(ExchangeType::DO,
1290 boost::static_pointer_cast<Pkt4>(pkt4));
1291 }
1292 saveFirstPacket(pkt4);
1293}
1294
1295bool
1296TestControl::sendMessageFromAck(const uint16_t msg_type) {
1297 // We only permit Request or Release messages to be sent using this
1298 // function.
1299 if (msg_type != DHCPREQUEST && msg_type != DHCPRELEASE) {
1300 isc_throw(isc::BadValue,
1301 "invalid message type "
1302 << msg_type
1303 << " to be sent, expected DHCPREQUEST or DHCPRELEASE");
1304 }
1305
1306 // Get one of the recorded DHCPACK messages.
1307 Pkt4Ptr ack = ack_storage_.getRandom();
1308 if (!ack) {
1309 return (false);
1310 }
1311
1312 // Create message of the specified type.
1313 Pkt4Ptr msg = createMessageFromAck(msg_type, ack);
1314 setDefaults4(msg);
1315
1316 // Override relay address
1317 msg->setGiaddr(ack->getGiaddr());
1318
1319 // Add any extra options that user may have specified.
1320 addExtraOpts(msg);
1321
1322 // Pack it.
1323 msg->pack();
1324
1325 // And send it.
1326 socket_.send(msg);
1327 address4Uniqueness(msg, ExchangeType::RLA);
1328 stats_mgr_.passSentPacket((msg_type == DHCPREQUEST ? ExchangeType::RNA :
1329 ExchangeType::RLA),
1330 msg);
1331 return (true);
1332}
1333
1334
1335bool
1336TestControl::sendMessageFromReply(const uint16_t msg_type) {
1337 // We only permit Release or Renew messages to be sent using this function.
1338 if (msg_type != DHCPV6_RENEW && msg_type != DHCPV6_RELEASE) {
1339 isc_throw(isc::BadValue, "invalid message type " << msg_type
1340 << " to be sent, expected DHCPV6_RENEW or DHCPV6_RELEASE");
1341 }
1342
1343 // Get one of the recorded DHCPV6_OFFER messages.
1344 Pkt6Ptr reply = reply_storage_.getRandom();
1345 if (!reply) {
1346 return (false);
1347 }
1348 // Prepare the message of the specified type.
1349 Pkt6Ptr msg = createMessageFromReply(msg_type, reply);
1350 setDefaults6(msg);
1351
1352 // Add any extra options that user may have specified.
1353 addExtraOpts(msg);
1354
1355 // Pack it.
1356 msg->pack();
1357
1358 // And send it.
1359 socket_.send(msg);
1360 address6Uniqueness(msg, ExchangeType::RL);
1361 stats_mgr_.passSentPacket((msg_type == DHCPV6_RENEW ? ExchangeType::RN
1362 : ExchangeType::RL), msg);
1363 return (true);
1364}
1365
1366void
1367TestControl::sendRequest4(const dhcp::Pkt4Ptr& discover_pkt4,
1368 const dhcp::Pkt4Ptr& offer_pkt4) {
1369 // Use the same transaction id as the one used in the discovery packet.
1370 const uint32_t transid = discover_pkt4->getTransid();
1371 Pkt4Ptr pkt4(new Pkt4(DHCPREQUEST, transid));
1372
1373 // Use first flags indicates that we want to use the server
1374 // id captured in first packet.
1375 if (options_.isUseFirst() &&
1376 (first_packet_serverid_.size() > 0)) {
1377 pkt4->addOption(Option::factory(Option::V4, DHO_DHCP_SERVER_IDENTIFIER,
1378 first_packet_serverid_));
1379 } else {
1380 OptionPtr opt_serverid =
1381 offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
1382 if (!opt_serverid) {
1383 isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
1384 << "in OFFER message");
1385 }
1386 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) == 1) {
1387 first_packet_serverid_ = opt_serverid->getData();
1388 }
1389 pkt4->addOption(opt_serverid);
1390 }
1391
1393 asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
1394 if (!yiaddr.isV4()) {
1395 isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
1396 " IPv4 address");
1397 }
1398 OptionPtr opt_requested_address =
1399 OptionPtr(new Option(Option::V4, DHO_DHCP_REQUESTED_ADDRESS,
1400 OptionBuffer()));
1401 opt_requested_address->setUint32(yiaddr.toUint32());
1402 pkt4->addOption(opt_requested_address);
1403 OptionPtr opt_parameter_list =
1404 Option::factory(Option::V4, DHO_DHCP_PARAMETER_REQUEST_LIST);
1405 pkt4->addOption(opt_parameter_list);
1406 // Set client's and server's ports as well as server's address
1407 setDefaults4(pkt4);
1408 // Override relay address
1409 pkt4->setGiaddr(offer_pkt4->getGiaddr());
1410 // Add any extra options that user may have specified.
1411 addExtraOpts(pkt4);
1412
1413 // Set hardware address
1414 pkt4->setHWAddr(offer_pkt4->getHWAddr());
1415 // Set client id.
1416 pkt4->addOption(generateClientId(pkt4->getHWAddr()));
1417 // Set elapsed time.
1418 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1419 pkt4->setSecs(static_cast<uint16_t>(elapsed_time / 1000));
1420 // Prepare on wire data to send.
1421 pkt4->pack();
1422 socket_.send(pkt4);
1423 stats_mgr_.passSentPacket(ExchangeType::RA, pkt4);
1424 saveFirstPacket(pkt4);
1425}
1426
1427void
1428 TestControl::sendRequest4(const std::vector<uint8_t>& template_buf,
1429 const dhcp::Pkt4Ptr& discover_pkt4,
1430 const dhcp::Pkt4Ptr& offer_pkt4) {
1431 // Get the second argument if multiple the same arguments specified
1432 // in the command line. Second one refers to REQUEST packets.
1433 const uint8_t arg_idx = 1;
1434 // Use the same transaction id as the one used in the discovery packet.
1435 const uint32_t transid = discover_pkt4->getTransid();
1436 // Get transaction id offset.
1437 size_t transid_offset = getTransactionIdOffset(arg_idx);
1438 // Get the offset of MAC's last octet.
1439 // We need to go back by HW_ETHER_LEN (MAC address length)
1440 // because this offset points to last octet of MAC address.
1441 size_t rand_offset = getRandomOffset(arg_idx) - HW_ETHER_LEN + 1;
1442 // Create temporary buffer from the template.
1443 std::vector<uint8_t> in_buf(template_buf.begin(),
1444 template_buf.end());
1445 // Check if given randomization offset is not out of bounds.
1446 if (rand_offset + HW_ETHER_LEN > in_buf.size()) {
1447 isc_throw(OutOfRange, "randomization offset is out of bounds");
1448 }
1449
1450 // Create packet from the temporary buffer.
1451 PerfPkt4Ptr pkt4(new PerfPkt4(&in_buf[0], in_buf.size(),
1452 transid_offset,
1453 transid));
1454
1455 // Set hardware address from OFFER packet received.
1456 HWAddrPtr hwaddr = offer_pkt4->getHWAddr();
1457 std::vector<uint8_t> mac_address(HW_ETHER_LEN, 0);
1458 uint8_t hw_len = hwaddr->hwaddr_.size();
1459 if (hw_len != 0) {
1460 memcpy(&mac_address[0], &hwaddr->hwaddr_[0],
1461 hw_len > HW_ETHER_LEN ? HW_ETHER_LEN : hw_len);
1462 }
1463 pkt4->writeAt(rand_offset, mac_address.begin(), mac_address.end());
1464
1465 // Set elapsed time.
1466 size_t elp_offset = getElapsedTimeOffset();
1467 uint32_t elapsed_time = getElapsedTime<Pkt4Ptr>(discover_pkt4, offer_pkt4);
1468 pkt4->writeValueAt<uint16_t>(elp_offset,
1469 static_cast<uint16_t>(elapsed_time / 1000));
1470
1471 // Get the actual server id offset.
1472 size_t sid_offset = getServerIdOffset();
1473 // Use first flags indicates that we want to use the server
1474 // id captured in first packet.
1475 if (options_.isUseFirst() &&
1476 (first_packet_serverid_.size() > 0)) {
1477 boost::shared_ptr<LocalizedOption>
1478 opt_serverid(new LocalizedOption(Option::V4,
1479 DHO_DHCP_SERVER_IDENTIFIER,
1480 first_packet_serverid_,
1481 sid_offset));
1482 pkt4->addOption(opt_serverid);
1483 } else {
1484 // Copy the contents of server identifier received in
1485 // OFFER packet to put this into REQUEST.
1486 OptionPtr opt_serverid_offer =
1487 offer_pkt4->getOption(DHO_DHCP_SERVER_IDENTIFIER);
1488 if (!opt_serverid_offer) {
1489 isc_throw(BadValue, "there is no SERVER_IDENTIFIER option "
1490 << "in OFFER message");
1491 }
1492 boost::shared_ptr<LocalizedOption>
1493 opt_serverid(new LocalizedOption(Option::V4,
1494 DHO_DHCP_SERVER_IDENTIFIER,
1495 opt_serverid_offer->getData(),
1496 sid_offset));
1497 pkt4->addOption(opt_serverid);
1498 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::DO) == 1) {
1499 first_packet_serverid_ = opt_serverid_offer->getData();
1500 }
1501 }
1502
1504 asiolink::IOAddress yiaddr = offer_pkt4->getYiaddr();
1505 if (!yiaddr.isV4()) {
1506 isc_throw(BadValue, "the YIADDR returned in OFFER packet is not "
1507 " IPv4 address");
1508 }
1509
1510 // Get the actual offset of requested ip.
1511 size_t rip_offset = getRequestedIpOffset();
1512 // Place requested IP option at specified position (rip_offset).
1513 boost::shared_ptr<LocalizedOption>
1514 opt_requested_ip(new LocalizedOption(Option::V4,
1515 DHO_DHCP_REQUESTED_ADDRESS,
1516 OptionBuffer(),
1517 rip_offset));
1518 // The IOAddress is convertible to uint32_t and returns exactly what we need.
1519 opt_requested_ip->setUint32(yiaddr.toUint32());
1520 pkt4->addOption(opt_requested_ip);
1521
1522 setDefaults4(boost::static_pointer_cast<Pkt4>(pkt4));
1523
1524 // Add any extra options that user may have specified.
1525 addExtraOpts(pkt4);
1526
1527 // Prepare on-wire data.
1528 pkt4->rawPack();
1529 socket_.send(boost::static_pointer_cast<Pkt4>(pkt4));
1530 // Update packet stats.
1531 stats_mgr_.passSentPacket(ExchangeType::RA,
1532 boost::static_pointer_cast<Pkt4>(pkt4));
1533 saveFirstPacket(pkt4);
1534}
1535
1536void
1537TestControl::sendRequest6(const Pkt6Ptr& advertise_pkt6) {
1538 const uint32_t transid = generateTransid();
1539 Pkt6Ptr pkt6(new Pkt6(DHCPV6_REQUEST, transid));
1540 // Set elapsed time.
1541 OptionPtr opt_elapsed_time =
1542 Option::factory(Option::V6, D6O_ELAPSED_TIME);
1543 pkt6->addOption(opt_elapsed_time);
1544 // Set client id.
1545 OptionPtr opt_clientid = advertise_pkt6->getOption(D6O_CLIENTID);
1546 if (!opt_clientid) {
1547 isc_throw(Unexpected, "client id not found in received packet");
1548 }
1549 pkt6->addOption(opt_clientid);
1550
1551 // Use first flags indicates that we want to use the server
1552 // id captured in first packet.
1553 if (options_.isUseFirst() &&
1554 (first_packet_serverid_.size() > 0)) {
1555 pkt6->addOption(Option::factory(Option::V6, D6O_SERVERID,
1556 first_packet_serverid_));
1557 } else {
1558 OptionPtr opt_serverid = advertise_pkt6->getOption(D6O_SERVERID);
1559 if (!opt_serverid) {
1560 isc_throw(Unexpected, "server id not found in received packet");
1561 }
1562 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) == 1) {
1563 first_packet_serverid_ = opt_serverid->getData();
1564 }
1565 pkt6->addOption(opt_serverid);
1566 }
1567
1568 // Copy IA_NA or IA_PD option from the Advertise message to the Request
1569 // message being sent to the server. This will throw exception if the
1570 // option to be copied is not found. Note that this function will copy
1571 // one of IA_NA or IA_PD options, depending on the lease-type value
1572 // specified in the command line.
1573 copyIaOptions(advertise_pkt6, pkt6);
1574
1575 // Set default packet data.
1576 setDefaults6(pkt6);
1577
1578 // Add any extra options that user may have specified.
1579 addExtraOpts(pkt6);
1580
1581 // Prepare on-wire data.
1582 pkt6->pack();
1583 socket_.send(pkt6);
1584 stats_mgr_.passSentPacket(ExchangeType::RR, pkt6);
1585 saveFirstPacket(pkt6);
1586}
1587
1588void
1589 TestControl::sendRequest6(const std::vector<uint8_t>& template_buf,
1590 const Pkt6Ptr& advertise_pkt6) {
1591 // Get the second argument if multiple the same arguments specified
1592 // in the command line. Second one refers to REQUEST packets.
1593 const uint8_t arg_idx = 1;
1594 // Generate transaction id.
1595 const uint32_t transid = generateTransid();
1596 // Get transaction id offset.
1597 size_t transid_offset = getTransactionIdOffset(arg_idx);
1598 PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
1599 transid_offset, transid));
1600 // Set elapsed time.
1601 size_t elp_offset = getElapsedTimeOffset();
1602 boost::shared_ptr<LocalizedOption>
1603 opt_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME,
1604 OptionBuffer(), elp_offset));
1605 pkt6->addOption(opt_elapsed_time);
1606
1607 // Get the actual server id offset.
1608 size_t sid_offset = getServerIdOffset();
1609 // Use first flags indicates that we want to use the server
1610 // id captured in first packet.
1611 if (options_.isUseFirst() &&
1612 (first_packet_serverid_.size() > 0)) {
1613 boost::shared_ptr<LocalizedOption>
1614 opt_serverid(new LocalizedOption(Option::V6,
1615 D6O_SERVERID,
1616 first_packet_serverid_,
1617 sid_offset));
1618 pkt6->addOption(opt_serverid);
1619
1620 } else {
1621 // Copy the contents of server identifier received in
1622 // ADVERTISE packet to put this into REQUEST.
1623 OptionPtr opt_serverid_advertise =
1624 advertise_pkt6->getOption(D6O_SERVERID);
1625 if (!opt_serverid_advertise) {
1626 isc_throw(BadValue, "there is no SERVERID option "
1627 << "in ADVERTISE message");
1628 }
1629 boost::shared_ptr<LocalizedOption>
1630 opt_serverid(new LocalizedOption(Option::V6,
1631 D6O_SERVERID,
1632 opt_serverid_advertise->getData(),
1633 sid_offset));
1634 pkt6->addOption(opt_serverid);
1635 if (stats_mgr_.getRcvdPacketsNum(ExchangeType::SA) == 1) {
1636 first_packet_serverid_ = opt_serverid_advertise->getData();
1637 }
1638 }
1639 // Set IA_NA
1640 OptionPtr opt_ia_na_advertise = advertise_pkt6->getOption(D6O_IA_NA);
1641 if (!opt_ia_na_advertise) {
1642 isc_throw(Unexpected, "DHCPv6 IA_NA option not found in received "
1643 "packet");
1644 }
1645 size_t addr_offset = getRequestedIpOffset();
1646 boost::shared_ptr<LocalizedOption>
1647 opt_ia_na(new LocalizedOption(Option::V6, D6O_IA_NA, opt_ia_na_advertise->getData(), addr_offset));
1648 if (!opt_ia_na->valid()) {
1649 isc_throw(BadValue, "Option IA_NA in advertise packet is invalid");
1650 }
1651 pkt6->addOption(opt_ia_na);
1652 // Set server id.
1653 OptionPtr opt_serverid_advertise = advertise_pkt6->getOption(D6O_SERVERID);
1654 if (!opt_serverid_advertise) {
1655 isc_throw(Unexpected, "DHCPV6 SERVERID option not found in received "
1656 "packet");
1657 }
1658 size_t srvid_offset = getServerIdOffset();
1659 boost::shared_ptr<LocalizedOption>
1660 opt_serverid(new LocalizedOption(Option::V6, D6O_SERVERID,
1661 opt_serverid_advertise->getData(),
1662 srvid_offset));
1663 pkt6->addOption(opt_serverid);
1664 // Get randomization offset.
1665 size_t rand_offset = getRandomOffset(arg_idx);
1666 OptionPtr opt_clientid_advertise = advertise_pkt6->getOption(D6O_CLIENTID);
1667 if (!opt_clientid_advertise) {
1668 isc_throw(Unexpected, "DHCPV6 CLIENTID option not found in received packet");
1669 }
1670 rand_offset -= (opt_clientid_advertise->len() - 1);
1671 // Set client id.
1672 boost::shared_ptr<LocalizedOption>
1673 opt_clientid(new LocalizedOption(Option::V6, D6O_CLIENTID,
1674 opt_clientid_advertise->getData(),
1675 rand_offset));
1676 pkt6->addOption(opt_clientid);
1677 // Set default packet data.
1678 setDefaults6(pkt6);
1679
1680 // Add any extra options that user may have specified.
1681 addExtraOpts(pkt6);
1682
1683 // Prepare on wire data.
1684 pkt6->rawPack();
1685 // Send packet.
1686 socket_.send(pkt6);
1687 // Update packet stats.
1688 stats_mgr_.passSentPacket(ExchangeType::RR, pkt6);
1689
1690 // When 'T' diagnostics flag is specified it means that user requested
1691 // printing packet contents. It will be just one (first) packet which
1692 // contents will be printed. Here we check if this packet has been already
1693 // collected. If it hasn't we save this packet so as we can print its
1694 // contents when test is finished.
1695 if (options_.testDiags('T') &&
1696 (template_packets_v6_.find(DHCPV6_REQUEST) == template_packets_v6_.end())) {
1697 template_packets_v6_[DHCPV6_REQUEST] = pkt6;
1698 }
1699}
1700
1701void
1702TestControl::sendSolicit6(const bool preload /*= false*/) {
1703 // Generate DUID to be passed to the packet
1704 uint8_t randomized = 0;
1705 std::vector<uint8_t> duid = generateDuid(randomized);
1706 // Generate transaction id to be set for the new exchange.
1707 const uint32_t transid = generateTransid();
1708 Pkt6Ptr pkt6(new Pkt6(DHCPV6_SOLICIT, transid));
1709 if (!pkt6) {
1710 isc_throw(Unexpected, "failed to create SOLICIT packet");
1711 }
1712
1713 // Check if we need to simulate HA failures by pretending no responses were received.
1714 // The DHCPv6 protocol signals that by increasing the elapsed option field. Note it is in 1/100 of a second.
1715 if (options_.getIncreaseElapsedTime() &&
1716 stats_mgr_.getTestPeriod().length().total_seconds() >= options_.getWaitForElapsedTime() &&
1717 stats_mgr_.getTestPeriod().length().total_seconds() < options_.getWaitForElapsedTime() +
1718 options_.getIncreaseElapsedTime()) {
1719
1720
1721 // Keep increasing elapsed time. The value should start increasing steadily.
1722 uint32_t val = (stats_mgr_.getTestPeriod().length().total_seconds() - options_.getWaitForElapsedTime() + 1)*100;
1723 if (val > 65535) {
1724 val = 65535;
1725 }
1726 OptionPtr elapsed(new OptionInt<uint16_t>(Option::V6, D6O_ELAPSED_TIME, val));
1727 pkt6->addOption(elapsed);
1728 } else {
1729 pkt6->addOption(Option::factory(Option::V6, D6O_ELAPSED_TIME));
1730 }
1731
1732 if (options_.isRapidCommit()) {
1733 pkt6->addOption(Option::factory(Option::V6, D6O_RAPID_COMMIT));
1734 }
1735 pkt6->addOption(Option::factory(Option::V6, D6O_CLIENTID, duid));
1736 pkt6->addOption(Option::factory(Option::V6, D6O_ORO));
1737
1738
1739 // Depending on the lease-type option specified, we should request
1740 // IPv6 address (with IA_NA) or IPv6 prefix (IA_PD) or both.
1741
1742 // IA_NA
1743 if (options_.getLeaseType().includes(CommandOptions::LeaseType::ADDRESS)) {
1744 pkt6->addOption(Option::factory(Option::V6, D6O_IA_NA));
1745 }
1746 // IA_PD
1747 if (options_.getLeaseType().includes(CommandOptions::LeaseType::PREFIX)) {
1748 pkt6->addOption(Option::factory(Option::V6, D6O_IA_PD));
1749 }
1750
1751 setDefaults6(pkt6);
1752
1753 // Add any extra options that user may have specified.
1754 addExtraOpts(pkt6);
1755
1756 pkt6->pack();
1757 socket_.send(pkt6);
1758 if (!preload) {
1759 stats_mgr_.passSentPacket(ExchangeType::SA, pkt6);
1760 }
1761
1762 saveFirstPacket(pkt6);
1763}
1764
1765void
1766 TestControl::sendSolicit6(const std::vector<uint8_t>& template_buf,
1767 const bool preload /*= false*/) {
1768 const int arg_idx = 0;
1769 // Get transaction id offset.
1770 size_t transid_offset = getTransactionIdOffset(arg_idx);
1771 // Generate transaction id to be set for the new exchange.
1772 const uint32_t transid = generateTransid();
1773 // Create packet.
1774 PerfPkt6Ptr pkt6(new PerfPkt6(&template_buf[0], template_buf.size(),
1775 transid_offset, transid));
1776 if (!pkt6) {
1777 isc_throw(Unexpected, "failed to create SOLICIT packet");
1778 }
1779 size_t rand_offset = getRandomOffset(arg_idx);
1780 // randomized will pick number of bytes randomized so we can
1781 // just use part of the generated duid and substitute a few bytes
1783 uint8_t randomized = 0;
1784 std::vector<uint8_t> duid = generateDuid(randomized);
1785 if (rand_offset > template_buf.size()) {
1786 isc_throw(OutOfRange, "randomization offset is out of bounds");
1787 }
1788 // Store random part of the DUID into the packet.
1789 pkt6->writeAt(rand_offset - randomized + 1,
1790 duid.end() - randomized, duid.end());
1791
1792 // Prepare on-wire data.
1793 pkt6->rawPack();
1794 setDefaults6(pkt6);
1795
1796 // Add any extra options that user may have specified.
1797 addExtraOpts(pkt6);
1798
1799 // Send solicit packet.
1800 socket_.send(pkt6);
1801 if (!preload) {
1802 // Update packet stats.
1803 stats_mgr_.passSentPacket(ExchangeType::SA, pkt6);
1804 }
1805 saveFirstPacket(pkt6);
1806}
1807
1808
1809void
1810TestControl::setDefaults4(const Pkt4Ptr& pkt) {
1811 // Interface name.
1812 IfacePtr iface = socket_.getIface();
1813 if (iface == NULL) {
1814 isc_throw(BadValue, "unable to find interface with given index");
1815 }
1816 pkt->setIface(iface->getName());
1817 // Interface index.
1818 pkt->setIndex(socket_.ifindex_);
1819 // Local client's port (68)
1820 pkt->setLocalPort(DHCP4_CLIENT_PORT);
1821 // Server's port (67)
1822 if (options_.getRemotePort()) {
1823 pkt->setRemotePort(options_.getRemotePort());
1824 } else {
1825 pkt->setRemotePort(DHCP4_SERVER_PORT);
1826 }
1827 // The remote server's name or IP.
1828 pkt->setRemoteAddr(IOAddress(options_.getServerName()));
1829 // Set local address.
1830 pkt->setLocalAddr(socket_.addr_);
1831 // Set relay (GIADDR) address to local address if multiple
1832 // subnet mode is not enabled
1833 if (!options_.checkMultiSubnet()) {
1834 pkt->setGiaddr(socket_.addr_);
1835 } else {
1836 pkt->setGiaddr(IOAddress(options_.getRandRelayAddr()));
1837 }
1838 // Pretend that we have one relay (which is us).
1839 pkt->setHops(1);
1840}
1841
1842void
1843TestControl::setDefaults6(const Pkt6Ptr& pkt) {
1844 // Interface name.
1845 IfacePtr iface = socket_.getIface();
1846 if (iface == NULL) {
1847 isc_throw(BadValue, "unable to find interface with given index");
1848 }
1849 pkt->setIface(iface->getName());
1850 // Interface index.
1851 pkt->setIndex(socket_.ifindex_);
1852 // Local client's port (547)
1853 pkt->setLocalPort(DHCP6_CLIENT_PORT);
1854 // Server's port (548)
1855 if (options_.getRemotePort()) {
1856 pkt->setRemotePort(options_.getRemotePort());
1857 } else {
1858 pkt->setRemotePort(DHCP6_SERVER_PORT);
1859 }
1860 // Set local address.
1861 pkt->setLocalAddr(socket_.addr_);
1862 // The remote server's name or IP.
1863 pkt->setRemoteAddr(IOAddress(options_.getServerName()));
1864
1865 // only act as a relay agent when told so.
1868 if (options_.isUseRelayedV6()) {
1869 Pkt6::RelayInfo relay_info;
1870 relay_info.msg_type_ = DHCPV6_RELAY_FORW;
1871 relay_info.hop_count_ = 0;
1872 if (options_.checkMultiSubnet()) {
1873 relay_info.linkaddr_ = IOAddress(options_.getRandRelayAddr());
1874 } else {
1875 relay_info.linkaddr_ = socket_.addr_;
1876 }
1877 relay_info.peeraddr_ = socket_.addr_;
1878 relay_info.options_.insert(options_.getRelayOpts().begin(), options_.getRelayOpts().end());
1879 pkt->addRelayInfo(relay_info);
1880 }
1881}
1882
1883namespace {
1884
1885static OptionBuffer const concatenateBuffers(OptionBuffer const& a,
1886 OptionBuffer const& b) {
1887 OptionBuffer result;
1888 result.insert(result.end(), a.begin(), a.end());
1889 result.insert(result.end(), b.begin(), b.end());
1890 return (result);
1891}
1892
1893static void mergeOptionIntoPacket(Pkt4Ptr const& packet,
1894 OptionPtr const& extra_option) {
1895 uint16_t const code(extra_option->getType());
1896 // If option already exists...
1897 OptionPtr const& option(packet->getOption(code));
1898 if (option) {
1899 switch (code) {
1900 // List here all the options for which we want to concatenate buffers.
1901 case DHO_DHCP_PARAMETER_REQUEST_LIST:
1902 packet->delOption(code);
1903 packet->addOption(boost::make_shared<Option>(
1904 Option::V4, code,
1905 concatenateBuffers(option->getData(),
1906 extra_option->getData())));
1907 return;
1908 default:
1909 // For all others, add option as usual, it will result in "Option
1910 // already present in this message" error.
1911 break;
1912 }
1913 }
1914 packet->addOption(extra_option);
1915}
1916
1917} // namespace
1918
1919void
1920TestControl::addExtraOpts(const Pkt4Ptr& pkt) {
1921 // Add all extra options that the user may have specified.
1922 const dhcp::OptionCollection& extra_opts = options_.getExtraOpts();
1923 for (auto const& entry : extra_opts) {
1924 mergeOptionIntoPacket(pkt, entry.second);
1925 }
1926}
1927
1928void
1929 TestControl::addExtraOpts(const Pkt6Ptr& pkt) {
1930 // Add all extra options that the user may have specified.
1931 const dhcp::OptionCollection& extra_opts = options_.getExtraOpts();
1932 for (auto const& entry : extra_opts) {
1933 pkt->addOption(entry.second);
1934 }
1935}
1936
1937} // namespace perfdhcp
1938} // namespace isc
check_valgrind.h
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::InvalidOperation
A generic exception that is thrown if a function is called in a prohibited way.
Definition exceptions/exceptions.h:143
isc::NotFound
A generic exception that is thrown when an object can not be found.
Definition exceptions/exceptions.h:175
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition exceptions/exceptions.h:115
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition exceptions/exceptions.h:153
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:53
isc::asiolink::IOAddress::toText
std::string toText() const
Convert the address to a string.
Definition io_address.cc:60
isc::asiolink::IOAddress::toUint32
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
Definition io_address.cc:121
isc::asiolink::IOAddress::isV4
bool isV4() const
Convenience function to check for an IPv4 address.
Definition io_address.h:122
isc::dhcp::IfaceMgr::instance
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:52
isc::dhcp::IfaceMgr::configureDHCPPacketQueue
bool configureDHCPPacketQueue(const uint16_t family, data::ConstElementPtr queue_control)
Configures DHCP packet queue.
Definition iface_mgr.cc:2248
isc::dhcp::LibDHCP::OptionFactoryRegister
static void OptionFactoryRegister(Option::Universe u, uint16_t type, Option::Factory *factory)
Registers factory method that produces options of specific option types.
Definition libdhcp++.cc:1286
isc::dhcp::Option6IAAddr
Definition option6_iaaddr.h:22
isc::dhcp::Option6IAAddr::getAddress
isc::asiolink::IOAddress getAddress() const
Returns address contained within this option.
Definition option6_iaaddr.h:108
isc::dhcp::Option6IAPrefix
Class that represents IAPREFIX option in DHCPv6.
Definition option6_iaprefix.h:51
isc::dhcp::OptionInt
Forward declaration to OptionInt.
Definition option_int.h:49
isc::dhcp::Option
Definition option.h:81
isc::dhcp::Option::factory
static OptionPtr factory(Option::Universe u, uint16_t type, const OptionBuffer &buf)
Factory function to create instance of option.
Definition option.cc:33
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
isc::dhcp::Option::V6
@ V6
Definition option.h:90
isc::dhcp::Option::V4
@ V4
Definition option.h:90
isc::dhcp::Pkt4
Represents DHCPv4 packet.
Definition pkt4.h:37
isc::dhcp::Pkt6
Represents a DHCPv6 packet.
Definition pkt6.h:44
isc::perfdhcp::BasePerfSocket
Socket wrapper structure.
Definition perf_socket.h:26
isc::perfdhcp::CommandOptions::LeaseType::ADDRESS
@ ADDRESS
Definition command_options.h:58
isc::perfdhcp::CommandOptions::LeaseType::ADDRESS_AND_PREFIX
@ ADDRESS_AND_PREFIX
Definition command_options.h:60
isc::perfdhcp::CommandOptions::LeaseType::PREFIX
@ PREFIX
Definition command_options.h:59
isc::perfdhcp::CommandOptions
Command Options.
Definition command_options.h:30
isc::perfdhcp::CommandOptions::ExchangeMode
ExchangeMode
2-way (cmd line param -i) or 4-way exchanges
Definition command_options.h:120
isc::perfdhcp::CommandOptions::DO_SA
@ DO_SA
Definition command_options.h:121
isc::perfdhcp::CommandOptions::DORA_SARR
@ DORA_SARR
Definition command_options.h:122
isc::perfdhcp::CommandOptions::MacAddrsVector
std::vector< std::vector< uint8_t > > MacAddrsVector
A vector holding MAC addresses.
Definition command_options.h:42
isc::perfdhcp::ExchangeStats::malformed_pkts_
static int malformed_pkts_
Definition bin/perfdhcp/stats_mgr.h:587
isc::perfdhcp::LocalizedOption
DHCP option at specific offset.
Definition localized_option.h:37
isc::perfdhcp::PerfPkt4
PerfPkt4 (DHCPv4 packet).
Definition perf_pkt4.h:42
isc::perfdhcp::PerfPkt6
PerfPkt6 (DHCPv6 packet).
Definition perf_pkt6.h:41
isc::perfdhcp::TestControl::RandomGenerator
Random numbers generator class.
Definition test_control.h:187
isc::perfdhcp::TestControl::SequentialGenerator
Sequential numbers generator class.
Definition test_control.h:157
isc::perfdhcp::TestControl::saveFirstPacket
void saveFirstPacket(const dhcp::Pkt4Ptr &pkt)
Save the first DHCPv4 sent packet of the specified type.
Definition test_control.cc:1171
isc::perfdhcp::TestControl::address6Uniqueness
void address6Uniqueness(const dhcp::Pkt6Ptr &pkt6, ExchangeType xchg_type)
Process received v6 addresses uniqueness.
Definition test_control.cc:855
isc::perfdhcp::TestControl::HW_ETHER_LEN
static const uint8_t HW_ETHER_LEN
Length of the Ethernet HW address (MAC) in bytes.
Definition test_control.h:222
isc::perfdhcp::TestControl::waitToExit
bool waitToExit()
Delay the exit by a fixed given time to catch up to all exchanges that were already started.
Definition test_control.cc:48
isc::perfdhcp::TestControl::template_packets_v4_
std::map< uint8_t, dhcp::Pkt4Ptr > template_packets_v4_
First packets send.
Definition test_control.h:1130
isc::perfdhcp::TestControl::sendMessageFromReply
bool sendMessageFromReply(const uint16_t msg_type)
Send DHCPv6 Renew or Release message.
Definition test_control.cc:1336
isc::perfdhcp::TestControl::addExtraOpts
void addExtraOpts(const dhcp::Pkt4Ptr &pkt4)
Inserts extra options specified by user.
Definition test_control.cc:1920
isc::perfdhcp::TestControl::printDiagnostics
void printDiagnostics() const
Print main diagnostics data.
Definition test_control.cc:610
isc::perfdhcp::TestControl::handleChild
static void handleChild(int sig)
Handle child signal.
Definition test_control.cc:536
isc::perfdhcp::TestControl::registerOptionFactories4
void registerOptionFactories4() const
Register option factory functions for DHCPv4.
Definition test_control.cc:1020
isc::perfdhcp::TestControl::transid_gen_
NumberGeneratorPtr transid_gen_
Transaction id generator.
Definition test_control.h:1115
isc::perfdhcp::TestControl::macaddr_gen_
NumberGeneratorPtr macaddr_gen_
Numbers generator for MAC address.
Definition test_control.h:1118
isc::perfdhcp::TestControl::getRequestedIpOffset
int getRequestedIpOffset() const
Return requested ip offset in a packet.
Definition test_control.cc:498
isc::perfdhcp::TestControl::random_generator_
NumberGeneratorPtr random_generator_
Generate uniformly distributed integers in range of [min, max].
Definition test_control.h:1112
isc::perfdhcp::TestControl::NumberGeneratorPtr
boost::shared_ptr< NumberGenerator > NumberGeneratorPtr
The default generator pointer.
Definition test_control.h:154
isc::perfdhcp::TestControl::sendMultipleMessages4
uint64_t sendMultipleMessages4(const uint32_t msg_type, const uint64_t msg_num)
Send number of DHCPREQUEST (renew) messages to a server.
Definition test_control.cc:588
isc::perfdhcp::TestControl::validateIA
bool validateIA(const dhcp::Pkt6Ptr &pkt6)
Process IA in received DHCPv6 packet.
Definition test_control.cc:906
isc::perfdhcp::TestControl::createMessageFromAck
dhcp::Pkt4Ptr createMessageFromAck(const uint16_t msg_type, const dhcp::Pkt4Ptr &ack)
Creates DHCPREQUEST from a DHCPACK message.
Definition test_control.cc:164
isc::perfdhcp::TestControl::interrupted_
static bool interrupted_
Program interrupted flag.
Definition test_control.h:1136
isc::perfdhcp::TestControl::readPacketTemplate
void readPacketTemplate(const std::string &file_name)
Read DHCP message template from file.
Definition test_control.cc:763
isc::perfdhcp::TestControl::getTemplateBuffer
TemplateBuffer getTemplateBuffer(const size_t idx) const
Return template buffer.
Definition test_control.cc:518
isc::perfdhcp::TestControl::generateMacAddress
std::vector< uint8_t > generateMacAddress(uint8_t &randomized)
Generate MAC address.
Definition test_control.cc:360
isc::perfdhcp::TestControl::setDefaults4
void setDefaults4(const dhcp::Pkt4Ptr &pkt)
Set default DHCPv4 packet parameters.
Definition test_control.cc:1810
isc::perfdhcp::TestControl::exit_time_
boost::posix_time::ptime exit_time_
Initialized at first exit condition with the time perfdhcp should exit.
Definition test_control.h:375
isc::perfdhcp::TestControl::options_
CommandOptions & options_
Command options.
Definition test_control.h:1139
isc::perfdhcp::TestControl::receiver_
Receiver receiver_
Receiver used to receive DHCP traffic.
Definition test_control.h:1096
isc::perfdhcp::TestControl::vector2Hex
static std::string vector2Hex(const std::vector< uint8_t > &vec, const std::string &separator="")
Convert vector in hexadecimal string.
Definition test_control.cc:747
isc::perfdhcp::TestControl::sendMultipleMessages6
uint64_t sendMultipleMessages6(const uint32_t msg_type, const uint64_t msg_num)
Send number of DHCPv6 Renew or Release messages to the server.
Definition test_control.cc:599
isc::perfdhcp::TestControl::setMacAddrGenerator
void setMacAddrGenerator(const NumberGeneratorPtr &generator)
Set new MAC address generator.
Definition test_control.h:238
isc::perfdhcp::TestControl::setDefaults6
void setDefaults6(const dhcp::Pkt6Ptr &pkt)
Set default DHCPv6 packet parameters.
Definition test_control.cc:1843
isc::perfdhcp::TestControl::last_report_
boost::posix_time::ptime last_report_
Last intermediate report time.
Definition test_control.h:1099
isc::perfdhcp::TestControl::haveAllPacketsBeenReceived
bool haveAllPacketsBeenReceived() const
Checks if all expected packets were already received.
Definition test_control.cc:69
isc::perfdhcp::TestControl::cleanCachedPackets
void cleanCachedPackets()
Removes cached DHCPv6 Reply packets every second.
Definition test_control.cc:96
isc::perfdhcp::TestControl::processReceivedPacket4
void processReceivedPacket4(const dhcp::Pkt4Ptr &pkt4)
Process received DHCPv4 packet.
Definition test_control.cc:811
isc::perfdhcp::TestControl::sendRequest6
void sendRequest6(const dhcp::Pkt6Ptr &advertise_pkt6)
Send DHCPv6 REQUEST message.
Definition test_control.cc:1537
isc::perfdhcp::TestControl::TestControl
TestControl(CommandOptions &options, BasePerfSocket &socket)
Default constructor.
Definition test_control.cc:1105
isc::perfdhcp::TestControl::factoryOptionRequestOption6
static dhcp::OptionPtr factoryOptionRequestOption6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 ORO option.
Definition test_control.cc:327
isc::perfdhcp::TestControl::sendSolicit6
void sendSolicit6(const bool preload=false)
Send DHCPv6 SOLICIT message.
Definition test_control.cc:1702
isc::perfdhcp::TestControl::factoryIapd6
static dhcp::OptionPtr factoryIapd6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create IA_PD option.
Definition test_control.cc:305
isc::perfdhcp::TestControl::template_packets_v6_
std::map< uint8_t, dhcp::Pkt6Ptr > template_packets_v6_
Template for v6.
Definition test_control.h:1133
isc::perfdhcp::TestControl::factoryRapidCommit6
static dhcp::OptionPtr factoryRapidCommit6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 RAPID_COMMIT option instance.
Definition test_control.cc:321
isc::perfdhcp::TestControl::reply_storage_
PacketStorage< dhcp::Pkt6 > reply_storage_
Storage for reply messages.
Definition test_control.h:1108
isc::perfdhcp::TestControl::registerOptionFactories6
void registerOptionFactories6() const
Register option factory functions for DHCPv6.
Definition test_control.cc:1040
isc::perfdhcp::TestControl::sendPackets
void sendPackets(const uint64_t packets_num, const bool preload=false)
Send number of packets to initiate new exchanges.
Definition test_control.cc:560
isc::perfdhcp::TestControl::registerOptionFactories
void registerOptionFactories() const
Register option factory functions for DHCPv4 or DHCPv6.
Definition test_control.cc:1079
isc::perfdhcp::TestControl::TemplateBuffer
std::vector< uint8_t > TemplateBuffer
Packet template buffer.
Definition test_control.h:123
isc::perfdhcp::TestControl::sendMessageFromAck
bool sendMessageFromAck(const uint16_t msg_type)
Send DHCPv4 renew (DHCPREQUEST).
Definition test_control.cc:1296
isc::perfdhcp::TestControl::runWrapped
void runWrapped(bool do_stop=false) const
Run wrapped command.
Definition test_control.cc:1157
isc::perfdhcp::TestControl::processReceivedPacket6
void processReceivedPacket6(const dhcp::Pkt6Ptr &pkt6)
Process received DHCPv6 packet.
Definition test_control.cc:940
isc::perfdhcp::TestControl::getElapsedTime
uint32_t getElapsedTime(const T &pkt1, const T &pkt2)
Calculate elapsed time between two packets.
Definition test_control.cc:474
isc::perfdhcp::TestControl::socket_
BasePerfSocket & socket_
Socket used for DHCP traffic.
Definition test_control.h:1093
isc::perfdhcp::TestControl::reset
void reset()
Resets internal state of the object.
Definition test_control.cc:1094
isc::perfdhcp::TestControl::addUniqeAddr
void addUniqeAddr(const std::set< std::string > &current, ExchangeType xchg_type)
add unique address to already assigned list.
Definition test_control.h:644
isc::perfdhcp::TestControl::address4Uniqueness
void address4Uniqueness(const dhcp::Pkt4Ptr &pkt4, ExchangeType xchg_type)
Process received v4 addresses uniqueness.
Definition test_control.cc:893
isc::perfdhcp::TestControl::getRandomOffset
int getRandomOffset(const int arg_idx) const
Return randomization offset in a packet.
Definition test_control.cc:488
isc::perfdhcp::TestControl::createMessageFromReply
dhcp::Pkt6Ptr createMessageFromReply(const uint16_t msg_type, const dhcp::Pkt6Ptr &reply)
Creates DHCPv6 message from the Reply packet.
Definition test_control.cc:225
isc::perfdhcp::TestControl::getElapsedTimeOffset
int getElapsedTimeOffset() const
Return elapsed time offset in a packet.
Definition test_control.cc:463
isc::perfdhcp::TestControl::byte2Hex
static std::string byte2Hex(const uint8_t b)
Convert binary value to hex string.
Definition test_control.cc:155
isc::perfdhcp::TestControl::printTemplates
void printTemplates() const
Print templates information.
Definition test_control.cc:677
isc::perfdhcp::TestControl::sendRequest4
void sendRequest4(const dhcp::Pkt4Ptr &discover_pkt4, const dhcp::Pkt4Ptr &offer_pkt4)
Send DHCPv4 REQUEST message.
Definition test_control.cc:1367
isc::perfdhcp::TestControl::consumeReceivedPackets
unsigned int consumeReceivedPackets()
Pull packets from receiver and process them.
Definition test_control.cc:1004
isc::perfdhcp::TestControl::template_buffers_
TemplateBufferCollection template_buffers_
Packet template buffers.
Definition test_control.h:1124
isc::perfdhcp::TestControl::stats_mgr_
StatsMgr stats_mgr_
Statistics Manager.
Definition test_control.h:1102
isc::perfdhcp::TestControl::printStats
void printStats() const
Print performance statistics.
Definition test_control.cc:738
isc::perfdhcp::TestControl::ack_storage_
PacketStorage< dhcp::Pkt4 > ack_storage_
Storage for DHCPACK messages.
Definition test_control.h:1105
isc::perfdhcp::TestControl::copyIaOptions
void copyIaOptions(const dhcp::Pkt6Ptr &pkt_from, dhcp::Pkt6Ptr &pkt_to)
Copies IA_NA or IA_PD option from one packet to another.
Definition test_control.cc:127
isc::perfdhcp::TestControl::setTransidGenerator
void setTransidGenerator(const NumberGeneratorPtr &generator)
Set new transaction id generator.
Definition test_control.h:227
isc::perfdhcp::TestControl::factoryGeneric
static dhcp::OptionPtr factoryGeneric(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create generic option.
Definition test_control.cc:282
isc::perfdhcp::TestControl::factoryRequestList4
static dhcp::OptionPtr factoryRequestList4(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv4 Request List option.
Definition test_control.cc:340
isc::perfdhcp::TestControl::factoryElapsedTime6
static dhcp::OptionPtr factoryElapsedTime6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create DHCPv6 ELAPSED_TIME option.
Definition test_control.cc:269
isc::perfdhcp::TestControl::handleInterrupt
static void handleInterrupt(int sig)
Handle interrupt signal.
Definition test_control.cc:544
isc::perfdhcp::TestControl::getTransactionIdOffset
int getTransactionIdOffset(const int arg_idx) const
Return transaction id offset in a packet.
Definition test_control.cc:526
isc::perfdhcp::TestControl::initPacketTemplates
void initPacketTemplates()
Reads packet templates from files.
Definition test_control.cc:549
isc::perfdhcp::TestControl::printRate
void printRate() const
Print rate statistics.
Definition test_control.cc:688
isc::perfdhcp::TestControl::printIntermediateStats
void printIntermediateStats()
Print intermediate statistics.
Definition test_control.cc:726
isc::perfdhcp::TestControl::printTemplate
void printTemplate(const uint8_t packet_type) const
Print template information.
Definition test_control.cc:624
isc::perfdhcp::TestControl::getServerIdOffset
int getServerIdOffset() const
Return server id offset in a packet.
Definition test_control.cc:508
isc::perfdhcp::TestControl::generateDuid
std::vector< uint8_t > generateDuid(uint8_t &randomized)
Generate DUID.
Definition test_control.cc:417
isc::perfdhcp::TestControl::sendDiscover4
void sendDiscover4(const bool preload=false)
Send DHCPv4 DISCOVER message.
Definition test_control.cc:1189
isc::perfdhcp::TestControl::generateClientId
dhcp::OptionPtr generateClientId(const dhcp::HWAddrPtr &hwaddr) const
Generate DHCPv4 client identifier from HW address.
Definition test_control.cc:406
isc::perfdhcp::TestControl::first_packet_serverid_
dhcp::OptionBuffer first_packet_serverid_
Buffer holding server id received in first packet.
Definition test_control.h:1121
isc::perfdhcp::TestControl::generateTransid
uint32_t generateTransid()
generate transaction id.
Definition test_control.h:567
isc::perfdhcp::TestControl::factoryIana6
static dhcp::OptionPtr factoryIana6(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer &buf)
Factory function to create IA_NA option.
Definition test_control.cc:289
command_options.h
dhcp4.h
D6O_SERVERID
@ D6O_SERVERID
Definition dhcp6.h:22
D6O_CLIENTID
@ D6O_CLIENTID
Definition dhcp6.h:21
D6O_NAME_SERVERS
@ D6O_NAME_SERVERS
Definition dhcp6.h:43
D6O_RAPID_COMMIT
@ D6O_RAPID_COMMIT
Definition dhcp6.h:34
D6O_IA_NA
@ D6O_IA_NA
Definition dhcp6.h:23
D6O_ORO
@ D6O_ORO
Definition dhcp6.h:26
D6O_IA_PD
@ D6O_IA_PD
Definition dhcp6.h:45
D6O_DOMAIN_SEARCH
@ D6O_DOMAIN_SEARCH
Definition dhcp6.h:44
D6O_IAADDR
@ D6O_IAADDR
Definition dhcp6.h:25
D6O_ELAPSED_TIME
@ D6O_ELAPSED_TIME
Definition dhcp6.h:28
D6O_IAPREFIX
@ D6O_IAPREFIX
Definition dhcp6.h:46
DHCPV6_ADVERTISE
@ DHCPV6_ADVERTISE
Definition dhcp6.h:209
DHCPV6_REQUEST
@ DHCPV6_REQUEST
Definition dhcp6.h:210
DHCPV6_RENEW
@ DHCPV6_RENEW
Definition dhcp6.h:212
DHCPV6_REPLY
@ DHCPV6_REPLY
Definition dhcp6.h:214
DHCPV6_SOLICIT
@ DHCPV6_SOLICIT
Definition dhcp6.h:208
DHCPV6_RELEASE
@ DHCPV6_RELEASE
Definition dhcp6.h:215
DHCPV6_RELAY_FORW
@ DHCPV6_RELAY_FORW
Definition dhcp6.h:219
exceptions.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
iface_mgr.h
libdhcp++.h
isc::asiolink
Definition addr_utilities.cc:170
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::dhcp::PktPtr
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:999
isc::dhcp::DHO_SUBNET_MASK
@ DHO_SUBNET_MASK
Definition dhcp4.h:70
isc::dhcp::DHO_ROUTERS
@ DHO_ROUTERS
Definition dhcp4.h:72
isc::dhcp::DHO_DOMAIN_NAME
@ DHO_DOMAIN_NAME
Definition dhcp4.h:84
isc::dhcp::DHO_DOMAIN_NAME_SERVERS
@ DHO_DOMAIN_NAME_SERVERS
Definition dhcp4.h:75
isc::dhcp::DHO_DHCP_MESSAGE_TYPE
@ DHO_DHCP_MESSAGE_TYPE
Definition dhcp4.h:122
isc::dhcp::DHO_DHCP_SERVER_IDENTIFIER
@ DHO_DHCP_SERVER_IDENTIFIER
Definition dhcp4.h:123
isc::dhcp::DHO_HOST_NAME
@ DHO_HOST_NAME
Definition dhcp4.h:81
isc::dhcp::DHO_DHCP_CLIENT_IDENTIFIER
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition dhcp4.h:130
isc::dhcp::DHO_DHCP_REQUESTED_ADDRESS
@ DHO_DHCP_REQUESTED_ADDRESS
Definition dhcp4.h:119
isc::dhcp::DHO_TIME_OFFSET
@ DHO_TIME_OFFSET
Definition dhcp4.h:71
isc::dhcp::DHO_DHCP_PARAMETER_REQUEST_LIST
@ DHO_DHCP_PARAMETER_REQUEST_LIST
Definition dhcp4.h:124
isc::dhcp::DHO_BROADCAST_ADDRESS
@ DHO_BROADCAST_ADDRESS
Definition dhcp4.h:97
isc::dhcp::Pkt4Ptr
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
isc::dhcp::IfacePtr
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition iface_mgr.h:555
isc::dhcp::OptionCollection
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition option.h:40
isc::dhcp::Option6IAPrefixPtr
boost::shared_ptr< Option6IAPrefix > Option6IAPrefixPtr
Pointer to the Option6IAPrefix object.
Definition option6_iaprefix.h:155
isc::dhcp::HWAddrPtr
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
isc::dhcp::Option6IAAddrPtr
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
Definition option6_iaaddr.h:20
isc::dhcp::DHCPREQUEST
@ DHCPREQUEST
Definition dhcp4.h:237
isc::dhcp::DHCPOFFER
@ DHCPOFFER
Definition dhcp4.h:236
isc::dhcp::DHCPRELEASE
@ DHCPRELEASE
Definition dhcp4.h:241
isc::dhcp::DHCPDISCOVER
@ DHCPDISCOVER
Definition dhcp4.h:235
isc::dhcp::DHCPACK
@ DHCPACK
Definition dhcp4.h:239
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
isc::dhcp::HTYPE_ETHER
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition dhcp4.h:56
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
isc::perfdhcp
Definition abstract_scen.h:15
isc::perfdhcp::PerfPkt4Ptr
boost::shared_ptr< PerfPkt4 > PerfPkt4Ptr
Definition perf_pkt4.h:128
isc::perfdhcp::ExchangeType
ExchangeType
DHCP packet exchange types.
Definition bin/perfdhcp/stats_mgr.h:32
isc::perfdhcp::ExchangeType::RA
@ RA
DHCPv4 REQUEST-ACK.
Definition bin/perfdhcp/stats_mgr.h:34
isc::perfdhcp::ExchangeType::SA
@ SA
DHCPv6 SOLICIT-ADVERTISE.
Definition bin/perfdhcp/stats_mgr.h:37
isc::perfdhcp::ExchangeType::RNA
@ RNA
DHCPv4 REQUEST-ACK (renewal).
Definition bin/perfdhcp/stats_mgr.h:35
isc::perfdhcp::ExchangeType::RL
@ RL
DHCPv6 RELEASE-REPLY.
Definition bin/perfdhcp/stats_mgr.h:40
isc::perfdhcp::ExchangeType::RLA
@ RLA
DHCPv4 RELEASE.
Definition bin/perfdhcp/stats_mgr.h:36
isc::perfdhcp::ExchangeType::RN
@ RN
DHCPv6 RENEW-REPLY.
Definition bin/perfdhcp/stats_mgr.h:39
isc::perfdhcp::ExchangeType::DO
@ DO
DHCPv4 DISCOVER-OFFER.
Definition bin/perfdhcp/stats_mgr.h:33
isc::perfdhcp::ExchangeType::RR
@ RR
DHCPv6 REQUEST-REPLY.
Definition bin/perfdhcp/stats_mgr.h:38
isc::perfdhcp::PerfPkt6Ptr
boost::shared_ptr< PerfPkt6 > PerfPkt6Ptr
Definition perf_pkt6.h:127
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
option6_ia.h
option6_iaaddr.h
option6_iaprefix.h
option_int.h
perf_pkt4.h
perf_pkt6.h
receiver.h
isc::dhcp::Pkt6::RelayInfo
structure that describes a single relay information
Definition pkt6.h:85
isc::dhcp::Pkt6::RelayInfo::options_
isc::dhcp::OptionCollection options_
options received from a specified relay, except relay-msg option
Definition pkt6.h:104
isc::dhcp::Pkt6::RelayInfo::msg_type_
uint8_t msg_type_
message type (RELAY-FORW oro RELAY-REPL)
Definition pkt6.h:94
isc::dhcp::Pkt6::RelayInfo::linkaddr_
isc::asiolink::IOAddress linkaddr_
fixed field in relay-forw/relay-reply
Definition pkt6.h:96
isc::dhcp::Pkt6::RelayInfo::hop_count_
uint8_t hop_count_
number of traversed relays (up to 32)
Definition pkt6.h:95
isc::dhcp::Pkt6::RelayInfo::peeraddr_
isc::asiolink::IOAddress peeraddr_
fixed field in relay-forw/relay-reply
Definition pkt6.h:97
test_control.h