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>
21 #include <database/db_exceptions.h>
23 #include <dhcp/duid.h>
24 #include <dhcp/libdhcp++.h>
25 #include <dhcp/option.h>
26 #include <dhcp/option_definition.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 
46 using namespace isc::asiolink;
47 using namespace isc::db;
48 using namespace isc::dhcp;
49 using namespace isc::util;
50 using namespace isc::data;
51 
52 namespace {
53 
55 typedef std::vector<uint8_t> HostIdentifier;
56 
60 typedef std::
61  tuple<HostIdentifier, Host::IdentifierType, SubnetID, SubnetID, IOAddress> HostKey;
62 
64 enum HostKeyComponent {
65  HOST_IDENTIFIER,
66  HOST_IDENTIFIER_TYPE,
67  IPv4_SUBNET_ID,
68  IPv6_SUBNET_ID,
69  IPv4_RESERVATION
70 };
71 
74 typedef std::unordered_map<HostKey, HostPtr, boost::hash<HostKey>> HostMap;
75 
77 typedef std::pair<HostKey, HostPtr> HostPair;
78 
80 struct 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 
90 static constexpr size_t CLIENT_CLASSES_MAX_LENGTH = 255u;
91 
95 static constexpr size_t HOSTNAME_MAX_LENGTH = 255u;
96 
98 static constexpr size_t OPTION_VALUE_MAX_LENGTH = 4096u;
99 
101 static constexpr size_t OPTION_FORMATTED_VALUE_MAX_LENGTH = 8192u;
102 
104 static constexpr size_t OPTION_SPACE_MAX_LENGTH = 128u;
105 
109 static constexpr cass_int32_t MAX_IDENTIFIER_TYPE = static_cast<cass_int32_t>(Host::IDENT_FLEX);
110 
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;
122 static const CassBlob NULL_OPTION_VALUE = CassBlob();
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;
131 
134 static const IPv6Resrv NULL_IPV6_RESERVATION =
135  IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("::"), 128);
136 
137 } // namespace
138 
139 namespace isc {
140 namespace dhcp {
141 
144 class CqlHostExchange : public virtual CqlExchange {
145 public:
149  CqlHostExchange();
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.
273  static constexpr StatementTag GET_HOST_BY_HOST_ID =
274  "GET_HOST_BY_HOST_ID";
275 
276  // Retrieves host information along with the IPv4 options associated
277  // with it.
278  static constexpr StatementTag GET_HOST_BY_IPV4_ADDRESS =
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).
283  static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID =
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).
289  static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID =
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.
294  static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS =
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.
303  static constexpr StatementTag GET_HOST_BY_IPV6_PREFIX =
304  "GET_HOST_BY_IPV6_PREFIX";
305 
306  // Retrieves host information and IPv6 options for the host using subnet
307  // identifier and IPv6 reservation.
308  static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS =
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 
319 private:
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 
413 constexpr StatementTag CqlHostExchange::INSERT_HOST;
414 constexpr StatementTag CqlHostExchange::GET_HOST;
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;
422 constexpr StatementTag CqlHostExchange::DELETE_HOST;
423 
424 StatementMap CqlHostExchange::tagged_statements_ = {
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 
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),
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 
788 void
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 
857 void
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 
1048 void
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 
1104 void
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 
1129 cass_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 
1163 boost::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 
1230 const 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 
1253 const 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 
1347 public:
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 
1451 protected:
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 
1513  virtual ConstHostCollection getHostCollection(StatementTag statement_tag,
1514  AnyArray& where_values) const;
1515 
1530  virtual bool insertOrDeleteHost(bool insert,
1531  const HostPtr& host,
1532  const OptionalValue<SubnetID>& subnet_id = OptionalValue<SubnetID>(),
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 
1548 private:
1550  mutable CqlConnection dbconn_;
1551 }; // class CqlHostDataSourceImpl
1552 
1561 std::size_t
1562 hash_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 
1584 bool
1585 operator==(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 
1594 CqlHostDataSourceImpl::CqlHostDataSourceImpl(const CqlConnection::ParameterMap& parameters)
1595  : dbconn_(parameters) {
1596  // Open the database.
1597  dbconn_.openDatabase();
1598 
1599  // Prepare the version exchange first.
1600  dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
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 
1622 bool
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 
1667 CqlHostDataSourceImpl::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.
1726  host = getHost(CqlHostExchange::GET_HOST_BY_IPV6_PREFIX, where_values);
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 
1779 CqlHostDataSourceImpl::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 
1844 std::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 
1861 bool
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 
1902 bool
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 
1990 bool
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 
2030 void
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 
2053 CqlHostDataSource::CqlHostDataSource(const CqlConnection::ParameterMap& parameters)
2054  : impl_(new CqlHostDataSourceImpl(parameters)) {
2055 }
2056 
2058  delete impl_;
2059 }
2060 
2061 void
2063  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_ADD);
2064 
2065  impl_->insertOrDelete(host, true);
2066 }
2067 
2068 bool
2069 CqlHostDataSource::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 
2075 bool
2076 CqlHostDataSource::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 
2084 bool
2085 CqlHostDataSource::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 
2159 std::string
2161  return std::string("cql");
2162 }
2163 
2164 std::string
2166  return (impl_->getName());
2167 }
2168 
2169 std::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 
2181 void
2183  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_COMMIT);
2184 }
2185 
2186 void
2188  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_ROLLBACK);
2189 }
2190 
2191 } // namespace dhcp
2192 } // namespace isc
isc::dhcp::CqlHostDataSource::getName
virtual std::string getName() const
Returns the name of the database.
Definition: cql_host_data_source.cc:2165
isc::dhcp::hash_value
std::size_t hash_value(const HostKey &key)
hash function for HostMap
Definition: cql_host_data_source.cc:1562
isc::dhcp::OptionContainerPtr
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
isc::dhcp::IPv6Resrv::getType
Type getType() const
Returns reservation type.
Definition: host.h:149
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
optional_value.h
isc::util::OptionalValue
Simple class representing an optional value.
Definition: optional_value.h:55
isc::dhcp::CqlHostExchange::retrieveOption
const OptionWrapper retrieveOption() const
Retrieves option from members.
Definition: cql_host_data_source.cc:1254
isc::dhcp::AuthKey
Authentication keys.
Definition: host.h:34
isc::dhcp::ConstCfgOptionPtr
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:500
isc::dhcp::OptionDefinitionPtr
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
Definition: option_definition.h:51
isc::db::CqlVersionExchange::retrieveVersion
virtual VersionPair retrieveVersion(const CqlConnection &connection)
Standalone method used to retrieve schema version.
Definition: cql_exchange.cc:995
isc::dhcp::CqlHostDataSource::getAll
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...
Definition: cql_host_data_source.cc:2094
isc::dhcp::Host::IdentifierType
IdentifierType
Type of the host identifier.
Definition: host.h:252
isc::dhcp::LibDHCP::optionSpaceToVendorId
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:916
isc::dhcp::CqlHostDataSourceImpl::getAll
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Implementation of CqlHostDataSource::getAll()
Definition: cql_host_data_source.cc:1797
isc::db
Definition: cql_connection.cc:29
isc::db::AnyArray::add
void add(const boost::any &value)
Add a value at the end of the vector.
Definition: cql_exchange.cc:165
libdhcp++.h
io_address.h
duid.h
isc::dhcp::CqlHostDataSource::CqlHostDataSource
CqlHostDataSource(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
Definition: cql_host_data_source.cc:2053
isc::util::OptionalValue::isSpecified
bool isSpecified() const
Checks if the value is specified or unspecified.
Definition: optional_value.h:110
isc::db::CqlVersionExchange
Exchange used to retrieve schema version from the keyspace.
Definition: cql_exchange.h:236
isc::dhcp::CqlHostDataSource::rollback
virtual void rollback() override
Rollback Transactions.
Definition: cql_host_data_source.cc:2187
isc::db::StatementNotApplied
Database statement not applied.
Definition: db_exceptions.h:20
isc::dhcp::DHCPSRV_DBG_TRACE_DETAIL
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
isc::db::AnyArray
Structure used to bind C++ input values to dynamic CQL parameters.
Definition: cql_exchange.h:50
cql_host_data_source.h
isc::dhcp::CqlHostDataSourceImpl::getHostCollection
virtual ConstHostCollection getHostCollection(StatementTag statement_tag, AnyArray &where_values) const
Retrieves a collection of hosts.
Definition: cql_host_data_source.cc:1953
DHCP6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17
isc::dhcp::Host
Represents a device with IPv4 and/or IPv6 reservations.
Definition: host.h:242
isc::dhcp::CqlHostExchange::GET_HOST_BY_IPV4_ADDRESS
static constexpr StatementTag GET_HOST_BY_IPV4_ADDRESS
Definition: cql_host_data_source.cc:278
db_exceptions.h
isc::dhcp::CqlHostDataSourceImpl::insertOrDelete
virtual bool insertOrDelete(const HostPtr &host, bool insert)
Implementation of CqlHostDataSource::add() and del()
Definition: cql_host_data_source.cc:1623
isc::dhcp::LibDHCP::getRuntimeOptionDef
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
isc::dhcp::CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID
Definition: cql_host_data_source.cc:289
isc::dhcp::HostPtr
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition: host.h:725
isc::dhcp::Host::hasReservation
bool hasReservation(const IPv6Resrv &reservation) const
Checks if specified IPv6 reservation exists for the host.
Definition: host.cc:391
isc::dhcp::CqlHostDataSourceImpl::get4
virtual ConstHostPtr get4(const SubnetID &subnet_id, const asiolink::IOAddress &address) const
Implementation of CqlHostDataSource::get4()
Definition: cql_host_data_source.cc:1667
isc::dhcp::CqlHostDataSource::commit
virtual void commit() override
Commit Transactions.
Definition: cql_host_data_source.cc:2182
isc::data
Definition: cfg_to_element.h:25
isc::db::CqlExchange
Cassandra Exchange.
Definition: cql_exchange.h:142
isc::dhcp::VersionPair
std::pair< uint32_t, uint32_t > VersionPair
Pair containing major and minor versions.
Definition: lease_mgr.h:40
isc::db::CqlConnection::openDatabase
void openDatabase()
Open database.
Definition: cql_connection.cc:78
isc::dhcp::CqlHostDataSource::del4
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).
Definition: cql_host_data_source.cc:2076
isc::dhcp::IPv6Resrv::TYPE_NA
@ TYPE_NA
Definition: host.h:113
isc::dhcp::OptionDescriptor::persistent_
bool persistent_
Persistence flag.
Definition: cfg_option.h:44
isc::Exception
This is a base class for exceptions thrown from the DNS library module.
Definition: exceptions/exceptions.h:23
isc::dhcp::CqlHostExchange::~CqlHostExchange
virtual ~CqlHostExchange()
Virtual destructor.
Definition: cql_host_data_source.cc:785
isc::data::UserContext::getContext
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition: user_context.h:24
isc::dhcp::IPv6Resrv::getPrefix
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Definition: host.h:135
isc::dhcp::CqlHostDataSourceImpl::getVersion
virtual VersionPair getVersion() const
Implementation of CqlHostDataSource::getVersion()
Definition: cql_host_data_source.cc:1856
isc::util
Definition: edns.h:19
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dhcp::CqlHostExchange
Provides mechanisms for sending and retrieving data from the host_reservations table.
Definition: cql_host_data_source.cc:144
isc::db::DatabaseConnection::getParameter
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
Definition: database_connection.cc:28
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc::dhcp::IPv6Resrv::Type
Type
Type of the reservation.
Definition: host.h:112
isc::db::DbOperationError
Exception thrown on failure to execute a database function.
Definition: database_connection.h:36
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::dhcp::operator==
bool operator==(const HostKey &key1, const HostKey &key2)
equals operator for HostKey
Definition: cql_host_data_source.cc:1585
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::dhcp::CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS
Definition: cql_host_data_source.cc:294
isc::dhcp::CqlHostDataSource::getAll4
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const override
Returns a collection of hosts using the specified IPv4 address.
Definition: cql_host_data_source.cc:2103
isc::dhcp::CqlHostExchange::GET_HOST_BY_HOST_ID
static constexpr StatementTag GET_HOST_BY_HOST_ID
Definition: cql_host_data_source.cc:273
isc::dhcp::CqlHostExchange::GET_HOST
static constexpr StatementTag GET_HOST
Definition: cql_host_data_source.cc:268
isc::db::CqlConnection
Common CQL connector pool.
Definition: cql_connection.h:119
dhcpsrv_log.h
isc::dhcp::CqlHostDataSource::get6
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.
Definition: cql_host_data_source.cc:2129
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp::CqlHostExchange::DELETE_HOST
static constexpr StatementTag DELETE_HOST
Definition: cql_host_data_source.cc:312
isc::dhcp::CqlHostDataSourceImpl::get6
virtual ConstHostPtr get6(const asiolink::IOAddress &prefix, const uint8_t prefix_len) const
Retrieves a host by its reserved IPv6 address or prefix.
Definition: cql_host_data_source.cc:1713
isc::dhcp::CqlHostDataSourceImpl::getAllHosts
virtual ConstHostCollection getAllHosts() const
Implementation of CqlHostDataSource::getAllHosts()
Definition: cql_host_data_source.cc:1833
isc::dhcp::CqlHostDataSourceImpl::getAll4
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Implementation of CqlHostDataSource::getAll4()
Definition: cql_host_data_source.cc:1817
isc::dhcp::CqlHostDataSource::del
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr) override
Attempts to delete a host by (subnet-id, address)
Definition: cql_host_data_source.cc:2069
isc::dhcp::IPv6Resrv
IPv6 reservation for a host.
Definition: host.h:106
isc::util::OutputBuffer::getLength
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
isc::dhcp::DUID::toText
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:74
isc::db::StatementTag
char const *const StatementTag
Statement index representing the statement name.
Definition: cql_connection.h:43
isc::dhcp
Definition: ctrl_dhcp4_srv.cc:75
isc::dhcp::LibDHCP::getOptionDef
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
cfg_option.h
DHCP4_OPTION_SPACE
#define DHCP4_OPTION_SPACE
Definition: option_space.h:16
isc::data::JSONError
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
Definition: data.h:43
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
isc::db::CqlConnection::prepareStatements
void prepareStatements(StatementMap &statements)
Prepare statements.
Definition: cql_connection.cc:315
isc::dhcp::CqlHostDataSource::del6
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).
Definition: cql_host_data_source.cc:2085
option_definition.h
isc::dhcp::LibDHCP::getVendorOptionDef
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
isc::dhcp::Host::addReservation
void addReservation(const IPv6Resrv &reservation)
Adds new IPv6 reservation.
Definition: host.cc:363
isc::db::MultipleRecords
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
isc::dhcp::CqlHostDataSourceImpl::~CqlHostDataSourceImpl
virtual ~CqlHostDataSourceImpl()
Destructor.
Definition: cql_host_data_source.cc:1617
isc::data::UserContext::setContext
void setContext(const data::ConstElementPtr &ctx)
Sets user context.
Definition: user_context.h:30
isc::dhcp::CqlHostExchange::tagged_statements_
static StatementMap tagged_statements_
Cassandra statements.
Definition: cql_host_data_source.cc:317
isc::dhcp::CqlHostDataSource::add
virtual void add(const HostPtr &host) override
Adds a new host to the collection.
Definition: cql_host_data_source.cc:2062
isc::dhcp::CqlHostDataSourceImpl::insertOrDeleteHostWithReservations
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.
Definition: cql_host_data_source.cc:1903
buffer.h
isc::db::CassBlob
std::vector< cass_byte_t > CassBlob
Host identifier converted to Cassandra data type.
Definition: cql_exchange.h:37
isc::db::CqlExchange::executeMutation
void executeMutation(const CqlConnection &connection, const AnyArray &assigned_values, StatementTag statement_tag)
Executes INSERT, UPDATE or DELETE statements.
Definition: cql_exchange.cc:873
isc::dhcp::OptionDescriptor::option_
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
isc::dhcp::IPv6Resrv::TYPE_PD
@ TYPE_PD
Definition: host.h:114
isc::dhcp::CqlHostExchange::GET_HOST_BY_IPV6_PREFIX
static constexpr StatementTag GET_HOST_BY_IPV6_PREFIX
Definition: cql_host_data_source.cc:303
isc::dhcp::Host::getCfgOption6
CfgOptionPtr getCfgOption6()
Returns pointer to the DHCPv6 option data configuration for this host.
Definition: host.h:595
isc::dhcp::CqlHostExchange::retrieveReservation
const IPv6Resrv retrieveReservation() const
Creates IPv6 reservation from the data contained in the currently processed row.
Definition: cql_host_data_source.cc:1231
isc::dhcp::Host::setHostId
void setHostId(HostID id)
Sets Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
Definition: host.h:610
isc::db::StatementMap
std::unordered_map< StatementTag, CqlTaggedStatement, StatementTagHash, StatementTagEqual > StatementMap
A container for all statements.
Definition: cql_connection.h:107
cfgmgr.h
isc::dhcp::DUID::MAX_DUID_LEN
static const size_t MAX_DUID_LEN
maximum duid size As defined in RFC 8415, section 11.1
Definition: duid.h:31
isc::db::CqlExchange::executeSelect
AnyArray executeSelect(const CqlConnection &connection, const AnyArray &where_values, StatementTag statement_tag, const bool &single=false)
Executes SELECT statements.
Definition: cql_exchange.cc:772
isc::dhcp::CqlHostExchange::createBindForSelect
virtual void createBindForSelect(AnyArray &data, StatementTag statement_tag=NULL) override
Binds member variables to data array to receive Host data.
Definition: cql_host_data_source.cc:789
isc::dhcp::Option::V6
@ V6
Definition: option.h:67
isc::dhcp::CqlHostDataSourceImpl::getName
virtual std::string getName() const
Implementation of CqlHostDataSource::getName()
Definition: cql_host_data_source.cc:1845
isc::dhcp::ConstHostCollection
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
Definition: host.h:731
isc::db::DuplicateEntry
Database duplicate entry error.
Definition: db_exceptions.h:42
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
isc::dhcp::CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID
Definition: cql_host_data_source.cc:283
isc::dhcp::ConstHostPtr
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:728
isc::dhcp::OptionDescriptor
Option descriptor.
Definition: cfg_option.h:35
isc::dhcp::CqlHostDataSourceImpl
Implementation of the CqlHostDataSource.
Definition: cql_host_data_source.cc:1346
isc::dhcp::CqlHostExchange::createBindForMutation
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.
Definition: cql_host_data_source.cc:1049
isc::db::CQL_SCHEMA_VERSION_MAJOR
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR
Define CQL schema version: 3.0.
Definition: cql_connection.h:54
isc::dhcp::CqlHostExchange::hashIntoId
cass_int64_t hashIntoId() const
Create unique hash for storage in table id.
Definition: cql_host_data_source.cc:1130
cql_exchange.h
isc::dhcp::Host::getCfgOption4
CfgOptionPtr getCfgOption4()
Returns pointer to the DHCPv4 option data configuration for this host.
Definition: host.h:580
hash.h
isc::dhcp::CqlHostDataSource::getAllHosts
virtual ConstHostCollection getAllHosts() const
Returns a collection of all the hosts.
Definition: cql_host_data_source.cc:2155
isc::dhcp::CqlHostDataSourceImpl::getHost
virtual ConstHostPtr getHost(StatementTag statement_tag, AnyArray &where_values) const
Retrieves a single host.
Definition: cql_host_data_source.cc:1935
isc::util::OutputBuffer::getData
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
isc::dhcp::IPv6Resrv::getPrefixLen
uint8_t getPrefixLen() const
Returns prefix length.
Definition: host.h:140
isc::dhcp::CqlHostExchange::INSERT_HOST
static constexpr StatementTag INSERT_HOST
Statement tags definitions.
Definition: cql_host_data_source.cc:263
isc::dhcp::CqlHostDataSourceImpl::insertOrDeleteHost
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.
Definition: cql_host_data_source.cc:1991
isc::dhcp::Option::Universe
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:67
isc::dhcp::DUID
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
isc::dhcp::CqlHostExchange::prepareExchange
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.
Definition: cql_host_data_source.cc:858
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
isc::dhcp::CqlHostExchange::retrieve
virtual boost::any retrieve() override
Copy received data into Host object.
Definition: cql_host_data_source.cc:1164
isc::dhcp::OptionDescriptorPtr
boost::shared_ptr< OptionDescriptor > OptionDescriptorPtr
A pointer to option descriptor.
Definition: cfg_option.h:132
isc::dhcp::CqlHostDataSourceImpl::insertOrDeleteHostWithOptions
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.
Definition: cql_host_data_source.cc:1862
isc::db::DbOpenError
Exception thrown on failure to open database.
Definition: database_connection.h:29
isc::dhcp::SubnetID
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
option.h
isc::db::CQL_SCHEMA_VERSION_MINOR
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR
Definition: cql_connection.h:55
isc::dhcp::CqlHostDataSourceImpl::CqlHostDataSourceImpl
CqlHostDataSourceImpl(const CqlConnection::ParameterMap &parameters)
Constructor.
Definition: cql_host_data_source.cc:1594
isc::dhcp::IPv6ResrvIterator
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
Definition: host.h:186
isc::dhcp::Option
Definition: option.h:58
isc::dhcp::CqlHostDataSource::get4
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.
Definition: cql_host_data_source.cc:2110
isc::dhcp::OptionDescriptor::formatted_value_
std::string formatted_value_
Option value in textual (CSV) format.
Definition: cfg_option.h:59
isc::dhcp::CqlHostDataSource::getType
virtual std::string getType() const override
Return backend type.
Definition: cql_host_data_source.cc:2160
isc::dhcp::Option::V4
@ V4
Definition: option.h:67
isc::dhcp::CqlHostDataSource::~CqlHostDataSource
virtual ~CqlHostDataSource()
Virtual destructor.
Definition: cql_host_data_source.cc:2057
isc::dhcp::dhcpsrv_logger
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
isc::dhcp::CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS
Definition: cql_host_data_source.cc:308
isc::dhcp::CqlHostDataSource::getVersion
virtual db::VersionPair getVersion() const
Retrieves schema version from the DB.
Definition: cql_host_data_source.cc:2175
isc::dhcp::CqlHostDataSourceImpl::mergeHosts
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.
Definition: cql_host_data_source.cc:2031
isc::dhcp::IPv6ResrvRange
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition: host.h:188
isc::dhcp::CqlHostExchange::createBindForDelete
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.
Definition: cql_host_data_source.cc:1105
isc::dhcp::CqlHostDataSource::getDescription
virtual std::string getDescription() const
Returns textual description of the backend.
Definition: cql_host_data_source.cc:2170
isc::dhcp::HostCollection
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:734