37 #include <boost/algorithm/string/classification.hpp> 38 #include <boost/algorithm/string/split.hpp> 39 #include <boost/assert.hpp> 40 #include <boost/unordered_map.hpp> 55 typedef std::vector<uint8_t> HostIdentifier;
61 tuple<HostIdentifier, Host::IdentifierType, SubnetID, SubnetID, IOAddress> HostKey;
74 typedef std::unordered_map<HostKey, HostPtr, boost::hash<HostKey>> HostMap;
77 typedef std::pair<HostKey, HostPtr> HostPair;
80 struct OptionWrapper {
82 : option_descriptor_(option_descriptor), option_space_(option_space) {
85 std::string option_space_;
90 static constexpr
size_t CLIENT_CLASSES_MAX_LENGTH = 255u;
95 static constexpr
size_t HOSTNAME_MAX_LENGTH = 255u;
98 static constexpr
size_t OPTION_VALUE_MAX_LENGTH = 4096u;
101 static constexpr
size_t OPTION_FORMATTED_VALUE_MAX_LENGTH = 8192u;
104 static constexpr
size_t OPTION_SPACE_MAX_LENGTH = 128u;
109 static constexpr cass_int32_t MAX_IDENTIFIER_TYPE = static_cast<cass_int32_t>(Host::IDENT_FLEX);
113 static constexpr
char NULL_DHCP4_SERVER_HOSTNAME[] =
"";
114 static constexpr
char NULL_DHCP4_BOOT_FILE_NAME[] =
"";
115 static constexpr
char NULL_USER_CONTEXT[] =
"";
116 static constexpr
char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] =
"::";
117 static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
118 static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
119 static constexpr cass_int32_t NULL_IAID = -1;
120 static constexpr cass_int32_t NULL_OPTION_UNIVERSE = -1;
121 static constexpr cass_int32_t NULL_OPTION_CODE = -1;
123 static constexpr
char NULL_OPTION_FORMATTED_VALUE[] =
"";
124 static constexpr
char NULL_OPTION_SPACE[] =
"";
125 static constexpr cass_bool_t NULL_OPTION_IS_PERSISTENT = cass_false;
126 static constexpr
char NULL_OPTION_CLIENT_CLASS[] =
"";
127 static constexpr cass_int32_t NULL_OPTION_SUBNET_ID = -1;
128 static constexpr
char NULL_OPTION_USER_CONTEXT[] =
"";
129 static constexpr cass_int32_t NULL_OPTION_SCOPE_ID = -1;
134 static const IPv6Resrv NULL_IPV6_RESERVATION =
176 void prepareExchange(
const HostPtr& host,
179 const std::string& option_space,
195 void createBindForMutation(
const HostPtr& host,
198 const std::string& option_space,
216 void createBindForDelete(
const HostPtr& host,
219 const std::string& option_space,
233 cass_int64_t hashIntoId()
const;
242 virtual boost::any retrieve()
override;
250 const IPv6Resrv retrieveReservation()
const;
258 const OptionWrapper retrieveOption()
const;
274 "GET_HOST_BY_HOST_ID";
279 "GET_HOST_BY_IPV4_ADDRESS";
284 "GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID";
290 "GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID";
295 "GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS";
304 "GET_HOST_BY_IPV6_PREFIX";
309 "GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS";
333 cass_int32_t host_identifier_type_;
336 cass_int32_t host_ipv4_subnet_id_;
339 cass_int32_t host_ipv6_subnet_id_;
342 cass_int32_t host_ipv4_address_;
345 cass_int32_t host_ipv4_next_server_;
348 std::string host_ipv4_server_hostname_;
351 std::string host_ipv4_boot_file_name_;
354 std::string auth_key_;
357 std::string hostname_;
360 std::string user_context_;
363 std::string host_ipv4_client_classes_;
366 std::string host_ipv6_client_classes_;
369 std::string reserved_ipv6_prefix_address_;
372 cass_int32_t reserved_ipv6_prefix_length_;
376 cass_int32_t reserved_ipv6_prefix_address_type_;
383 cass_int32_t option_universe_;
386 cass_int32_t option_code_;
392 std::string option_formatted_value_;
395 std::string option_space_;
398 cass_bool_t option_is_persistent_;
401 std::string option_client_class_;
404 cass_int32_t option_subnet_id_;
407 std::string option_user_context_;
410 cass_int32_t option_scope_id_;
415 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_HOST_ID;
416 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_IPV4_ADDRESS;
417 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID;
418 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID;
419 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS;
420 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_IPV6_PREFIX;
421 constexpr
StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS;
427 "INSERT INTO host_reservations ( " 430 "host_identifier_type, " 431 "host_ipv4_subnet_id, " 432 "host_ipv6_subnet_id, " 433 "host_ipv4_address, " 434 "host_ipv4_next_server, " 435 "host_ipv4_server_hostname, " 436 "host_ipv4_boot_file_name, " 440 "host_ipv4_client_classes, " 441 "host_ipv6_client_classes, " 442 "reserved_ipv6_prefix_address, " 443 "reserved_ipv6_prefix_length, " 444 "reserved_ipv6_prefix_address_type, " 449 "option_formatted_value, " 451 "option_is_persistent, " 452 "option_client_class, " 454 "option_user_context, " 460 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " 462 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? " 472 "host_identifier_type, " 473 "host_ipv4_subnet_id, " 474 "host_ipv6_subnet_id, " 475 "host_ipv4_address, " 476 "host_ipv4_next_server, " 477 "host_ipv4_server_hostname, " 478 "host_ipv4_boot_file_name, " 482 "host_ipv4_client_classes, " 483 "host_ipv6_client_classes, " 484 "reserved_ipv6_prefix_address, " 485 "reserved_ipv6_prefix_length, " 486 "reserved_ipv6_prefix_address_type, " 491 "option_formatted_value, " 493 "option_is_persistent, " 494 "option_client_class, " 496 "option_user_context, " 498 "FROM host_reservations " 501 {GET_HOST_BY_HOST_ID,
502 {GET_HOST_BY_HOST_ID,
506 "host_identifier_type, " 507 "host_ipv4_subnet_id, " 508 "host_ipv6_subnet_id, " 509 "host_ipv4_address, " 510 "host_ipv4_next_server, " 511 "host_ipv4_server_hostname, " 512 "host_ipv4_boot_file_name, " 516 "host_ipv4_client_classes, " 517 "host_ipv6_client_classes, " 518 "reserved_ipv6_prefix_address, " 519 "reserved_ipv6_prefix_length, " 520 "reserved_ipv6_prefix_address_type, " 525 "option_formatted_value, " 527 "option_is_persistent, " 528 "option_client_class, " 530 "option_user_context, " 532 "FROM host_reservations " 533 "WHERE host_identifier = ? " 534 "AND host_identifier_type = ? " 538 {GET_HOST_BY_IPV4_ADDRESS,
539 {GET_HOST_BY_IPV4_ADDRESS,
543 "host_identifier_type, " 544 "host_ipv4_subnet_id, " 545 "host_ipv6_subnet_id, " 546 "host_ipv4_address, " 547 "host_ipv4_next_server, " 548 "host_ipv4_server_hostname, " 549 "host_ipv4_boot_file_name, " 553 "host_ipv4_client_classes, " 554 "host_ipv6_client_classes, " 555 "reserved_ipv6_prefix_address, " 556 "reserved_ipv6_prefix_length, " 557 "reserved_ipv6_prefix_address_type, " 562 "option_formatted_value, " 564 "option_is_persistent, " 565 "option_client_class, " 567 "option_user_context, " 569 "FROM host_reservations " 570 "WHERE host_ipv4_address = ? " 574 {GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
575 {GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
579 "host_identifier_type, " 580 "host_ipv4_subnet_id, " 581 "host_ipv6_subnet_id, " 582 "host_ipv4_address, " 583 "host_ipv4_next_server, " 584 "host_ipv4_server_hostname, " 585 "host_ipv4_boot_file_name, " 589 "host_ipv4_client_classes, " 590 "host_ipv6_client_classes, " 591 "reserved_ipv6_prefix_address, " 592 "reserved_ipv6_prefix_length, " 593 "reserved_ipv6_prefix_address_type, " 598 "option_formatted_value, " 600 "option_is_persistent, " 601 "option_client_class, " 603 "option_user_context, " 605 "FROM host_reservations " 606 "WHERE host_ipv4_subnet_id = ? " 607 "AND host_identifier = ? " 608 "AND host_identifier_type = ? " 612 {GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
613 {GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
617 "host_identifier_type, " 618 "host_ipv4_subnet_id, " 619 "host_ipv6_subnet_id, " 620 "host_ipv4_address, " 621 "host_ipv4_next_server, " 622 "host_ipv4_server_hostname, " 623 "host_ipv4_boot_file_name, " 627 "host_ipv4_client_classes, " 628 "host_ipv6_client_classes, " 629 "reserved_ipv6_prefix_address, " 630 "reserved_ipv6_prefix_length, " 631 "reserved_ipv6_prefix_address_type, " 636 "option_formatted_value, " 638 "option_is_persistent, " 639 "option_client_class, " 641 "option_user_context, " 643 "FROM host_reservations " 644 "WHERE host_ipv6_subnet_id = ? " 645 "AND host_identifier = ? " 646 "AND host_identifier_type = ? " 650 {GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
651 {GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
655 "host_identifier_type, " 656 "host_ipv4_subnet_id, " 657 "host_ipv6_subnet_id, " 658 "host_ipv4_address, " 659 "host_ipv4_next_server, " 660 "host_ipv4_server_hostname, " 661 "host_ipv4_boot_file_name, " 665 "host_ipv4_client_classes, " 666 "host_ipv6_client_classes, " 667 "reserved_ipv6_prefix_address, " 668 "reserved_ipv6_prefix_length, " 669 "reserved_ipv6_prefix_address_type, " 674 "option_formatted_value, " 676 "option_is_persistent, " 677 "option_client_class, " 679 "option_user_context, " 681 "FROM host_reservations " 682 "WHERE host_ipv4_subnet_id = ? " 683 "AND host_ipv4_address = ? " 687 {GET_HOST_BY_IPV6_PREFIX,
688 {GET_HOST_BY_IPV6_PREFIX,
692 "host_identifier_type, " 693 "host_ipv4_subnet_id, " 694 "host_ipv6_subnet_id, " 695 "host_ipv4_address, " 696 "host_ipv4_next_server, " 697 "host_ipv4_server_hostname, " 698 "host_ipv4_boot_file_name, " 702 "host_ipv4_client_classes, " 703 "host_ipv6_client_classes, " 704 "reserved_ipv6_prefix_address, " 705 "reserved_ipv6_prefix_length, " 706 "reserved_ipv6_prefix_address_type, " 711 "option_formatted_value, " 713 "option_is_persistent, " 714 "option_client_class, " 716 "option_user_context, " 718 "FROM host_reservations " 719 "WHERE reserved_ipv6_prefix_address = ? " 720 "AND reserved_ipv6_prefix_length = ? " 724 {GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
725 {GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
729 "host_identifier_type, " 730 "host_ipv4_subnet_id, " 731 "host_ipv6_subnet_id, " 732 "host_ipv4_address, " 733 "host_ipv4_next_server, " 734 "host_ipv4_server_hostname, " 735 "host_ipv4_boot_file_name, " 739 "host_ipv4_client_classes, " 740 "host_ipv6_client_classes, " 741 "reserved_ipv6_prefix_address, " 742 "reserved_ipv6_prefix_length, " 743 "reserved_ipv6_prefix_address_type, " 748 "option_formatted_value, " 750 "option_is_persistent, " 751 "option_client_class, " 753 "option_user_context, " 755 "FROM host_reservations " 756 "WHERE host_ipv6_subnet_id = ? " 757 "AND reserved_ipv6_prefix_address = ? " 763 "DELETE FROM host_reservations WHERE id = ? " 768 CqlHostExchange::CqlHostExchange()
769 : host_(NULL), id_(0), host_identifier_type_(0), host_ipv4_subnet_id_(0),
770 host_ipv6_subnet_id_(0), host_ipv4_address_(0), host_ipv4_next_server_(0),
771 host_ipv4_server_hostname_(NULL_DHCP4_SERVER_HOSTNAME),
772 host_ipv4_boot_file_name_(NULL_DHCP4_BOOT_FILE_NAME),
774 user_context_(NULL_USER_CONTEXT),
775 reserved_ipv6_prefix_length_(NULL_RESERVED_IPV6_PREFIX_LENGTH),
776 reserved_ipv6_prefix_address_type_(NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE),
777 iaid_(NULL_IAID), option_universe_(NULL_OPTION_UNIVERSE),
778 option_code_(NULL_OPTION_CODE),
779 option_is_persistent_(NULL_OPTION_IS_PERSISTENT),
780 option_subnet_id_(NULL_OPTION_SUBNET_ID),
781 option_user_context_(NULL_OPTION_USER_CONTEXT),
782 option_scope_id_(NULL_OPTION_SCOPE_ID) {
796 data.
add(&host_identifier_);
798 data.
add(&host_identifier_type_);
800 data.
add(&host_ipv4_subnet_id_);
802 data.
add(&host_ipv6_subnet_id_);
804 data.
add(&host_ipv4_address_);
806 data.
add(&host_ipv4_next_server_);
808 data.
add(&host_ipv4_server_hostname_);
810 data.
add(&host_ipv4_boot_file_name_);
812 data.
add(&auth_key_);
814 data.
add(&hostname_);
816 data.
add(&user_context_);
818 data.
add(&host_ipv4_client_classes_);
820 data.
add(&host_ipv6_client_classes_);
824 data.
add(&reserved_ipv6_prefix_address_);
826 data.
add(&reserved_ipv6_prefix_length_);
828 data.
add(&reserved_ipv6_prefix_address_type_);
835 data.
add(&option_universe_);
837 data.
add(&option_code_);
839 data.
add(&option_value_);
841 data.
add(&option_formatted_value_);
843 data.
add(&option_space_);
845 data.
add(&option_is_persistent_);
847 data.
add(&option_client_class_);
849 data.
add(&option_subnet_id_);
851 data.
add(&option_user_context_);
853 data.
add(&option_scope_id_);
861 const std::string& option_space,
873 HostIdentifier host_identifier = host->getIdentifier();
874 host_identifier_ =
CassBlob(host_identifier.begin(), host_identifier.end());
877 << host_identifier_.data() <<
" of length " << host_identifier_.size()
882 host_identifier_type_ = static_cast<cass_int32_t>(host->getIdentifierType());
883 if (host_identifier_type_ > MAX_IDENTIFIER_TYPE) {
885 "host identifier type returned: " << host_identifier_type_);
889 host_ipv4_subnet_id_ = static_cast<cass_int32_t>(host->getIPv4SubnetID());
892 host_ipv6_subnet_id_ = static_cast<cass_int32_t>(host->getIPv6SubnetID());
895 host_ipv4_address_ = static_cast<cass_int32_t>(host->getIPv4Reservation().toUint32());
898 host_ipv4_next_server_ = static_cast<cass_int32_t>(host->getNextServer().toUint32());
901 host_ipv4_server_hostname_ = host->getServerHostname();
904 host_ipv4_boot_file_name_ = host->getBootFileName();
907 auth_key_ = host->getKey().ToText();
910 hostname_ = host->getHostname();
911 if (hostname_.size() > HOSTNAME_MAX_LENGTH) {
913 << hostname_ <<
" of length " << hostname_.size()
914 <<
" is greater than allowed of " << HOSTNAME_MAX_LENGTH);
920 user_context_ = ctx->str();
922 user_context_ = NULL_USER_CONTEXT;
926 host_ipv4_client_classes_ = host->getClientClasses4().toText(
",");
927 if (host_ipv4_client_classes_.size() > CLIENT_CLASSES_MAX_LENGTH) {
929 "IPv4 client classes " << host_ipv4_client_classes_ <<
" of length " 930 << host_ipv4_client_classes_.size() <<
" is greater than allowed of " 931 << CLIENT_CLASSES_MAX_LENGTH);
935 host_ipv6_client_classes_ = host->getClientClasses6().toText(
",");
936 if (host_ipv6_client_classes_.size() > CLIENT_CLASSES_MAX_LENGTH) {
938 "IPv6 client classes " << host_ipv6_client_classes_ <<
" of length " 939 << host_ipv6_client_classes_.size() <<
" is greater than allowed of " 940 << CLIENT_CLASSES_MAX_LENGTH);
943 if (reservation == NULL) {
945 reserved_ipv6_prefix_address_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS;
947 reserved_ipv6_prefix_length_ = NULL_RESERVED_IPV6_PREFIX_LENGTH;
949 reserved_ipv6_prefix_address_type_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE;
956 reserved_ipv6_prefix_length_ = static_cast<cass_int32_t>(reservation->
getPrefixLen());
959 reserved_ipv6_prefix_address_type_ =
967 if (option_descriptor.
option_ == NULL) {
968 option_universe_ = NULL_OPTION_UNIVERSE;
969 option_code_ = NULL_OPTION_CODE;
970 option_value_ = NULL_OPTION_VALUE;
971 option_formatted_value_ = NULL_OPTION_FORMATTED_VALUE;
972 option_space_ = NULL_OPTION_SPACE;
973 option_is_persistent_ = NULL_OPTION_IS_PERSISTENT;
974 option_client_class_ = NULL_OPTION_CLIENT_CLASS;
975 option_subnet_id_ = NULL_OPTION_SUBNET_ID;
976 option_user_context_ = NULL_OPTION_USER_CONTEXT;
977 option_scope_id_ = NULL_OPTION_SCOPE_ID;
980 option_universe_ = option_descriptor.
option_->getUniverse();
983 option_code_ = option_descriptor.
option_->getType();
988 if (option_descriptor.
option_->len() >
989 option_descriptor.
option_->getHeaderLen()) {
995 option_descriptor.
option_->pack(buffer);
996 const char* buffer_ptr = static_cast<const char*>(buffer.getData());
997 option_value_.assign(buffer_ptr + option_descriptor.
option_->getHeaderLen(),
998 buffer_ptr + buffer.getLength());
1000 option_value_.clear();
1002 option_formatted_value_.clear();
1004 option_value_.clear();
1009 option_space_ = option_space;
1012 option_is_persistent_ = option_descriptor.
persistent_ ? cass_true : cass_false;
1016 option_client_class_.clear();
1020 option_subnet_id_ = subnet_id;
1022 option_subnet_id_ = 0;
1028 option_user_context_ = ctx->str();
1030 option_user_context_ = NULL_OPTION_USER_CONTEXT;
1035 option_scope_id_ = 3;
1042 "CqlHostExchange::prepareExchange(): " 1043 "could not copy data from host " 1044 << host->getHostname() <<
", reason: " << ex.
what());
1052 const std::string& option_space,
1055 prepareExchange(host, subnet_id, reservation, option_space, option_descriptor);
1063 data.
add(&host_identifier_);
1064 data.
add(&host_identifier_type_);
1065 data.
add(&host_ipv4_subnet_id_);
1066 data.
add(&host_ipv6_subnet_id_);
1067 data.
add(&host_ipv4_address_);
1068 data.
add(&host_ipv4_next_server_);
1069 data.
add(&host_ipv4_server_hostname_);
1070 data.
add(&host_ipv4_boot_file_name_);
1071 data.
add(&auth_key_);
1072 data.
add(&hostname_);
1073 data.
add(&user_context_);
1074 data.
add(&host_ipv4_client_classes_);
1075 data.
add(&host_ipv6_client_classes_);
1079 data.
add(&reserved_ipv6_prefix_address_);
1080 data.
add(&reserved_ipv6_prefix_length_);
1081 data.
add(&reserved_ipv6_prefix_address_type_);
1085 data.
add(&option_universe_);
1086 data.
add(&option_code_);
1087 data.
add(&option_value_);
1088 data.
add(&option_formatted_value_);
1089 data.
add(&option_space_);
1090 data.
add(&option_is_persistent_);
1091 data.
add(&option_client_class_);
1092 data.
add(&option_subnet_id_);
1093 data.
add(&option_user_context_);
1094 data.
add(&option_scope_id_);
1098 "CqlHostExchange::createBindForMutation(): " 1099 "could not create bind array from host " 1100 << host->getHostname() <<
", reason: " << ex.
what());
1108 const std::string& option_space,
1111 prepareExchange(host, subnet_id, reservation, option_space, option_descriptor);
1123 "CqlHostExchange::createBindForDelete(): " 1124 "could not create bind array from host " 1125 << host->getHostname() <<
", reason: " << ex.
what());
1135 std::stringstream key_stream;
1136 if (host_ipv4_address_) {
1139 key_stream << std::setw(10) << std::setfill(
'-') <<
"-";
1143 key_stream << std::setw(10) << std::setfill(
'-') << host_identifier_type_;
1145 key_stream << std::setw(10) << std::setfill(
'-') << host_ipv4_subnet_id_;
1146 key_stream << std::setw(10) << std::setfill(
'-') << host_ipv6_subnet_id_;
1147 key_stream << std::setw(V4ADDRESS_TEXT_MAX_LEN) << std::setfill(
'-')
1148 << host_ipv4_address_;
1149 key_stream << std::setw(V6ADDRESS_TEXT_MAX_LEN) << std::setfill(
'-')
1150 << reserved_ipv6_prefix_address_;
1151 key_stream << std::setw(4) << std::setfill(
'-')
1152 << reserved_ipv6_prefix_length_;
1153 key_stream << std::setw(4) << std::setfill(
'-') << option_code_;
1154 key_stream << std::setw(OPTION_SPACE_MAX_LENGTH) << std::setfill(
'-')
1156 const std::string key = key_stream.str();
1158 const cass_int64_t hash = static_cast<cass_int64_t>(Hash64::hash(key));
1165 const uint64_t
id = static_cast<uint64_t>(id_);
1167 HostIdentifier host_identifier =
1168 HostIdentifier(host_identifier_.begin(), host_identifier_.end());
1173 static_cast<Host::IdentifierType>(host_identifier_type_);
1176 SubnetID ipv4_subnet_id = static_cast<SubnetID>(host_ipv4_subnet_id_);
1179 SubnetID ipv6_subnet_id = static_cast<SubnetID>(host_ipv6_subnet_id_);
1185 Host* host =
new Host(host_identifier.data(), host_identifier.size(),
1186 host_identifier_type, ipv4_subnet_id, ipv6_subnet_id,
1187 ipv4_reservation, hostname_,
1188 host_ipv4_client_classes_, host_ipv6_client_classes_,
1189 static_cast<uint32_t>(host_ipv4_next_server_),
1190 host_ipv4_server_hostname_, host_ipv4_boot_file_name_,
1194 if (!user_context_.empty()) {
1197 if (!ctx || (ctx->getType() != Element::map)) {
1199 <<
"' is not a JSON map");
1204 <<
"' is invalid JSON: " << ex.
what());
1211 if (reservation != NULL_IPV6_RESERVATION &&
1217 if (option_wrapper.option_descriptor_) {
1218 if (option_wrapper.option_descriptor_->option_->getUniverse() ==
Option::V4) {
1219 host->
getCfgOption4()->add(*option_wrapper.option_descriptor_,
1220 option_wrapper.option_space_);
1221 }
else if (option_wrapper.option_descriptor_->option_->getUniverse() ==
Option::V6) {
1222 host->
getCfgOption6()->add(*option_wrapper.option_descriptor_,
1223 option_wrapper.option_space_);
1234 switch (reserved_ipv6_prefix_address_type_) {
1241 case NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE:
1242 return (NULL_IPV6_RESERVATION);
1245 "reservation type returned: " << reserved_ipv6_prefix_address_type_
1246 <<
". Only 0 (IA_NA) or 2 (IA_PD) are allowed.");
1250 reserved_ipv6_prefix_length_));
1264 if (option_space_.empty() || option_universe_ == NULL_OPTION_UNIVERSE) {
1276 if (vendor_id > 0) {
1278 static_cast<Option::Universe>(option_universe_), vendor_id,
1285 if (!option_definition_ptr) {
1286 option_definition_ptr =
1291 if (!option_definition_ptr) {
1293 OptionBuffer option_buffer(option_value_.begin(), option_value_.end());
1294 option.reset(
new Option(static_cast<Option::Universe>(option_universe_),
1295 static_cast<uint16_t>(option_code_),
1296 option_buffer.begin(), option_buffer.end()));
1304 if (option_formatted_value_.empty()) {
1306 option_value_.end());
1307 option = option_definition_ptr->optionFactory(
1308 static_cast<Option::Universe>(option_universe_),
1309 static_cast<uint16_t>(option_code_), option_buffer.begin(),
1310 option_buffer.end());
1314 std::vector<std::string> split_vector;
1315 boost::split(split_vector, option_formatted_value_,
1316 boost::is_any_of(
","));
1317 option = option_definition_ptr->optionFactory(
1318 static_cast<Option::Universe>(option_universe_),
1319 static_cast<uint16_t>(option_code_), split_vector);
1324 option_formatted_value_)), option_space_);
1326 if (!option_user_context_.empty()) {
1329 if (!ctx || (ctx->getType() != Element::map)) {
1331 <<
"' is no a JSON map");
1333 result.option_descriptor_->setContext(ctx);
1336 <<
"' is invalid JSON: " << ex.
what());
1385 const uint8_t* identifier_begin,
1386 const size_t identifier_len)
const;
1395 const uint8_t prefix_len)
const;
1407 const uint8_t* identifier_begin,
1408 const size_t identifier_len)
const;
1428 const uint8_t* identifier_begin,
1429 const size_t identifier_len)
const;
1446 virtual std::string
getName()
const;
1464 const IPv6Resrv*
const reservation = NULL,
1465 const std::list<std::string>& option_spaces = std::list<std::string>(),
1485 const std::list<std::string>& option_spaces4,
1487 const std::list<std::string>& option_spaces6,
1533 const IPv6Resrv*
const reservation = NULL,
1534 const std::string& option_space = NULL_OPTION_SPACE,
1564 std::stringstream key_stream;
1565 HostIdentifier host_identifier = std::get<HOST_IDENTIFIER>(key);
1566 key_stream <<
DUID(host_identifier).
toText() <<
"-";
1567 key_stream << std::get<HOST_IDENTIFIER_TYPE>(key) <<
"-";
1568 key_stream << std::get<IPv4_SUBNET_ID>(key) <<
"-";
1569 key_stream << std::get<IPv6_SUBNET_ID>(key) <<
"-";
1570 key_stream << std::get<IPv4_RESERVATION>(key);
1571 const std::string key_string = key_stream.str();
1573 const uint64_t hash = Hash64::hash(key_string);
1575 return (static_cast<std::size_t>(hash));
1586 return (std::get<HOST_IDENTIFIER>(key1) == std::get<HOST_IDENTIFIER>(key2) &&
1587 std::get<HOST_IDENTIFIER_TYPE>(key1) ==
1588 std::get<HOST_IDENTIFIER_TYPE>(key2) &&
1589 std::get<IPv4_SUBNET_ID>(key1) == std::get<IPv4_SUBNET_ID>(key2) &&
1590 std::get<IPv6_SUBNET_ID>(key1) == std::get<IPv6_SUBNET_ID>(key2) &&
1591 std::get<IPv4_RESERVATION>(key1) == std::get<IPv4_RESERVATION>(key2));
1595 : dbconn_(parameters) {
1605 std::pair<uint32_t, uint32_t> db_version =
getVersion();
1606 if (code_version != db_version) {
1608 << code_version.first <<
"." << code_version.second
1609 <<
" found version: " << db_version.first <<
"." 1610 << db_version.second);
1634 std::list<std::string> option_spaces4 = cfg_option4->getOptionSpaceNames();
1635 std::list<std::string> vendor_spaces4 = cfg_option4->getVendorIdsSpaceNames();
1636 option_spaces4.insert(option_spaces4.end(), vendor_spaces4.begin(),
1637 vendor_spaces4.end());
1641 std::list<std::string> option_spaces6 = cfg_option6->getOptionSpaceNames();
1642 std::list<std::string> vendor_spaces6 = cfg_option6->getVendorIdsSpaceNames();
1643 option_spaces6.insert(option_spaces6.end(), vendor_spaces6.begin(),
1644 vendor_spaces6.end());
1651 if (std::distance(reservations.first, reservations.second) > 0) {
1652 for (
IPv6ResrvIterator it = reservations.first; result && it != reservations.second; ++it) {
1654 option_spaces6, cfg_option6);
1660 option_spaces6, cfg_option6);
1668 if (!address.
isV4()) {
1670 "address supplied is not an IPv4 address");
1674 cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
1675 cass_int32_t host_ipv4_address = static_cast<cass_int32_t>(address.
toUint32());
1679 where_values.
add(&host_ipv4_subnet_id);
1680 where_values.add(&host_ipv4_address);
1692 const uint8_t* identifier_begin,
1693 const size_t identifier_len)
const {
1695 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
1696 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
1697 cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
1701 where_values.
add(&host_ipv4_subnet_id);
1702 where_values.
add(&host_identifier);
1703 where_values.
add(&host_identifier_type);
1714 const uint8_t prefix_len)
const {
1716 std::string reserved_ipv6_prefix_address = prefix.
toText();
1717 cass_int32_t reserved_ipv6_prefix_length = prefix_len;
1722 where_values.
add(&reserved_ipv6_prefix_address);
1723 where_values.
add(&reserved_ipv6_prefix_length);
1733 HostIdentifier host_identifier = host->getIdentifier();
1736 host_identifier.size());
1738 if (collection.empty()) {
1742 if (collection.size() >= 2u) {
1744 "CqlHostDataSource::get6(2): multiple records were " 1746 "database where only one was expected for statement " 1758 const uint8_t* identifier_begin,
1759 const size_t identifier_len)
const {
1761 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
1762 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
1763 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
1767 where_values.
add(&host_ipv6_subnet_id);
1768 where_values.
add(&host_identifier);
1769 where_values.
add(&host_identifier_type);
1781 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
1782 std::string reserved_ipv6_prefix_address = address.
toText();
1786 where_values.
add(&host_ipv6_subnet_id);
1787 where_values.
add(&reserved_ipv6_prefix_address);
1798 const uint8_t* identifier_begin,
1799 const size_t identifier_len)
const {
1801 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
1802 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
1806 where_values.
add(&host_identifier);
1807 where_values.
add(&host_identifier_type);
1819 cass_int32_t host_ipv4_address = static_cast<cass_int32_t>(address.
toUint32());
1823 where_values.
add(&host_ipv4_address);
1865 const std::list<std::string>& option_spaces,
1876 bool option_found =
false;
1877 for (
const std::string& space : option_spaces) {
1882 if (options && !options->empty()) {
1887 option_found =
true;
1894 if (result && !option_found) {
1906 const std::list<std::string>& option_spaces4,
1908 const std::list<std::string>& option_spaces6,
1919 if (result && cfg_option4 && !cfg_option4->empty()) {
1922 if (result && cfg_option6 && !cfg_option6->empty()) {
1926 (!cfg_option4 || cfg_option4->empty()) &&
1927 (!cfg_option6 || cfg_option6->empty())) {
1939 if (collection.empty()) {
1943 if (collection.size() >= 2u) {
1945 "found in the database where only one was expected for statement " 1949 return (*collection.begin());
1957 std::unique_ptr<CqlHostExchange> host_exchange(
new CqlHostExchange());
1959 statement_tag,
false);
1963 for (boost::any& host : collection) {
1964 host_collection.push_back(
HostPtr(boost::any_cast<Host*>(host)));
1971 for (
HostPtr& host : host_collection) {
1973 HostKey key = HostKey(host->getIdentifier(), host->getIdentifierType(),
1974 host->getIPv4SubnetID(), host->getIPv6SubnetID(),
1975 host->getIPv4Reservation());
1976 if (map.find(key) == map.end()) {
1984 for (HostPair pair : map) {
1985 result_collection.push_back(pair.second);
1987 return (result_collection);
1995 const std::string& option_space,
2004 std::unique_ptr<CqlHostExchange> host_exchange(
new CqlHostExchange());
2035 source_host->getIPv6Reservations();
2036 if (std::distance(reservations_range.first, reservations_range.second) > 0) {
2038 reservations_iterator != reservations_range.second;
2039 ++reservations_iterator) {
2040 if (!target_host->hasReservation(reservations_iterator->second)) {
2041 target_host->addReservation(reservations_iterator->second);
2047 source_host->getCfgOption4()->mergeTo(*target_host->getCfgOption4());
2050 source_host->getCfgOption6()->mergeTo(*target_host->getCfgOption6());
2070 HostPtr host = boost::const_pointer_cast<Host>(impl_->
get4(subnet_id, address));
2077 const uint8_t* identifier_begin,
const size_t identifier_len) {
2078 HostPtr host = boost::const_pointer_cast<Host>(impl_->
get4(subnet_id, identifier_type,
2079 identifier_begin, identifier_len));
2086 const uint8_t* identifier_begin,
const size_t identifier_len) {
2087 HostPtr host = boost::const_pointer_cast<Host>(impl_->
get6(subnet_id, identifier_type,
2088 identifier_begin, identifier_len));
2095 const uint8_t* identifier_begin,
2096 const size_t identifier_len)
const {
2099 return (impl_->
getAll(identifier_type, identifier_begin, identifier_len));
2106 return (impl_->
getAll4(address));
2112 const uint8_t* identifier_begin,
2113 const size_t identifier_len)
const {
2116 return (impl_->
get4(subnet_id, identifier_type, identifier_begin,
2125 return (impl_->
get4(subnet_id, address));
2131 const uint8_t* identifier_begin,
2132 const size_t identifier_len)
const {
2135 return (impl_->
get6(subnet_id, identifier_type, identifier_begin, identifier_len));
2140 const uint8_t prefix_len)
const {
2143 return (impl_->
get6(prefix, prefix_len));
2151 return (impl_->
get6(subnet_id, address));
2161 return std::string(
"cql");
2171 return std::string(
"Host data source that stores host information in the CQL database");
Database statement not applied.
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr) override
Attempts to delete a host by (subnet-id, address)
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Implementation of CqlHostDataSource::getAll4()
virtual ~CqlHostExchange()
Virtual destructor.
virtual bool del6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) override
Attempts to delete a host by (subnet-id6, identifier-type, identifier).
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
void setContext(const data::ConstElementPtr &ctx)
Sets user context.
void executeMutation(const CqlConnection &connection, const AnyArray &assigned_values, StatementTag statement_tag)
Executes INSERT, UPDATE or DELETE statements.
std::pair< uint32_t, uint32_t > VersionPair
Pair containing major and minor versions.
void createBindForDelete(const HostPtr &host, const OptionalValue< SubnetID > &subnet_id, const IPv6Resrv *const reservation, const std::string &option_space, const OptionDescriptor &option_descriptor, StatementTag statement_tag, AnyArray &data)
Binds Host to data array to send data to the Cassandra database.
virtual boost::any retrieve() override
Copy received data into Host object.
Simple class representing an optional value.
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const override
Returns a collection of hosts using the specified IPv4 address.
static constexpr StatementTag GET_HOST_BY_HOST_ID
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
boost::shared_ptr< OptionDescriptor > OptionDescriptorPtr
A pointer to option descriptor.
Structure used to bind C++ input values to dynamic CQL parameters.
virtual void mergeHosts(const ConstHostPtr &source_host, HostPtr &target_host) const
Merge denormalized table entries that belong to the same host into a single host, one by one.
uint8_t getPrefixLen() const
Returns prefix length.
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
#define DHCP6_OPTION_SPACE
virtual ConstHostPtr get6(const asiolink::IOAddress &prefix, const uint8_t prefix_len) const
Retrieves a host by its reserved IPv6 address or prefix.
virtual ConstHostCollection getHostCollection(StatementTag statement_tag, AnyArray &where_values) const
Retrieves a collection of hosts.
virtual bool insertOrDeleteHost(bool insert, const HostPtr &host, const OptionalValue< SubnetID > &subnet_id=OptionalValue< SubnetID >(), const IPv6Resrv *const reservation=NULL, const std::string &option_space=NULL_OPTION_SPACE, const OptionDescriptor &option_descriptor=OptionDescriptor(false))
Inserts or deletes a single host.
boost::shared_ptr< Option > OptionPtr
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override
Binds member variables to data array to receive Host data.
static constexpr StatementTag GET_HOST
void prepareStatements(StatementMap &statements)
Prepare statements.
CqlHostDataSourceImpl(const CqlConnection::ParameterMap ¶meters)
Constructor.
void openDatabase()
Open database.
virtual db::VersionPair getVersion() const
Retrieves schema version from the DB.
std::vector< HostPtr > HostCollection
Collection of the Host objects.
static StatementMap tagged_statements_
Cassandra statements.
const IPv6Resrv retrieveReservation() const
Creates IPv6 reservation from the data contained in the currently processed row.
IPv6 reservation for a host.
CfgOptionPtr getCfgOption6()
Returns pointer to the DHCPv6 option data configuration for this host.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
const OptionWrapper retrieveOption() const
Retrieves option from members.
Holds DUID (DHCPv6 Unique Identifier)
Exception thrown on failure to open database.
char const *const StatementTag
Statement index representing the statement name.
static constexpr StatementTag GET_HOST_BY_IPV4_ADDRESS
Multiple lease records found where one expected.
static constexpr StatementTag DELETE_HOST
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
std::string formatted_value_
Option value in textual (CSV) format.
void setHostId(HostID id)
Sets Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
static constexpr StatementTag GET_HOST_BY_IPV6_PREFIX
void add(const boost::any &value)
Add a value at the end of the vector.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
virtual std::string getName() const
Returns the name of the database.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
bool persistent_
Persistence flag.
std::vector< cass_byte_t > CassBlob
Host identifier converted to Cassandra data type.
Implementation of the CqlHostDataSource.
virtual bool insertOrDeleteHostWithOptions(bool insert, const HostPtr &host, const IPv6Resrv *const reservation=NULL, const std::list< std::string > &option_spaces=std::list< std::string >(), const ConstCfgOptionPtr cfg_option=ConstCfgOptionPtr())
Adds/deletes any options found in the Host object to/from a separate table entry.
virtual void commit() override
Commit Transactions.
virtual ConstHostPtr get6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const override
Returns a Host connected to an IPv6 subnet.
virtual bool del4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) override
Attempts to delete a host by (subnet-id4, identifier-type, identifier).
virtual void rollback() override
Rollback Transactions.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Provides mechanisms for sending and retrieving data from the host_reservations table.
bool operator==(const HostKey &key1, const HostKey &key2)
equals operator for HostKey
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
Represents a device with IPv4 and/or IPv6 reservations.
Type
Type of the reservation.
virtual ConstHostCollection getAllHosts() const
Returns a collection of all the hosts.
CqlHostDataSource(const db::DatabaseConnection::ParameterMap ¶meters)
Constructor.
#define DHCP4_OPTION_SPACE
bool isV4() const
Convenience function to check for an IPv4 address.
void createBindForMutation(const HostPtr &host, const OptionalValue< SubnetID > &subnet_id, const IPv6Resrv *const reservation, const std::string &option_space, const OptionDescriptor &option_descriptor, StatementTag statement_tag, AnyArray &data)
Binds Host to data array to send data to the Cassandra database.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
virtual bool insertOrDeleteHostWithReservations(bool insert, const HostPtr &host, const IPv6Resrv *const reservation, const std::list< std::string > &option_spaces4, const ConstCfgOptionPtr cfg_option4, const std::list< std::string > &option_spaces6, const ConstCfgOptionPtr cfg_option6)
Adds/deletes any reservations found in the Host object to/from a separate table entry.
OptionPtr option_
Option instance.
virtual void add(const HostPtr &host) override
Adds a new host to the collection.
This is a base class for exceptions thrown from the DNS library module.
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR
Define CQL schema version: 3.0.
Defines the logger used by the top-level component of kea-dhcp-ddns.
Type getType() const
Returns reservation type.
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const override
Return all hosts connected to any subnet for which reservations have been made using a specified iden...
std::string toText() const
Convert the address to a string.
Exchange used to retrieve schema version from the keyspace.
virtual ConstHostPtr get4(const SubnetID &subnet_id, const asiolink::IOAddress &address) const
Implementation of CqlHostDataSource::get4()
virtual ConstHostCollection getAllHosts() const
Implementation of CqlHostDataSource::getAllHosts()
static const size_t MAX_DUID_LEN
maximum duid size As defined in RFC 8415, section 11.1
void addReservation(const IPv6Resrv &reservation)
Adds new IPv6 reservation.
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Implementation of CqlHostDataSource::getAll()
cass_int64_t hashIntoId() const
Create unique hash for storage in table id.
virtual ConstHostPtr getHost(StatementTag statement_tag, AnyArray &where_values) const
Retrieves a single host.
std::unordered_map< StatementTag, CqlTaggedStatement, StatementTagHash, StatementTagEqual > StatementMap
A container for all statements.
bool isSpecified() const
Checks if the value is specified or unspecified.
AnyArray executeSelect(const CqlConnection &connection, const AnyArray &where_values, StatementTag statement_tag, const bool &single=false)
Executes SELECT statements.
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR
virtual ~CqlHostDataSourceImpl()
Destructor.
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
virtual bool insertOrDelete(const HostPtr &host, bool insert)
Implementation of CqlHostDataSource::add() and del()
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
bool hasReservation(const IPv6Resrv &reservation) const
Checks if specified IPv6 reservation exists for the host.
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
IdentifierType
Type of the host identifier.
Common CQL connector pool.
HostKeyComponent
Identifies components of the host key.
The IOAddress class represents an IP addresses (version agnostic)
virtual VersionPair getVersion() const
Implementation of CqlHostDataSource::getVersion()
std::size_t hash_value(const HostKey &key)
hash function for HostMap
static constexpr StatementTag INSERT_HOST
Statement tags definitions.
virtual std::string getDescription() const
Returns textual description of the backend.
void prepareExchange(const HostPtr &host, const OptionalValue< SubnetID > &subnet_id, const IPv6Resrv *const reservation, const std::string &option_space, const OptionDescriptor &option_descriptor)
Sets the exchange members with data of Host.
virtual ~CqlHostDataSource()
Virtual destructor.
virtual std::string getType() const override
Return backend type.
virtual VersionPair retrieveVersion(const CqlConnection &connection)
Standalone method used to retrieve schema version.
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Exception thrown on failure to execute a database function.
CfgOptionPtr getCfgOption4()
Returns pointer to the DHCPv4 option data configuration for this host.
Database duplicate entry error.
virtual std::string getName() const
Implementation of CqlHostDataSource::getName()
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS
virtual ConstHostPtr get4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const override
Retrieves a Host connected to an IPv4 subnet.