Kea 1.5.0
cql_host_data_source.cc
Go to the documentation of this file.
1// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
2// Copyright (C) 2016-2017 Deutsche Telekom AG.
3//
4// Author: Andrei Pavel <andrei.pavel@qualitance.com>
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18#include <config.h>
19
20#include <cql/cql_exchange.h>
23#include <dhcp/duid.h>
24#include <dhcp/libdhcp++.h>
25#include <dhcp/option.h>
27#include <dhcpsrv/cfg_option.h>
28#include <dhcpsrv/cfgmgr.h>
29#include <dhcpsrv/dhcpsrv_log.h>
30#include <util/buffer.h>
31#include <util/hash.h>
32#include <util/optional_value.h>
33#include <asiolink/io_address.h>
34
35#include <stdint.h> // for uint64_t
36
37#include <boost/algorithm/string/classification.hpp> // for boost::is_any_of
38#include <boost/algorithm/string/split.hpp> // for split
39#include <boost/assert.hpp> // for BOOST_ASSERT
40#include <boost/unordered_map.hpp> // for std::unordered_map
41
42#include <iosfwd> // for size_t, std::stringstream
43#include <memory> // for std::unique_ptr
44#include <string> // for std::string
45
46using namespace isc::asiolink;
47using namespace isc::db;
48using namespace isc::dhcp;
49using namespace isc::util;
50using namespace isc::data;
51
52namespace {
53
55typedef std::vector<uint8_t> HostIdentifier;
56
60typedef std::
61 tuple<HostIdentifier, Host::IdentifierType, SubnetID, SubnetID, IOAddress> HostKey;
62
64enum HostKeyComponent {
65 HOST_IDENTIFIER,
66 HOST_IDENTIFIER_TYPE,
67 IPv4_SUBNET_ID,
68 IPv6_SUBNET_ID,
69 IPv4_RESERVATION
70};
71
74typedef std::unordered_map<HostKey, HostPtr, boost::hash<HostKey>> HostMap;
75
77typedef std::pair<HostKey, HostPtr> HostPair;
78
80struct OptionWrapper {
81 OptionWrapper(OptionDescriptorPtr option_descriptor, std::string option_space)
82 : option_descriptor_(option_descriptor), option_space_(option_space) {
83 }
84 OptionDescriptorPtr option_descriptor_;
85 std::string option_space_;
86};
87
90static constexpr size_t CLIENT_CLASSES_MAX_LENGTH = 255u;
91
95static constexpr size_t HOSTNAME_MAX_LENGTH = 255u;
96
98static constexpr size_t OPTION_VALUE_MAX_LENGTH = 4096u;
99
101static constexpr size_t OPTION_FORMATTED_VALUE_MAX_LENGTH = 8192u;
102
104static constexpr size_t OPTION_SPACE_MAX_LENGTH = 128u;
105
109static constexpr cass_int32_t MAX_IDENTIFIER_TYPE = static_cast<cass_int32_t>(Host::IDENT_FLEX);
110
113static constexpr char NULL_DHCP4_SERVER_HOSTNAME[] = "";
114static constexpr char NULL_DHCP4_BOOT_FILE_NAME[] = "";
115static constexpr char NULL_USER_CONTEXT[] = "";
116static constexpr char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] = "::";
117static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
118static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
119static constexpr cass_int32_t NULL_IAID = -1;
120static constexpr cass_int32_t NULL_OPTION_UNIVERSE = -1;
121static constexpr cass_int32_t NULL_OPTION_CODE = -1;
122static const CassBlob NULL_OPTION_VALUE = CassBlob();
123static constexpr char NULL_OPTION_FORMATTED_VALUE[] = "";
124static constexpr char NULL_OPTION_SPACE[] = "";
125static constexpr cass_bool_t NULL_OPTION_IS_PERSISTENT = cass_false;
126static constexpr char NULL_OPTION_CLIENT_CLASS[] = "";
127static constexpr cass_int32_t NULL_OPTION_SUBNET_ID = -1;
128static constexpr char NULL_OPTION_USER_CONTEXT[] = "";
129static constexpr cass_int32_t NULL_OPTION_SCOPE_ID = -1;
131
134static const IPv6Resrv NULL_IPV6_RESERVATION =
136
137} // namespace
138
139namespace isc {
140namespace dhcp {
141
144class CqlHostExchange : public virtual CqlExchange {
145public:
150
152 virtual ~CqlHostExchange();
153
164 virtual void
165 createBindForSelect(AnyArray& data, StatementTag statement_tag = NULL) override;
166
176 void prepareExchange(const HostPtr& host,
177 const OptionalValue<SubnetID>& subnet_id,
178 const IPv6Resrv* const reservation,
179 const std::string& option_space,
180 const OptionDescriptor& option_descriptor);
181
195 void createBindForMutation(const HostPtr& host,
196 const OptionalValue<SubnetID>& subnet_id,
197 const IPv6Resrv* const reservation,
198 const std::string& option_space,
199 const OptionDescriptor& option_descriptor,
200 StatementTag statement_tag,
201 AnyArray& data);
202
216 void createBindForDelete(const HostPtr& host,
217 const OptionalValue<SubnetID>& subnet_id,
218 const IPv6Resrv* const reservation,
219 const std::string& option_space,
220 const OptionDescriptor& option_descriptor,
221 StatementTag statement_tag,
222 AnyArray& data);
223
233 cass_int64_t hashIntoId() const;
234
242 virtual boost::any retrieve() override;
243
250 const IPv6Resrv retrieveReservation() const;
251
258 const OptionWrapper retrieveOption() const;
259
262 // Inserts all parameters belonging to any reservation from a single host.
263 static constexpr StatementTag INSERT_HOST =
264 "INSERT_HOST";
265
266 // Retrieves hosts informations, IPv6 reservations and both IPv4 and IPv6
267 // options associated with the hosts.
268 static constexpr StatementTag GET_HOST =
269 "GET_HOST";
270
271 // Retrieves host information, IPv6 reservations and both IPv4 and IPv6
272 // options associated with the host.
274 "GET_HOST_BY_HOST_ID";
275
276 // Retrieves host information along with the IPv4 options associated
277 // with it.
279 "GET_HOST_BY_IPV4_ADDRESS";
280
281 // Retrieves host information and IPv4 options using subnet identifier
282 // and client's identifier (i.e. hardware address or DUID).
284 "GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID";
285
286 // Retrieves host information; IPv6 reservations and IPv6 options
287 // associated with a host using subnet identifier and client's
288 // identifier (i.e. hardware address or DUID).
290 "GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID";
291
292 // Retrieves host information and IPv4 options for the host using subnet
293 // identifier and IPv4 reservation.
295 "GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS";
296
297 // Retrieves host information, IPv6 reservations and IPv6 options
298 // associated with a host using prefix and prefix length. This query
299 // returns host information for a single host. However, multiple rows
300 // are returned due to left joining IPv6 reservations and IPv6 options.
301 // The number of rows returned is multiplication of number of existing
302 // IPv6 reservations and IPv6 options.
304 "GET_HOST_BY_IPV6_PREFIX";
305
306 // Retrieves host information and IPv6 options for the host using subnet
307 // identifier and IPv6 reservation.
309 "GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS";
310
311 // Deletes a host reservation.
312 static constexpr StatementTag DELETE_HOST =
313 "DELETE_HOST";
315
318
319private:
321 HostPtr host_;
322
326 cass_int64_t id_;
327
329 CassBlob host_identifier_;
330
333 cass_int32_t host_identifier_type_;
334
336 cass_int32_t host_ipv4_subnet_id_;
337
339 cass_int32_t host_ipv6_subnet_id_;
340
342 cass_int32_t host_ipv4_address_;
343
345 cass_int32_t host_ipv4_next_server_;
346
348 std::string host_ipv4_server_hostname_;
349
351 std::string host_ipv4_boot_file_name_;
352
354 std::string auth_key_;
355
357 std::string hostname_;
358
360 std::string user_context_;
361
363 std::string host_ipv4_client_classes_;
364
366 std::string host_ipv6_client_classes_;
367
369 std::string reserved_ipv6_prefix_address_;
370
372 cass_int32_t reserved_ipv6_prefix_length_;
373
376 cass_int32_t reserved_ipv6_prefix_address_type_;
377
379 cass_int32_t iaid_;
380
383 cass_int32_t option_universe_;
384
386 cass_int32_t option_code_;
387
389 CassBlob option_value_;
390
392 std::string option_formatted_value_;
393
395 std::string option_space_;
396
398 cass_bool_t option_is_persistent_;
399
401 std::string option_client_class_;
402
404 cass_int32_t option_subnet_id_;
405
407 std::string option_user_context_;
408
410 cass_int32_t option_scope_id_;
411}; // CqlHostExchange
412
423
425 {INSERT_HOST,
426 {INSERT_HOST,
427 "INSERT INTO host_reservations ( "
428 "id, "
429 "host_identifier, "
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, "
437 "auth_key, "
438 "hostname, "
439 "user_context, "
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, "
445 "iaid, "
446 "option_universe, "
447 "option_code, "
448 "option_value, "
449 "option_formatted_value, "
450 "option_space, "
451 "option_is_persistent, "
452 "option_client_class, "
453 "option_subnet_id, "
454 "option_user_context, "
455 "option_scope_id "
456 ") VALUES ( "
457 // id
458 "?, "
459 // host
460 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
461 // denormalized reservation, option
462 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
463 ") "
464 "IF NOT EXISTS "
465 }},
466
467 {GET_HOST,
468 {GET_HOST,
469 "SELECT "
470 "id, "
471 "host_identifier, "
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, "
479 "auth_key, "
480 "hostname, "
481 "user_context, "
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, "
487 "iaid, "
488 "option_universe, "
489 "option_code, "
490 "option_value, "
491 "option_formatted_value, "
492 "option_space, "
493 "option_is_persistent, "
494 "option_client_class, "
495 "option_subnet_id, "
496 "option_user_context, "
497 "option_scope_id "
498 "FROM host_reservations "
499 }},
500
501 {GET_HOST_BY_HOST_ID,
502 {GET_HOST_BY_HOST_ID,
503 "SELECT "
504 "id, "
505 "host_identifier, "
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, "
513 "auth_key, "
514 "hostname, "
515 "user_context, "
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, "
521 "iaid, "
522 "option_universe, "
523 "option_code, "
524 "option_value, "
525 "option_formatted_value, "
526 "option_space, "
527 "option_is_persistent, "
528 "option_client_class, "
529 "option_subnet_id, "
530 "option_user_context, "
531 "option_scope_id "
532 "FROM host_reservations "
533 "WHERE host_identifier = ? "
534 "AND host_identifier_type = ? "
535 "ALLOW FILTERING "
536 }},
537
538 {GET_HOST_BY_IPV4_ADDRESS,
539 {GET_HOST_BY_IPV4_ADDRESS,
540 "SELECT "
541 "id, "
542 "host_identifier, "
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, "
550 "auth_key, "
551 "hostname, "
552 "user_context, "
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, "
558 "iaid, "
559 "option_universe, "
560 "option_code, "
561 "option_value, "
562 "option_formatted_value, "
563 "option_space, "
564 "option_is_persistent, "
565 "option_client_class, "
566 "option_subnet_id, "
567 "option_user_context, "
568 "option_scope_id "
569 "FROM host_reservations "
570 "WHERE host_ipv4_address = ? "
571 "ALLOW FILTERING "
572 }},
573
574 {GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
575 {GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
576 "SELECT "
577 "id, "
578 "host_identifier, "
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, "
586 "auth_key, "
587 "hostname, "
588 "user_context, "
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, "
594 "iaid, "
595 "option_universe, "
596 "option_code, "
597 "option_value, "
598 "option_formatted_value, "
599 "option_space, "
600 "option_is_persistent, "
601 "option_client_class, "
602 "option_subnet_id, "
603 "option_user_context, "
604 "option_scope_id "
605 "FROM host_reservations "
606 "WHERE host_ipv4_subnet_id = ? "
607 "AND host_identifier = ? "
608 "AND host_identifier_type = ? "
609 "ALLOW FILTERING "
610 }},
611
612 {GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
613 {GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
614 "SELECT "
615 "id, "
616 "host_identifier, "
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, "
624 "auth_key, "
625 "hostname, "
626 "user_context, "
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, "
632 "iaid, "
633 "option_universe, "
634 "option_code, "
635 "option_value, "
636 "option_formatted_value, "
637 "option_space, "
638 "option_is_persistent, "
639 "option_client_class, "
640 "option_subnet_id, "
641 "option_user_context, "
642 "option_scope_id "
643 "FROM host_reservations "
644 "WHERE host_ipv6_subnet_id = ? "
645 "AND host_identifier = ? "
646 "AND host_identifier_type = ? "
647 "ALLOW FILTERING "
648 }},
649
650 {GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
651 {GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
652 "SELECT "
653 "id, "
654 "host_identifier, "
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, "
662 "auth_key, "
663 "hostname, "
664 "user_context, "
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, "
670 "iaid, "
671 "option_universe, "
672 "option_code, "
673 "option_value, "
674 "option_formatted_value, "
675 "option_space, "
676 "option_is_persistent, "
677 "option_client_class, "
678 "option_subnet_id, "
679 "option_user_context, "
680 "option_scope_id "
681 "FROM host_reservations "
682 "WHERE host_ipv4_subnet_id = ? "
683 "AND host_ipv4_address = ? "
684 "ALLOW FILTERING "
685 }},
686
687 {GET_HOST_BY_IPV6_PREFIX,
688 {GET_HOST_BY_IPV6_PREFIX,
689 "SELECT "
690 "id, "
691 "host_identifier, "
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, "
699 "auth_key, "
700 "hostname, "
701 "user_context, "
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, "
707 "iaid, "
708 "option_universe, "
709 "option_code, "
710 "option_value, "
711 "option_formatted_value, "
712 "option_space, "
713 "option_is_persistent, "
714 "option_client_class, "
715 "option_subnet_id, "
716 "option_user_context, "
717 "option_scope_id "
718 "FROM host_reservations "
719 "WHERE reserved_ipv6_prefix_address = ? "
720 "AND reserved_ipv6_prefix_length = ? "
721 "ALLOW FILTERING "
722 }},
723
724 {GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
725 {GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
726 "SELECT "
727 "id, "
728 "host_identifier, "
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, "
736 "auth_key, "
737 "hostname, "
738 "user_context, "
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, "
744 "iaid, "
745 "option_universe, "
746 "option_code, "
747 "option_value, "
748 "option_formatted_value, "
749 "option_space, "
750 "option_is_persistent, "
751 "option_client_class, "
752 "option_subnet_id, "
753 "option_user_context, "
754 "option_scope_id "
755 "FROM host_reservations "
756 "WHERE host_ipv6_subnet_id = ? "
757 "AND reserved_ipv6_prefix_address = ? "
758 "ALLOW FILTERING "
759 }},
760
761 {DELETE_HOST,
762 {DELETE_HOST,
763 "DELETE FROM host_reservations WHERE id = ? "
764 "IF EXISTS "
765 }}
766};
767
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),
773 auth_key_(""),
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) {
783}
784
786}
787
788void
790 // Start with a fresh array.
791 data.clear();
792
793 // id: blob
794 data.add(&id_);
795 // host_identifier: blob
796 data.add(&host_identifier_);
797 // host_identifier_type: int
798 data.add(&host_identifier_type_);
799 // host_ipv4_subnet_id: int
800 data.add(&host_ipv4_subnet_id_);
801 // host_ipv6_subnet_id: int
802 data.add(&host_ipv6_subnet_id_);
803 // host_ipv4_address: int
804 data.add(&host_ipv4_address_);
805 // host_ipv4_next_server: int
806 data.add(&host_ipv4_next_server_);
807 // host_ipv4_server_hostname: text
808 data.add(&host_ipv4_server_hostname_);
809 // host_ipv4_boot_file_name: text
810 data.add(&host_ipv4_boot_file_name_);
811 // auth_key: text
812 data.add(&auth_key_);
813 // hostname: text
814 data.add(&hostname_);
815 // user_context: text
816 data.add(&user_context_);
817 // host_ipv4_client_classes: text
818 data.add(&host_ipv4_client_classes_);
819 // host_ipv6_client_classes: text
820 data.add(&host_ipv6_client_classes_);
823 // reserved_ipv6_prefix_address: text
824 data.add(&reserved_ipv6_prefix_address_);
825 // reserved_ipv6_prefix_length: int
826 data.add(&reserved_ipv6_prefix_length_);
827 // reserved_ipv6_prefix_address_type: int
828 data.add(&reserved_ipv6_prefix_address_type_);
829 // iaid: int
830 data.add(&iaid_);
834 // option_universe: int
835 data.add(&option_universe_);
836 // option_code: int
837 data.add(&option_code_);
838 // option_value: blob
839 data.add(&option_value_);
840 // option_formatted_value: text
841 data.add(&option_formatted_value_);
842 // option_space: text
843 data.add(&option_space_);
844 // option_is_persistent: boolean
845 data.add(&option_is_persistent_);
846 // option_client_class: text
847 data.add(&option_client_class_);
848 // option_subnet_id: int
849 data.add(&option_subnet_id_);
850 // option_user_context: text
851 data.add(&option_user_context_);
852 // option_scope_id: int
853 data.add(&option_scope_id_);
855}
856
857void
859 const OptionalValue<SubnetID>& subnet_id,
860 const IPv6Resrv* const reservation,
861 const std::string& option_space,
862 const OptionDescriptor& option_descriptor) {
863
864 // Store host object to ensure it remains valid.
865 host_ = host;
866
867 // Set up the structures for the various components of the host
868 // structure.
869 try {
870 // host_identifier: blob
871 // Convert from std::vector<uint8_t> to
872 // std::vector<cass_byte_t>.
873 HostIdentifier host_identifier = host->getIdentifier();
874 host_identifier_ = CassBlob(host_identifier.begin(), host_identifier.end());
875 if (host_identifier_.size() > DUID::MAX_DUID_LEN) {
876 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): host identifier "
877 << host_identifier_.data() << " of length " << host_identifier_.size()
878 << " is greater than allowed of " << DUID::MAX_DUID_LEN);
879 }
880
881 // host_identifier_type: tinyint
882 host_identifier_type_ = static_cast<cass_int32_t>(host->getIdentifierType());
883 if (host_identifier_type_ > MAX_IDENTIFIER_TYPE) {
884 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): invalid "
885 "host identifier type returned: " << host_identifier_type_);
886 }
887
888 // host_ipv4_subnet_id: int
889 host_ipv4_subnet_id_ = static_cast<cass_int32_t>(host->getIPv4SubnetID());
890
891 // host_ipv6_subnet_id: int
892 host_ipv6_subnet_id_ = static_cast<cass_int32_t>(host->getIPv6SubnetID());
893
894 // host_ipv4_address: int
895 host_ipv4_address_ = static_cast<cass_int32_t>(host->getIPv4Reservation().toUint32());
896
897 // host_ipv4_next_server: int
898 host_ipv4_next_server_ = static_cast<cass_int32_t>(host->getNextServer().toUint32());
899
900 // host_ipv4_server_hostname: text
901 host_ipv4_server_hostname_ = host->getServerHostname();
902
903 // host_ipv4_boot_file_name: text
904 host_ipv4_boot_file_name_ = host->getBootFileName();
905
906 // auth_key: varchar
907 auth_key_ = host->getKey().ToText();
908
909 // hostname: text
910 hostname_ = host->getHostname();
911 if (hostname_.size() > HOSTNAME_MAX_LENGTH) {
912 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): hostname "
913 << hostname_ << " of length " << hostname_.size()
914 << " is greater than allowed of " << HOSTNAME_MAX_LENGTH);
915 }
916
917 // user_context: text
918 ConstElementPtr ctx = host->getContext();
919 if (ctx) {
920 user_context_ = ctx->str();
921 } else {
922 user_context_ = NULL_USER_CONTEXT;
923 }
924
925 // host_ipv4_client_classes: text
926 host_ipv4_client_classes_ = host->getClientClasses4().toText(",");
927 if (host_ipv4_client_classes_.size() > CLIENT_CLASSES_MAX_LENGTH) {
928 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): "
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);
932 }
933
934 // host_ipv6_client_classes: text
935 host_ipv6_client_classes_ = host->getClientClasses6().toText(",");
936 if (host_ipv6_client_classes_.size() > CLIENT_CLASSES_MAX_LENGTH) {
937 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): "
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);
941 }
942
943 if (reservation == NULL) {
944 // reserved_ipv6_prefix_address: text
945 reserved_ipv6_prefix_address_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS;
946 // reserved_ipv6_prefix_length: int
947 reserved_ipv6_prefix_length_ = NULL_RESERVED_IPV6_PREFIX_LENGTH;
948 // reserved_ipv6_prefix_address_type: int
949 reserved_ipv6_prefix_address_type_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE;
950 iaid_ = NULL_IAID;
951 } else {
952 // reserved_ipv6_prefix_address: text
953 reserved_ipv6_prefix_address_ = reservation->getPrefix().toText();
954
955 // reserved_ipv6_prefix_length: int
956 reserved_ipv6_prefix_length_ = static_cast<cass_int32_t>(reservation->getPrefixLen());
957
958 // reserved_ipv6_prefix_address_type: int
959 reserved_ipv6_prefix_address_type_ =
960 reservation->getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
961
962 // iaid: int
964 iaid_ = 0;
965 }
966
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;
978 } else {
979 // option_universe: int
980 option_universe_ = option_descriptor.option_->getUniverse();
981
982 // option_code: int
983 option_code_ = option_descriptor.option_->getType();
984
985 // option_value: blob
986 // option_formatted_value: text
987 if (option_descriptor.formatted_value_.empty()) {
988 if (option_descriptor.option_->len() >
989 option_descriptor.option_->getHeaderLen()) {
990 // The formatted_value is empty and the option value
991 // is not empty so we need to prepare on-wire format
992 // for the option and store it in the database as a
993 // blob.
994 OutputBuffer buffer(option_descriptor.option_->len());
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());
999 } else {
1000 option_value_.clear();
1001 }
1002 option_formatted_value_.clear();
1003 } else {
1004 option_value_.clear();
1005 option_formatted_value_ = option_descriptor.formatted_value_;
1006 }
1007
1008 // option_space: text
1009 option_space_ = option_space;
1010
1011 // option_is_persistent: boolean
1012 option_is_persistent_ = option_descriptor.persistent_ ? cass_true : cass_false;
1013
1014 // option_client_class: text
1016 option_client_class_.clear();
1017
1018 // option_subnet_id: int
1019 if (subnet_id.isSpecified()) {
1020 option_subnet_id_ = subnet_id;
1021 } else {
1022 option_subnet_id_ = 0;
1023 }
1024
1025 // option_user_context: text
1026 ConstElementPtr ctx = option_descriptor.getContext();
1027 if (ctx) {
1028 option_user_context_ = ctx->str();
1029 } else {
1030 option_user_context_ = NULL_OPTION_USER_CONTEXT;
1031 }
1032
1033 // option_scope_id: int
1034 // Using fixed scope_id = 3, which associates an option with host.
1035 option_scope_id_ = 3;
1036 }
1037
1038 // id: bigint
1039 id_ = hashIntoId();
1040 } catch (const Exception& ex) {
1042 "CqlHostExchange::prepareExchange(): "
1043 "could not copy data from host "
1044 << host->getHostname() << ", reason: " << ex.what());
1045 }
1046}
1047
1048void
1050 const OptionalValue<SubnetID>& subnet_id,
1051 const IPv6Resrv* const reservation,
1052 const std::string& option_space,
1053 const OptionDescriptor& option_descriptor,
1054 StatementTag statement_tag, AnyArray& data) {
1055 prepareExchange(host, subnet_id, reservation, option_space, option_descriptor);
1056
1057 try {
1058 // Add all parameters to bind array.
1059 data.clear();
1060
1061 if (statement_tag == CqlHostExchange::INSERT_HOST) {
1062 data.add(&id_);
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_);
1076 }
1077
1078 // Reservation
1079 data.add(&reserved_ipv6_prefix_address_);
1080 data.add(&reserved_ipv6_prefix_length_);
1081 data.add(&reserved_ipv6_prefix_address_type_);
1082 data.add(&iaid_);
1083
1084 // Option
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_);
1095
1096 } catch (const Exception& ex) {
1098 "CqlHostExchange::createBindForMutation(): "
1099 "could not create bind array from host "
1100 << host->getHostname() << ", reason: " << ex.what());
1101 }
1102}
1103
1104void
1106 const OptionalValue<SubnetID>& subnet_id,
1107 const IPv6Resrv* const reservation,
1108 const std::string& option_space,
1109 const OptionDescriptor& option_descriptor,
1110 StatementTag statement_tag, AnyArray& data) {
1111 prepareExchange(host, subnet_id, reservation, option_space, option_descriptor);
1112
1113 try {
1114 // Add all parameters to bind array.
1115 data.clear();
1116
1117 if (statement_tag == CqlHostExchange::DELETE_HOST) {
1118 data.add(&id_);
1119 }
1120
1121 } catch (const Exception& ex) {
1123 "CqlHostExchange::createBindForDelete(): "
1124 "could not create bind array from host "
1125 << host->getHostname() << ", reason: " << ex.what());
1126 }
1127}
1128
1129cass_int64_t
1131 // Add a separator between aggregated field to avoid collisions
1132 // between distinct entries.
1133
1134 // Get key.
1135 std::stringstream key_stream;
1136 if (host_ipv4_address_) {
1137 key_stream << std::setw(3 * DUID::MAX_DUID_LEN - 1) << std::setfill('-')
1138 << "-";
1139 key_stream << std::setw(10) << std::setfill('-') << "-";
1140 } else {
1141 key_stream << std::setw(3 * DUID::MAX_DUID_LEN - 1) << std::setfill('-')
1142 << DUID(host_identifier_).toText();
1143 key_stream << std::setw(10) << std::setfill('-') << host_identifier_type_;
1144 }
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('-')
1155 << option_space_;
1156 const std::string key = key_stream.str();
1157
1158 const cass_int64_t hash = static_cast<cass_int64_t>(Hash64::hash(key));
1159
1160 return (hash);
1161}
1162
1163boost::any
1165 const uint64_t id = static_cast<uint64_t>(id_);
1166
1167 HostIdentifier host_identifier =
1168 HostIdentifier(host_identifier_.begin(), host_identifier_.end());
1169
1170 // Set the host identifier type in a variable of the appropriate
1171 // data type.
1172 Host::IdentifierType host_identifier_type =
1173 static_cast<Host::IdentifierType>(host_identifier_type_);
1174
1175 // Set IPv4 subnet ID to the value returned.
1176 SubnetID ipv4_subnet_id = static_cast<SubnetID>(host_ipv4_subnet_id_);
1177
1178 // Set IPv6 subnet ID to the value returned.
1179 SubnetID ipv6_subnet_id = static_cast<SubnetID>(host_ipv6_subnet_id_);
1180
1181 // Set IPv4 address reservation.
1182 asiolink::IOAddress ipv4_reservation =
1183 asiolink::IOAddress(static_cast<uint32_t>(host_ipv4_address_));
1184
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_,
1191 AuthKey(auth_key_));
1192
1193 // Set the user context if there is one.
1194 if (!user_context_.empty()) {
1195 try {
1196 ConstElementPtr ctx = Element::fromJSON(user_context_);
1197 if (!ctx || (ctx->getType() != Element::map)) {
1198 isc_throw(BadValue, "user context '" << user_context_
1199 << "' is not a JSON map");
1200 }
1201 host->setContext(ctx);
1202 } catch (const isc::data::JSONError& ex) {
1203 isc_throw(BadValue, "user context '" << user_context_
1204 << "' is invalid JSON: " << ex.what());
1205 }
1206 }
1207
1208 host->setHostId(id);
1209
1210 const IPv6Resrv reservation = retrieveReservation();
1211 if (reservation != NULL_IPV6_RESERVATION &&
1212 !host->hasReservation(reservation)) {
1213 host->addReservation(reservation);
1214 }
1215
1216 OptionWrapper option_wrapper = retrieveOption();
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_);
1224 }
1225 }
1226
1227 return (host);
1228}
1229
1230const IPv6Resrv
1232 // Set the IPv6 Reservation type (0 = IA_NA, 2 = IA_PD).
1233 IPv6Resrv::Type type;
1234 switch (reserved_ipv6_prefix_address_type_) {
1235 case 0:
1236 type = IPv6Resrv::TYPE_NA;
1237 break;
1238 case 2:
1239 type = IPv6Resrv::TYPE_PD;
1240 break;
1241 case NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE:
1242 return (NULL_IPV6_RESERVATION);
1243 default:
1244 isc_throw(BadValue, "CqlHostExchange::retrieveReservation(): invalid IPv6 "
1245 "reservation type returned: " << reserved_ipv6_prefix_address_type_
1246 << ". Only 0 (IA_NA) or 2 (IA_PD) are allowed.");
1247 }
1248
1249 return (IPv6Resrv(type, IOAddress(reserved_ipv6_prefix_address_),
1250 reserved_ipv6_prefix_length_));
1251}
1252
1253const OptionWrapper
1255 // Options are held in a binary or textual format in the database.
1256 // This is similar to having an option specified in a server
1257 // configuration file. Such option is converted to appropriate C++
1258 // class, using option definition. Thus, we need to find the
1259 // option definition for this option code and option space.
1260
1261 // If the option space is a standard DHCPv4 or DHCPv6 option space,
1262 // this is most likely a standard option, for which we have a
1263 // definition created within libdhcp++.
1264 if (option_space_.empty() || option_universe_ == NULL_OPTION_UNIVERSE) {
1265 return (OptionWrapper(OptionDescriptorPtr(), ""));
1266 }
1267
1268 OptionDefinitionPtr option_definition_ptr =
1269 LibDHCP::getOptionDef(option_space_, option_code_);
1270
1271 // Otherwise, we may check if this an option encapsulated within the
1272 // vendor space.
1273 if (!option_definition_ptr && option_space_ != DHCP4_OPTION_SPACE &&
1274 option_space_ != DHCP6_OPTION_SPACE) {
1275 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space_);
1276 if (vendor_id > 0) {
1277 option_definition_ptr = LibDHCP::getVendorOptionDef(
1278 static_cast<Option::Universe>(option_universe_), vendor_id,
1279 option_code_);
1280 }
1281 }
1282
1283 // In all other cases, we use runtime option definitions, which
1284 // should be also registered within the libdhcp++.
1285 if (!option_definition_ptr) {
1286 option_definition_ptr =
1287 LibDHCP::getRuntimeOptionDef(option_space_, option_code_);
1288 }
1289
1290 OptionPtr option;
1291 if (!option_definition_ptr) {
1292 // If no definition found, we use generic option type.
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()));
1297 } else {
1298 // The option value may be specified in textual or binary format
1299 // in the
1300 // database. If formatted_value is empty, the binary format is
1301 // used.
1302 // Depending on the format we use a different variant of @ref
1303 // optionFactory().
1304 if (option_formatted_value_.empty()) {
1305 OptionBuffer option_buffer(option_value_.begin(),
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());
1311 } else {
1312 // Spit the value specified in comma separated values
1313 // format.
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);
1320 }
1321 }
1322
1323 OptionWrapper result(OptionDescriptorPtr(new OptionDescriptor(option, option_is_persistent_,
1324 option_formatted_value_)), option_space_);
1325 // Set the user context if there is one into the option descriptor.
1326 if (!option_user_context_.empty()) {
1327 try {
1328 ConstElementPtr ctx = Element::fromJSON(option_user_context_);
1329 if (!ctx || (ctx->getType() != Element::map)) {
1330 isc_throw(BadValue, "option user context '" << option_user_context_
1331 << "' is no a JSON map");
1332 }
1333 result.option_descriptor_->setContext(ctx);
1334 } catch (const isc::data::JSONError& ex) {
1335 isc_throw(BadValue, "option user context '" << option_user_context_
1336 << "' is invalid JSON: " << ex.what());
1337 }
1338 }
1339
1340 return result;
1341}
1342
1347public:
1353 explicit CqlHostDataSourceImpl(const CqlConnection::ParameterMap& parameters);
1354
1356 virtual ~CqlHostDataSourceImpl();
1357
1364 virtual bool insertOrDelete(const HostPtr& host, bool insert);
1365
1372 virtual ConstHostPtr get4(const SubnetID& subnet_id,
1373 const asiolink::IOAddress& address) const;
1374
1383 virtual ConstHostPtr get4(const SubnetID& subnet_id,
1384 const Host::IdentifierType& identifier_type,
1385 const uint8_t* identifier_begin,
1386 const size_t identifier_len) const;
1387
1394 virtual ConstHostPtr get6(const asiolink::IOAddress& prefix,
1395 const uint8_t prefix_len) const;
1396
1405 virtual ConstHostPtr get6(const SubnetID& subnet_id,
1406 const Host::IdentifierType& identifier_type,
1407 const uint8_t* identifier_begin,
1408 const size_t identifier_len) const;
1409
1416 virtual ConstHostPtr get6(const SubnetID& subnet_id,
1417 const asiolink::IOAddress& address) const;
1418
1426 virtual ConstHostCollection
1427 getAll(const Host::IdentifierType& identifier_type,
1428 const uint8_t* identifier_begin,
1429 const size_t identifier_len) const;
1430
1436 virtual ConstHostCollection
1437 getAll4(const asiolink::IOAddress& address) const;
1438
1442 virtual ConstHostCollection
1443 getAllHosts() const;
1444
1446 virtual std::string getName() const;
1447
1449 virtual VersionPair getVersion() const;
1450
1451protected:
1462 virtual bool insertOrDeleteHostWithOptions(bool insert,
1463 const HostPtr& host,
1464 const IPv6Resrv* const reservation = NULL,
1465 const std::list<std::string>& option_spaces = std::list<std::string>(),
1466 const ConstCfgOptionPtr cfg_option = ConstCfgOptionPtr());
1467
1482 virtual bool insertOrDeleteHostWithReservations(bool insert,
1483 const HostPtr& host,
1484 const IPv6Resrv* const reservation,
1485 const std::list<std::string>& option_spaces4,
1486 const ConstCfgOptionPtr cfg_option4,
1487 const std::list<std::string>& option_spaces6,
1488 const ConstCfgOptionPtr cfg_option6);
1489
1502 virtual ConstHostPtr getHost(StatementTag statement_tag,
1503 AnyArray& where_values) const;
1504
1514 AnyArray& where_values) const;
1515
1530 virtual bool insertOrDeleteHost(bool insert,
1531 const HostPtr& host,
1533 const IPv6Resrv* const reservation = NULL,
1534 const std::string& option_space = NULL_OPTION_SPACE,
1535 const OptionDescriptor& option_descriptor = OptionDescriptor(false));
1536
1545 virtual void mergeHosts(const ConstHostPtr& source_host,
1546 HostPtr& target_host) const;
1547
1548private:
1550 mutable CqlConnection dbconn_;
1551}; // class CqlHostDataSourceImpl
1552
1561std::size_t
1562hash_value(const HostKey& key) {
1563 // Get key.
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();
1572
1573 const uint64_t hash = Hash64::hash(key_string);
1574
1575 return (static_cast<std::size_t>(hash));
1576}
1577
1584bool
1585operator==(const HostKey& key1, const HostKey& key2) {
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));
1592}
1593
1595 : dbconn_(parameters) {
1596 // Open the database.
1597 dbconn_.openDatabase();
1598
1599 // Prepare the version exchange first.
1601
1602 // Validate the schema version.
1603 std::pair<uint32_t, uint32_t> code_version(CQL_SCHEMA_VERSION_MAJOR,
1605 std::pair<uint32_t, uint32_t> db_version = getVersion();
1606 if (code_version != db_version) {
1607 isc_throw(DbOpenError, "Cassandra schema version mismatch: need version: "
1608 << code_version.first << "." << code_version.second
1609 << " found version: " << db_version.first << "."
1610 << db_version.second);
1611 }
1612
1613 // Prepare all possible statements.
1615}
1616
1618 // There is no need to close the database in this destructor: it is
1619 // closed in the destructor of the dbconn_ member variable.
1620}
1621
1622bool
1624 // If there is no host, there is nothing to do.
1625 if (!host) {
1626 return (false);
1627 }
1628
1629 // Get option space names and vendor space names and combine them within a
1630 // single list.
1631
1632 // For IPv4:
1633 ConstCfgOptionPtr cfg_option4 = host->getCfgOption4();
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());
1638
1639 // For IPv6:
1640 ConstCfgOptionPtr cfg_option6 = host->getCfgOption6();
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());
1645
1646 bool result = true;
1647
1648 // For every IPv6 reservation, add each of their options to the
1649 // database.
1650 IPv6ResrvRange reservations = host->getIPv6Reservations();
1651 if (std::distance(reservations.first, reservations.second) > 0) {
1652 for (IPv6ResrvIterator it = reservations.first; result && it != reservations.second; ++it) {
1653 result = insertOrDeleteHostWithReservations(insert, host, &it->second, option_spaces4, cfg_option4,
1654 option_spaces6, cfg_option6);
1655 }
1656 } else {
1657 // If host has no reservation, add entries with null
1658 // reservation. Options could still be present.
1659 result = insertOrDeleteHostWithReservations(insert, host, NULL, option_spaces4, cfg_option4,
1660 option_spaces6, cfg_option6);
1661 }
1662
1663 return (result);
1664}
1665
1667CqlHostDataSourceImpl::get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const {
1668 if (!address.isV4()) {
1669 isc_throw(BadValue, "CqlHostDataSource::get4(2): wrong address type, "
1670 "address supplied is not an IPv4 address");
1671 }
1672
1673 // Convert to CQL data types.
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());
1676
1677 // Bind to array.
1678 AnyArray where_values;
1679 where_values.add(&host_ipv4_subnet_id);
1680 where_values.add(&host_ipv4_address);
1681
1682 // Run statement.
1684 where_values);
1685
1686 return (result);
1687}
1688
1691 const Host::IdentifierType& identifier_type,
1692 const uint8_t* identifier_begin,
1693 const size_t identifier_len) const {
1694 // Convert to CQL data types.
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);
1698
1699 // Bind to array.
1700 AnyArray where_values;
1701 where_values.add(&host_ipv4_subnet_id);
1702 where_values.add(&host_identifier);
1703 where_values.add(&host_identifier_type);
1704
1705 // Run statement.
1707 where_values);
1708
1709 return (result);
1710}
1711
1714 const uint8_t prefix_len) const {
1715 // Convert to CQL data types.
1716 std::string reserved_ipv6_prefix_address = prefix.toText();
1717 cass_int32_t reserved_ipv6_prefix_length = prefix_len;
1718
1719 ConstHostPtr host;
1720 // Bind to array.
1721 AnyArray where_values;
1722 where_values.add(&reserved_ipv6_prefix_address);
1723 where_values.add(&reserved_ipv6_prefix_length);
1724
1725 // Get host id.
1727
1728 if (host == ConstHostPtr()) {
1729 return (ConstHostPtr());
1730 }
1731
1732 // Get host.
1733 HostIdentifier host_identifier = host->getIdentifier();
1734 // Delegate to getAll(3).
1735 ConstHostCollection collection = getAll(host->getIdentifierType(), host_identifier.data(),
1736 host_identifier.size());
1737
1738 if (collection.empty()) {
1739 return (ConstHostPtr());
1740 }
1741
1742 if (collection.size() >= 2u) {
1744 "CqlHostDataSource::get6(2): multiple records were "
1745 "found in the "
1746 "database where only one was expected for statement "
1748 }
1749
1750 ConstHostPtr result = *collection.begin();
1751
1752 return (result);
1753}
1754
1757 const Host::IdentifierType& identifier_type,
1758 const uint8_t* identifier_begin,
1759 const size_t identifier_len) const {
1760 // Convert to CQL data types.
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);
1764
1765 // Bind to array.
1766 AnyArray where_values;
1767 where_values.add(&host_ipv6_subnet_id);
1768 where_values.add(&host_identifier);
1769 where_values.add(&host_identifier_type);
1770
1771 // Run statement.
1773 where_values);
1774
1775 return (result);
1776}
1777
1779CqlHostDataSourceImpl::get6(const SubnetID& subnet_id, const IOAddress& address) const {
1780 // Convert to CQL data types.
1781 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
1782 std::string reserved_ipv6_prefix_address = address.toText();
1783
1784 // Bind to array.
1785 AnyArray where_values;
1786 where_values.add(&host_ipv6_subnet_id);
1787 where_values.add(&reserved_ipv6_prefix_address);
1788
1789 // Run statement.
1791 where_values);
1792
1793 return (result);
1794}
1795
1798 const uint8_t* identifier_begin,
1799 const size_t identifier_len) const {
1800 // Convert to CQL data types.
1801 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
1802 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
1803
1804 // Bind to array.
1805 AnyArray where_values;
1806 where_values.add(&host_identifier);
1807 where_values.add(&host_identifier_type);
1808
1809 // Run statement.
1811 where_values);
1812
1813 return (result);
1814}
1815
1818 // Convert to CQL data types.
1819 cass_int32_t host_ipv4_address = static_cast<cass_int32_t>(address.toUint32());
1820
1821 // Bind to array.
1822 AnyArray where_values;
1823 where_values.add(&host_ipv4_address);
1824
1825 // Run statement.
1827 where_values);
1828
1829 return (result);
1830}
1831
1834
1835 // Bind to array.
1836 AnyArray where_values;
1837
1838 // Run statement.
1840
1841 return (result);
1842}
1843
1844std::string
1846 std::string name;
1847 try {
1848 name = dbconn_.getParameter("name");
1849 } catch (...) {
1850 // Return an empty name.
1851 }
1852 return (name);
1853}
1854
1857 std::unique_ptr<CqlVersionExchange> version_exchange(new CqlVersionExchange());
1858 return (version_exchange->retrieveVersion(dbconn_));
1859}
1860
1861bool
1863 const HostPtr& host,
1864 const IPv6Resrv* const reservation,
1865 const std::list<std::string>& option_spaces,
1866 const ConstCfgOptionPtr cfg_option) {
1867 // If there is no host, there is nothing to do.
1868 if (!host) {
1869 return (false);
1870 }
1871
1872 bool result = true;
1873
1874 // For each option space retrieve all options and insert them into
1875 // the database.
1876 bool option_found = false;
1877 for (const std::string& space : option_spaces) {
1878 if (!result) {
1879 break;
1880 }
1881 OptionContainerPtr options = cfg_option->getAll(space);
1882 if (options && !options->empty()) {
1883 for (const OptionDescriptor& option : *options) {
1884 if (!result) {
1885 break;
1886 }
1887 option_found = true;
1889 result = insertOrDeleteHost(insert, host, OptionalValue<SubnetID>(), reservation,
1890 space, option);
1891 }
1892 }
1893 }
1894 if (result && !option_found) {
1895 // @todo: Assign actual value to subnet id.
1896 result = insertOrDeleteHost(insert, host, OptionalValue<SubnetID>(), reservation);
1897 }
1898
1899 return (result);
1900}
1901
1902bool
1904 const HostPtr& host,
1905 const IPv6Resrv* const reservation,
1906 const std::list<std::string>& option_spaces4,
1907 const ConstCfgOptionPtr cfg_option4,
1908 const std::list<std::string>& option_spaces6,
1909 const ConstCfgOptionPtr cfg_option6) {
1910 // If there is no host, there is nothing to do.
1911 if (!host) {
1912 return (false);
1913 }
1914
1915 bool result = true;
1916
1917 // If host has no reservation, add entries with null reservation.
1918 // Options could still be present.
1919 if (result && cfg_option4 && !cfg_option4->empty()) {
1920 result = insertOrDeleteHostWithOptions(insert, host, reservation, option_spaces4, cfg_option4);
1921 }
1922 if (result && cfg_option6 && !cfg_option6->empty()) {
1923 result = insertOrDeleteHostWithOptions(insert, host, reservation, option_spaces6, cfg_option6);
1924 }
1925 if (result &&
1926 (!cfg_option4 || cfg_option4->empty()) &&
1927 (!cfg_option6 || cfg_option6->empty())) {
1928 result = insertOrDeleteHostWithOptions(insert, host, reservation);
1929 }
1930
1931 return (result);
1932}
1933
1936 AnyArray& where_values) const {
1937 ConstHostCollection collection = getHostCollection(statement_tag, where_values);
1938
1939 if (collection.empty()) {
1940 return (ConstHostPtr());
1941 }
1942
1943 if (collection.size() >= 2u) {
1944 isc_throw(MultipleRecords, "CqlHostDataSourceImpl::getHost(): multiple records were "
1945 "found in the database where only one was expected for statement "
1946 << statement_tag);
1947 }
1948
1949 return (*collection.begin());
1950}
1951
1954 AnyArray& where_values) const {
1955
1956 // Run statement.
1957 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
1958 AnyArray collection = host_exchange->executeSelect(dbconn_, where_values,
1959 statement_tag, false);
1960
1961 // Form HostPtr objects.
1962 HostCollection host_collection;
1963 for (boost::any& host : collection) {
1964 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
1965 }
1966
1967 // Merge the denormalized table entries that belong to the same host
1968 // into a
1969 // single host.
1970 HostMap map;
1971 for (HostPtr& host : host_collection) {
1972
1973 HostKey key = HostKey(host->getIdentifier(), host->getIdentifierType(),
1974 host->getIPv4SubnetID(), host->getIPv6SubnetID(),
1975 host->getIPv4Reservation());
1976 if (map.find(key) == map.end()) {
1977 map[key] = host;
1978 } else {
1979 mergeHosts(host, map[key]);
1980 }
1981 }
1982
1983 ConstHostCollection result_collection;
1984 for (HostPair pair : map) {
1985 result_collection.push_back(pair.second);
1986 }
1987 return (result_collection);
1988}
1989
1990bool
1992 const HostPtr& host,
1993 const OptionalValue<SubnetID>& subnet_id,
1994 const IPv6Resrv* const reservation,
1995 const std::string& option_space,
1996 const OptionDescriptor& option_descriptor) {
1997 // If there is no host, there is nothing to do.
1998 if (!host) {
1999 return (false);
2000 }
2001
2002 AnyArray assigned_values;
2003
2004 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
2005
2006 try {
2007 if (insert) {
2008 host_exchange->createBindForMutation(host, subnet_id, reservation, option_space,
2009 option_descriptor, CqlHostExchange::INSERT_HOST, assigned_values);
2010
2011
2012 host_exchange->executeMutation(dbconn_, assigned_values, CqlHostExchange::INSERT_HOST);
2013 } else {
2014 host_exchange->createBindForDelete(host, subnet_id, reservation, option_space,
2015 option_descriptor, CqlHostExchange::DELETE_HOST, assigned_values);
2016
2017 host_exchange->executeMutation(dbconn_, assigned_values, CqlHostExchange::DELETE_HOST);
2018 }
2019 } catch (const StatementNotApplied& exception) {
2020 if (insert) {
2021 isc_throw(DuplicateEntry, exception.what());
2022 } else {
2023 return (false);
2024 }
2025 }
2026
2027 return (true);
2028}
2029
2030void
2032 HostPtr& target_host) const {
2033 // Merge reservations.
2034 const IPv6ResrvRange reservations_range =
2035 source_host->getIPv6Reservations();
2036 if (std::distance(reservations_range.first, reservations_range.second) > 0) {
2037 for (IPv6ResrvIterator reservations_iterator = reservations_range.first;
2038 reservations_iterator != reservations_range.second;
2039 ++reservations_iterator) {
2040 if (!target_host->hasReservation(reservations_iterator->second)) {
2041 target_host->addReservation(reservations_iterator->second);
2042 }
2043 }
2044 }
2045
2046 // Merge DHCPv4 options.
2047 source_host->getCfgOption4()->mergeTo(*target_host->getCfgOption4());
2048
2049 // Merge DHCPv6 options.
2050 source_host->getCfgOption6()->mergeTo(*target_host->getCfgOption6());
2051}
2052
2054 : impl_(new CqlHostDataSourceImpl(parameters)) {
2055}
2056
2058 delete impl_;
2059}
2060
2061void
2063 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_ADD);
2064
2065 impl_->insertOrDelete(host, true);
2066}
2067
2068bool
2069CqlHostDataSource::del(const SubnetID& subnet_id, const asiolink::IOAddress& address) {
2070 HostPtr host = boost::const_pointer_cast<Host>(impl_->get4(subnet_id, address));
2071
2072 return (host ? impl_->insertOrDelete(host, false) : false);
2073}
2074
2075bool
2076CqlHostDataSource::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
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));
2080
2081 return (host ? impl_->insertOrDelete(host, false) : false);
2082}
2083
2084bool
2085CqlHostDataSource::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
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));
2089
2090 return (host ? impl_->insertOrDelete(host, false) : false);
2091}
2092
2095 const uint8_t* identifier_begin,
2096 const size_t identifier_len) const {
2097 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
2098
2099 return (impl_->getAll(identifier_type, identifier_begin, identifier_len));
2100}
2101
2104 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
2105
2106 return (impl_->getAll4(address));
2107}
2108
2111 const Host::IdentifierType& identifier_type,
2112 const uint8_t* identifier_begin,
2113 const size_t identifier_len) const {
2114 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET4);
2115
2116 return (impl_->get4(subnet_id, identifier_type, identifier_begin,
2117 identifier_len));
2118}
2119
2122 const asiolink::IOAddress& address) const {
2123 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET4);
2124
2125 return (impl_->get4(subnet_id, address));
2126}
2127
2130 const Host::IdentifierType& identifier_type,
2131 const uint8_t* identifier_begin,
2132 const size_t identifier_len) const {
2133 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET6);
2134
2135 return (impl_->get6(subnet_id, identifier_type, identifier_begin, identifier_len));
2136}
2137
2140 const uint8_t prefix_len) const {
2141 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET6);
2142
2143 return (impl_->get6(prefix, prefix_len));
2144}
2145
2148 const asiolink::IOAddress& address) const {
2149 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET6);
2150
2151 return (impl_->get6(subnet_id, address));
2152}
2153
2156 return (impl_->getAllHosts());
2157}
2158
2159std::string
2161 return std::string("cql");
2162}
2163
2164std::string
2166 return (impl_->getName());
2167}
2168
2169std::string
2171 return std::string("Host data source that stores host information in the CQL database");
2172}
2173
2176 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_DB_GET_VERSION);
2177
2178 return impl_->getVersion();
2179}
2180
2181void
2184}
2185
2186void
2188 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_ROLLBACK);
2189}
2190
2191} // namespace dhcp
2192} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition: data.cc:750
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
Definition: data.h:43
Structure used to bind C++ input values to dynamic CQL parameters.
Definition: cql_exchange.h:50
void add(const boost::any &value)
Add a value at the end of the vector.
Common CQL connector pool.
void openDatabase()
Open database.
void prepareStatements(StatementMap &statements)
Prepare statements.
Cassandra Exchange.
Definition: cql_exchange.h:142
Exchange used to retrieve schema version from the keyspace.
Definition: cql_exchange.h:236
static StatementMap tagged_statements_
Cassandra statements.
Definition: cql_exchange.h:280
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Database duplicate entry error.
Definition: db_exceptions.h:42
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
Database statement not applied.
Definition: db_exceptions.h:20
Authentication keys.
Definition: host.h:34
Implementation of the CqlHostDataSource.
virtual ConstHostCollection getAllHosts() const
Implementation of CqlHostDataSource::getAllHosts()
virtual ConstHostPtr get6(const asiolink::IOAddress &prefix, const uint8_t prefix_len) const
Retrieves a host by its reserved IPv6 address or prefix.
virtual ConstHostPtr getHost(StatementTag statement_tag, AnyArray &where_values) const
Retrieves a single host.
CqlHostDataSourceImpl(const CqlConnection::ParameterMap &parameters)
Constructor.
virtual VersionPair getVersion() const
Implementation of CqlHostDataSource::getVersion()
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.
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Implementation of CqlHostDataSource::getAll()
virtual bool insertOrDelete(const HostPtr &host, bool insert)
Implementation of CqlHostDataSource::add() and del()
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.
virtual ConstHostPtr get4(const SubnetID &subnet_id, const asiolink::IOAddress &address) const
Implementation of CqlHostDataSource::get4()
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.
virtual ConstHostCollection getHostCollection(StatementTag statement_tag, AnyArray &where_values) const
Retrieves a collection of hosts.
virtual std::string getName() const
Implementation of CqlHostDataSource::getName()
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Implementation of CqlHostDataSource::getAll4()
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.
CqlHostDataSource(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
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...
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).
virtual void rollback() override
Rollback Transactions.
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const override
Returns a collection of hosts using the specified IPv4 address.
virtual std::string getDescription() const
Returns textual description of the backend.
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 std::string getName() const
Returns the name of the database.
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.
virtual ~CqlHostDataSource()
Virtual destructor.
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 ConstHostCollection getAllHosts() const
Returns a collection of all the hosts.
virtual std::string getType() const override
Return backend type.
virtual void commit() override
Commit Transactions.
virtual void add(const HostPtr &host) override
Adds a new host to the collection.
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr) override
Attempts to delete a host by (subnet-id, address)
virtual db::VersionPair getVersion() const
Retrieves schema version from the DB.
Provides mechanisms for sending and retrieving data from the host_reservations table.
static constexpr StatementTag GET_HOST
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 constexpr StatementTag INSERT_HOST
Statement tags definitions.
static constexpr StatementTag GET_HOST_BY_IPV6_PREFIX
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.
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS
static StatementMap tagged_statements_
Cassandra statements.
static constexpr StatementTag GET_HOST_BY_HOST_ID
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override
Binds member variables to data array to receive Host data.
virtual boost::any retrieve() override
Copy received data into Host object.
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID
static constexpr StatementTag DELETE_HOST
const IPv6Resrv retrieveReservation() const
Creates IPv6 reservation from the data contained in the currently processed row.
virtual ~CqlHostExchange()
Virtual destructor.
cass_int64_t hashIntoId() const
Create unique hash for storage in table id.
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.
const OptionWrapper retrieveOption() const
Retrieves option from members.
static constexpr StatementTag GET_HOST_BY_IPV4_ADDRESS
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:74
static const size_t MAX_DUID_LEN
maximum duid size As defined in RFC 8415, section 11.1
Definition: duid.h:31
Represents a device with IPv4 and/or IPv6 reservations.
Definition: host.h:242
void setHostId(HostID id)
Sets Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
Definition: host.h:610
CfgOptionPtr getCfgOption4()
Returns pointer to the DHCPv4 option data configuration for this host.
Definition: host.h:580
IdentifierType
Type of the host identifier.
Definition: host.h:252
@ IDENT_FLEX
Flexible host identifier.
Definition: host.h:257
void addReservation(const IPv6Resrv &reservation)
Adds new IPv6 reservation.
Definition: host.cc:363
CfgOptionPtr getCfgOption6()
Returns pointer to the DHCPv6 option data configuration for this host.
Definition: host.h:595
bool hasReservation(const IPv6Resrv &reservation) const
Checks if specified IPv6 reservation exists for the host.
Definition: host.cc:391
IPv6 reservation for a host.
Definition: host.h:106
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Definition: host.h:135
Type getType() const
Returns reservation type.
Definition: host.h:149
Type
Type of the reservation.
Definition: host.h:112
uint8_t getPrefixLen() const
Returns prefix length.
Definition: host.h:140
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:144
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.
Definition: libdhcp++.cc:184
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:916
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
Definition: libdhcp++.cc:205
Option descriptor.
Definition: cfg_option.h:35
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:59
bool persistent_
Persistence flag.
Definition: cfg_option.h:44
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
Simple class representing an optional value.
bool isSpecified() const
Checks if the value is specified or unspecified.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
char const *const StatementTag
Statement index representing the statement name.
std::vector< cass_byte_t > CassBlob
Host identifier converted to Cassandra data type.
Definition: cql_exchange.h:37
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR
Define CQL schema version: 3.0.
std::unordered_map< StatementTag, CqlTaggedStatement, StatementTagHash, StatementTagEqual > StatementMap
A container for all statements.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
Definition: host.h:186
std::pair< uint32_t, uint32_t > VersionPair
Pair containing major and minor versions.
Definition: lease_mgr.h:40
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition: host.h:725
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition: host.h:731
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition: host.h:188
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:734
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
bool operator==(const HostKey &key1, const HostKey &key2)
equals operator for HostKey
boost::shared_ptr< OptionDescriptor > OptionDescriptorPtr
A pointer to option descriptor.
Definition: cfg_option.h:132
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
std::size_t hash_value(const HostKey &key)
hash function for HostMap
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:728
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
boost::shared_ptr< Option > OptionPtr
Definition: option.h:38
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:500
Definition: edns.h:19
Defines the logger used by the top-level component of kea-dhcp-ddns.
#define DHCP4_OPTION_SPACE
Definition: option_space.h:16
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition: user_context.h:24
void setContext(const data::ConstElementPtr &ctx)
Sets user context.
Definition: user_context.h:30
static uint64_t hash(const uint8_t *data, size_t length)
Compute the hash.
Definition: hash.h:27