1 // Copyright (C) 2018-2021 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>
22 #include <dhcpsrv/cql_host_data_source.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.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
54 /// @brief Host identifier consisting of DUID or hardware address
55 typedef std::vector<uint8_t> HostIdentifier;
56
57 /// @brief key for HostMap containing objects which uniquely identify a
58 /// host: host identifier, host identifier type, subnets for IPv4 and IPv6
59 /// and the IPv4 reservation
60 typedef std::
61 tuple<HostIdentifier, Host::IdentifierType, SubnetID, SubnetID, IOAddress> HostKey;
62
63 /// @brief Identifies components of the host key
64 enum HostKeyComponent {
65 HOST_IDENTIFIER,
66 HOST_IDENTIFIER_TYPE,
67 IPv4_SUBNET_ID,
68 IPv6_SUBNET_ID,
69 IPv4_RESERVATION
70 };
71
72 /// @brief Map used to merge reservations and options into a single host on
73 /// retrieve from database
74 typedef std::unordered_map<HostKey, HostPtr, boost::hash<HostKey>> HostMap;
75
76 /// @brief A pair of (host key and a pointer to a host)
77 typedef std::pair<HostKey, HostPtr> HostPair;
78
79 /// @brief Wrapper used to specify option space alongside option descriptor
80 struct OptionWrapper {
OptionWrapper__anond1ec75dc0111::OptionWrapper81 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
88 /// @brief Numeric value representing the last supported identifier. This value
89 /// is used to validate whether the identifier type stored in a database is
90 /// within bounds of supported identifiers.
91 static constexpr cass_int32_t MAX_IDENTIFIER_TYPE = static_cast<cass_int32_t>(Host::IDENT_FLEX);
92
93 /// @{
94 /// @brief Invalid values in the Cassandra database
95 static constexpr char NULL_DHCP4_SERVER_HOSTNAME[] = "";
96 static constexpr char NULL_DHCP4_BOOT_FILE_NAME[] = "";
97 static constexpr char NULL_USER_CONTEXT[] = "";
98 static constexpr char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] = "::";
99 static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
100 static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
101 static constexpr cass_int32_t NULL_IAID = -1;
102 static constexpr cass_int32_t NULL_OPTION_UNIVERSE = -1;
103 static constexpr cass_int32_t NULL_OPTION_CODE = -1;
104 static const CassBlob NULL_OPTION_VALUE = CassBlob();
105 static constexpr char NULL_OPTION_FORMATTED_VALUE[] = "";
106 static constexpr char NULL_OPTION_SPACE[] = "";
107 static constexpr cass_bool_t NULL_OPTION_IS_PERSISTENT = cass_false;
108 static constexpr char NULL_OPTION_CLIENT_CLASS[] = "";
109 static constexpr cass_int32_t NULL_OPTION_SUBNET_ID = -1;
110 static constexpr char NULL_OPTION_USER_CONTEXT[] = "";
111 static constexpr cass_int32_t NULL_OPTION_SCOPE_ID = -1;
112 /// @}
113
114 /// @brief Invalid reservation used to check for an invalid IPv6Resrv formed
115 /// from database values.
116 static const IPv6Resrv NULL_IPV6_RESERVATION =
117 IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("::"), 128);
118
119 } // namespace
120
121 namespace isc {
122 namespace dhcp {
123
124 /// @brief Provides mechanisms for sending and retrieving data from the
125 /// hosts table.
126 class CqlHostExchange : public virtual CqlExchange {
127 public:
128 /// @brief Constructor
129 ///
130 /// Specifies table columns.
131 CqlHostExchange();
132
133 /// @brief Virtual destructor.
134 virtual ~CqlHostExchange();
135
136 /// @brief Binds member variables to data array to receive @ref Host data.
137 ///
138 /// Creates a bind array to receive @ref Host data from the Cassandra
139 /// database. After data is successfully received, @ref retrieve() can be
140 /// called to retrieve the @ref Host object. Called in @ref
141 /// db::CqlExchange::executeSelect().
142 ///
143 /// @param data array of objects representing data being retrieved
144 /// @param statement_tag prepared statement being executed; defaults to an
145 /// invalid statement
146 virtual void
147 createBindForSelect(AnyArray& data, StatementTag statement_tag = NULL) override;
148
149 /// @brief Sets the exchange members with data of @ref Host.
150 ///
151 /// Fills in the members of the exchange with data from @ref Host object.
152 ///
153 /// @param host @ref Host object being modified in the Cassandra database
154 /// @param subnet_id identifier of the subnet to which the host belongs
155 /// @param reservation IPv6 reservation belonging to the host
156 /// @param option_space option space
157 /// @param option_descriptor structure used to hold option information
158 void prepareExchange(const HostPtr& host,
159 const Optional<SubnetID>& subnet_id,
160 const IPv6Resrv* const reservation,
161 const std::string& option_space,
162 const OptionDescriptor& option_descriptor);
163
164 /// @brief Binds @ref Host to data array to send data to the Cassandra
165 /// database.
166 ///
167 /// Fills in the bind array for sending data stored in the @ref Host object
168 /// to the database.
169 ///
170 /// @param host @ref Host object being added to the Cassandra database
171 /// @param subnet_id identifier of the subnet to which the host belongs
172 /// @param reservation IPv6 reservation belonging to the host
173 /// @param option_space option space
174 /// @param option_descriptor structure used to hold option information
175 /// @param statement_tag tag of the statement being executed
176 /// @param data array being filled with data from to the Host object
177 void createBindForMutation(const HostPtr& host,
178 const Optional<SubnetID>& subnet_id,
179 const IPv6Resrv* const reservation,
180 const std::string& option_space,
181 const OptionDescriptor& option_descriptor,
182 StatementTag statement_tag,
183 AnyArray& data);
184
185 /// @brief Binds @ref Host to data array to send data to the Cassandra
186 /// database.
187 ///
188 /// Fills in the bind array for sending data stored in the @ref Host object
189 /// to the database.
190 ///
191 /// @param host @ref Host object being deleted from the Cassandra database
192 /// @param subnet_id identifier of the subnet to which the host belongs
193 /// @param reservation IPv6 reservation belonging to the host
194 /// @param option_space option space
195 /// @param option_descriptor structure used to hold option information
196 /// @param statement_tag tag of the statement being executed
197 /// @param data array being filled with data from to the Host object
198 void createBindForDelete(const HostPtr& host,
199 const Optional<SubnetID>& subnet_id,
200 const IPv6Resrv* const reservation,
201 const std::string& option_space,
202 const OptionDescriptor& option_descriptor,
203 StatementTag statement_tag,
204 AnyArray& data);
205
206 /// @brief Create unique hash for storage in table id.
207 ///
208 /// Hash function used for creating a pseudo-unique hash from member
209 /// values which uniquely determine an entry in the table. Uses FNV-1a
210 /// on 64 bits.
211 ///
212 /// The primary key clustering column aggregates: host_identifier,
213 /// host_identifier_type, host_ipv4_subnet_id, host_ipv6_subnet_id,
214 /// host_ipv4_address, reserved_ipv6_prefix_address,
215 /// reserved_ipv6_prefix_length, option_code, option_space.
216 uint64_t hashIntoId() const;
217
218 /// @brief Create unique key for storage in table key.
219 ///
220 /// The primary key partition key aggregates: host_identifier,
221 /// host_identifier_type, host_ipv4_subnet_id, host_ipv6_subnet_id,
222 /// host_ipv4_address
223 uint64_t hashIntoKey() const;
224
225 /// @brief Create unique key string for a host.
226 ///
227 /// The primary key partition key aggregates: host_identifier,
228 /// host_identifier_type, host_ipv4_subnet_id, host_ipv6_subnet_id,
229 /// host_ipv4_address
230 std::string hostKey() const;
231
232 /// @brief Copy received data into Host object
233 ///
234 /// Copies information about the host into a newly created @ref Host object
235 /// Called in @ref executeSelect after @ref createBindForSelect().
236 ///
237 /// @return Host Pointer to a @ref HostPtr object holding a pointer to the
238 /// @ref Host object returned.
239 virtual boost::any retrieve() override;
240
241 /// @brief Creates IPv6 reservation from the data contained in the
242 /// currently processed row.
243 ///
244 /// Called after createBindForSelect().
245 ///
246 /// @return IPv6Resrv object (containing IPv6 address or prefix reservation)
247 const IPv6Resrv retrieveReservation() const;
248
249 /// @brief Retrieves option from members.
250 ///
251 /// Called after createBindForSelect().
252 ///
253 /// @return OptionDescriptorPtr object (containing the option from the
254 /// database)
255 const OptionWrapper retrieveOption() const;
256
257 /// @brief Statement tags
258 /// @{
259 // Inserts all parameters belonging to any reservation from a single host.
260 static constexpr StatementTag INSERT_HOST = "INSERT_HOST";
261
262 // Retrieves host information, IPv6 reservations and both IPv4 and IPv6
263 // options associated with it.
264 static constexpr StatementTag GET_HOST = "GET_HOST";
265
266 // Retrieves host information, IPv6 reservations and both IPv4 and IPv6
267 // options associated with it.
268 static constexpr StatementTag GET_HOST_BY_HOST_ID = "GET_HOST_BY_HOST_ID";
269
270 // Retrieves host information along with the IPv4 options associated
271 // with it.
272 static constexpr StatementTag GET_HOST_BY_IPV4_ADDRESS = "GET_HOST_BY_IPV4_ADDRESS";
273
274 // Retrieves host information and IPv4 options using subnet identifier
275 // and client's identifier (i.e. hardware address or DUID).
276 static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID =
277 "GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID";
278
279 // Retrieves host information; IPv6 reservations and IPv6 options
280 // associated with it using subnet identifier and client's
281 // identifier (i.e. hardware address or DUID).
282 static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID =
283 "GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID";
284
285 // Retrieves host information and IPv4 options for the host using subnet
286 // identifier and IPv4 reservation.
287 static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS =
288 "GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS";
289
290 // Retrieves host information, IPv6 reservations and IPv6 options
291 // associated with it using prefix and prefix length. The query returns
292 // host information for a single host. However, multiple rows are returned
293 // due to left joining IPv6 reservations and IPv6 options. The number of
294 // rows returned is multiplication of number of existing IPv6 reservations
295 // and IPv6 options.
296 static constexpr StatementTag GET_HOST_BY_IPV6_PREFIX = "GET_HOST_BY_IPV6_PREFIX";
297
298 // Retrieves host information and IPv6 options for the host using subnet
299 // identifier and IPv6 reservation.
300 static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS =
301 "GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS";
302
303 // Deletes a host reservation.
304 static constexpr StatementTag DELETE_HOST =
305 "DELETE_HOST";
306
307 // Retrieves host information along with the IPv4 options associated
308 // with it using a subnet identifier.
309 static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID =
310 "GET_HOST_BY_IPV4_SUBNET_ID";
311
312 // Retrieves host information; IPv6 reservations and IPv6 options
313 // associated with a host using subnet identifier.
314 static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID =
315 "GET_HOST_BY_IPV6_SUBNET_ID";
316
317 // Retrieves host information, IPv6 reservations and both IPv4 and IPv6
318 // options associated with it using hostname.
319 static constexpr StatementTag GET_HOST_BY_HOST_NAME =
320 "GET_HOST_BY_HOST_NAME";
321
322 // Retrieves host information along with the IPv4 options associated
323 // with it using hostname and subnet identifier.
324 static constexpr StatementTag GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID =
325 "GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID";
326
327 // Retrieves host information; IPv6 reservations and IPv6 options
328 // associated with it using hostname and subnet identifier.
329 static constexpr StatementTag GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID =
330 "GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID";
331
332 // Retrieves host information along with the IPv4 options associated
333 // with it using a subnet identifier from first host (paging).
334 static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_LIMIT =
335 "GET_HOST_BY_IPV4_SUBNET_ID_LIMIT";
336
337 // Retrieves host information along with the IPv4 options associated
338 // with it using a subnet identifier from next host (paging).
339 static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY =
340 "GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY";
341
342 // Retrieves host information along with the IPv4 options associated
343 // with it using a subnet identifier from host with a limit (paging).
344 static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID_PAGE =
345 "GET_HOST_BY_IPV4_SUBNET_ID_PAGE";
346
347 // Retrieves host information; IPv6 reservations and IPv6 options
348 // associated with it using subnet identifier from first host (paging).
349 static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_LIMIT =
350 "GET_HOST_BY_IPV6_SUBNET_ID_LIMIT";
351
352 // Retrieves host information; IPv6 reservations and IPv6 options
353 // associated with it using subnet identifier from next host (paging).
354 static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_NEXT_KEY =
355 "GET_HOST_BY_IPV6_SUBNET_ID_NEXT_KEY";
356
357 // Retrieves host information; IPv6 reservations and IPv6 options
358 // associated with it using subnet identifier from host with a limit
359 // (paging).
360 static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID_PAGE =
361 "GET_HOST_BY_IPV6_SUBNET_ID_PAGE";
362
363 // Retrieves host information; reservations and options associated
364 // with it from first host (paging).
365 static constexpr StatementTag GET_HOST_LIMIT = "GET_HOST_LIMIT";
366
367 // Retrieves host information; reservations and options associated
368 // with it from host (paging).
369 static constexpr StatementTag GET_HOST_KEY = "GET_HOST_KEY";
370
371 // Retrieves host information; reservations and options associated
372 // with it from next host (paging).
373 static constexpr StatementTag GET_HOST_NEXT_KEY = "GET_HOST_NEXT_KEY";
374
375 // Retrieves host information; reservations and options associated
376 // with it from host with a limit (paging).
377 static constexpr StatementTag GET_HOST_PAGE = "GET_HOST_PAGE";
378 /// @}
379
380 /// @brief Cassandra statements
381 static StatementMap tagged_statements_;
382
383 private:
384 /// Pointer to Host object holding information being inserted into database.
385 HostPtr host_;
386
387 /// @brief Primary key. Partition key. Aggregates: host_identifier,
388 /// host_identifier_type, host_ipv4_subnet_id host_ipv6_subnet_id,
389 /// host_ipv4_address
390 cass_int64_t key_;
391
392 /// @brief Primary key. Clustering key. Aggregates: host_identifier,
393 /// host_identifier_type, reserved_ipv6_prefix_address,
394 /// reserved_ipv6_prefix_length, option_code, option_space.
395 cass_int64_t id_;
396
397 /// @brief Client's identifier (e.g. DUID, HW address) in binary format
398 CassBlob host_identifier_;
399
400 /// @brief Type of the identifier in the host_identifier_
401 /// This value corresponds to the @ref Host::IdentifierType value.
402 cass_int32_t host_identifier_type_;
403
404 /// @brief IPv4 subnet identifier
405 cass_int32_t host_ipv4_subnet_id_;
406
407 /// @brief IPv6 subnet identifier
408 cass_int32_t host_ipv6_subnet_id_;
409
410 /// @brief Reserved IPv4 address
411 cass_int32_t host_ipv4_address_;
412
413 /// @brief Next server address (siaddr).
414 cass_int32_t host_ipv4_next_server_;
415
416 /// @brief Server hostname (sname).
417 std::string host_ipv4_server_hostname_;
418
419 /// @brief Boot file name (file).
420 std::string host_ipv4_boot_file_name_;
421
422 /// @brief Key for authentication
423 std::string auth_key_;
424
425 /// @brief Name reserved for the host
426 std::string hostname_;
427
428 /// @brief Lower case name reserved for the host
429 std::string lower_case_hostname_;
430
431 /// @brief User context
432 std::string user_context_;
433
434 /// @brief A string holding comma separated list of IPv4 client classes
435 std::string host_ipv4_client_classes_;
436
437 /// @brief A string holding comma separated list of IPv6 client classes
438 std::string host_ipv6_client_classes_;
439
440 /// @brief Address belonging to the reserved IPv6 prefix
441 std::string reserved_ipv6_prefix_address_;
442
443 /// @brief Length of the reserved IPv6 prefix
444 cass_int32_t reserved_ipv6_prefix_length_;
445
446 /// @brief Reserver IPv6 prefix type
447 /// This value corresponds to the @ref Host::IdentifierType value.
448 cass_int32_t reserved_ipv6_prefix_address_type_;
449
450 /// @brief The reservation's IAID
451 cass_int32_t iaid_;
452
453 /// @brief Version of DHCP (i.e. 0 for DHCPv4 and 1 for DHCPv6) to which the
454 /// option belongs.
455 cass_int32_t option_universe_;
456
457 /// @brief Option code
458 cass_int32_t option_code_;
459
460 /// @brief Option value
461 CassBlob option_value_;
462
463 /// @brief The textual value of an option
464 std::string option_formatted_value_;
465
466 /// @brief Option space name
467 std::string option_space_;
468
469 /// @brief Flag indicating if option is always sent or only on request
470 cass_bool_t option_is_persistent_;
471
472 /// @brief Option client class
473 std::string option_client_class_;
474
475 /// @brief Subnet identifier
476 cass_int32_t option_subnet_id_;
477
478 /// @brief Buffer holding textual user context of an option.
479 std::string option_user_context_;
480
481 /// @brief Option scope id
482 cass_int32_t option_scope_id_;
483 }; // CqlHostExchange
484
485 constexpr StatementTag CqlHostExchange::INSERT_HOST;
486 constexpr StatementTag CqlHostExchange::GET_HOST;
487 constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_ID;
488 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_ADDRESS;
489 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID;
490 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID;
491 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS;
492 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_PREFIX;
493 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS;
494 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID;
495 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID;
496 constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_NAME;
497 constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID;
498 constexpr StatementTag CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID;
499 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_LIMIT;
500 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_LIMIT;
501 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY;
502 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_NEXT_KEY;
503 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_PAGE;
504 constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_PAGE;
505 constexpr StatementTag CqlHostExchange::GET_HOST_LIMIT;
506 constexpr StatementTag CqlHostExchange::GET_HOST_NEXT_KEY;
507 constexpr StatementTag CqlHostExchange::GET_HOST_KEY;
508 constexpr StatementTag CqlHostExchange::GET_HOST_PAGE;
509 constexpr StatementTag CqlHostExchange::DELETE_HOST;
510
511 StatementMap CqlHostExchange::tagged_statements_ = {
512 {INSERT_HOST,
513 {INSERT_HOST,
514 "INSERT INTO hosts ( "
515 "key, "
516 "id, "
517 "host_identifier, "
518 "host_identifier_type, "
519 "host_ipv4_subnet_id, "
520 "host_ipv6_subnet_id, "
521 "host_ipv4_address, "
522 "host_ipv4_next_server, "
523 "host_ipv4_server_hostname, "
524 "host_ipv4_boot_file_name, "
525 "auth_key, "
526 "hostname, "
527 "lower_case_hostname, "
528 "user_context, "
529 "host_ipv4_client_classes, "
530 "host_ipv6_client_classes, "
531 "reserved_ipv6_prefix_address, "
532 "reserved_ipv6_prefix_length, "
533 "reserved_ipv6_prefix_address_type, "
534 "iaid, "
535 "option_universe, "
536 "option_code, "
537 "option_value, "
538 "option_formatted_value, "
539 "option_space, "
540 "option_is_persistent, "
541 "option_client_class, "
542 "option_subnet_id, "
543 "option_user_context, "
544 "option_scope_id "
545 ") VALUES ( "
546 // key
547 "?, "
548 // id
549 "?, "
550 // host
551 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
552 // denormalized reservation, option
553 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
554 ") "
555 "IF NOT EXISTS "
556 }},
557
558 {GET_HOST,
559 {GET_HOST,
560 "SELECT "
561 "key, "
562 "id, "
563 "host_identifier, "
564 "host_identifier_type, "
565 "host_ipv4_subnet_id, "
566 "host_ipv6_subnet_id, "
567 "host_ipv4_address, "
568 "host_ipv4_next_server, "
569 "host_ipv4_server_hostname, "
570 "host_ipv4_boot_file_name, "
571 "auth_key, "
572 "hostname, "
573 "user_context, "
574 "host_ipv4_client_classes, "
575 "host_ipv6_client_classes, "
576 "reserved_ipv6_prefix_address, "
577 "reserved_ipv6_prefix_length, "
578 "reserved_ipv6_prefix_address_type, "
579 "iaid, "
580 "option_universe, "
581 "option_code, "
582 "option_value, "
583 "option_formatted_value, "
584 "option_space, "
585 "option_is_persistent, "
586 "option_client_class, "
587 "option_subnet_id, "
588 "option_user_context, "
589 "option_scope_id "
590 "FROM hosts "
591 }},
592
593 {GET_HOST_BY_HOST_ID,
594 {GET_HOST_BY_HOST_ID,
595 "SELECT "
596 "key, "
597 "id, "
598 "host_identifier, "
599 "host_identifier_type, "
600 "host_ipv4_subnet_id, "
601 "host_ipv6_subnet_id, "
602 "host_ipv4_address, "
603 "host_ipv4_next_server, "
604 "host_ipv4_server_hostname, "
605 "host_ipv4_boot_file_name, "
606 "auth_key, "
607 "hostname, "
608 "user_context, "
609 "host_ipv4_client_classes, "
610 "host_ipv6_client_classes, "
611 "reserved_ipv6_prefix_address, "
612 "reserved_ipv6_prefix_length, "
613 "reserved_ipv6_prefix_address_type, "
614 "iaid, "
615 "option_universe, "
616 "option_code, "
617 "option_value, "
618 "option_formatted_value, "
619 "option_space, "
620 "option_is_persistent, "
621 "option_client_class, "
622 "option_subnet_id, "
623 "option_user_context, "
624 "option_scope_id "
625 "FROM hosts "
626 "WHERE host_identifier = ? "
627 "AND host_identifier_type = ? "
628 "ALLOW FILTERING "
629 }},
630
631 {GET_HOST_BY_IPV4_ADDRESS,
632 {GET_HOST_BY_IPV4_ADDRESS,
633 "SELECT "
634 "key, "
635 "id, "
636 "host_identifier, "
637 "host_identifier_type, "
638 "host_ipv4_subnet_id, "
639 "host_ipv6_subnet_id, "
640 "host_ipv4_address, "
641 "host_ipv4_next_server, "
642 "host_ipv4_server_hostname, "
643 "host_ipv4_boot_file_name, "
644 "auth_key, "
645 "hostname, "
646 "user_context, "
647 "host_ipv4_client_classes, "
648 "host_ipv6_client_classes, "
649 "reserved_ipv6_prefix_address, "
650 "reserved_ipv6_prefix_length, "
651 "reserved_ipv6_prefix_address_type, "
652 "iaid, "
653 "option_universe, "
654 "option_code, "
655 "option_value, "
656 "option_formatted_value, "
657 "option_space, "
658 "option_is_persistent, "
659 "option_client_class, "
660 "option_subnet_id, "
661 "option_user_context, "
662 "option_scope_id "
663 "FROM hosts "
664 "WHERE host_ipv4_address = ? "
665 "ALLOW FILTERING "
666 }},
667
668 {GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
669 {GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
670 "SELECT "
671 "key, "
672 "id, "
673 "host_identifier, "
674 "host_identifier_type, "
675 "host_ipv4_subnet_id, "
676 "host_ipv6_subnet_id, "
677 "host_ipv4_address, "
678 "host_ipv4_next_server, "
679 "host_ipv4_server_hostname, "
680 "host_ipv4_boot_file_name, "
681 "auth_key, "
682 "hostname, "
683 "user_context, "
684 "host_ipv4_client_classes, "
685 "host_ipv6_client_classes, "
686 "reserved_ipv6_prefix_address, "
687 "reserved_ipv6_prefix_length, "
688 "reserved_ipv6_prefix_address_type, "
689 "iaid, "
690 "option_universe, "
691 "option_code, "
692 "option_value, "
693 "option_formatted_value, "
694 "option_space, "
695 "option_is_persistent, "
696 "option_client_class, "
697 "option_subnet_id, "
698 "option_user_context, "
699 "option_scope_id "
700 "FROM hosts "
701 "WHERE host_ipv4_subnet_id = ? "
702 "AND host_identifier = ? "
703 "AND host_identifier_type = ? "
704 "ALLOW FILTERING "
705 }},
706
707 {GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
708 {GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
709 "SELECT "
710 "key, "
711 "id, "
712 "host_identifier, "
713 "host_identifier_type, "
714 "host_ipv4_subnet_id, "
715 "host_ipv6_subnet_id, "
716 "host_ipv4_address, "
717 "host_ipv4_next_server, "
718 "host_ipv4_server_hostname, "
719 "host_ipv4_boot_file_name, "
720 "auth_key, "
721 "hostname, "
722 "user_context, "
723 "host_ipv4_client_classes, "
724 "host_ipv6_client_classes, "
725 "reserved_ipv6_prefix_address, "
726 "reserved_ipv6_prefix_length, "
727 "reserved_ipv6_prefix_address_type, "
728 "iaid, "
729 "option_universe, "
730 "option_code, "
731 "option_value, "
732 "option_formatted_value, "
733 "option_space, "
734 "option_is_persistent, "
735 "option_client_class, "
736 "option_subnet_id, "
737 "option_user_context, "
738 "option_scope_id "
739 "FROM hosts "
740 "WHERE host_ipv6_subnet_id = ? "
741 "AND host_identifier = ? "
742 "AND host_identifier_type = ? "
743 "ALLOW FILTERING "
744 }},
745
746 {GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
747 {GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
748 "SELECT "
749 "key, "
750 "id, "
751 "host_identifier, "
752 "host_identifier_type, "
753 "host_ipv4_subnet_id, "
754 "host_ipv6_subnet_id, "
755 "host_ipv4_address, "
756 "host_ipv4_next_server, "
757 "host_ipv4_server_hostname, "
758 "host_ipv4_boot_file_name, "
759 "auth_key, "
760 "hostname, "
761 "user_context, "
762 "host_ipv4_client_classes, "
763 "host_ipv6_client_classes, "
764 "reserved_ipv6_prefix_address, "
765 "reserved_ipv6_prefix_length, "
766 "reserved_ipv6_prefix_address_type, "
767 "iaid, "
768 "option_universe, "
769 "option_code, "
770 "option_value, "
771 "option_formatted_value, "
772 "option_space, "
773 "option_is_persistent, "
774 "option_client_class, "
775 "option_subnet_id, "
776 "option_user_context, "
777 "option_scope_id "
778 "FROM hosts "
779 "WHERE host_ipv4_subnet_id = ? "
780 "AND host_ipv4_address = ? "
781 "ALLOW FILTERING "
782 }},
783
784 {GET_HOST_BY_IPV6_PREFIX,
785 {GET_HOST_BY_IPV6_PREFIX,
786 "SELECT "
787 "key, "
788 "id, "
789 "host_identifier, "
790 "host_identifier_type, "
791 "host_ipv4_subnet_id, "
792 "host_ipv6_subnet_id, "
793 "host_ipv4_address, "
794 "host_ipv4_next_server, "
795 "host_ipv4_server_hostname, "
796 "host_ipv4_boot_file_name, "
797 "auth_key, "
798 "hostname, "
799 "user_context, "
800 "host_ipv4_client_classes, "
801 "host_ipv6_client_classes, "
802 "reserved_ipv6_prefix_address, "
803 "reserved_ipv6_prefix_length, "
804 "reserved_ipv6_prefix_address_type, "
805 "iaid, "
806 "option_universe, "
807 "option_code, "
808 "option_value, "
809 "option_formatted_value, "
810 "option_space, "
811 "option_is_persistent, "
812 "option_client_class, "
813 "option_subnet_id, "
814 "option_user_context, "
815 "option_scope_id "
816 "FROM hosts "
817 "WHERE reserved_ipv6_prefix_address = ? "
818 "AND reserved_ipv6_prefix_length = ? "
819 "ALLOW FILTERING "
820 }},
821
822 {GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
823 {GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
824 "SELECT "
825 "key, "
826 "id, "
827 "host_identifier, "
828 "host_identifier_type, "
829 "host_ipv4_subnet_id, "
830 "host_ipv6_subnet_id, "
831 "host_ipv4_address, "
832 "host_ipv4_next_server, "
833 "host_ipv4_server_hostname, "
834 "host_ipv4_boot_file_name, "
835 "auth_key, "
836 "hostname, "
837 "user_context, "
838 "host_ipv4_client_classes, "
839 "host_ipv6_client_classes, "
840 "reserved_ipv6_prefix_address, "
841 "reserved_ipv6_prefix_length, "
842 "reserved_ipv6_prefix_address_type, "
843 "iaid, "
844 "option_universe, "
845 "option_code, "
846 "option_value, "
847 "option_formatted_value, "
848 "option_space, "
849 "option_is_persistent, "
850 "option_client_class, "
851 "option_subnet_id, "
852 "option_user_context, "
853 "option_scope_id "
854 "FROM hosts "
855 "WHERE host_ipv6_subnet_id = ? "
856 "AND reserved_ipv6_prefix_address = ? "
857 "ALLOW FILTERING "
858 }},
859
860 {GET_HOST_BY_IPV4_SUBNET_ID,
861 {GET_HOST_BY_IPV4_SUBNET_ID,
862 "SELECT "
863 "key, "
864 "id, "
865 "host_identifier, "
866 "host_identifier_type, "
867 "host_ipv4_subnet_id, "
868 "host_ipv6_subnet_id, "
869 "host_ipv4_address, "
870 "host_ipv4_next_server, "
871 "host_ipv4_server_hostname, "
872 "host_ipv4_boot_file_name, "
873 "auth_key, "
874 "hostname, "
875 "user_context, "
876 "host_ipv4_client_classes, "
877 "host_ipv6_client_classes, "
878 "reserved_ipv6_prefix_address, "
879 "reserved_ipv6_prefix_length, "
880 "reserved_ipv6_prefix_address_type, "
881 "iaid, "
882 "option_universe, "
883 "option_code, "
884 "option_value, "
885 "option_formatted_value, "
886 "option_space, "
887 "option_is_persistent, "
888 "option_client_class, "
889 "option_subnet_id, "
890 "option_user_context, "
891 "option_scope_id "
892 "FROM hosts "
893 "WHERE host_ipv4_subnet_id = ? "
894 "ALLOW FILTERING "
895 }},
896
897 {GET_HOST_BY_IPV6_SUBNET_ID,
898 {GET_HOST_BY_IPV6_SUBNET_ID,
899 "SELECT "
900 "key, "
901 "id, "
902 "host_identifier, "
903 "host_identifier_type, "
904 "host_ipv4_subnet_id, "
905 "host_ipv6_subnet_id, "
906 "host_ipv4_address, "
907 "host_ipv4_next_server, "
908 "host_ipv4_server_hostname, "
909 "host_ipv4_boot_file_name, "
910 "auth_key, "
911 "hostname, "
912 "user_context, "
913 "host_ipv4_client_classes, "
914 "host_ipv6_client_classes, "
915 "reserved_ipv6_prefix_address, "
916 "reserved_ipv6_prefix_length, "
917 "reserved_ipv6_prefix_address_type, "
918 "iaid, "
919 "option_universe, "
920 "option_code, "
921 "option_value, "
922 "option_formatted_value, "
923 "option_space, "
924 "option_is_persistent, "
925 "option_client_class, "
926 "option_subnet_id, "
927 "option_user_context, "
928 "option_scope_id "
929 "FROM hosts "
930 "WHERE host_ipv6_subnet_id = ? "
931 "ALLOW FILTERING "
932 }},
933
934 {GET_HOST_BY_HOST_NAME,
935 {GET_HOST_BY_HOST_NAME,
936 "SELECT "
937 "key, "
938 "id, "
939 "host_identifier, "
940 "host_identifier_type, "
941 "host_ipv4_subnet_id, "
942 "host_ipv6_subnet_id, "
943 "host_ipv4_address, "
944 "host_ipv4_next_server, "
945 "host_ipv4_server_hostname, "
946 "host_ipv4_boot_file_name, "
947 "auth_key, "
948 "hostname, "
949 "user_context, "
950 "host_ipv4_client_classes, "
951 "host_ipv6_client_classes, "
952 "reserved_ipv6_prefix_address, "
953 "reserved_ipv6_prefix_length, "
954 "reserved_ipv6_prefix_address_type, "
955 "iaid, "
956 "option_universe, "
957 "option_code, "
958 "option_value, "
959 "option_formatted_value, "
960 "option_space, "
961 "option_is_persistent, "
962 "option_client_class, "
963 "option_subnet_id, "
964 "option_user_context, "
965 "option_scope_id "
966 "FROM hosts "
967 "WHERE lower_case_hostname = ? "
968 "ALLOW FILTERING "
969 }},
970
971 {GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID,
972 {GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID,
973 "SELECT "
974 "key, "
975 "id, "
976 "host_identifier, "
977 "host_identifier_type, "
978 "host_ipv4_subnet_id, "
979 "host_ipv6_subnet_id, "
980 "host_ipv4_address, "
981 "host_ipv4_next_server, "
982 "host_ipv4_server_hostname, "
983 "host_ipv4_boot_file_name, "
984 "auth_key, "
985 "hostname, "
986 "user_context, "
987 "host_ipv4_client_classes, "
988 "host_ipv6_client_classes, "
989 "reserved_ipv6_prefix_address, "
990 "reserved_ipv6_prefix_length, "
991 "reserved_ipv6_prefix_address_type, "
992 "iaid, "
993 "option_universe, "
994 "option_code, "
995 "option_value, "
996 "option_formatted_value, "
997 "option_space, "
998 "option_is_persistent, "
999 "option_client_class, "
1000 "option_subnet_id, "
1001 "option_user_context, "
1002 "option_scope_id "
1003 "FROM hosts "
1004 "WHERE lower_case_hostname = ? "
1005 "AND host_ipv4_subnet_id = ? "
1006 "ALLOW FILTERING "
1007 }},
1008
1009 {GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID,
1010 {GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID,
1011 "SELECT "
1012 "key, "
1013 "id, "
1014 "host_identifier, "
1015 "host_identifier_type, "
1016 "host_ipv4_subnet_id, "
1017 "host_ipv6_subnet_id, "
1018 "host_ipv4_address, "
1019 "host_ipv4_next_server, "
1020 "host_ipv4_server_hostname, "
1021 "host_ipv4_boot_file_name, "
1022 "auth_key, "
1023 "hostname, "
1024 "user_context, "
1025 "host_ipv4_client_classes, "
1026 "host_ipv6_client_classes, "
1027 "reserved_ipv6_prefix_address, "
1028 "reserved_ipv6_prefix_length, "
1029 "reserved_ipv6_prefix_address_type, "
1030 "iaid, "
1031 "option_universe, "
1032 "option_code, "
1033 "option_value, "
1034 "option_formatted_value, "
1035 "option_space, "
1036 "option_is_persistent, "
1037 "option_client_class, "
1038 "option_subnet_id, "
1039 "option_user_context, "
1040 "option_scope_id "
1041 "FROM hosts "
1042 "WHERE lower_case_hostname = ? "
1043 "AND host_ipv6_subnet_id = ? "
1044 "ALLOW FILTERING "
1045 }},
1046
1047 {GET_HOST_BY_IPV4_SUBNET_ID_LIMIT,
1048 {GET_HOST_BY_IPV4_SUBNET_ID_LIMIT,
1049 "SELECT "
1050 "key, "
1051 "id, "
1052 "host_identifier, "
1053 "host_identifier_type, "
1054 "host_ipv4_subnet_id, "
1055 "host_ipv6_subnet_id, "
1056 "host_ipv4_address, "
1057 "host_ipv4_next_server, "
1058 "host_ipv4_server_hostname, "
1059 "host_ipv4_boot_file_name, "
1060 "auth_key, "
1061 "hostname, "
1062 "user_context, "
1063 "host_ipv4_client_classes, "
1064 "host_ipv6_client_classes, "
1065 "reserved_ipv6_prefix_address, "
1066 "reserved_ipv6_prefix_length, "
1067 "reserved_ipv6_prefix_address_type, "
1068 "iaid, "
1069 "option_universe, "
1070 "option_code, "
1071 "option_value, "
1072 "option_formatted_value, "
1073 "option_space, "
1074 "option_is_persistent, "
1075 "option_client_class, "
1076 "option_subnet_id, "
1077 "option_user_context, "
1078 "option_scope_id "
1079 "FROM hosts "
1080 "WHERE host_ipv4_subnet_id = ? "
1081 "LIMIT 1 "
1082 "ALLOW FILTERING "
1083 }},
1084
1085 {GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY,
1086 {GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY,
1087 "SELECT "
1088 "key, "
1089 "id, "
1090 "host_identifier, "
1091 "host_identifier_type, "
1092 "host_ipv4_subnet_id, "
1093 "host_ipv6_subnet_id, "
1094 "host_ipv4_address, "
1095 "host_ipv4_next_server, "
1096 "host_ipv4_server_hostname, "
1097 "host_ipv4_boot_file_name, "
1098 "auth_key, "
1099 "hostname, "
1100 "user_context, "
1101 "host_ipv4_client_classes, "
1102 "host_ipv6_client_classes, "
1103 "reserved_ipv6_prefix_address, "
1104 "reserved_ipv6_prefix_length, "
1105 "reserved_ipv6_prefix_address_type, "
1106 "iaid, "
1107 "option_universe, "
1108 "option_code, "
1109 "option_value, "
1110 "option_formatted_value, "
1111 "option_space, "
1112 "option_is_persistent, "
1113 "option_client_class, "
1114 "option_subnet_id, "
1115 "option_user_context, "
1116 "option_scope_id "
1117 "FROM hosts "
1118 "WHERE host_ipv4_subnet_id = ? "
1119 "AND TOKEN(key) > TOKEN(?) "
1120 "LIMIT 1 "
1121 "ALLOW FILTERING "
1122 }},
1123
1124 {GET_HOST_BY_IPV4_SUBNET_ID_PAGE,
1125 {GET_HOST_BY_IPV4_SUBNET_ID_PAGE,
1126 "SELECT "
1127 "key, "
1128 "id, "
1129 "host_identifier, "
1130 "host_identifier_type, "
1131 "host_ipv4_subnet_id, "
1132 "host_ipv6_subnet_id, "
1133 "host_ipv4_address, "
1134 "host_ipv4_next_server, "
1135 "host_ipv4_server_hostname, "
1136 "host_ipv4_boot_file_name, "
1137 "auth_key, "
1138 "hostname, "
1139 "user_context, "
1140 "host_ipv4_client_classes, "
1141 "host_ipv6_client_classes, "
1142 "reserved_ipv6_prefix_address, "
1143 "reserved_ipv6_prefix_length, "
1144 "reserved_ipv6_prefix_address_type, "
1145 "iaid, "
1146 "option_universe, "
1147 "option_code, "
1148 "option_value, "
1149 "option_formatted_value, "
1150 "option_space, "
1151 "option_is_persistent, "
1152 "option_client_class, "
1153 "option_subnet_id, "
1154 "option_user_context, "
1155 "option_scope_id "
1156 "FROM hosts "
1157 "WHERE host_ipv4_subnet_id = ? "
1158 "AND id = ? "
1159 "LIMIT 1 "
1160 "ALLOW FILTERING "
1161 }},
1162
1163 {GET_HOST_BY_IPV6_SUBNET_ID_LIMIT,
1164 {GET_HOST_BY_IPV6_SUBNET_ID_LIMIT,
1165 "SELECT "
1166 "key, "
1167 "id, "
1168 "host_identifier, "
1169 "host_identifier_type, "
1170 "host_ipv4_subnet_id, "
1171 "host_ipv6_subnet_id, "
1172 "host_ipv4_address, "
1173 "host_ipv4_next_server, "
1174 "host_ipv4_server_hostname, "
1175 "host_ipv4_boot_file_name, "
1176 "auth_key, "
1177 "hostname, "
1178 "user_context, "
1179 "host_ipv4_client_classes, "
1180 "host_ipv6_client_classes, "
1181 "reserved_ipv6_prefix_address, "
1182 "reserved_ipv6_prefix_length, "
1183 "reserved_ipv6_prefix_address_type, "
1184 "iaid, "
1185 "option_universe, "
1186 "option_code, "
1187 "option_value, "
1188 "option_formatted_value, "
1189 "option_space, "
1190 "option_is_persistent, "
1191 "option_client_class, "
1192 "option_subnet_id, "
1193 "option_user_context, "
1194 "option_scope_id "
1195 "FROM hosts "
1196 "WHERE host_ipv6_subnet_id = ? "
1197 "LIMIT 1 "
1198 "ALLOW FILTERING "
1199 }},
1200
1201 {GET_HOST_BY_IPV6_SUBNET_ID_NEXT_KEY,
1202 {GET_HOST_BY_IPV6_SUBNET_ID_NEXT_KEY,
1203 "SELECT "
1204 "key, "
1205 "id, "
1206 "host_identifier, "
1207 "host_identifier_type, "
1208 "host_ipv4_subnet_id, "
1209 "host_ipv6_subnet_id, "
1210 "host_ipv4_address, "
1211 "host_ipv4_next_server, "
1212 "host_ipv4_server_hostname, "
1213 "host_ipv4_boot_file_name, "
1214 "auth_key, "
1215 "hostname, "
1216 "user_context, "
1217 "host_ipv4_client_classes, "
1218 "host_ipv6_client_classes, "
1219 "reserved_ipv6_prefix_address, "
1220 "reserved_ipv6_prefix_length, "
1221 "reserved_ipv6_prefix_address_type, "
1222 "iaid, "
1223 "option_universe, "
1224 "option_code, "
1225 "option_value, "
1226 "option_formatted_value, "
1227 "option_space, "
1228 "option_is_persistent, "
1229 "option_client_class, "
1230 "option_subnet_id, "
1231 "option_user_context, "
1232 "option_scope_id "
1233 "FROM hosts "
1234 "WHERE host_ipv6_subnet_id = ? "
1235 "AND TOKEN(key) > TOKEN(?) "
1236 "LIMIT 1 "
1237 "ALLOW FILTERING "
1238 }},
1239
1240 {GET_HOST_BY_IPV6_SUBNET_ID_PAGE,
1241 {GET_HOST_BY_IPV6_SUBNET_ID_PAGE,
1242 "SELECT "
1243 "key, "
1244 "id, "
1245 "host_identifier, "
1246 "host_identifier_type, "
1247 "host_ipv4_subnet_id, "
1248 "host_ipv6_subnet_id, "
1249 "host_ipv4_address, "
1250 "host_ipv4_next_server, "
1251 "host_ipv4_server_hostname, "
1252 "host_ipv4_boot_file_name, "
1253 "auth_key, "
1254 "hostname, "
1255 "user_context, "
1256 "host_ipv4_client_classes, "
1257 "host_ipv6_client_classes, "
1258 "reserved_ipv6_prefix_address, "
1259 "reserved_ipv6_prefix_length, "
1260 "reserved_ipv6_prefix_address_type, "
1261 "iaid, "
1262 "option_universe, "
1263 "option_code, "
1264 "option_value, "
1265 "option_formatted_value, "
1266 "option_space, "
1267 "option_is_persistent, "
1268 "option_client_class, "
1269 "option_subnet_id, "
1270 "option_user_context, "
1271 "option_scope_id "
1272 "FROM hosts "
1273 "WHERE host_ipv6_subnet_id = ? "
1274 "AND id = ? "
1275 "LIMIT 1 "
1276 "ALLOW FILTERING "
1277 }},
1278
1279 {GET_HOST_LIMIT,
1280 {GET_HOST_LIMIT,
1281 "SELECT "
1282 "key, "
1283 "id, "
1284 "host_identifier, "
1285 "host_identifier_type, "
1286 "host_ipv4_subnet_id, "
1287 "host_ipv6_subnet_id, "
1288 "host_ipv4_address, "
1289 "host_ipv4_next_server, "
1290 "host_ipv4_server_hostname, "
1291 "host_ipv4_boot_file_name, "
1292 "auth_key, "
1293 "hostname, "
1294 "user_context, "
1295 "host_ipv4_client_classes, "
1296 "host_ipv6_client_classes, "
1297 "reserved_ipv6_prefix_address, "
1298 "reserved_ipv6_prefix_length, "
1299 "reserved_ipv6_prefix_address_type, "
1300 "iaid, "
1301 "option_universe, "
1302 "option_code, "
1303 "option_value, "
1304 "option_formatted_value, "
1305 "option_space, "
1306 "option_is_persistent, "
1307 "option_client_class, "
1308 "option_subnet_id, "
1309 "option_user_context, "
1310 "option_scope_id "
1311 "FROM hosts "
1312 "LIMIT 1 "
1313 "ALLOW FILTERING "
1314 }},
1315
1316 {GET_HOST_NEXT_KEY,
1317 {GET_HOST_NEXT_KEY,
1318 "SELECT "
1319 "key, "
1320 "id, "
1321 "host_identifier, "
1322 "host_identifier_type, "
1323 "host_ipv4_subnet_id, "
1324 "host_ipv6_subnet_id, "
1325 "host_ipv4_address, "
1326 "host_ipv4_next_server, "
1327 "host_ipv4_server_hostname, "
1328 "host_ipv4_boot_file_name, "
1329 "auth_key, "
1330 "hostname, "
1331 "user_context, "
1332 "host_ipv4_client_classes, "
1333 "host_ipv6_client_classes, "
1334 "reserved_ipv6_prefix_address, "
1335 "reserved_ipv6_prefix_length, "
1336 "reserved_ipv6_prefix_address_type, "
1337 "iaid, "
1338 "option_universe, "
1339 "option_code, "
1340 "option_value, "
1341 "option_formatted_value, "
1342 "option_space, "
1343 "option_is_persistent, "
1344 "option_client_class, "
1345 "option_subnet_id, "
1346 "option_user_context, "
1347 "option_scope_id "
1348 "FROM hosts "
1349 "WHERE TOKEN(key) > TOKEN(?) "
1350 "LIMIT 1 "
1351 "ALLOW FILTERING "
1352 }},
1353
1354 {GET_HOST_KEY,
1355 {GET_HOST_KEY,
1356 "SELECT "
1357 "key, "
1358 "id, "
1359 "host_identifier, "
1360 "host_identifier_type, "
1361 "host_ipv4_subnet_id, "
1362 "host_ipv6_subnet_id, "
1363 "host_ipv4_address, "
1364 "host_ipv4_next_server, "
1365 "host_ipv4_server_hostname, "
1366 "host_ipv4_boot_file_name, "
1367 "auth_key, "
1368 "hostname, "
1369 "user_context, "
1370 "host_ipv4_client_classes, "
1371 "host_ipv6_client_classes, "
1372 "reserved_ipv6_prefix_address, "
1373 "reserved_ipv6_prefix_length, "
1374 "reserved_ipv6_prefix_address_type, "
1375 "iaid, "
1376 "option_universe, "
1377 "option_code, "
1378 "option_value, "
1379 "option_formatted_value, "
1380 "option_space, "
1381 "option_is_persistent, "
1382 "option_client_class, "
1383 "option_subnet_id, "
1384 "option_user_context, "
1385 "option_scope_id "
1386 "FROM hosts "
1387 "WHERE key = ? "
1388 "ALLOW FILTERING "
1389 }},
1390
1391 {GET_HOST_PAGE,
1392 {GET_HOST_PAGE,
1393 "SELECT "
1394 "key, "
1395 "id, "
1396 "host_identifier, "
1397 "host_identifier_type, "
1398 "host_ipv4_subnet_id, "
1399 "host_ipv6_subnet_id, "
1400 "host_ipv4_address, "
1401 "host_ipv4_next_server, "
1402 "host_ipv4_server_hostname, "
1403 "host_ipv4_boot_file_name, "
1404 "auth_key, "
1405 "hostname, "
1406 "user_context, "
1407 "host_ipv4_client_classes, "
1408 "host_ipv6_client_classes, "
1409 "reserved_ipv6_prefix_address, "
1410 "reserved_ipv6_prefix_length, "
1411 "reserved_ipv6_prefix_address_type, "
1412 "iaid, "
1413 "option_universe, "
1414 "option_code, "
1415 "option_value, "
1416 "option_formatted_value, "
1417 "option_space, "
1418 "option_is_persistent, "
1419 "option_client_class, "
1420 "option_subnet_id, "
1421 "option_user_context, "
1422 "option_scope_id "
1423 "FROM hosts "
1424 "WHERE id = ? "
1425 "LIMIT 1 "
1426 "ALLOW FILTERING "
1427 }},
1428
1429 {DELETE_HOST,
1430 {DELETE_HOST,
1431 "DELETE FROM hosts WHERE key = ? AND id = ? "
1432 "IF EXISTS "
1433 }}
1434 };
1435
CqlHostExchange()1436 CqlHostExchange::CqlHostExchange()
1437 : host_(NULL), id_(0), host_identifier_type_(0), host_ipv4_subnet_id_(0),
1438 host_ipv6_subnet_id_(0), host_ipv4_address_(0), host_ipv4_next_server_(0),
1439 host_ipv4_server_hostname_(NULL_DHCP4_SERVER_HOSTNAME),
1440 host_ipv4_boot_file_name_(NULL_DHCP4_BOOT_FILE_NAME),
1441 auth_key_(""),
1442 user_context_(NULL_USER_CONTEXT),
1443 reserved_ipv6_prefix_length_(NULL_RESERVED_IPV6_PREFIX_LENGTH),
1444 reserved_ipv6_prefix_address_type_(NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE),
1445 iaid_(NULL_IAID), option_universe_(NULL_OPTION_UNIVERSE),
1446 option_code_(NULL_OPTION_CODE),
1447 option_is_persistent_(NULL_OPTION_IS_PERSISTENT),
1448 option_subnet_id_(NULL_OPTION_SUBNET_ID),
1449 option_user_context_(NULL_OPTION_USER_CONTEXT),
1450 option_scope_id_(NULL_OPTION_SCOPE_ID) {
1451 }
1452
~CqlHostExchange()1453 CqlHostExchange::~CqlHostExchange() {
1454 }
1455
1456 void
createBindForSelect(AnyArray & data,StatementTag)1457 CqlHostExchange::createBindForSelect(AnyArray& data, StatementTag /* not used */) {
1458 // Start with a fresh array.
1459 data.clear();
1460
1461 // key: bigint
1462 data.add(&key_);
1463 // id: bigint
1464 data.add(&id_);
1465 // host_identifier: blob
1466 data.add(&host_identifier_);
1467 // host_identifier_type: int
1468 data.add(&host_identifier_type_);
1469 // host_ipv4_subnet_id: int
1470 data.add(&host_ipv4_subnet_id_);
1471 // host_ipv6_subnet_id: int
1472 data.add(&host_ipv6_subnet_id_);
1473 // host_ipv4_address: int
1474 data.add(&host_ipv4_address_);
1475 // host_ipv4_next_server: int
1476 data.add(&host_ipv4_next_server_);
1477 // host_ipv4_server_hostname: text
1478 data.add(&host_ipv4_server_hostname_);
1479 // host_ipv4_boot_file_name: text
1480 data.add(&host_ipv4_boot_file_name_);
1481 // auth_key: text
1482 data.add(&auth_key_);
1483 // hostname: text
1484 data.add(&hostname_);
1485 // user_context: text
1486 data.add(&user_context_);
1487 // host_ipv4_client_classes: text
1488 data.add(&host_ipv4_client_classes_);
1489 // host_ipv6_client_classes: text
1490 data.add(&host_ipv6_client_classes_);
1491 /// @brief Denormalized reservation columns
1492 /// @{
1493 // reserved_ipv6_prefix_address: text
1494 data.add(&reserved_ipv6_prefix_address_);
1495 // reserved_ipv6_prefix_length: int
1496 data.add(&reserved_ipv6_prefix_length_);
1497 // reserved_ipv6_prefix_address_type: int
1498 data.add(&reserved_ipv6_prefix_address_type_);
1499 // iaid: int
1500 data.add(&iaid_);
1501 /// @}
1502 /// @brief Denormalized option columns
1503 /// @{
1504 // option_universe: int
1505 data.add(&option_universe_);
1506 // option_code: int
1507 data.add(&option_code_);
1508 // option_value: blob
1509 data.add(&option_value_);
1510 // option_formatted_value: text
1511 data.add(&option_formatted_value_);
1512 // option_space: text
1513 data.add(&option_space_);
1514 // option_is_persistent: boolean
1515 data.add(&option_is_persistent_);
1516 // option_client_class: text
1517 data.add(&option_client_class_);
1518 // option_subnet_id: int
1519 data.add(&option_subnet_id_);
1520 // option_user_context: text
1521 data.add(&option_user_context_);
1522 // option_scope_id: int
1523 data.add(&option_scope_id_);
1524 /// @}
1525 }
1526
1527 void
prepareExchange(const HostPtr & host,const Optional<SubnetID> & subnet_id,const IPv6Resrv * const reservation,const std::string & option_space,const OptionDescriptor & option_descriptor)1528 CqlHostExchange::prepareExchange(const HostPtr& host,
1529 const Optional<SubnetID>& subnet_id,
1530 const IPv6Resrv* const reservation,
1531 const std::string& option_space,
1532 const OptionDescriptor& option_descriptor) {
1533
1534 // Store host object to ensure it remains valid.
1535 host_ = host;
1536
1537 // Set up the structures for the various components of the host
1538 // structure.
1539 try {
1540 // host_identifier: blob
1541 // Convert from std::vector<uint8_t> to
1542 // std::vector<cass_byte_t>.
1543 HostIdentifier host_identifier = host->getIdentifier();
1544 host_identifier_ = CassBlob(host_identifier.begin(), host_identifier.end());
1545 if (host_identifier_.size() > DUID::MAX_DUID_LEN) {
1546 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): host identifier "
1547 << host_identifier_.data() << " of length " << host_identifier_.size()
1548 << " is greater than allowed of " << DUID::MAX_DUID_LEN);
1549 }
1550
1551 // host_identifier_type: tinyint
1552 host_identifier_type_ = static_cast<cass_int32_t>(host->getIdentifierType());
1553 if (host_identifier_type_ > MAX_IDENTIFIER_TYPE) {
1554 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): invalid "
1555 "host identifier type returned: " << host_identifier_type_);
1556 }
1557
1558 // host_ipv4_subnet_id: int
1559 host_ipv4_subnet_id_ = static_cast<cass_int32_t>(host->getIPv4SubnetID());
1560
1561 // host_ipv6_subnet_id: int
1562 host_ipv6_subnet_id_ = static_cast<cass_int32_t>(host->getIPv6SubnetID());
1563
1564 // host_ipv4_address: int
1565 host_ipv4_address_ = static_cast<cass_int32_t>(host->getIPv4Reservation().toUint32());
1566
1567 // host_ipv4_next_server: int
1568 host_ipv4_next_server_ = static_cast<cass_int32_t>(host->getNextServer().toUint32());
1569
1570 // host_ipv4_server_hostname: text
1571 host_ipv4_server_hostname_ = host->getServerHostname();
1572
1573 // host_ipv4_boot_file_name: text
1574 host_ipv4_boot_file_name_ = host->getBootFileName();
1575
1576 // auth_key: varchar
1577 auth_key_ = host->getKey().toText();
1578
1579 // hostname: text
1580 hostname_ = host->getHostname();
1581 if (hostname_.size() > HOSTNAME_MAX_LEN) {
1582 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): hostname "
1583 << hostname_ << " of length " << hostname_.size()
1584 << " is greater than allowed of " << HOSTNAME_MAX_LEN);
1585 }
1586
1587 // lower_case_hostname: text
1588 lower_case_hostname_ = host->getLowerHostname();
1589 if (lower_case_hostname_.size() > HOSTNAME_MAX_LEN) {
1590 // Should never happen...
1591 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): lower "
1592 "case hostname " << lower_case_hostname_ << " of length "
1593 << lower_case_hostname_.size()
1594 << " is greater than allowed of " << HOSTNAME_MAX_LEN);
1595 }
1596
1597 // user_context: text
1598 ConstElementPtr ctx = host->getContext();
1599 if (ctx) {
1600 user_context_ = ctx->str();
1601 } else {
1602 user_context_ = NULL_USER_CONTEXT;
1603 }
1604
1605 // host_ipv4_client_classes: text
1606 host_ipv4_client_classes_ = host->getClientClasses4().toText(",");
1607 if (host_ipv4_client_classes_.size() > CLIENT_CLASSES_MAX_LEN) {
1608 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): "
1609 "IPv4 client classes " << host_ipv4_client_classes_ << " of length "
1610 << host_ipv4_client_classes_.size() << " is greater than allowed of "
1611 << CLIENT_CLASSES_MAX_LEN);
1612 }
1613
1614 // host_ipv6_client_classes: text
1615 host_ipv6_client_classes_ = host->getClientClasses6().toText(",");
1616 if (host_ipv6_client_classes_.size() > CLIENT_CLASSES_MAX_LEN) {
1617 isc_throw(BadValue, "CqlHostExchange::prepareExchange(): "
1618 "IPv6 client classes " << host_ipv6_client_classes_ << " of length "
1619 << host_ipv6_client_classes_.size() << " is greater than allowed of "
1620 << CLIENT_CLASSES_MAX_LEN);
1621 }
1622
1623 if (reservation == NULL) {
1624 // reserved_ipv6_prefix_address: text
1625 reserved_ipv6_prefix_address_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS;
1626 // reserved_ipv6_prefix_length: int
1627 reserved_ipv6_prefix_length_ = NULL_RESERVED_IPV6_PREFIX_LENGTH;
1628 // reserved_ipv6_prefix_address_type: int
1629 reserved_ipv6_prefix_address_type_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE;
1630 iaid_ = NULL_IAID;
1631 } else {
1632 // reserved_ipv6_prefix_address: text
1633 reserved_ipv6_prefix_address_ = reservation->getPrefix().toText();
1634
1635 // reserved_ipv6_prefix_length: int
1636 reserved_ipv6_prefix_length_ = static_cast<cass_int32_t>(reservation->getPrefixLen());
1637
1638 // reserved_ipv6_prefix_address_type: int
1639 reserved_ipv6_prefix_address_type_ =
1640 reservation->getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1641
1642 // iaid: int
1643 /// @todo: We don't support iaid in the IPv6Resrv yet.
1644 iaid_ = 0;
1645 }
1646
1647 if (option_descriptor.option_ == NULL) {
1648 option_universe_ = NULL_OPTION_UNIVERSE;
1649 option_code_ = NULL_OPTION_CODE;
1650 option_value_ = NULL_OPTION_VALUE;
1651 option_formatted_value_ = NULL_OPTION_FORMATTED_VALUE;
1652 option_space_ = NULL_OPTION_SPACE;
1653 option_is_persistent_ = NULL_OPTION_IS_PERSISTENT;
1654 option_client_class_ = NULL_OPTION_CLIENT_CLASS;
1655 option_subnet_id_ = NULL_OPTION_SUBNET_ID;
1656 option_user_context_ = NULL_OPTION_USER_CONTEXT;
1657 option_scope_id_ = NULL_OPTION_SCOPE_ID;
1658 } else {
1659 // option_universe: int
1660 option_universe_ = option_descriptor.option_->getUniverse();
1661
1662 // option_code: int
1663 option_code_ = option_descriptor.option_->getType();
1664
1665 // option_value: blob
1666 // option_formatted_value: text
1667 if (option_descriptor.formatted_value_.empty()) {
1668 if (option_descriptor.option_->len() >
1669 option_descriptor.option_->getHeaderLen()) {
1670 // The formatted_value is empty and the option value
1671 // is not empty so we need to prepare on-wire format
1672 // for the option and store it in the database as a
1673 // blob.
1674 OutputBuffer buffer(option_descriptor.option_->len());
1675 option_descriptor.option_->pack(buffer);
1676 const char* buffer_ptr = static_cast<const char*>(buffer.getData());
1677 option_value_.assign(buffer_ptr + option_descriptor.option_->getHeaderLen(),
1678 buffer_ptr + buffer.getLength());
1679 } else {
1680 option_value_.clear();
1681 }
1682 option_formatted_value_.clear();
1683 } else {
1684 option_value_.clear();
1685 option_formatted_value_ = option_descriptor.formatted_value_;
1686 }
1687
1688 // option_space: text
1689 option_space_ = option_space;
1690
1691 // option_is_persistent: boolean
1692 option_is_persistent_ = option_descriptor.persistent_ ? cass_true : cass_false;
1693
1694 // option_client_class: text
1695 /// @todo Assign actual value to client class string. See #5503.
1696 option_client_class_.clear();
1697
1698 // option_subnet_id: int
1699 if (!subnet_id.unspecified()) {
1700 option_subnet_id_ = subnet_id;
1701 } else {
1702 option_subnet_id_ = 0;
1703 }
1704
1705 // option_user_context: text
1706 ConstElementPtr ctx = option_descriptor.getContext();
1707 if (ctx) {
1708 option_user_context_ = ctx->str();
1709 } else {
1710 option_user_context_ = NULL_OPTION_USER_CONTEXT;
1711 }
1712
1713 // option_scope_id: int
1714 // Using fixed scope_id = 3, which associates an option with host.
1715 option_scope_id_ = 3;
1716 }
1717
1718 // id: bigint
1719 id_ = static_cast<cass_int64_t>(hashIntoId());
1720
1721 // key: bigint
1722 key_ = static_cast<cass_int64_t>(hashIntoKey());
1723 } catch (const Exception& ex) {
1724 isc_throw(DbOperationError,
1725 "CqlHostExchange::prepareExchange(): "
1726 "could not copy data from host "
1727 << host->getHostname() << ", reason: " << ex.what());
1728 }
1729 }
1730
1731 void
createBindForMutation(const HostPtr & host,const Optional<SubnetID> & subnet_id,const IPv6Resrv * const reservation,const std::string & option_space,const OptionDescriptor & option_descriptor,StatementTag statement_tag,AnyArray & data)1732 CqlHostExchange::createBindForMutation(const HostPtr& host,
1733 const Optional<SubnetID>& subnet_id,
1734 const IPv6Resrv* const reservation,
1735 const std::string& option_space,
1736 const OptionDescriptor& option_descriptor,
1737 StatementTag statement_tag, AnyArray& data) {
1738 prepareExchange(host, subnet_id, reservation, option_space, option_descriptor);
1739
1740 try {
1741 // Add all parameters to bind array.
1742 data.clear();
1743
1744 if (statement_tag == CqlHostExchange::INSERT_HOST) {
1745 data.add(&key_);
1746 data.add(&id_);
1747 data.add(&host_identifier_);
1748 data.add(&host_identifier_type_);
1749 data.add(&host_ipv4_subnet_id_);
1750 data.add(&host_ipv6_subnet_id_);
1751 data.add(&host_ipv4_address_);
1752 data.add(&host_ipv4_next_server_);
1753 data.add(&host_ipv4_server_hostname_);
1754 data.add(&host_ipv4_boot_file_name_);
1755 data.add(&auth_key_);
1756 data.add(&hostname_);
1757 data.add(&lower_case_hostname_);
1758 data.add(&user_context_);
1759 data.add(&host_ipv4_client_classes_);
1760 data.add(&host_ipv6_client_classes_);
1761 }
1762
1763 // Reservation
1764 data.add(&reserved_ipv6_prefix_address_);
1765 data.add(&reserved_ipv6_prefix_length_);
1766 data.add(&reserved_ipv6_prefix_address_type_);
1767 data.add(&iaid_);
1768
1769 // Option
1770 data.add(&option_universe_);
1771 data.add(&option_code_);
1772 data.add(&option_value_);
1773 data.add(&option_formatted_value_);
1774 data.add(&option_space_);
1775 data.add(&option_is_persistent_);
1776 data.add(&option_client_class_);
1777 data.add(&option_subnet_id_);
1778 data.add(&option_user_context_);
1779 data.add(&option_scope_id_);
1780
1781 } catch (const Exception& ex) {
1782 isc_throw(DbOperationError,
1783 "CqlHostExchange::createBindForMutation(): "
1784 "could not create bind array from host "
1785 << host->getHostname() << ", reason: " << ex.what());
1786 }
1787 }
1788
1789 void
createBindForDelete(const HostPtr & host,const Optional<SubnetID> & subnet_id,const IPv6Resrv * const reservation,const std::string & option_space,const OptionDescriptor & option_descriptor,StatementTag statement_tag,AnyArray & data)1790 CqlHostExchange::createBindForDelete(const HostPtr& host,
1791 const Optional<SubnetID>& subnet_id,
1792 const IPv6Resrv* const reservation,
1793 const std::string& option_space,
1794 const OptionDescriptor& option_descriptor,
1795 StatementTag statement_tag, AnyArray& data) {
1796 prepareExchange(host, subnet_id, reservation, option_space, option_descriptor);
1797
1798 try {
1799 // Add all parameters to bind array.
1800 data.clear();
1801
1802 if (statement_tag == CqlHostExchange::DELETE_HOST) {
1803 data.add(&key_);
1804 data.add(&id_);
1805 }
1806
1807 } catch (const Exception& ex) {
1808 isc_throw(DbOperationError,
1809 "CqlHostExchange::createBindForDelete(): "
1810 "could not create bind array from host "
1811 << host->getHostname() << ", reason: " << ex.what());
1812 }
1813 }
1814
1815 uint64_t
hashIntoId() const1816 CqlHostExchange::hashIntoId() const {
1817 // Add a separator between aggregated field to avoid collisions
1818 // between distinct entries.
1819
1820 // Get key.
1821 std::stringstream key_stream;
1822 key_stream << hostKey();
1823 key_stream << std::setw(V6ADDRESS_TEXT_MAX_LEN) << std::setfill('-')
1824 << reserved_ipv6_prefix_address_;
1825 key_stream << std::setw(4) << std::setfill('-')
1826 << reserved_ipv6_prefix_length_;
1827 key_stream << std::setw(4) << std::setfill('-') << option_code_;
1828 key_stream << std::setw(OPTION_SPACE_MAX_LEN) << std::setfill('-')
1829 << option_space_;
1830 const std::string key = key_stream.str();
1831
1832 return (Hash64::hash(key));
1833 }
1834
1835 uint64_t
hashIntoKey() const1836 CqlHostExchange::hashIntoKey() const {
1837 const std::string key = hostKey();
1838
1839 return (Hash64::hash(key));
1840 }
1841
1842 std::string
hostKey() const1843 CqlHostExchange::hostKey() const {
1844 // Add a separator between aggregated field to avoid collisions
1845 // between distinct entries.
1846 // Get key.
1847 std::stringstream key_stream;
1848 if (host_ipv4_address_) {
1849 key_stream << std::setw(3 * DUID::MAX_DUID_LEN - 1) << std::setfill('-')
1850 << "-";
1851 key_stream << std::setw(10) << std::setfill('-') << "-";
1852 } else {
1853 key_stream << std::setw(3 * DUID::MAX_DUID_LEN - 1) << std::setfill('-')
1854 << DUID(host_identifier_).toText();
1855 key_stream << std::setw(10) << std::setfill('-') << host_identifier_type_;
1856 }
1857 key_stream << std::setw(10) << std::setfill('-') << host_ipv4_subnet_id_;
1858 key_stream << std::setw(10) << std::setfill('-') << host_ipv6_subnet_id_;
1859 key_stream << std::setw(V4ADDRESS_TEXT_MAX_LEN) << std::setfill('-')
1860 << host_ipv4_address_;
1861 return key_stream.str();
1862 }
1863
1864 boost::any
retrieve()1865 CqlHostExchange::retrieve() {
1866 const uint64_t id = static_cast<uint64_t>(id_);
1867
1868 HostIdentifier host_identifier =
1869 HostIdentifier(host_identifier_.begin(), host_identifier_.end());
1870
1871 // Set the host identifier type in a variable of the appropriate
1872 // data type.
1873 Host::IdentifierType host_identifier_type =
1874 static_cast<Host::IdentifierType>(host_identifier_type_);
1875
1876 // Set IPv4 subnet ID to the value returned.
1877 SubnetID ipv4_subnet_id = static_cast<SubnetID>(host_ipv4_subnet_id_);
1878
1879 // Set IPv6 subnet ID to the value returned.
1880 SubnetID ipv6_subnet_id = static_cast<SubnetID>(host_ipv6_subnet_id_);
1881
1882 // Set IPv4 address reservation.
1883 asiolink::IOAddress ipv4_reservation =
1884 asiolink::IOAddress(static_cast<uint32_t>(host_ipv4_address_));
1885
1886 Host* host = new Host(host_identifier.data(), host_identifier.size(),
1887 host_identifier_type, ipv4_subnet_id, ipv6_subnet_id,
1888 ipv4_reservation, hostname_,
1889 host_ipv4_client_classes_, host_ipv6_client_classes_,
1890 static_cast<uint32_t>(host_ipv4_next_server_),
1891 host_ipv4_server_hostname_, host_ipv4_boot_file_name_,
1892 AuthKey(auth_key_));
1893
1894 // Set the user context if there is one.
1895 if (!user_context_.empty()) {
1896 try {
1897 ConstElementPtr ctx = Element::fromJSON(user_context_);
1898 if (!ctx || (ctx->getType() != Element::map)) {
1899 isc_throw(BadValue, "user context '" << user_context_
1900 << "' is not a JSON map");
1901 }
1902 host->setContext(ctx);
1903 } catch (const isc::data::JSONError& ex) {
1904 isc_throw(BadValue, "user context '" << user_context_
1905 << "' is invalid JSON: " << ex.what());
1906 }
1907 }
1908
1909 host->setHostId(id);
1910
1911 const IPv6Resrv reservation = retrieveReservation();
1912 if (reservation != NULL_IPV6_RESERVATION &&
1913 !host->hasReservation(reservation)) {
1914 host->addReservation(reservation);
1915 }
1916
1917 OptionWrapper option_wrapper = retrieveOption();
1918 if (option_wrapper.option_descriptor_) {
1919 if (option_wrapper.option_descriptor_->option_->getUniverse() == Option::V4) {
1920 host->getCfgOption4()->add(*option_wrapper.option_descriptor_,
1921 option_wrapper.option_space_);
1922 } else if (option_wrapper.option_descriptor_->option_->getUniverse() == Option::V6) {
1923 host->getCfgOption6()->add(*option_wrapper.option_descriptor_,
1924 option_wrapper.option_space_);
1925 }
1926 }
1927
1928 return (host);
1929 }
1930
1931 const IPv6Resrv
retrieveReservation() const1932 CqlHostExchange::retrieveReservation() const {
1933 // Set the IPv6 Reservation type (0 = IA_NA, 2 = IA_PD).
1934 IPv6Resrv::Type type;
1935 switch (reserved_ipv6_prefix_address_type_) {
1936 case 0:
1937 type = IPv6Resrv::TYPE_NA;
1938 break;
1939 case 2:
1940 type = IPv6Resrv::TYPE_PD;
1941 break;
1942 case NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE:
1943 return (NULL_IPV6_RESERVATION);
1944 default:
1945 isc_throw(BadValue, "CqlHostExchange::retrieveReservation(): invalid IPv6 "
1946 "reservation type returned: " << reserved_ipv6_prefix_address_type_
1947 << ". Only 0 (IA_NA) or 2 (IA_PD) are allowed.");
1948 }
1949
1950 return (IPv6Resrv(type, IOAddress(reserved_ipv6_prefix_address_),
1951 reserved_ipv6_prefix_length_));
1952 }
1953
1954 const OptionWrapper
retrieveOption() const1955 CqlHostExchange::retrieveOption() const {
1956 // Options are held in a binary or textual format in the database.
1957 // This is similar to having an option specified in a server
1958 // configuration file. Such option is converted to appropriate C++
1959 // class, using option definition. Thus, we need to find the
1960 // option definition for this option code and option space.
1961
1962 // If the option space is a standard DHCPv4 or DHCPv6 option space,
1963 // this is most likely a standard option, for which we have a
1964 // definition created within libdhcp++.
1965 if (option_space_.empty() || option_universe_ == NULL_OPTION_UNIVERSE) {
1966 return (OptionWrapper(OptionDescriptorPtr(), ""));
1967 }
1968
1969 OptionDefinitionPtr option_definition_ptr =
1970 LibDHCP::getOptionDef(option_space_, option_code_);
1971
1972 // Otherwise, we may check if this an option encapsulated within the
1973 // vendor space.
1974 if (!option_definition_ptr && option_space_ != DHCP4_OPTION_SPACE &&
1975 option_space_ != DHCP6_OPTION_SPACE) {
1976 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space_);
1977 if (vendor_id > 0) {
1978 option_definition_ptr = LibDHCP::getVendorOptionDef(
1979 static_cast<Option::Universe>(option_universe_), vendor_id,
1980 option_code_);
1981 }
1982 }
1983
1984 // In all other cases, we use runtime option definitions, which
1985 // should be also registered within the libdhcp++.
1986 if (!option_definition_ptr) {
1987 option_definition_ptr =
1988 LibDHCP::getRuntimeOptionDef(option_space_, option_code_);
1989 }
1990
1991 OptionPtr option;
1992 if (!option_definition_ptr) {
1993 // If no definition found, we use generic option type.
1994 OptionBuffer option_buffer(option_value_.begin(), option_value_.end());
1995 option = boost::make_shared<Option>(static_cast<Option::Universe>(option_universe_),
1996 static_cast<uint16_t>(option_code_),
1997 option_buffer.begin(), option_buffer.end());
1998 } else {
1999 // The option value may be specified in textual or binary format
2000 // in the
2001 // database. If formatted_value is empty, the binary format is
2002 // used.
2003 // Depending on the format we use a different variant of @ref
2004 // optionFactory().
2005 if (option_formatted_value_.empty()) {
2006 OptionBuffer option_buffer(option_value_.begin(),
2007 option_value_.end());
2008 option = option_definition_ptr->optionFactory(
2009 static_cast<Option::Universe>(option_universe_),
2010 static_cast<uint16_t>(option_code_), option_buffer.begin(),
2011 option_buffer.end());
2012 } else {
2013 // Spit the value specified in comma separated values
2014 // format.
2015 std::vector<std::string> split_vector;
2016 boost::split(split_vector, option_formatted_value_,
2017 boost::is_any_of(","));
2018 option = option_definition_ptr->optionFactory(
2019 static_cast<Option::Universe>(option_universe_),
2020 static_cast<uint16_t>(option_code_), split_vector);
2021 }
2022 }
2023
2024 OptionWrapper result(boost::make_shared<OptionDescriptor>(option, option_is_persistent_,
2025 option_formatted_value_),
2026 option_space_);
2027 // Set the user context if there is one into the option descriptor.
2028 if (!option_user_context_.empty()) {
2029 try {
2030 ConstElementPtr ctx = Element::fromJSON(option_user_context_);
2031 if (!ctx || (ctx->getType() != Element::map)) {
2032 isc_throw(BadValue, "option user context '" << option_user_context_
2033 << "' is no a JSON map");
2034 }
2035 result.option_descriptor_->setContext(ctx);
2036 } catch (const isc::data::JSONError& ex) {
2037 isc_throw(BadValue, "option user context '" << option_user_context_
2038 << "' is invalid JSON: " << ex.what());
2039 }
2040 }
2041
2042 return result;
2043 }
2044
2045 /// @brief Implementation of the @ref CqlHostDataSource.
2046 ///
2047 /// This class is encapsulate all the Cassandra communication details.
2048 class CqlHostDataSourceImpl {
2049 public:
2050 /// @brief Constructor.
2051 ///
2052 /// This constructor opens database connection and initializes
2053 /// prepared statements used in the queries.
2054 /// @param parameters parameters passed to the CQL connection.
2055 explicit CqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters);
2056
2057 /// @brief Destructor.
2058 virtual ~CqlHostDataSourceImpl();
2059
2060 /// @brief Implementation of @ref CqlHostDataSource::add() and del()
2061 ///
2062 /// See @ref CqlHostDataSource::add() for parameter details.
2063 ///
2064 /// @param host host to be added or deleted
2065 /// @param insert insert (true) or delete (false) the host
2066 virtual bool insertOrDelete(const HostPtr& host, bool insert);
2067
2068 /// @brief Implementation of @ref CqlHostDataSource::get4()
2069 ///
2070 /// See @ref CqlHostDataSource::get4() for parameter details.
2071 ///
2072 /// @param subnet_id Id of the subnet to look into
2073 /// @param address IPv4 address to be retrieved
2074 virtual ConstHostPtr get4(const SubnetID& subnet_id,
2075 const asiolink::IOAddress& address) const;
2076
2077 /// @brief Implementation of @ref CqlHostDataSource::get4()
2078 ///
2079 /// See @ref CqlHostDataSource::get4() for parameter details.
2080 ///
2081 /// @param subnet_id Id of the subnet to look into
2082 /// @param identifier_type type of the identifier
2083 /// @param identifier_begin pointer to the first byte of the identifier
2084 /// @param identifier_len length of the identifier
2085 virtual ConstHostPtr get4(const SubnetID& subnet_id,
2086 const Host::IdentifierType& identifier_type,
2087 const uint8_t* identifier_begin,
2088 const size_t identifier_len) const;
2089
2090 /// @brief Retrieves a host by its reserved IPv6 address or prefix
2091 ///
2092 /// See @ref CqlHostDataSource::get6() for parameter details.
2093 ///
2094 /// @param prefix IPv6 address or prefix
2095 /// @param prefix_len length of the prefix (or 128 for address)
2096 virtual ConstHostPtr get6(const asiolink::IOAddress& prefix,
2097 const uint8_t prefix_len) const;
2098
2099 /// @brief Implementation of @ref CqlHostDataSource::get6()
2100 ///
2101 /// See @ref CqlHostDataSource::get6() for parameter details.
2102 ///
2103 /// @param subnet_id Id of the subnet to look into
2104 /// @param identifier_type type of the identifier (duid, hwaddr, flex, etc.)
2105 /// @param identifier_begin pointer to the first byte of the identifier
2106 /// @param identifier_len length of the identifier
2107 virtual ConstHostPtr get6(const SubnetID& subnet_id,
2108 const Host::IdentifierType& identifier_type,
2109 const uint8_t* identifier_begin,
2110 const size_t identifier_len) const;
2111
2112 /// @brief Implementation of @ref CqlHostDataSource::get6()
2113 ///
2114 /// See @ref CqlHostDataSource::get6() for parameter details.
2115 ///
2116 /// @param subnet_id Id of the subnet to look into
2117 /// @param address IPv6 address to be retrieved
2118 virtual ConstHostPtr get6(const SubnetID& subnet_id,
2119 const asiolink::IOAddress& address) const;
2120
2121 /// @brief Implementation of @ref CqlHostDataSource::getAll()
2122 ///
2123 /// See @ref CqlHostDataSource::getAll() for parameter details.
2124 ///
2125 /// @param identifier_type type of the identifier (duid, hwaddr, flex, etc.)
2126 /// @param identifier_begin pointer to the first byte of the identifier
2127 /// @param identifier_len length of the identifier
2128 virtual ConstHostCollection
2129 getAll(const Host::IdentifierType& identifier_type,
2130 const uint8_t* identifier_begin,
2131 const size_t identifier_len) const;
2132
2133 /// @brief Implementation of @ref CqlHostDataSource::getAll4()
2134 ///
2135 /// See @ref CqlHostDataSource::getAll4() for parameter details.
2136 ///
2137 /// @param subnet_id identifier of the subnet to which hosts belong
2138 virtual ConstHostCollection getAll4(const SubnetID& subnet_id) const;
2139
2140 /// @brief Implementation of @ref CqlHostDataSource::getAll6()
2141 ///
2142 /// See @ref CqlHostDataSource::getAll6() for parameter details.
2143 ///
2144 /// @param subnet_id identifier of the subnet to which hosts belong
2145 virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const;
2146
2147 /// @brief Implementation of @ref CqlHostDataSource::getAllbyHostname()
2148 ///
2149 /// See @ref CqlHostDataSource::getAllbyHostname() for parameter details.
2150 ///
2151 /// @param hostname The lower case hostname.
2152 virtual ConstHostCollection
2153 getAllbyHostname(const std::string& hostname) const;
2154
2155 /// @brief Implementation of @ref CqlHostDataSource::getAllbyHostname4()
2156 ///
2157 /// See @ref CqlHostDataSource::getAllbyHostname4() for parameter details.
2158 ///
2159 /// @param hostname The lower case hostname.
2160 /// @param subnet_id Subnet identifier.
2161 virtual ConstHostCollection
2162 getAllbyHostname4(const std::string& hostname, const SubnetID& subnet_id) const;
2163
2164 /// @brief Implementation of @ref CqlHostDataSource::getAllbyHostname6()
2165 ///
2166 /// See @ref CqlHostDataSource::getAllbyHostname6() for parameter details.
2167 ///
2168 /// @param hostname The lower case hostname.
2169 /// @param subnet_id Subnet identifier.
2170 virtual ConstHostCollection
2171 getAllbyHostname6(const std::string& hostname, const SubnetID& subnet_id) const;
2172
2173 /// @brief Implementation of @ref CqlHostDataSource::getPage4()
2174 ///
2175 /// See @ref CqlHostDataSource::getPage4() for parameter details.
2176 ///
2177 /// @param subnet_id identifier of the subnet to which hosts belong
2178 /// @param lower_host_id Host identifier used as lower bound for the
2179 /// returned range.
2180 /// @param page_size maximum size of the page returned.
2181 virtual ConstHostCollection
2182 getPage4(const SubnetID& subnet_id,
2183 uint64_t lower_host_id,
2184 const HostPageSize& page_size) const;
2185
2186 /// @brief Implementation of @ref CqlHostDataSource::getPage6()
2187 ///
2188 /// See @ref CqlHostDataSource::getPage6() for parameter details.
2189 ///
2190 /// @param subnet_id identifier of the subnet to which hosts belong
2191 /// @param lower_host_id Host identifier used as lower bound for the
2192 /// returned range.
2193 /// @param page_size maximum size of the page returned.
2194 virtual ConstHostCollection
2195 getPage6(const SubnetID& subnet_id,
2196 uint64_t lower_host_id,
2197 const HostPageSize& page_size) const;
2198
2199 /// @brief Implementation of @ref CqlHostDataSource::getPage4()
2200 ///
2201 /// See @ref CqlHostDataSource::getPage4() for parameter details.
2202 ///
2203 /// @param lower_host_id Host identifier used as lower bound for the
2204 /// returned range.
2205 /// @param page_size maximum size of the page returned.
2206 virtual ConstHostCollection
2207 getPage4(uint64_t lower_host_id,
2208 const HostPageSize& page_size) const;
2209
2210 /// @brief Implementation of @ref CqlHostDataSource::getPage6()
2211 ///
2212 /// See @ref CqlHostDataSource::getPage6() for parameter details.
2213 ///
2214 /// @param lower_host_id Host identifier used as lower bound for the
2215 /// returned range.
2216 /// @param page_size maximum size of the page returned.
2217 virtual ConstHostCollection
2218 getPage6(uint64_t lower_host_id,
2219 const HostPageSize& page_size) const;
2220
2221 /// @brief Implementation of @ref CqlHostDataSource::getAll4()
2222 ///
2223 /// See @ref CqlHostDataSource::getAll4() for parameter details.
2224 ///
2225 /// @param address IPv4 address of the reservation to be retrieved
2226 virtual ConstHostCollection
2227 getAll4(const asiolink::IOAddress& address) const;
2228
2229 /// @brief Implementation of @ref CqlHostDataSource::getAllHosts()
2230 ///
2231 /// See @ref CqlHostDataSource::getAllHosts() for parameter details.
2232 virtual ConstHostCollection
2233 getAllHosts() const;
2234
2235 /// @brief Implementation of @ref CqlHostDataSource::getName()
2236 virtual std::string getName() const;
2237
2238 /// @brief Implementation of @ref CqlHostDataSource::getVersion()
2239 virtual VersionPair getVersion() const;
2240
2241 protected:
2242 /// @brief Adds/deletes any options found in the @ref Host object to/from a separate
2243 /// table entry.
2244 ///
2245 /// @param insert insert or delete a host with options
2246 /// @param host @ref Host object from which options are retrieved and
2247 /// inserted/deleted into/from the Cassandra database
2248 /// @param reservation reservation for the current denormalized table entry
2249 /// @param option_spaces list of option spaces to search for
2250 /// @param cfg_option option configuration used to match option spaces in
2251 /// order to obtain actual options
2252 virtual bool insertOrDeleteHostWithOptions(bool insert,
2253 const HostPtr& host,
2254 const IPv6Resrv* const reservation = NULL,
2255 const std::list<std::string>& option_spaces = std::list<std::string>(),
2256 const ConstCfgOptionPtr cfg_option = ConstCfgOptionPtr());
2257
2258 /// @brief Adds/deletes any reservations found in the @ref Host object to/from a separate
2259 /// table entry.
2260 ///
2261 /// @param insert insert or deletes a host with reservations
2262 /// @param host @ref Host object from which reservations are retrieved and
2263 /// inserted/deleted into/from the Cassandra database
2264 /// @param reservation reservation for the current denormalized table entry
2265 /// @param option_spaces4 list of option spaces for universe Option::V4 to search in
2266 /// @param cfg_option4 option configuration for universe Option::V4 used to
2267 /// match option spaces in order to obtain actual options
2268 /// @param option_spaces6 list of option spaces for universe Option::V6 to
2269 /// search in
2270 /// @param cfg_option6 option configuration for universe Option::V6 used to
2271 /// match option spaces in order to obtain actual options
2272 virtual bool insertOrDeleteHostWithReservations(bool insert,
2273 const HostPtr& host,
2274 const IPv6Resrv* const reservation,
2275 const std::list<std::string>& option_spaces4,
2276 const ConstCfgOptionPtr cfg_option4,
2277 const std::list<std::string>& option_spaces6,
2278 const ConstCfgOptionPtr cfg_option6);
2279
2280 /// @brief Retrieves a single host.
2281 ///
2282 /// Calls @ref getHostCollection() and checks if a single host was
2283 /// returned.
2284 ///
2285 /// @param where_values array of bound objects used to filter the results
2286 /// @param statement_tag prepared statement being executed
2287 ///
2288 /// @return one host or a null pointer to a host
2289 ///
2290 /// @throw MultipleRecords exception if two or more hosts are
2291 /// returned
2292 virtual ConstHostPtr getHost(StatementTag statement_tag,
2293 AnyArray& where_values) const;
2294
2295 /// @brief Retrieves a collection of hosts.
2296 ///
2297 /// Calls @ref db::CqlExchange::executeSelect().
2298 ///
2299 /// @param where_values array of bound objects used to filter the results
2300 /// @param statement_tag prepared statement being executed
2301 ///
2302 /// @return a collection of hosts containing one or more hosts
2303 virtual ConstHostCollection getHostCollection(StatementTag statement_tag,
2304 AnyArray& where_values) const;
2305
2306 /// @brief Retrieves a page of hosts.
2307 ///
2308 /// @param subnet_id identifier of the subnet to which hosts belong
2309 /// @param lower_host_id Host identifier used as lower bound for the
2310 /// returned range.
2311 /// @param count the size of the page
2312 ///
2313 /// @return a collection of hosts containing one or more hosts
2314 virtual ConstHostCollection getHostCollectionPage4(const SubnetID& subnet_id,
2315 uint64_t lower_host_id,
2316 size_t count = 0) const;
2317
2318 /// @brief Retrieves a page of hosts.
2319 ///
2320 /// @param subnet_id identifier of the subnet to which hosts belong
2321 /// @param lower_host_id Host identifier used as lower bound for the
2322 /// returned range.
2323 /// @param count the size of the page
2324 ///
2325 /// @return a collection of hosts containing one or more hosts
2326 virtual ConstHostCollection getHostCollectionPage6(const SubnetID& subnet_id,
2327 uint64_t lower_host_id,
2328 size_t count = 0) const;
2329
2330 /// @brief Retrieves a page of hosts.
2331 ///
2332 /// @param lower_host_id Host identifier used as lower bound for the
2333 /// returned range.
2334 /// @param count the size of the page
2335 ///
2336 /// @return a collection of hosts containing one or more hosts
2337 virtual ConstHostCollection getHostCollectionPage4(uint64_t lower_host_id,
2338 size_t count = 0) const;
2339
2340 /// @brief Retrieves a page of hosts.
2341 ///
2342 /// @param lower_host_id Host identifier used as lower bound for the
2343 /// returned range.
2344 /// @param count the size of the page
2345 ///
2346 /// @return a collection of hosts containing one or more hosts
2347 virtual ConstHostCollection getHostCollectionPage6(uint64_t lower_host_id,
2348 size_t count = 0) const;
2349
2350 /// @brief Retrieves a host by key.
2351 ///
2352 /// @param key identifier of the host
2353 ///
2354 /// @return a host for the specific key
2355 virtual ConstHostPtr getHostByKey(uint64_t key) const;
2356
2357 /// @brief Retrieves a valid host key.
2358 /// if lower_host_id is 0 the key parameter will be updated with the key of
2359 /// the first host
2360 /// if lower_host_id is not 0 the key parameter will be updated with the
2361 /// next valid host key
2362 ///
2363 /// @param subnet_id identifier of the subnet to which hosts belong
2364 /// @param lower_host_id Host identifier used as lower bound for the
2365 /// returned range.
2366 /// @param key identifier of the host which will be updated
2367 ///
2368 /// @return true if there is such a host
2369 virtual bool getHostKey4(const SubnetID& subnet_id,
2370 uint64_t lower_host_id,
2371 uint64_t& key) const;
2372
2373 /// @brief Retrieves a valid host key.
2374 /// if lower_host_id is 0 the key parameter will be updated with the key of
2375 /// the first host
2376 /// if lower_host_id is not 0 the key parameter will be updated with the
2377 /// next valid host key
2378 ///
2379 /// @param subnet_id identifier of the subnet to which hosts belong
2380 /// @param lower_host_id Host identifier used as lower bound for the
2381 /// returned range.
2382 /// @param key identifier of the host which will be updated
2383 ///
2384 /// @return true if there is such a host
2385 virtual bool getHostKey6(const SubnetID& subnet_id,
2386 uint64_t lower_host_id,
2387 uint64_t& key) const;
2388
2389 /// @brief Retrieves a valid host key.
2390 /// if lower_host_id is 0 the key parameter will be updated with the key of
2391 /// the first host
2392 /// if lower_host_id is not 0 the key parameter will be updated with the
2393 /// next valid host key
2394 ///
2395 /// @param lower_host_id Host identifier used as lower bound for the
2396 /// returned range.
2397 /// @param key identifier of the host which will be updated
2398 ///
2399 /// @return true if there is such a host
2400 virtual bool getHostKey(uint64_t lower_host_id,
2401 uint64_t& key) const;
2402
2403 /// @brief Retrieves next valid host key.
2404 ///
2405 /// @param subnet_id identifier of the subnet to which hosts belong
2406 /// @param key identifier of the host which will be updated with the next
2407 /// valid host key
2408 ///
2409 /// @return true if there is such a host
2410 virtual bool getNextHostKey4(const SubnetID& subnet_id,
2411 uint64_t& key) const;
2412
2413 /// @brief Retrieves next valid host key.
2414 ///
2415 /// @param subnet_id identifier of the subnet to which hosts belong
2416 /// @param key identifier of the host which will be updated with the next
2417 /// valid host key
2418 ///
2419 /// @return true if there is such a host
2420 virtual bool getNextHostKey6(const SubnetID& subnet_id,
2421 uint64_t& key) const;
2422
2423 /// @brief Retrieves next valid host key.
2424 ///
2425 /// @param key identifier of the host which will be updated with the next
2426 /// valid host key
2427 ///
2428 /// @return true if there is such a host
2429 virtual bool getNextHostKey(uint64_t& key) const;
2430
2431 /// @brief Inserts or deletes a single host.
2432 ///
2433 /// All information is available here. Calls @ref
2434 /// db::CqlExchange::executeMutation().
2435 ///
2436 /// @param insert insert or delete a host
2437 /// @param host @ref Host object from which options are retrieved and
2438 /// inserted/deleted into/from the Cassandra database
2439 /// @param subnet_id identifier of the subnet to which the host belongs
2440 /// @param reservation reservation for the current denormalized table entry
2441 /// @param option_space option space for the current denormalized table
2442 /// entry's option
2443 /// @param option_descriptor option descriptor containing
2444 /// information for the current denormalized table entry's option
2445 virtual bool insertOrDeleteHost(bool insert,
2446 const HostPtr& host,
2447 const Optional<SubnetID>& subnet_id = Optional<SubnetID>(),
2448 const IPv6Resrv* const reservation = NULL,
2449 const std::string& option_space = NULL_OPTION_SPACE,
2450 const OptionDescriptor& option_descriptor = OptionDescriptor(false));
2451
2452 /// @brief Merge denormalized table entries that belong to the same host
2453 /// into a single host, one by one.
2454 ///
2455 /// @param target_host host which can contain multiple reservations and
2456 /// options to which other distinct reservations and options are
2457 /// added.
2458 /// @param source_host host that is being search for new reservations and
2459 /// options that will be merged into the old host.
2460 virtual void mergeHosts(const ConstHostPtr& source_host,
2461 HostPtr& target_host) const;
2462
2463 private:
2464 /// @brief Parameters
2465 db::DatabaseConnection::ParameterMap parameters_;
2466
2467 /// @brief CQL connection
2468 mutable CqlConnection dbconn_;
2469 }; // class CqlHostDataSourceImpl
2470
2471 /// @brief hash function for HostMap
2472 ///
2473 /// Returns a 64-bits key value. The key is generated with FNV-1a 64 bit
2474 /// algorithm.
2475 ///
2476 /// @param key being hashed
2477 ///
2478 /// @return hash value
2479 std::size_t
hash_value(const HostKey & key)2480 hash_value(const HostKey& key) {
2481 // Get key.
2482 std::stringstream key_stream;
2483 HostIdentifier host_identifier = std::get<HOST_IDENTIFIER>(key);
2484 key_stream << DUID(host_identifier).toText() << "-";
2485 key_stream << std::get<HOST_IDENTIFIER_TYPE>(key) << "-";
2486 key_stream << std::get<IPv4_SUBNET_ID>(key) << "-";
2487 key_stream << std::get<IPv6_SUBNET_ID>(key) << "-";
2488 key_stream << std::get<IPv4_RESERVATION>(key);
2489 const std::string key_string = key_stream.str();
2490
2491 const uint64_t hash = Hash64::hash(key_string);
2492
2493 return (static_cast<std::size_t>(hash));
2494 }
2495
2496 /// @brief equals operator for HostKey
2497 ///
2498 /// @param key1 left hand side operand
2499 /// @param key2 right hand side operand
2500 ///
2501 /// @return true if keys are equal. Deep comparison is made.
2502 bool
operator ==(const HostKey & key1,const HostKey & key2)2503 operator==(const HostKey& key1, const HostKey& key2) {
2504 return (std::get<HOST_IDENTIFIER>(key1) == std::get<HOST_IDENTIFIER>(key2) &&
2505 std::get<HOST_IDENTIFIER_TYPE>(key1) ==
2506 std::get<HOST_IDENTIFIER_TYPE>(key2) &&
2507 std::get<IPv4_SUBNET_ID>(key1) == std::get<IPv4_SUBNET_ID>(key2) &&
2508 std::get<IPv6_SUBNET_ID>(key1) == std::get<IPv6_SUBNET_ID>(key2) &&
2509 std::get<IPv4_RESERVATION>(key1) == std::get<IPv4_RESERVATION>(key2));
2510 }
2511
CqlHostDataSourceImpl(const DatabaseConnection::ParameterMap & parameters)2512 CqlHostDataSourceImpl::CqlHostDataSourceImpl(const DatabaseConnection::ParameterMap& parameters)
2513 : parameters_(parameters), dbconn_(parameters) {
2514 // Validate the schema version first.
2515 std::pair<uint32_t, uint32_t> code_version(CQL_SCHEMA_VERSION_MAJOR,
2516 CQL_SCHEMA_VERSION_MINOR);
2517 std::pair<uint32_t, uint32_t> db_version = getVersion();
2518 if (code_version != db_version) {
2519 isc_throw(DbOpenError, "Cassandra schema version mismatch: need version: "
2520 << code_version.first << "." << code_version.second
2521 << " found version: " << db_version.first << "."
2522 << db_version.second);
2523 }
2524
2525 // Open the database.
2526 dbconn_.openDatabase();
2527
2528 // Prepare all possible statements.
2529 dbconn_.prepareStatements(CqlHostExchange::tagged_statements_);
2530 }
2531
~CqlHostDataSourceImpl()2532 CqlHostDataSourceImpl::~CqlHostDataSourceImpl() {
2533 // There is no need to close the database in this destructor: it is
2534 // closed in the destructor of the dbconn_ member variable.
2535 }
2536
2537 bool
insertOrDelete(const HostPtr & host,bool insert)2538 CqlHostDataSourceImpl::insertOrDelete(const HostPtr& host, bool insert) {
2539 // If there is no host, there is nothing to do.
2540 if (!host) {
2541 return (false);
2542 }
2543
2544 // Get option space names and vendor space names and combine them within a
2545 // single list.
2546
2547 // For IPv4:
2548 ConstCfgOptionPtr cfg_option4 = host->getCfgOption4();
2549 std::list<std::string> option_spaces4 = cfg_option4->getOptionSpaceNames();
2550 std::list<std::string> vendor_spaces4 = cfg_option4->getVendorIdsSpaceNames();
2551 option_spaces4.insert(option_spaces4.end(), vendor_spaces4.begin(),
2552 vendor_spaces4.end());
2553
2554 // For IPv6:
2555 ConstCfgOptionPtr cfg_option6 = host->getCfgOption6();
2556 std::list<std::string> option_spaces6 = cfg_option6->getOptionSpaceNames();
2557 std::list<std::string> vendor_spaces6 = cfg_option6->getVendorIdsSpaceNames();
2558 option_spaces6.insert(option_spaces6.end(), vendor_spaces6.begin(),
2559 vendor_spaces6.end());
2560
2561 bool result = true;
2562
2563 // For every IPv6 reservation, add each of their options to the
2564 // database.
2565 IPv6ResrvRange reservations = host->getIPv6Reservations();
2566 if (std::distance(reservations.first, reservations.second) > 0) {
2567 for (IPv6ResrvIterator it = reservations.first; result && it != reservations.second; ++it) {
2568 result = insertOrDeleteHostWithReservations(insert, host, &it->second, option_spaces4, cfg_option4,
2569 option_spaces6, cfg_option6);
2570 }
2571 } else {
2572 // If host has no reservation, add entries with null
2573 // reservation. Options could still be present.
2574 result = insertOrDeleteHostWithReservations(insert, host, NULL, option_spaces4, cfg_option4,
2575 option_spaces6, cfg_option6);
2576 }
2577
2578 return (result);
2579 }
2580
2581 ConstHostPtr
get4(const SubnetID & subnet_id,const asiolink::IOAddress & address) const2582 CqlHostDataSourceImpl::get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const {
2583 if (!address.isV4()) {
2584 isc_throw(BadValue, "CqlHostDataSource::get4(2): wrong address type, "
2585 "address supplied is not an IPv4 address");
2586 }
2587
2588 // Convert to CQL data types.
2589 cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
2590 cass_int32_t host_ipv4_address = static_cast<cass_int32_t>(address.toUint32());
2591
2592 // Bind to array.
2593 AnyArray where_values;
2594 where_values.add(&host_ipv4_subnet_id);
2595 where_values.add(&host_ipv4_address);
2596
2597 // Run statement.
2598 ConstHostPtr result = getHost(CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS,
2599 where_values);
2600
2601 return (result);
2602 }
2603
2604 ConstHostPtr
get4(const SubnetID & subnet_id,const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len) const2605 CqlHostDataSourceImpl::get4(const SubnetID& subnet_id,
2606 const Host::IdentifierType& identifier_type,
2607 const uint8_t* identifier_begin,
2608 const size_t identifier_len) const {
2609 // Convert to CQL data types.
2610 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
2611 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
2612 cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
2613
2614 // Bind to array.
2615 AnyArray where_values;
2616 where_values.add(&host_ipv4_subnet_id);
2617 where_values.add(&host_identifier);
2618 where_values.add(&host_identifier_type);
2619
2620 // Run statement.
2621 ConstHostPtr result = getHost(CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_HOST_ID,
2622 where_values);
2623
2624 return (result);
2625 }
2626
2627 ConstHostPtr
get6(const asiolink::IOAddress & prefix,const uint8_t prefix_len) const2628 CqlHostDataSourceImpl::get6(const asiolink::IOAddress& prefix,
2629 const uint8_t prefix_len) const {
2630 // Convert to CQL data types.
2631 std::string reserved_ipv6_prefix_address = prefix.toText();
2632 cass_int32_t reserved_ipv6_prefix_length = prefix_len;
2633
2634 ConstHostPtr host;
2635 // Bind to array.
2636 AnyArray where_values;
2637 where_values.add(&reserved_ipv6_prefix_address);
2638 where_values.add(&reserved_ipv6_prefix_length);
2639
2640 // Get host id.
2641 host = getHost(CqlHostExchange::GET_HOST_BY_IPV6_PREFIX, where_values);
2642
2643 if (!host) {
2644 return ConstHostPtr();
2645 }
2646
2647 // Get host.
2648 HostIdentifier host_identifier = host->getIdentifier();
2649 // Delegate to getAll(3).
2650 ConstHostCollection collection = getAll(host->getIdentifierType(), host_identifier.data(),
2651 host_identifier.size());
2652
2653 if (collection.empty()) {
2654 return (ConstHostPtr());
2655 }
2656
2657 if (collection.size() >= 2u) {
2658 isc_throw(MultipleRecords,
2659 "CqlHostDataSource::get6(2): multiple records were "
2660 "found in the "
2661 "database where only one was expected for statement "
2662 << CqlHostExchange::GET_HOST_BY_IPV6_PREFIX);
2663 }
2664
2665 ConstHostPtr result = *collection.begin();
2666
2667 return (result);
2668 }
2669
2670 ConstHostPtr
get6(const SubnetID & subnet_id,const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len) const2671 CqlHostDataSourceImpl::get6(const SubnetID& subnet_id,
2672 const Host::IdentifierType& identifier_type,
2673 const uint8_t* identifier_begin,
2674 const size_t identifier_len) const {
2675 // Convert to CQL data types.
2676 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
2677 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
2678 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
2679
2680 // Bind to array.
2681 AnyArray where_values;
2682 where_values.add(&host_ipv6_subnet_id);
2683 where_values.add(&host_identifier);
2684 where_values.add(&host_identifier_type);
2685
2686 // Run statement.
2687 ConstHostPtr result = getHost(CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_HOST_ID,
2688 where_values);
2689
2690 return (result);
2691 }
2692
2693 ConstHostPtr
get6(const SubnetID & subnet_id,const IOAddress & address) const2694 CqlHostDataSourceImpl::get6(const SubnetID& subnet_id, const IOAddress& address) const {
2695 // Convert to CQL data types.
2696 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
2697 std::string reserved_ipv6_prefix_address = address.toText();
2698
2699 // Bind to array.
2700 AnyArray where_values;
2701 where_values.add(&host_ipv6_subnet_id);
2702 where_values.add(&reserved_ipv6_prefix_address);
2703
2704 // Run statement.
2705 ConstHostPtr result = getHost(CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS,
2706 where_values);
2707
2708 return (result);
2709 }
2710
2711 ConstHostCollection
getAll(const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len) const2712 CqlHostDataSourceImpl::getAll(const Host::IdentifierType& identifier_type,
2713 const uint8_t* identifier_begin,
2714 const size_t identifier_len) const {
2715 // Convert to CQL data types.
2716 CassBlob host_identifier(identifier_begin, identifier_begin + identifier_len);
2717 cass_int32_t host_identifier_type = static_cast<cass_int32_t>(identifier_type);
2718
2719 // Bind to array.
2720 AnyArray where_values;
2721 where_values.add(&host_identifier);
2722 where_values.add(&host_identifier_type);
2723
2724 // Run statement.
2725 ConstHostCollection result = getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_ID,
2726 where_values);
2727
2728 return (result);
2729 }
2730
2731 ConstHostCollection
getAll4(const SubnetID & subnet_id) const2732 CqlHostDataSourceImpl::getAll4(const SubnetID& subnet_id) const {
2733 // Convert to CQL data types.
2734 cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
2735
2736 // Bind to array.
2737 AnyArray where_values;
2738 where_values.add(&host_ipv4_subnet_id);
2739
2740 // Run statement.
2741 ConstHostCollection result =
2742 getHostCollection(CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID,
2743 where_values);
2744
2745 return (result);
2746 }
2747
2748 ConstHostCollection
getAll6(const SubnetID & subnet_id) const2749 CqlHostDataSourceImpl::getAll6(const SubnetID& subnet_id) const {
2750 // Convert to CQL data types.
2751 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
2752
2753 // Bind to array.
2754 AnyArray where_values;
2755 where_values.add(&host_ipv6_subnet_id);
2756
2757 // Run statement.
2758 ConstHostCollection result =
2759 getHostCollection(CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID,
2760 where_values);
2761
2762 return (result);
2763 }
2764
2765 ConstHostCollection
getAllbyHostname(const std::string & hostname) const2766 CqlHostDataSourceImpl::getAllbyHostname(const std::string& hostname) const {
2767 // Convert to CQL data types.
2768 std::string hostname_ = hostname;
2769
2770 // Bind to array.
2771 AnyArray where_values;
2772 where_values.add(&hostname_);
2773
2774 // Run statement.
2775 ConstHostCollection result =
2776 getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_NAME,
2777 where_values);
2778
2779 return (result);
2780 }
2781
2782 ConstHostCollection
getAllbyHostname4(const std::string & hostname,const SubnetID & subnet_id) const2783 CqlHostDataSourceImpl::getAllbyHostname4(const std::string& hostname,
2784 const SubnetID& subnet_id) const {
2785 // Convert to CQL data types.
2786 std::string hostname_ = hostname;
2787 cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
2788
2789 // Bind to array.
2790 AnyArray where_values;
2791 where_values.add(&hostname_);
2792 where_values.add(&host_ipv4_subnet_id);
2793
2794 // Run statement.
2795 ConstHostCollection result =
2796 getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV4_SUBNET_ID,
2797 where_values);
2798
2799 return (result);
2800 }
2801
2802 ConstHostCollection
getAllbyHostname6(const std::string & hostname,const SubnetID & subnet_id) const2803 CqlHostDataSourceImpl::getAllbyHostname6(const std::string& hostname,
2804 const SubnetID& subnet_id) const {
2805 // Convert to CQL data types.
2806 std::string hostname_ = hostname;
2807 cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
2808
2809 // Bind to array.
2810 AnyArray where_values;
2811 where_values.add(&hostname_);
2812 where_values.add(&host_ipv6_subnet_id);
2813
2814 // Run statement.
2815 ConstHostCollection result =
2816 getHostCollection(CqlHostExchange::GET_HOST_BY_HOST_NAME_AND_IPV6_SUBNET_ID,
2817 where_values);
2818
2819 return (result);
2820 }
2821
2822 // There are some problems implementing this for Cassandra.
2823 // Attempts show the per page ordering does not work and
2824 // it is not possible to order by TOKEN(host_id).
2825 // If the issue solved by paging is the Kea API overhead then
2826 // a solution is to get and cache all reservations and to handle
2827 // paging at the API level.
2828
2829 ConstHostCollection
getPage4(const SubnetID & subnet_id,uint64_t lower_host_id,const HostPageSize & page_size) const2830 CqlHostDataSourceImpl::getPage4(const SubnetID& subnet_id,
2831 uint64_t lower_host_id,
2832 const HostPageSize& page_size) const {
2833 // Run statement.
2834 ConstHostCollection result =
2835 getHostCollectionPage4(subnet_id, lower_host_id, page_size.page_size_);
2836
2837 return (result);
2838 }
2839
2840 ConstHostCollection
getPage6(const SubnetID & subnet_id,uint64_t lower_host_id,const HostPageSize & page_size) const2841 CqlHostDataSourceImpl::getPage6(const SubnetID& subnet_id,
2842 uint64_t lower_host_id,
2843 const HostPageSize& page_size) const {
2844 // Run statement.
2845 ConstHostCollection result =
2846 getHostCollectionPage6(subnet_id, lower_host_id, page_size.page_size_);
2847
2848 return (result);
2849 }
2850
2851 ConstHostCollection
getPage4(uint64_t lower_host_id,const HostPageSize & page_size) const2852 CqlHostDataSourceImpl::getPage4(uint64_t lower_host_id,
2853 const HostPageSize& page_size) const {
2854 // Run statement.
2855 ConstHostCollection result =
2856 getHostCollectionPage4(lower_host_id, page_size.page_size_);
2857
2858 return (result);
2859 }
2860
2861 ConstHostCollection
getPage6(uint64_t lower_host_id,const HostPageSize & page_size) const2862 CqlHostDataSourceImpl::getPage6(uint64_t lower_host_id,
2863 const HostPageSize& page_size) const {
2864 // Run statement.
2865 ConstHostCollection result =
2866 getHostCollectionPage6(lower_host_id, page_size.page_size_);
2867
2868 return (result);
2869 }
2870
2871 ConstHostCollection
getAll4(const asiolink::IOAddress & address) const2872 CqlHostDataSourceImpl::getAll4(const asiolink::IOAddress& address) const {
2873 // Convert to CQL data types.
2874 cass_int32_t host_ipv4_address = static_cast<cass_int32_t>(address.toUint32());
2875
2876 // Bind to array.
2877 AnyArray where_values;
2878 where_values.add(&host_ipv4_address);
2879
2880 // Run statement.
2881 ConstHostCollection result = getHostCollection(CqlHostExchange::GET_HOST_BY_IPV4_ADDRESS,
2882 where_values);
2883
2884 return (result);
2885 }
2886
2887 ConstHostCollection
getAllHosts() const2888 CqlHostDataSourceImpl::getAllHosts() const {
2889
2890 // Bind to array.
2891 AnyArray where_values;
2892
2893 // Run statement.
2894 ConstHostCollection result = getHostCollection(CqlHostExchange::GET_HOST, where_values);
2895
2896 return (result);
2897 }
2898
2899 std::string
getName() const2900 CqlHostDataSourceImpl::getName() const {
2901 std::string name;
2902 try {
2903 name = dbconn_.getParameter("name");
2904 } catch (...) {
2905 // Return an empty name.
2906 }
2907 return (name);
2908 }
2909
2910 VersionPair
getVersion() const2911 CqlHostDataSourceImpl::getVersion() const {
2912 return CqlConnection::getVersion(parameters_);
2913 }
2914
2915 bool
insertOrDeleteHostWithOptions(bool insert,const HostPtr & host,const IPv6Resrv * const reservation,const std::list<std::string> & option_spaces,const ConstCfgOptionPtr cfg_option)2916 CqlHostDataSourceImpl::insertOrDeleteHostWithOptions(bool insert,
2917 const HostPtr& host,
2918 const IPv6Resrv* const reservation,
2919 const std::list<std::string>& option_spaces,
2920 const ConstCfgOptionPtr cfg_option) {
2921 // If there is no host, there is nothing to do.
2922 if (!host) {
2923 return (false);
2924 }
2925
2926 bool result = true;
2927
2928 // For each option space retrieve all options and insert them into
2929 // the database.
2930 bool option_found = false;
2931 for (const std::string& space : option_spaces) {
2932 if (!result) {
2933 break;
2934 }
2935 OptionContainerPtr options = cfg_option->getAll(space);
2936 if (options && !options->empty()) {
2937 for (const OptionDescriptor& option : *options) {
2938 if (!result) {
2939 break;
2940 }
2941 option_found = true;
2942 /// @todo: Assign actual value to subnet id.
2943 result = insertOrDeleteHost(insert, host, Optional<SubnetID>(), reservation,
2944 space, option);
2945 }
2946 }
2947 }
2948 if (result && !option_found) {
2949 // @todo: Assign actual value to subnet id.
2950 result = insertOrDeleteHost(insert, host, Optional<SubnetID>(), reservation);
2951 }
2952
2953 return (result);
2954 }
2955
2956 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)2957 CqlHostDataSourceImpl::insertOrDeleteHostWithReservations(bool insert,
2958 const HostPtr& host,
2959 const IPv6Resrv* const reservation,
2960 const std::list<std::string>& option_spaces4,
2961 const ConstCfgOptionPtr cfg_option4,
2962 const std::list<std::string>& option_spaces6,
2963 const ConstCfgOptionPtr cfg_option6) {
2964 // If there is no host, there is nothing to do.
2965 if (!host) {
2966 return (false);
2967 }
2968
2969 bool result = true;
2970
2971 // If host has no reservation, add entries with null reservation.
2972 // Options could still be present.
2973 if (result && cfg_option4 && !cfg_option4->empty()) {
2974 result = insertOrDeleteHostWithOptions(insert, host, reservation, option_spaces4, cfg_option4);
2975 }
2976 if (result && cfg_option6 && !cfg_option6->empty()) {
2977 result = insertOrDeleteHostWithOptions(insert, host, reservation, option_spaces6, cfg_option6);
2978 }
2979 if (result &&
2980 (!cfg_option4 || cfg_option4->empty()) &&
2981 (!cfg_option6 || cfg_option6->empty())) {
2982 result = insertOrDeleteHostWithOptions(insert, host, reservation);
2983 }
2984
2985 return (result);
2986 }
2987
2988 ConstHostPtr
getHost(StatementTag statement_tag,AnyArray & where_values) const2989 CqlHostDataSourceImpl::getHost(StatementTag statement_tag,
2990 AnyArray& where_values) const {
2991 ConstHostCollection collection = getHostCollection(statement_tag, where_values);
2992
2993 if (collection.empty()) {
2994 return (ConstHostPtr());
2995 }
2996
2997 if (collection.size() >= 2u) {
2998 isc_throw(MultipleRecords, "CqlHostDataSourceImpl::getHost(): multiple records were "
2999 "found in the database where only one was expected for statement "
3000 << statement_tag);
3001 }
3002
3003 return (*collection.begin());
3004 }
3005
3006 ConstHostCollection
getHostCollection(StatementTag statement_tag,AnyArray & where_values) const3007 CqlHostDataSourceImpl::getHostCollection(StatementTag statement_tag,
3008 AnyArray& where_values) const {
3009 // Run statement.
3010 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3011 AnyArray collection = host_exchange->executeSelect(dbconn_, where_values,
3012 statement_tag, false);
3013
3014 // Create HostPtr objects.
3015 HostCollection host_collection;
3016 for (boost::any& host : collection) {
3017 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3018 }
3019
3020 // Merge the denormalized table entries that belong to the same host into a single host.
3021 HostMap map;
3022 for (HostPtr& host : host_collection) {
3023 HostKey key = HostKey(host->getIdentifier(), host->getIdentifierType(),
3024 host->getIPv4SubnetID(), host->getIPv6SubnetID(),
3025 host->getIPv4Reservation());
3026 if (map.find(key) == map.end()) {
3027 map[key] = host;
3028 } else {
3029 mergeHosts(host, map[key]);
3030 }
3031 }
3032
3033 ConstHostCollection result_collection;
3034
3035 for (HostPtr& host : host_collection) {
3036 HostKey key = HostKey(host->getIdentifier(), host->getIdentifierType(),
3037 host->getIPv4SubnetID(), host->getIPv6SubnetID(),
3038 host->getIPv4Reservation());
3039 if (map.find(key) != map.end()) {
3040 result_collection.push_back(map[key]);
3041 map.erase(key);
3042 }
3043 }
3044 return (result_collection);
3045 }
3046
3047 ConstHostPtr
getHostByKey(uint64_t key) const3048 CqlHostDataSourceImpl::getHostByKey(uint64_t key) const {
3049 // Bind to array.
3050 AnyArray where_values;
3051 cass_int64_t key_data = static_cast<cass_int64_t>(key);
3052 where_values.add(&key_data);
3053
3054 // Run statement.
3055 ConstHostCollection collection =
3056 getHostCollection(CqlHostExchange::GET_HOST_KEY,
3057 where_values);
3058
3059 if (collection.empty()) {
3060 return (ConstHostPtr());
3061 }
3062
3063 if (collection.size() >= 2u) {
3064 isc_throw(MultipleRecords, "CqlHostDataSourceImpl::getHost(): multiple records were "
3065 "found in the database where only one was expected for statement "
3066 << CqlHostExchange::GET_HOST_KEY);
3067 }
3068
3069 return (*collection.begin());
3070 }
3071
3072 ConstHostCollection
getHostCollectionPage4(const SubnetID & subnet_id,uint64_t lower_host_id,size_t count) const3073 CqlHostDataSourceImpl::getHostCollectionPage4(const SubnetID& subnet_id,
3074 uint64_t lower_host_id,
3075 size_t count) const {
3076 ConstHostCollection result_collection;
3077 for (; count; count--) {
3078 uint64_t key;
3079 bool valid_key = getHostKey4(subnet_id, lower_host_id, key);
3080
3081 if (!valid_key) {
3082 break;
3083 }
3084
3085 ConstHostPtr host = getHostByKey(key);
3086 result_collection.push_back(host);
3087 lower_host_id = host->getHostId();
3088 }
3089
3090 return (result_collection);
3091 }
3092
3093 ConstHostCollection
getHostCollectionPage6(const SubnetID & subnet_id,uint64_t lower_host_id,size_t count) const3094 CqlHostDataSourceImpl::getHostCollectionPage6(const SubnetID& subnet_id,
3095 uint64_t lower_host_id,
3096 size_t count) const {
3097 ConstHostCollection result_collection;
3098 for (; count; count--) {
3099 uint64_t key;
3100 bool valid_key = getHostKey6(subnet_id, lower_host_id, key);
3101
3102 if (!valid_key) {
3103 break;
3104 }
3105
3106 ConstHostPtr host = getHostByKey(key);
3107 result_collection.push_back(host);
3108 lower_host_id = host->getHostId();
3109 }
3110
3111 return (result_collection);
3112 }
3113
3114 ConstHostCollection
getHostCollectionPage4(uint64_t lower_host_id,size_t count) const3115 CqlHostDataSourceImpl::getHostCollectionPage4(uint64_t lower_host_id,
3116 size_t count) const {
3117 ConstHostCollection result_collection;
3118 for (; count; count--) {
3119 uint64_t key;
3120 bool valid_key = getHostKey(lower_host_id, key);
3121
3122 if (!valid_key) {
3123 break;
3124 }
3125
3126 ConstHostPtr host = getHostByKey(key);
3127 result_collection.push_back(host);
3128 lower_host_id = host->getHostId();
3129 }
3130
3131 return (result_collection);
3132 }
3133
3134 ConstHostCollection
getHostCollectionPage6(uint64_t lower_host_id,size_t count) const3135 CqlHostDataSourceImpl::getHostCollectionPage6(uint64_t lower_host_id,
3136 size_t count) const {
3137 ConstHostCollection result_collection;
3138 for (; count; count--) {
3139 uint64_t key;
3140 bool valid_key = getHostKey(lower_host_id, key);
3141
3142 if (!valid_key) {
3143 break;
3144 }
3145
3146 ConstHostPtr host = getHostByKey(key);
3147 result_collection.push_back(host);
3148 lower_host_id = host->getHostId();
3149 }
3150
3151 return (result_collection);
3152 }
3153
3154 bool
getHostKey4(const SubnetID & subnet_id,uint64_t lower_host_id,uint64_t & key) const3155 CqlHostDataSourceImpl::getHostKey4(const SubnetID& subnet_id,
3156 uint64_t lower_host_id,
3157 uint64_t& key) const {
3158 // Convert to CQL data types.
3159 cass_int32_t host_subnet_id = static_cast<cass_int32_t>(subnet_id);
3160
3161 // Bind to array.
3162 AnyArray where_values;
3163 where_values.add(&host_subnet_id);
3164
3165 cass_int64_t host_data = 0;
3166 if (lower_host_id) {
3167 host_data = static_cast<cass_int64_t>(lower_host_id);
3168 where_values.add(&host_data);
3169 }
3170
3171 // Run statement.
3172 // This will retrieve first row of the first host (lower_host_id == 0)
3173 // or the first row of the host (lower_host_id != 0)
3174 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3175 AnyArray collection;
3176 if (lower_host_id) {
3177 collection = host_exchange->executeSelect(dbconn_, where_values,
3178 CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_PAGE, false);
3179 } else {
3180 collection = host_exchange->executeSelect(dbconn_, where_values,
3181 CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_LIMIT, false);
3182 }
3183
3184 // Create HostPtr objects.
3185 HostCollection host_collection;
3186 for (boost::any& host : collection) {
3187 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3188 }
3189
3190 // If there is no host, just exit
3191 if (host_collection.empty()) {
3192 return false;
3193 }
3194
3195 key = host_exchange->hashIntoKey();
3196
3197 if (lower_host_id) {
3198 return getNextHostKey4(subnet_id, key);
3199 }
3200
3201 return true;
3202 }
3203
3204 bool
getHostKey6(const SubnetID & subnet_id,uint64_t lower_host_id,uint64_t & key) const3205 CqlHostDataSourceImpl::getHostKey6(const SubnetID& subnet_id,
3206 uint64_t lower_host_id,
3207 uint64_t& key) const {
3208 // Convert to CQL data types.
3209 cass_int32_t host_subnet_id = static_cast<cass_int32_t>(subnet_id);
3210
3211 // Bind to array.
3212 AnyArray where_values;
3213 where_values.add(&host_subnet_id);
3214
3215 cass_int64_t host_data = 0;
3216 if (lower_host_id) {
3217 host_data = static_cast<cass_int64_t>(lower_host_id);
3218 where_values.add(&host_data);
3219 }
3220
3221 // Run statement.
3222 // This will retrieve first row of the first host (lower_host_id == 0)
3223 // or the first row of the host (lower_host_id != 0)
3224 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3225 AnyArray collection;
3226 if (lower_host_id) {
3227 collection = host_exchange->executeSelect(dbconn_, where_values,
3228 CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_PAGE, false);
3229 } else {
3230 collection = host_exchange->executeSelect(dbconn_, where_values,
3231 CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_LIMIT, false);
3232 }
3233
3234 // Create HostPtr objects.
3235 HostCollection host_collection;
3236 for (boost::any& host : collection) {
3237 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3238 }
3239
3240 // If there is no host, just exit
3241 if (host_collection.empty()) {
3242 return false;
3243 }
3244
3245 key = host_exchange->hashIntoKey();
3246
3247 if (lower_host_id) {
3248 return getNextHostKey6(subnet_id, key);
3249 }
3250
3251 return true;
3252 }
3253
3254 bool
getHostKey(uint64_t lower_host_id,uint64_t & key) const3255 CqlHostDataSourceImpl::getHostKey(uint64_t lower_host_id,
3256 uint64_t& key) const {
3257 // Bind to array.
3258 AnyArray where_values;
3259 cass_int64_t host_data = 0;
3260 if (lower_host_id) {
3261 host_data = static_cast<cass_int64_t>(lower_host_id);
3262 where_values.add(&host_data);
3263 }
3264
3265 // Run statement.
3266 // This will retrieve first row of the first host (lower_host_id == 0)
3267 // or the first row of the host (lower_host_id != 0)
3268 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3269 AnyArray collection;
3270 if (lower_host_id) {
3271 collection = host_exchange->executeSelect(dbconn_, where_values,
3272 CqlHostExchange::GET_HOST_PAGE, false);
3273 } else {
3274 collection = host_exchange->executeSelect(dbconn_, where_values,
3275 CqlHostExchange::GET_HOST_LIMIT, false);
3276 }
3277
3278 // Create HostPtr objects.
3279 HostCollection host_collection;
3280 for (boost::any& host : collection) {
3281 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3282 }
3283
3284 // If there is no host, just exit
3285 if (host_collection.empty()) {
3286 return false;
3287 }
3288
3289 key = host_exchange->hashIntoKey();
3290
3291 if (lower_host_id) {
3292 return getNextHostKey(key);
3293 }
3294
3295 return true;
3296 }
3297
3298 bool
getNextHostKey4(const SubnetID & subnet_id,uint64_t & key) const3299 CqlHostDataSourceImpl::getNextHostKey4(const SubnetID& subnet_id,
3300 uint64_t& key) const {
3301 // Convert to CQL data types.
3302 cass_int32_t host_subnet_id = static_cast<cass_int32_t>(subnet_id);
3303 cass_int64_t key_data = static_cast<cass_int64_t>(key);
3304
3305 // Bind to array.
3306 AnyArray where_values;
3307 where_values.add(&host_subnet_id);
3308 where_values.add(&key_data);
3309
3310 // This will retrieve first row of the next host (lower_host_id != 0)
3311 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3312 AnyArray collection = host_exchange->executeSelect(dbconn_, where_values,
3313 CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_NEXT_KEY, false);
3314
3315 // Create HostPtr objects.
3316 HostCollection host_collection;
3317 for (boost::any& host : collection) {
3318 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3319 }
3320
3321 if (host_collection.empty()) {
3322 return false;
3323 }
3324
3325 key = host_exchange->hashIntoKey();
3326 return true;
3327 }
3328
3329 bool
getNextHostKey6(const SubnetID & subnet_id,uint64_t & key) const3330 CqlHostDataSourceImpl::getNextHostKey6(const SubnetID& subnet_id,
3331 uint64_t& key) const {
3332 // Convert to CQL data types.
3333 cass_int32_t host_subnet_id = static_cast<cass_int32_t>(subnet_id);
3334 cass_int64_t key_data = static_cast<cass_int64_t>(key);
3335
3336 // Bind to array.
3337 AnyArray where_values;
3338 where_values.add(&host_subnet_id);
3339 where_values.add(&key_data);
3340
3341 // This will retrieve first row of the next host (lower_host_id != 0)
3342 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3343 AnyArray collection = host_exchange->executeSelect(dbconn_, where_values,
3344 CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_NEXT_KEY, false);
3345
3346 // Create HostPtr objects.
3347 HostCollection host_collection;
3348 for (boost::any& host : collection) {
3349 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3350 }
3351
3352 if (host_collection.empty()) {
3353 return false;
3354 }
3355
3356 key = host_exchange->hashIntoKey();
3357 return true;
3358 }
3359
3360 bool
getNextHostKey(uint64_t & key) const3361 CqlHostDataSourceImpl::getNextHostKey(uint64_t& key) const {
3362 // Convert to CQL data types.
3363 cass_int64_t key_data = static_cast<cass_int64_t>(key);
3364
3365 // Bind to array.
3366 AnyArray where_values;
3367 where_values.add(&key_data);
3368
3369 // This will retrieve first row of the next host (lower_host_id != 0)
3370 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3371 AnyArray collection = host_exchange->executeSelect(dbconn_, where_values,
3372 CqlHostExchange::GET_HOST_NEXT_KEY, false);
3373
3374 // Create HostPtr objects.
3375 HostCollection host_collection;
3376 for (boost::any& host : collection) {
3377 host_collection.push_back(HostPtr(boost::any_cast<Host*>(host)));
3378 }
3379
3380 if (host_collection.empty()) {
3381 return false;
3382 }
3383
3384 key = host_exchange->hashIntoKey();
3385 return true;
3386 }
3387
3388 bool
insertOrDeleteHost(bool insert,const HostPtr & host,const Optional<SubnetID> & subnet_id,const IPv6Resrv * const reservation,const std::string & option_space,const OptionDescriptor & option_descriptor)3389 CqlHostDataSourceImpl::insertOrDeleteHost(bool insert,
3390 const HostPtr& host,
3391 const Optional<SubnetID>& subnet_id,
3392 const IPv6Resrv* const reservation,
3393 const std::string& option_space,
3394 const OptionDescriptor& option_descriptor) {
3395 // If there is no host, there is nothing to do.
3396 if (!host) {
3397 return (false);
3398 }
3399
3400 AnyArray assigned_values;
3401
3402 std::unique_ptr<CqlHostExchange> host_exchange(new CqlHostExchange());
3403
3404 try {
3405 if (insert) {
3406 host_exchange->createBindForMutation(host, subnet_id, reservation, option_space,
3407 option_descriptor, CqlHostExchange::INSERT_HOST, assigned_values);
3408
3409 host_exchange->executeMutation(dbconn_, assigned_values, CqlHostExchange::INSERT_HOST);
3410 } else {
3411 host_exchange->createBindForDelete(host, subnet_id, reservation, option_space,
3412 option_descriptor, CqlHostExchange::DELETE_HOST, assigned_values);
3413
3414 host_exchange->executeMutation(dbconn_, assigned_values, CqlHostExchange::DELETE_HOST);
3415 }
3416 } catch (const StatementNotApplied& exception) {
3417 if (insert) {
3418 isc_throw(DuplicateEntry, exception.what());
3419 } else {
3420 return (false);
3421 }
3422 }
3423
3424 return (true);
3425 }
3426
3427 void
mergeHosts(const ConstHostPtr & source_host,HostPtr & target_host) const3428 CqlHostDataSourceImpl::mergeHosts(const ConstHostPtr& source_host,
3429 HostPtr& target_host) const {
3430 // Merge reservations.
3431 const IPv6ResrvRange reservations_range =
3432 source_host->getIPv6Reservations();
3433 if (std::distance(reservations_range.first, reservations_range.second) > 0) {
3434 for (IPv6ResrvIterator reservations_iterator = reservations_range.first;
3435 reservations_iterator != reservations_range.second;
3436 ++reservations_iterator) {
3437 if (!target_host->hasReservation(reservations_iterator->second)) {
3438 target_host->addReservation(reservations_iterator->second);
3439 }
3440 }
3441 }
3442
3443 // Merge DHCPv4 options.
3444 source_host->getCfgOption4()->mergeTo(*target_host->getCfgOption4());
3445
3446 // Merge DHCPv6 options.
3447 source_host->getCfgOption6()->mergeTo(*target_host->getCfgOption6());
3448 }
3449
CqlHostDataSource(const DatabaseConnection::ParameterMap & parameters)3450 CqlHostDataSource::CqlHostDataSource(const DatabaseConnection::ParameterMap& parameters)
3451 : impl_(new CqlHostDataSourceImpl(parameters)) {
3452 // Cassandra support is now deprecated.
3453 LOG_WARN(dhcpsrv_logger, DHCPSRV_DEPRECATED).arg("Cassandra host backend");
3454 }
3455
~CqlHostDataSource()3456 CqlHostDataSource::~CqlHostDataSource() {
3457 delete impl_;
3458 }
3459
3460 void
add(const HostPtr & host)3461 CqlHostDataSource::add(const HostPtr& host) {
3462 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_ADD);
3463
3464 impl_->insertOrDelete(host, true);
3465 }
3466
3467 bool
del(const SubnetID & subnet_id,const asiolink::IOAddress & address)3468 CqlHostDataSource::del(const SubnetID& subnet_id, const asiolink::IOAddress& address) {
3469 HostPtr host = boost::const_pointer_cast<Host>(impl_->get4(subnet_id, address));
3470
3471 return (host ? impl_->insertOrDelete(host, false) : false);
3472 }
3473
3474 bool
del4(const SubnetID & subnet_id,const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len)3475 CqlHostDataSource::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
3476 const uint8_t* identifier_begin, const size_t identifier_len) {
3477 HostPtr host = boost::const_pointer_cast<Host>(impl_->get4(subnet_id, identifier_type,
3478 identifier_begin, identifier_len));
3479
3480 return (host ? impl_->insertOrDelete(host, false) : false);
3481 }
3482
3483 bool
del6(const SubnetID & subnet_id,const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len)3484 CqlHostDataSource::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
3485 const uint8_t* identifier_begin, const size_t identifier_len) {
3486 HostPtr host = boost::const_pointer_cast<Host>(impl_->get6(subnet_id, identifier_type,
3487 identifier_begin, identifier_len));
3488
3489 return (host ? impl_->insertOrDelete(host, false) : false);
3490 }
3491
3492 ConstHostCollection
getAll(const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len) const3493 CqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
3494 const uint8_t* identifier_begin,
3495 const size_t identifier_len) const {
3496 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3497
3498 return (impl_->getAll(identifier_type, identifier_begin, identifier_len));
3499 }
3500
3501 ConstHostCollection
getAll4(const SubnetID & subnet_id) const3502 CqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
3503 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3504
3505 return (impl_->getAll4(subnet_id));
3506 }
3507
3508 ConstHostCollection
getAll6(const SubnetID & subnet_id) const3509 CqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
3510 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3511
3512 return (impl_->getAll6(subnet_id));
3513 }
3514
3515 ConstHostCollection
getAllbyHostname(const std::string & hostname) const3516 CqlHostDataSource::getAllbyHostname(const std::string& hostname) const {
3517 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3518
3519 return (impl_->getAllbyHostname(hostname));
3520 }
3521
3522 ConstHostCollection
getAllbyHostname4(const std::string & hostname,const SubnetID & subnet_id) const3523 CqlHostDataSource::getAllbyHostname4(const std::string& hostname,
3524 const SubnetID& subnet_id) const {
3525 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3526
3527 return (impl_->getAllbyHostname4(hostname, subnet_id));
3528 }
3529
3530 ConstHostCollection
getAllbyHostname6(const std::string & hostname,const SubnetID & subnet_id) const3531 CqlHostDataSource::getAllbyHostname6(const std::string& hostname,
3532 const SubnetID& subnet_id) const {
3533 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3534
3535 return (impl_->getAllbyHostname6(hostname, subnet_id));
3536 }
3537
3538 ConstHostCollection
getPage4(const SubnetID & subnet_id,size_t &,uint64_t lower_host_id,const HostPageSize & page_size) const3539 CqlHostDataSource::getPage4(const SubnetID& subnet_id,
3540 size_t& /*source_index*/,
3541 uint64_t lower_host_id,
3542 const HostPageSize& page_size) const {
3543 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3544
3545 return (impl_->getPage4(subnet_id, lower_host_id, page_size));
3546 }
3547
3548 ConstHostCollection
getPage6(const SubnetID & subnet_id,size_t &,uint64_t lower_host_id,const HostPageSize & page_size) const3549 CqlHostDataSource::getPage6(const SubnetID& subnet_id,
3550 size_t& /*source_index*/,
3551 uint64_t lower_host_id,
3552 const HostPageSize& page_size) const {
3553 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3554
3555 return (impl_->getPage6(subnet_id, lower_host_id, page_size));
3556 }
3557
3558 ConstHostCollection
getPage4(size_t &,uint64_t lower_host_id,const HostPageSize & page_size) const3559 CqlHostDataSource::getPage4(size_t& /*source_index*/,
3560 uint64_t lower_host_id,
3561 const HostPageSize& page_size) const {
3562 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3563
3564 return (impl_->getPage4(lower_host_id, page_size));
3565 }
3566
3567 ConstHostCollection
getPage6(size_t &,uint64_t lower_host_id,const HostPageSize & page_size) const3568 CqlHostDataSource::getPage6(size_t& /*source_index*/,
3569 uint64_t lower_host_id,
3570 const HostPageSize& page_size) const {
3571 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3572
3573 return (impl_->getPage6(lower_host_id, page_size));
3574 }
3575
3576 ConstHostCollection
getAll4(const asiolink::IOAddress & address) const3577 CqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
3578 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
3579
3580 return (impl_->getAll4(address));
3581 }
3582
3583 ConstHostPtr
get4(const SubnetID & subnet_id,const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len) const3584 CqlHostDataSource::get4(const SubnetID& subnet_id,
3585 const Host::IdentifierType& identifier_type,
3586 const uint8_t* identifier_begin,
3587 const size_t identifier_len) const {
3588 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET4);
3589
3590 return (impl_->get4(subnet_id, identifier_type, identifier_begin,
3591 identifier_len));
3592 }
3593
3594 ConstHostPtr
get4(const SubnetID & subnet_id,const asiolink::IOAddress & address) const3595 CqlHostDataSource::get4(const SubnetID& subnet_id,
3596 const asiolink::IOAddress& address) const {
3597 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET4);
3598
3599 return (impl_->get4(subnet_id, address));
3600 }
3601
3602 ConstHostCollection
getAll4(const SubnetID & subnet_id,const asiolink::IOAddress & address) const3603 CqlHostDataSource::getAll4(const SubnetID& subnet_id,
3604 const asiolink::IOAddress& address) const {
3605 ConstHostCollection hosts;
3606 auto host = get4(subnet_id, address);
3607 if (host) {
3608 hosts.push_back(host);
3609 }
3610 return (hosts);
3611 }
3612
3613 ConstHostPtr
get6(const SubnetID & subnet_id,const Host::IdentifierType & identifier_type,const uint8_t * identifier_begin,const size_t identifier_len) const3614 CqlHostDataSource::get6(const SubnetID& subnet_id,
3615 const Host::IdentifierType& identifier_type,
3616 const uint8_t* identifier_begin,
3617 const size_t identifier_len) const {
3618 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET6);
3619
3620 return (impl_->get6(subnet_id, identifier_type, identifier_begin, identifier_len));
3621 }
3622
3623 ConstHostPtr
get6(const asiolink::IOAddress & prefix,const uint8_t prefix_len) const3624 CqlHostDataSource::get6(const asiolink::IOAddress& prefix,
3625 const uint8_t prefix_len) const {
3626 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET6);
3627
3628 return (impl_->get6(prefix, prefix_len));
3629 }
3630
3631 ConstHostPtr
get6(const SubnetID & subnet_id,const asiolink::IOAddress & address) const3632 CqlHostDataSource::get6(const SubnetID& subnet_id,
3633 const asiolink::IOAddress& address) const {
3634 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET6);
3635
3636 return (impl_->get6(subnet_id, address));
3637 }
3638
3639 ConstHostCollection
getAll6(const SubnetID & subnet_id,const asiolink::IOAddress & address) const3640 CqlHostDataSource::getAll6(const SubnetID& subnet_id,
3641 const asiolink::IOAddress& address) const {
3642 ConstHostCollection hosts;
3643 auto host = get6(subnet_id, address);
3644 if (host) {
3645 hosts.push_back(host);
3646 }
3647 return (hosts);
3648 }
3649
3650 ConstHostCollection
getAllHosts() const3651 CqlHostDataSource::getAllHosts() const {
3652 return (impl_->getAllHosts());
3653 }
3654
3655 std::string
getType() const3656 CqlHostDataSource::getType() const {
3657 return std::string("cql");
3658 }
3659
3660 std::string
getName() const3661 CqlHostDataSource::getName() const {
3662 return (impl_->getName());
3663 }
3664
3665 std::string
getDescription() const3666 CqlHostDataSource::getDescription() const {
3667 return std::string("Host data source that stores host information in the CQL database");
3668 }
3669
3670 VersionPair
getVersion() const3671 CqlHostDataSource::getVersion() const {
3672 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_DB_GET_VERSION);
3673
3674 return impl_->getVersion();
3675 }
3676
3677 void
commit()3678 CqlHostDataSource::commit() {
3679 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_COMMIT);
3680 }
3681
3682 void
rollback()3683 CqlHostDataSource::rollback() {
3684 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_ROLLBACK);
3685 }
3686
3687 bool
setIPReservationsUnique(const bool unique)3688 CqlHostDataSource::setIPReservationsUnique(const bool unique) {
3689 // This backend does not support the mode in which multiple reservations
3690 // for the same IP address are created. If selecting this mode is
3691 // attempted this function returns false to indicate that this is
3692 // not allowed.
3693 return (unique);
3694 }
3695
3696 } // namespace dhcp
3697 } // namespace isc
3698