1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
|
// Copyright (C) 2016-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef PGSQL_HOST_DATA_SOURCE_H
#define PGSQL_HOST_DATA_SOURCE_H
#include <database/database_connection.h>
#include <dhcpsrv/base_host_data_source.h>
#include <pgsql/pgsql_connection.h>
#include <pgsql/pgsql_exchange.h>
namespace isc {
namespace dhcp {
/// Forward declaration to the implementation of the @ref PgSqlHostDataSource.
class PgSqlHostDataSourceImpl;
/// @brief Type of pointers to PgSqlHostDataSourceImpl.
typedef boost::shared_ptr<PgSqlHostDataSourceImpl> PgSqlHostDataSourceImplPtr;
/// Forward declaration for the thread context for the manager pool.
class PgSqlHostContext;
/// @brief Type of pointers to contexts.
typedef boost::shared_ptr<PgSqlHostContext> PgSqlHostContextPtr;
/// @brief PostgreSQL Host Data Source
///
/// This class implements the @ref isc::dhcp::BaseHostDataSource interface to
/// the PostgreSQL database. Use of this backend presupposes that a PostgreSQL
/// database is available and that the Kea schema has been created within it.
///
/// Reservations are uniquely identified by identifier type and value.
/// The currently supported values are defined in @ref Host::IdentifierType
/// as well as in host_identifier_table:
///
/// - IDENT_HWADDR
/// - IDENT_DUID
/// - IDENT_CIRCUIT_ID
/// - IDENT_CLIENT_ID
///
class PgSqlHostDataSource : public BaseHostDataSource {
public:
/// @brief Constructor
///
/// Uses the following keywords in the parameters passed to it to
/// connect to the database:
/// - name - Name of the database to which to connect (mandatory)
/// - host - Host to which to connect (optional, defaults to "localhost")
/// - user - Username under which to connect (optional)
/// - password - Password for "user" on the database (optional)
///
/// If the database is successfully opened, the version number in the
/// schema_version table will be checked against hard-coded value in
/// the implementation file.
///
/// Finally, all the SQL commands are pre-compiled.
///
/// @param parameters A data structure relating keywords and values
/// concerned with the database.
///
/// @throw isc::db::NoDatabaseName Mandatory database name not given
/// @throw isc::db::DbOpenError Error opening the database
/// @throw isc::db::DbOperationError An operation on the open database has
/// failed.
PgSqlHostDataSource(const db::DatabaseConnection::ParameterMap& parameters);
/// @brief Virtual destructor.
///
/// Frees database resources and closes the database connection through
/// the destruction of member impl_.
virtual ~PgSqlHostDataSource();
/// @brief Return backend parameters
///
/// Returns the backend parameters
///
/// @return Parameters of the backend.
virtual isc::db::DatabaseConnection::ParameterMap getParameters() const;
/// @brief Adds a new host to the collection.
///
/// The method will insert the given host and all of its children (v4
/// options, v6 options, and v6 reservations) into the database. It
/// relies on constraints defined as part of the PostgreSQL schema to
/// defend against duplicate entries and to ensure referential
/// integrity.
///
/// Violation of any of these constraints for a host will result in a
/// DuplicateEntry exception:
///
/// -# IPV4_ADDRESS and DHCP4_SUBNET_ID combination must be unique
/// -# IPV6 ADDRESS and PREFIX_LEN combination must be unique
/// -# DHCP ID, DHCP ID TYPE, and DHCP4_SUBNET_ID combination must be unique
/// -# DHCP ID, DHCP ID TYPE, and DHCP6_SUBNET_ID combination must be unique
///
/// In addition, violating the following referential constraints will
/// a DbOperationError exception:
///
/// -# DHCP ID TYPE must be defined in the HOST_IDENTIFIER_TYPE table
/// -# For DHCP4 Options:
/// -# HOST_ID must exist with HOSTS
/// -# SCOPE_ID must be defined in DHCP_OPTION_SCOPE
/// -# For DHCP6 Options:
/// -# HOST_ID must exist with HOSTS
/// -# SCOPE_ID must be defined in DHCP_OPTION_SCOPE
/// -# For IPV6 Reservations:
/// -# HOST_ID must exist with HOSTS
/// -# Address and Prefix Length must be unique (DuplicateEntry)
///
/// @param host Pointer to the new @c Host object being added.
/// @throw DuplicateEntry or DbOperationError dependent on the constraint
/// violation
virtual void add(const HostPtr& host);
/// @brief Attempts to delete hosts by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
/// @param subnet_id subnet identifier.
/// @param addr specified address.
/// @return true if deletion was successful, false if the host was not there.
/// @throw various exceptions in case of errors
virtual bool del(const SubnetID& subnet_id,
const asiolink::IOAddress& addr);
/// @brief Attempts to delete a host by (subnet4-id, identifier type, identifier)
///
/// This method supports v4 hosts only.
///
/// @param subnet_id subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return true if deletion was successful, false if the host was not there.
/// @throw various exceptions in case of errors
virtual bool del4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len);
/// @brief Attempts to delete a host by (subnet6-id, identifier type, identifier)
///
/// This method supports v6 hosts only.
///
/// @param subnet_id subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return true if deletion was successful, false if the host was not there.
/// @throw various exceptions in case of errors
virtual bool del6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len);
/// @brief Return all hosts connected to any subnet for which reservations
/// have been made using a specified identifier.
///
/// This method returns all @c Host objects which represent reservations
/// for a specified identifier. This method may return multiple hosts
/// because a particular client may have reservations in multiple subnets.
///
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection getAll(const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Return all hosts in a DHCPv4 subnet.
///
/// This method returns all @ref Host objects which represent reservations
/// in a specified subnet. Global reservations are returned for the
/// subnet id 0.
///
/// @param subnet_id subnet identifier to filter by
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection getAll4(const SubnetID& subnet_id) const;
/// @brief Return all hosts in a DHCPv6 subnet.
///
/// This method returns all @ref Host objects which represent reservations
/// in a specified subnet. Global reservations are returned for the
/// subnet id 0.
///
/// @param subnet_id subnet identifier to filter by
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const;
/// @brief Return all hosts with a hostname.
///
/// This method returns all @c Host objects which represent reservations
/// using a specified hostname.
///
/// PostgreSQL uses the hosts_by_hostname index on LOWER(hostname).
///
/// @param hostname The lower case hostname.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection getAllbyHostname(const std::string& hostname) const;
/// @brief Return all hosts with a hostname in a DHCPv4 subnet.
///
/// This method returns all @c Host objects which represent reservations
/// using a specified hostname in a specified subnet.
///
/// @param hostname The lower case hostname.
/// @param subnet_id Subnet identifier.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection getAllbyHostname4(const std::string& hostname,
const SubnetID& subnet_id) const;
/// @brief Return all hosts with a hostname in a DHCPv6 subnet.
///
/// This method returns all @c Host objects which represent reservations
/// using a specified hostname in a specified subnet.
///
/// @param hostname The lower case hostname.
/// @param subnet_id Subnet identifier.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection getAllbyHostname6(const std::string& hostname,
const SubnetID& subnet_id) const;
/// @brief Returns range of hosts in a DHCPv4 subnet.
///
/// This method implements paged browsing of host databases. The
/// parameters specify a page size, an index in sources and the
/// starting host id of the range. If not zero this host id is
/// excluded from the returned range. When a source is exhausted
/// the index is updated. There is no guarantee about the order
/// of returned host reservations, only the sources and
/// reservations from the same source are ordered.
///
/// @param subnet_id Subnet identifier.
/// @param source_index Index of the source (unused).
/// @param lower_host_id Host identifier used as lower bound for the
/// returned range.
/// @param page_size maximum size of the page returned.
///
/// @return Collection of const @c Host objects (may be empty).
virtual ConstHostCollection getPage4(const SubnetID& subnet_id,
size_t& source_index,
uint64_t lower_host_id,
const HostPageSize& page_size) const;
/// @brief Returns range of hosts in a DHCPv6 subnet.
///
/// This method implements paged browsing of host databases. The
/// parameters specify a page size, an index in sources and the
/// starting host id of the range. If not zero this host id is
/// excluded from the returned range. When a source is exhausted
/// the index is updated. There is no guarantee about the order
/// of returned host reservations, only the sources and
/// reservations from the same source are ordered.
///
/// @param subnet_id Subnet identifier.
/// @param source_index Index of the source (unused).
/// @param lower_host_id Host identifier used as lower bound for the
/// returned range.
/// @param page_size maximum size of the page returned.
///
/// @return Collection of const @c Host objects (may be empty).
virtual ConstHostCollection getPage6(const SubnetID& subnet_id,
size_t& source_index,
uint64_t lower_host_id,
const HostPageSize& page_size) const;
/// @brief Returns range of hosts.
///
/// This method implements paged browsing of host databases. The
/// parameters specify a page size, an index in sources and the
/// starting host id of the range. If not zero this host id is
/// excluded from the returned range. When a source is exhausted
/// the index is updated. There is no guarantee about the order
/// of returned host reservations, only the sources and
/// reservations from the same source are ordered.
///
/// @param source_index Index of the source (unused).
/// @param lower_host_id Host identifier used as lower bound for the
/// returned range.
/// @param page_size maximum size of the page returned.
///
/// @return Collection of const @c Host objects (may be empty).
virtual ConstHostCollection getPage4(size_t& source_index,
uint64_t lower_host_id,
const HostPageSize& page_size) const;
/// @brief Returns range of hosts.
///
/// This method implements paged browsing of host databases. The
/// parameters specify a page size, an index in sources and the
/// starting host id of the range. If not zero this host id is
/// excluded from the returned range. When a source is exhausted
/// the index is updated. There is no guarantee about the order
/// of returned host reservations, only the sources and
/// reservations from the same source are ordered.
///
/// @param source_index Index of the source (unused).
/// @param lower_host_id Host identifier used as lower bound for the
/// returned range.
/// @param page_size maximum size of the page returned.
///
/// @return Collection of const @c Host objects (may be empty).
virtual ConstHostCollection getPage6(size_t& source_index,
uint64_t lower_host_id,
const HostPageSize& page_size) const;
/// @brief Returns a collection of hosts using the specified IPv4 address.
///
/// This method may return multiple @c Host objects if they are connected
/// to different subnets.
///
/// @param address IPv4 address for which the @c Host object is searched.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection getAll4(const asiolink::IOAddress& address) const;
/// @brief Returns a host connected to the IPv4 subnet.
///
/// @param subnet_id Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return Const @c Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a host connected to the IPv4 subnet and having
/// a reservation for a specified IPv4 address.
///
/// One of the use cases for this method is to detect collisions between
/// dynamically allocated addresses and reserved addresses. When the new
/// address is assigned to a client, the allocation mechanism should check
/// if this address is not reserved for some other host and do not allocate
/// this address if reservation is present.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv4 address.
///
/// @return Const @c Host object using a specified IPv4 address.
/// @throw BadValue is given an IPv6 address
virtual ConstHostPtr get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const;
/// @brief Returns all hosts connected to the IPv4 subnet and having
/// a reservation for a specified address.
///
/// In most cases it is desired that there is at most one reservation
/// for a given IPv4 address within a subnet. In a default configuration,
/// the backend does not allow for inserting more than one host with
/// the same IPv4 reservation. In that case, the number of hosts returned
/// by this function is 0 or 1.
///
/// If the backend is configured to allow multiple hosts with reservations
/// for the same IPv4 address in the given subnet, this method can return
/// more than one host.
///
/// The typical use case when a single IPv4 address is reserved for multiple
/// hosts is when these hosts represent different interfaces of the same
/// machine and each interface comes with a different MAC address. In that
/// case, the same IPv4 address is assigned regardless of which interface is
/// used by the DHCP client to communicate with the server.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv4 address.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection
getAll4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const;
/// @brief Returns a host connected to the IPv6 subnet.
///
/// @param subnet_id Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return Const @c Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Returns a host using the specified IPv6 prefix.
///
/// @param prefix IPv6 prefix for which the @c Host object is searched.
/// @param prefix_len IPv6 prefix length.
///
/// @return Const @c Host object using a specified IPv6 prefix.
virtual ConstHostPtr get6(const asiolink::IOAddress& prefix,
const uint8_t prefix_len) const;
/// @brief Returns a host connected to the IPv6 subnet and having
/// a reservation for a specified IPv6 address or prefix.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv6 address/prefix.
///
/// @return Const @c Host object using a specified IPv6 address/prefix.
virtual ConstHostPtr get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const;
/// @brief Returns all hosts connected to the IPv6 subnet and having
/// a reservation for a specified address or delegated prefix (lease).
///
/// In most cases it is desired that there is at most one reservation
/// for a given IPv6 lease within a subnet. In a default configuration,
/// the backend does not allow for inserting more than one host with
/// the same IPv6 address or prefix. In that case, the number of hosts
/// returned by this function is 0 or 1.
///
/// If the backend is configured to allow multiple hosts with reservations
/// for the same IPv6 lease in the given subnet, this method can return
/// more than one host.
///
/// The typical use case when a single IPv6 lease is reserved for multiple
/// hosts is when these hosts represent different interfaces of the same
/// machine and each interface comes with a different MAC address. In that
/// case, the same IPv6 lease is assigned regardless of which interface is
/// used by the DHCP client to communicate with the server.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv6 address/prefix.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection
getAll6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const;
/// @brief Implements @ref BaseHostDataSource::update() for PostgreSQL.
///
/// Attempts to update an existing host entry.
///
/// @param host the host up to date with the requested changes
void update(HostPtr const& host);
/// @brief Return backend type
///
/// Returns the type of database as the string "postgresql". This is
/// same value as used for configuration purposes.
///
/// @return Type of the backend.
virtual std::string getType() const {
return (std::string("postgresql"));
}
/// @brief Returns the name of the open database
///
/// @return String containing the name of the database
virtual std::string getName() const;
/// @brief Returns description of the backend.
///
/// This description may be multiline text that describes the backend.
///
/// @return Description of the backend.
virtual std::string getDescription() const;
/// @brief Returns backend version.
///
/// The method is called by the constructor after opening the database
/// but prior to preparing SQL statements, to verify that the schema version
/// is correct. Thus it must not rely on a pre-prepared statement or
/// formal statement execution error checking.
///
/// @return Version number stored in the database, as a pair of unsigned
/// integers. "first" is the major version number, "second" the
/// minor number.
///
/// @throw isc::db::DbOperationError An operation on the open database
/// has failed.
virtual std::pair<uint32_t, uint32_t> getVersion() const;
/// @brief Commit Transactions
///
/// Commits all pending database operations.
virtual void commit();
/// @brief Rollback Transactions
///
/// Rolls back all pending database operations.
virtual void rollback();
/// @brief Controls whether IP reservations are unique or non-unique.
///
/// In a typical case, the IP reservations are unique and backends verify
/// prior to adding a host reservation to the database that the reservation
/// for a given IP address/subnet does not exist. In some cases it may be
/// required to allow non-unique IP reservations, e.g. in the case when a
/// host has several interfaces and independently of which interface is used
/// by this host to communicate with the DHCP server the same IP address
/// should be assigned. In this case the @c unique value should be set to
/// false to disable the checks for uniqueness on the backend side.
///
/// @param unique boolean flag indicating if the IP reservations must be
/// unique within the subnet or can be non-unique.
/// @return always true because this backend supports both the case when
/// the addresses must be unique and when they may be non-unique.
virtual bool setIPReservationsUnique(const bool unique);
/// @brief Flag which indicates if the host manager has at least one
/// unusable connection.
///
/// @return true if there is at least one unusable connection, false
/// otherwise
virtual bool isUnusable();
/// @brief Context RAII Allocator.
class PgSqlHostContextAlloc {
public:
/// @brief Constructor
///
/// This constructor takes a context of the pool if one is available
/// or creates a new one.
///
/// @param mgr A parent instance
PgSqlHostContextAlloc(PgSqlHostDataSourceImpl& mgr);
/// @brief Destructor
///
/// This destructor puts back the context in the pool.
~PgSqlHostContextAlloc();
/// @brief The context
PgSqlHostContextPtr ctx_;
private:
/// @brief The manager
PgSqlHostDataSourceImpl& mgr_;
};
private:
/// @brief Pointer to the implementation of the @ref PgSqlHostDataSource.
PgSqlHostDataSourceImplPtr impl_;
};
} // namespace dhcp
} // namespace isc
#endif // PGSQL_HOST_DATA_SOURCE_H
|