lease_mgr.h 21.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
16
#ifndef LEASE_MGR_H
#define LEASE_MGR_H
17

18
#include <asiolink/io_address.h>
19
#include <dhcp/duid.h>
20
#include <dhcp/option.h>
21
#include <dhcp/hwaddr.h>
22
#include <dhcpsrv/subnet.h>
23
24
25
26
27
#include <exceptions/exceptions.h>

#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

28
#include <fstream>
29
#include <iostream>
30
#include <map>
31
32
33
34
#include <string>
#include <utility>
#include <vector>

35
/// @file lease_mgr.h
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
/// @brief An abstract API for lease database
///
/// This file contains declarations of Lease4, Lease6 and LeaseMgr classes.
/// They are essential components of the interface to any database backend.
/// Each concrete database backend (e.g. MySQL) will define a class derived
/// from LeaseMgr class.
///
/// Failover considerations:
/// There are no intermediate plans to implement DHCPv4 failover
/// (draft-ietf-dhc-failover-12.txt). Currently (Oct. 2012) the DHCPv6 failover
/// is being defined in DHC WG in IETF (draft-ietf-dhcpv6-failover-requirements,
/// draft-ietf-dhcpv6-dailover-design), but the work is not advanced enough
/// for implementation plans yet. v4 failover requires additional parameters
/// to be kept with a lease. It is likely that v6 failover will require similar
/// fields. Such implementation will require database schema extension.
/// We have designed a way to expand/upgrade schemas during upgrades: a database
/// schema is versioned and sanity checks about required version will be done
/// upon start and/or upgrade. With this mechanism in place, we can add new
/// fields to the database. In particular we can use that capability to
/// introduce failover related fields.
///
/// However, there is another approach that can be reliably used to provide
/// failover, even without the actual failover protocol implemented. As the
/// first backend will use MySQL, we will be able to use Multi-Master capability
/// offered by MySQL and use two separatate Kea instances connecting to the
/// same database.
///
/// Nevertheless, we hope to have failover protocol eventually implemented in
/// the Kea.

66
67
68
namespace isc {
namespace dhcp {

69
70
71
72
73
74
75
/// @brief Exception thrown if name of database is not specified
class NoDatabaseName : public Exception {
public:
    NoDatabaseName(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

76
77
/// @brief Exception thrown on failure to open database
class DbOpenError : public Exception {
78
public:
79
80
81
82
    DbOpenError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

83
84
85
86
87
88
89
/// @brief Exception thrown on failure to execute a database function
class DbOperationError : public Exception {
public:
    DbOperationError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

90
91
92
93
94
95
96
/// @brief Multiple lease records found where one expected
class MultipleRecords : public Exception {
public:
    MultipleRecords(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

97
98
99
100
101
102
103
/// @brief Attempt to update lease that was not there
class NoSuchLease : public Exception {
public:
    NoSuchLease(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

104
105
106
107
108
109
110
/// @brief Data is truncated
class DataTruncated : public Exception {
public:
    DataTruncated(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

111
/// @brief a common structure for IPv4 and IPv6 leases
112
///
113
114
115
/// This structure holds all information that is common between IPv4 and IPv6
/// leases.
struct Lease {
116

117
118
    Lease(const isc::asiolink::IOAddress& addr, uint32_t t1, uint32_t t2,
          uint32_t valid_lft, SubnetID subnet_id, time_t cltt);
119

120
    virtual ~Lease() {}
121

122
    /// @brief IPv4 ot IPv6 address
123
    ///
124
125
    /// IPv4, IPv6 address or, in the case of a prefix delegation, the prefix.
    isc::asiolink::IOAddress addr_;
126

127
    /// @brief Renewal timer
128
    ///
129
130
131
132
133
    /// Specifies renewal time. Although technically it is a property of the
    /// IA container and not the address itself, since our data model does not
    /// define a separate IA entity, we are keeping it in the lease. In the
    /// case of multiple addresses/prefixes for the same IA, each must have
    /// consistent T1 and T2 values. This is specified in seconds since cltt.
134
135
    uint32_t t1_;

136
    /// @brief Rebinding timer
137
    ///
138
139
140
141
    /// Specifies rebinding time. Although technically it is a property of the
    /// IA container and not the address itself, since our data model does not
    /// define a separate IA entity, we are keeping it in the lease. In the
    /// case of multiple addresses/prefixes for the same IA, each must have
142
    /// consistent T1 and T2 values. This is specified in seconds since cltt.
143
144
    uint32_t t2_;

145
    /// @brief Valid lifetime
146
    ///
147
    /// Expressed as number of seconds since cltt.
148
    uint32_t valid_lft_;
149

150
    /// @brief Client last transmission time
151
    ///
152
153
    /// Specifies a timestamp giving the time when the last transmission from a
    /// client was received.
154
    time_t cltt_;
155

156
    /// @brief Subnet identifier
157
    ///
158
    /// Specifies the identification of the subnet to which the lease belongs.
159
    SubnetID subnet_id_;
160

161
    /// @brief Fixed lease?
162
163
    ///
    /// Fixed leases are kept after they are released/expired.
164
    bool fixed_;
165

166
    /// @brief Client hostname
167
168
    ///
    /// This field may be empty
169
    std::string hostname_;
170

171
172
173
    /// @brief Forward zone updated?
    ///
    /// Set true if the DNS AAAA record for this lease has been updated.
174
    bool fqdn_fwd_;
175

176
177
178
    /// @brief Reverse zone updated?
    ///
    /// Set true if the DNS PTR record for this lease has been updated.
179
    bool fqdn_rev_;
180

181
    /// @brief Lease comments
182
183
184
    ///
    /// Currently not used. It may be used for keeping comments made by the
    /// system administrator.
185
    std::string comments_;
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
    /// @brief Convert Lease to Printable Form
    ///
    /// @return String form of the lease
    virtual std::string toText() const = 0;

    /// @brief returns true if the lease is expired
    /// @return true if the lease is expired
    bool expired() const;

};

/// @brief Structure that holds a lease for IPv4 address
///
/// For performance reasons it is a simple structure, not a class. If we chose
/// make it a class, all fields would have to made private and getters/setters
/// would be required. As this is a critical part of the code that will be used
/// extensively, direct access is warranted.
struct Lease4 : public Lease {
    /// @brief Maximum size of a hardware address
    static const size_t HWADDR_MAX = 20;

    /// @brief Address extension
    ///
    /// It is envisaged that in some cases IPv4 address will be accompanied
    /// with some additional data. One example of such use are Address + Port
    /// solutions (or Port-restricted Addresses), where several clients may get
    /// the same address, but different port ranges. This feature is not
    /// expected to be widely used.  Under normal circumstances, the value
    /// should be 0.
    uint32_t ext_;

    /// @brief Hardware address
    std::vector<uint8_t> hwaddr_;

    /// @brief Client identifier
    ///
    /// @todo Should this be a pointer to a client ID or the ID itself?
    ///       Compare with the DUID in the Lease6 structure.
    ClientIdPtr client_id_;

227
228
229
230
231
232
233
234
235
236
237
    /// @brief Constructor
    ///
    /// @param addr IPv4 address as unsigned 32-bit integer in network byte
    ///        order.
    /// @param hwaddr Hardware address buffer
    /// @param hwaddr_len Length of hardware address buffer
    /// @param clientid Client identification buffer
    /// @param clientid_len Length of client identification buffer
    /// @param valid_lft Lifetime of the lease
    /// @param cltt Client last transmission time
    /// @param subnet_id Subnet identification
238
    Lease4(const isc::asiolink::IOAddress& addr, const uint8_t* hwaddr, size_t hwaddr_len,
239
           const uint8_t* clientid, size_t clientid_len, uint32_t valid_lft,
240
241
           uint32_t t1, uint32_t t2, time_t cltt, uint32_t subnet_id)
        : Lease(addr, t1, t2, valid_lft, subnet_id, cltt),
242
243
244
        ext_(0), hwaddr_(hwaddr, hwaddr + hwaddr_len),
        client_id_(new ClientId(clientid, clientid_len)) {
    }
245

246
    /// @brief Default constructor
247
248
    ///
    /// Initialize fields that don't have a default constructor.
249
250
    Lease4() : Lease(0, 0, 0, 0, 0, 0) {
    }
251

252
253
254
255
256
257
258
259
260
261
262
263
    /// @brief Compare two leases for equality
    ///
    /// @param other lease6 object with which to compare
    bool operator==(const Lease4& other) const;

    /// @brief Compare two leases for inequality
    ///
    /// @param other lease6 object with which to compare
    bool operator!=(const Lease4& other) const {
        return (!operator==(other));
    }

264
    /// @brief Convert lease to printable form
265
    ///
266
    /// @return Textual represenation of lease data
267
268
    virtual std::string toText() const;

269
    /// @todo: Add DHCPv4 failover related fields here
270
271
272
273
274
};

/// @brief Pointer to a Lease4 structure.
typedef boost::shared_ptr<Lease4> Lease4Ptr;

275
/// @brief A collection of IPv4 leases.
276
typedef std::vector<Lease4Ptr> Lease4Collection;
277

278
279


280
281
/// @brief Structure that holds a lease for IPv6 address and/or prefix
///
282
283
/// For performance reasons it is a simple structure, not a class. If we chose
/// make it a class, all fields would have to made private and getters/setters
284
/// would be required. As this is a critical part of the code that will be used
285
/// extensively, direct access is warranted.
286
struct Lease6 : public Lease {
287
288

    /// @brief Type of lease contents
289
290
291
292
293
294
    typedef enum {
        LEASE_IA_NA, /// the lease contains non-temporary IPv6 address
        LEASE_IA_TA, /// the lease contains temporary IPv6 address
        LEASE_IA_PD  /// the lease contains IPv6 prefix (for prefix delegation)
    } LeaseType;

295
296
297
298
299
300
301
302
    /// @brief Lease type
    ///
    /// One of normal address, temporary address, or prefix.
    LeaseType type_;

    /// @brief IPv6 prefix length
    ///
    /// This is used only for prefix delegations and is ignored otherwise.
303
304
    uint8_t prefixlen_;

305
    /// @brief Identity Association Identifier (IAID)
306
    ///
307
    /// DHCPv6 stores all addresses and prefixes in IA containers (IA_NA,
308
    /// IA_TA, IA_PD). All containers may appear more than once in a message.
309
    /// To differentiate between them, the IAID field is present
310
311
    uint32_t iaid_;

312
    /// @brief Client identifier
313
    DuidPtr duid_;
314
315
316

    /// @brief preferred lifetime
    ///
317
318
    /// This parameter specifies the preferred lifetime since the lease was
    /// assigned or renewed (cltt), expressed in seconds.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
319
    uint32_t preferred_lft_;
320

321
    /// @todo: Add DHCPv6 failover related fields here
322

323
324
325
326
327
    /// @brief Constructor
    Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
           uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
           uint32_t t2, SubnetID subnet_id, uint8_t prefixlen_ = 0);

328
329
330
    /// @brief Constructor
    ///
    /// Initialize fields that don't have a default constructor.
331
332
333
    Lease6() : Lease(isc::asiolink::IOAddress("::"), 0, 0, 0, 0, 0),
        type_(LEASE_IA_NA) {
    }
334

335
336
337
338
339
340
341
342
343
344
345
    /// @brief Compare two leases for equality
    ///
    /// @param other lease6 object with which to compare
    bool operator==(const Lease6& other) const;

    /// @brief Compare two leases for inequality
    ///
    /// @param other lease6 object with which to compare
    bool operator!=(const Lease6& other) const {
        return (!operator==(other));
    }
346
347
348
349
350

    /// @brief Convert Lease to Printable Form
    ///
    /// @return String form of the lease
    virtual std::string toText() const;
351
352
353
354
355
};

/// @brief Pointer to a Lease6 structure.
typedef boost::shared_ptr<Lease6> Lease6Ptr;

Stephen Morris's avatar
Stephen Morris committed
356
/// @brief Pointer to a const Lease6 structure.
357
358
typedef boost::shared_ptr<const Lease6> ConstLease6Ptr;

359
/// @brief A collection of IPv6 leases.
360
typedef std::vector<Lease6Ptr> Lease6Collection;
361

362
/// @brief Abstract Lease Manager
363
///
364
365
366
367
/// This is an abstract API for lease database backends. It provides unified
/// interface to all backends. As this is an abstract class, it should not
/// be used directly, but rather specialized derived class should be used
/// instead.
368
369
370
371
///
/// As all methods are virtual, this class throws no exceptions.  However,
/// methods in concrete implementations of this class may throw exceptions:
/// see the documentation of those classes for details.
372
373
class LeaseMgr {
public:
374
375
376
    /// Database configuration parameter map
    typedef std::map<std::string, std::string> ParameterMap;

377
    /// @brief Constructor
378
    ///
379
380
    /// @param parameters A data structure relating keywords and values
    ///        concerned with the database.
381
382
    LeaseMgr(const ParameterMap& parameters) : parameters_(parameters)
    {}
383

384
    /// @brief Destructor
385
386
    virtual ~LeaseMgr()
    {}
387

388
    /// @brief Adds an IPv4 lease.
389
390
    ///
    /// @param lease lease to be added
391
392
393
394
    ///
    /// @result true if the lease was added, false if not (because a lease
    ///         with the same address was already there).
    virtual bool addLease(const Lease4Ptr& lease) = 0;
395

396
    /// @brief Adds an IPv6 lease.
397
398
    ///
    /// @param lease lease to be added
399
400
401
402
    ///
    /// @result true if the lease was added, false if not (because a lease
    ///         with the same address was already there).
    virtual bool addLease(const Lease6Ptr& lease) = 0;
403

404
405
406
407
408
409
410
411
    /// @brief Returns an IPv4 lease for specified IPv4 address
    ///
    /// This method return a lease that is associated with a given address.
    /// For other query types (by hardware addr, by client-id) there can be
    /// several leases in different subnets (e.g. for mobile clients that
    /// got address in different subnets). However, for a single address
    /// there can be only one lease, so this method returns a pointer to
    /// a single lease, not a container of leases.
412
413
414
    ///
    /// @param addr address of the searched lease
    ///
415
    /// @return smart pointer to the lease (or NULL if a lease is not found)
416
    virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const = 0;
417

418
419
420
421
422
423
    /// @brief Returns existing IPv4 leases for specified hardware address.
    ///
    /// Although in the usual case there will be only one lease, for mobile
    /// clients or clients with multiple static/fixed/reserved leases there
    /// can be more than one. Thus return type is a container, not a single
    /// pointer.
424
425
426
    ///
    /// @param hwaddr hardware address of the client
    ///
427
    /// @return lease collection
428
    virtual Lease4Collection getLease4(const isc::dhcp::HWAddr& hwaddr) const = 0;
429
430
431
432
433
434
435
436
437
438
439

    /// @brief Returns existing IPv4 leases for specified hardware address
    ///        and a subnet
    ///
    /// There can be at most one lease for a given HW address in a single
    /// pool, so this method with either return a single lease or NULL.
    ///
    /// @param hwaddr hardware address of the client
    /// @param subnet_id identifier of the subnet that lease must belong to
    ///
    /// @return a pointer to the lease (or NULL if a lease is not found)
440
    virtual Lease4Ptr getLease4(const isc::dhcp::HWAddr& hwaddr,
441
                                SubnetID subnet_id) const = 0;
442

443
444
    /// @brief Returns existing IPv4 lease for specified client-id
    ///
445
446
447
448
449
    /// Although in the usual case there will be only one lease, for mobile
    /// clients or clients with multiple static/fixed/reserved leases there
    /// can be more than one. Thus return type is a container, not a single
    /// pointer.
    ///
450
    /// @param clientid client identifier
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
    ///
    /// @return lease collection
    virtual Lease4Collection getLease4(const ClientId& clientid) const = 0;

    /// @brief Returns existing IPv4 lease for specified client-id
    ///
    /// There can be at most one lease for a given HW address in a single
    /// pool, so this method with either return a single lease or NULL.
    ///
    /// @param clientid client identifier
    /// @param subnet_id identifier of the subnet that lease must belong to
    ///
    /// @return a pointer to the lease (or NULL if a lease is not found)
    virtual Lease4Ptr getLease4(const ClientId& clientid,
                                SubnetID subnet_id) const = 0;
466

467
    /// @brief Returns existing IPv6 lease for a given IPv6 address.
468
    ///
469
470
471
472
    /// For a given address, we assume that there will be only one lease.
    /// The assumtion here is that there will not be site or link-local
    /// addresses used, so there is no way of having address duplication.
    ///
473
474
    /// @param addr address of the searched lease
    ///
475
    /// @return smart pointer to the lease (or NULL if a lease is not found)
476
    virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const = 0;
477

478
479
480
481
482
483
484
485
486
487
488
    /// @brief Returns existing IPv6 leases for a given DUID+IA combination
    ///
    /// Although in the usual case there will be only one lease, for mobile
    /// clients or clients with multiple static/fixed/reserved leases there
    /// can be more than one. Thus return type is a container, not a single
    /// pointer.
    ///
    /// @param duid client DUID
    /// @param iaid IA identifier
    ///
    /// @return smart pointer to the lease (or NULL if a lease is not found)
489
    virtual Lease6Collection getLease6(const DUID& duid,
490
491
                                       uint32_t iaid) const = 0;

492
493
494
495
    /// @brief Returns existing IPv6 lease for a given DUID+IA combination
    ///
    /// @param duid client DUID
    /// @param iaid IA identifier
496
    /// @param subnet_id subnet id of the subnet the lease belongs to
497
498
    ///
    /// @return smart pointer to the lease (or NULL if a lease is not found)
499
500
    virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
                                SubnetID subnet_id) const = 0;
501

502
503
504
505
506
    /// @brief Updates IPv4 lease.
    ///
    /// @param lease4 The lease to be updated.
    ///
    /// If no such lease is present, an exception will be thrown.
507
    virtual void updateLease4(const Lease4Ptr& lease4) = 0;
508

Marcin Siodelski's avatar
Marcin Siodelski committed
509
    /// @brief Updates IPv6 lease.
510
    ///
Marcin Siodelski's avatar
Marcin Siodelski committed
511
    /// @param lease6 The lease to be updated.
512
    virtual void updateLease6(const Lease6Ptr& lease6) = 0;
513
514
515

    /// @brief Deletes a lease.
    ///
516
517
    /// @param addr Address of the lease to be deleted. (This can be IPv4 or
    ///        IPv6.)
518
519
    ///
    /// @return true if deletion was successful, false if no such lease exists
520
    virtual bool deleteLease(const isc::asiolink::IOAddress& addr) = 0;
521

522
523
524
525
526
527
528
    /// @brief Return backend type
    ///
    /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
    ///
    /// @return Type of the backend.
    virtual std::string getType() const = 0;

529
530
    /// @brief Returns backend name.
    ///
531
532
533
534
    /// If the backend is a database, this is the name of the database or the
    /// file.  Otherwise it is just the same as the type.
    ///
    /// @return Name of the backend.
535
    virtual std::string getName() const = 0;
536

537
538
539
    /// @brief Returns description of the backend.
    ///
    /// This description may be multiline text that describes the backend.
540
541
    ///
    /// @return Description of the backend.
542
    virtual std::string getDescription() const = 0;
543

544
    /// @brief Returns backend version.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
545
    ///
546
547
548
    /// @return Version number as a pair of unsigned integers.  "first" is the
    ///         major version number, "second" the minor number.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
549
550
551
552
553
554
555
556
    /// @todo: We will need to implement 3 version functions eventually:
    /// A. abstract API version
    /// B. backend version
    /// C. database version (stored in the database scheme)
    ///
    /// and then check that:
    /// B>=A and B=C (it is ok to have newer backend, as it should be backward
    /// compatible)
557
    /// Also if B>C, some database upgrade procedure may be triggered
558
    virtual std::pair<uint32_t, uint32_t> getVersion() const = 0;
559

560
561
562
563
564
565
566
567
568
569
570
571
    /// @brief Commit Transactions
    ///
    /// Commits all pending database operations.  On databases that don't
    /// support transactions, this is a no-op.
    virtual void commit() = 0;

    /// @brief Rollback Transactions
    ///
    /// Rolls back all pending database operations.  On databases that don't
    /// support transactions, this is a no-op.
    virtual void rollback() = 0;

572
    /// @todo: Add host management here
Tomek Mrugalski's avatar
Tomek Mrugalski committed
573
574
575
576
    /// As host reservation is outside of scope for 2012, support for hosts
    /// is currently postponed.

    /// @brief returns value of the parameter
577
    virtual std::string getParameter(const std::string& name) const;
578

579
private:
580
    /// @brief list of parameters passed in dbconfig
Tomek Mrugalski's avatar
Tomek Mrugalski committed
581
582
583
584
    ///
    /// That will be mostly used for storing database name, username,
    /// password and other parameters required for DB access. It is not
    /// intended to keep any DHCP-related parameters.
585
    ParameterMap parameters_;
586
};
587
588
589

}; // end of isc::dhcp namespace
}; // end of isc namespace
590

591
#endif // LEASE_MGR_H