alloc_engine.h 22.3 KB
Newer Older
1
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//
// 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.

#ifndef ALLOC_ENGINE_H
#define ALLOC_ENGINE_H

18 19
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
20
#include <dhcp/hwaddr.h>
21 22
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease_mgr.h>
23
#include <hooks/callout_handle.h>
24

Tomek Mrugalski's avatar
Tomek Mrugalski committed
25
#include <boost/shared_ptr.hpp>
26 27 28 29 30 31 32 33 34 35
#include <boost/noncopyable.hpp>

namespace isc {
namespace dhcp {

/// An exception that is thrown when allocation module fails (e.g. due to
/// lack of available addresses)
class AllocFailed : public isc::Exception {
public:

Tomek Mrugalski's avatar
Tomek Mrugalski committed
36 37 38 39 40 41 42
    /// @brief constructor
    ///
    /// @param file name of the file, where exception occurred
    /// @param line line of the file, where exception occurred
    /// @param what text description of the issue that caused exception
    AllocFailed(const char* file, size_t line, const char* what)
        : isc::Exception(file, line, what) {}
43 44 45 46 47 48 49
};

/// @brief DHCPv4 and DHCPv6 allocation engine
///
/// This class represents DHCP allocation engine. It is responsible
/// for picking subnets, choosing and allocating a lease, extending,
/// renewing, releasing and possibly expiring leases.
50 51 52
///
/// @todo: Does not handle out of leases well
/// @todo: Does not handle out of allocation attempts well
53 54 55
class AllocEngine : public boost::noncopyable {
protected:

56 57 58 59
    /// @brief base class for all address/prefix allocation algorithms
    ///
    /// This is an abstract class that should not be used directly, but rather
    /// specialized implementations should be used instead.
60 61
    class Allocator {
    public:
62 63 64 65 66 67 68 69

        /// @brief picks one address out of available pools in a given subnet
        ///
        /// This method returns one address from the available pools in the
        /// specified subnet. It should not check if the address is used or
        /// reserved - AllocEngine will check that and will call pickAddress
        /// again if necessary. The number of times this method is called will
        /// increase as the number of available leases will decrease.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
70 71 72 73 74 75
        ///
        /// @param subnet next address will be returned from pool of that subnet
        /// @param duid Client's DUID
        /// @param hint client's hint
        ///
        /// @return the next address
76
        virtual isc::asiolink::IOAddress
77
        pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
Tomek Mrugalski's avatar
Tomek Mrugalski committed
78
                    const isc::asiolink::IOAddress& hint) = 0;
79

80 81 82
        /// @brief Default constructor.
        ///
        /// Specifies which type of leases this allocator will assign
Tomek Mrugalski's avatar
Tomek Mrugalski committed
83
        /// @param pool_type specifies pool type (addresses, temp. addr or prefixes)
84
        Allocator(Lease::Type pool_type)
Tomek Mrugalski's avatar
Tomek Mrugalski committed
85
            :pool_type_(pool_type) {
86 87
        }

88 89 90
        /// @brief virtual destructor
        virtual ~Allocator() {
        }
91
    protected:
92

93 94
        /// @brief defines pool type allocation
        Lease::Type pool_type_;
95 96
    };

97 98 99
    /// @brief Address/prefix allocator that iterates over all addresses
    ///
    /// This class implements iterative algorithm that returns all addresses in
Tomek Mrugalski's avatar
Tomek Mrugalski committed
100 101 102
    /// a pool iteratively, one after another. Once the last address is reached,
    /// it starts allocating from the beginning of the first pool (i.e. it loops
    /// over).
103 104
    class IterativeAllocator : public Allocator {
    public:
105 106 107 108

        /// @brief default constructor
        ///
        /// Does not do anything
109
        /// @param type - specifies allocation type
110
        IterativeAllocator(Lease::Type type);
111 112 113 114 115 116 117

        /// @brief returns the next address from pools in a subnet
        ///
        /// @param subnet next address will be returned from pool of that subnet
        /// @param duid Client's DUID (ignored)
        /// @param hint client's hint (ignored)
        /// @return the next address
118
        virtual isc::asiolink::IOAddress
119
            pickAddress(const SubnetPtr& subnet,
120 121 122
                        const DuidPtr& duid,
                        const isc::asiolink::IOAddress& hint);
    private:
123 124 125 126

        /// @brief returns an address by one
        /// @param addr address to be increased
        /// @return address increased by one
127
        isc::asiolink::IOAddress increaseAddress(const isc::asiolink::IOAddress& addr);
128 129 130

    };

131 132 133 134
    /// @brief Address/prefix allocator that gets an address based on a hash
    ///
    /// @todo: This is a skeleton class for now and is missing implementation.
    class HashedAllocator : public Allocator {
135 136
    public:

137
        /// @brief default constructor (does nothing)
138
        /// @param type - specifies allocation type
139
        HashedAllocator(Lease::Type type);
140 141 142 143 144 145 146 147 148

        /// @brief returns an address based on hash calculated from client's DUID.
        ///
        /// @todo: Implement this method
        ///
        /// @param subnet an address will be picked from pool of that subnet
        /// @param duid Client's DUID
        /// @param hint a hint (last address that was picked)
        /// @return selected address
149
        virtual isc::asiolink::IOAddress pickAddress(const SubnetPtr& subnet,
150 151 152 153 154 155 156 157
                                                     const DuidPtr& duid,
                                                     const isc::asiolink::IOAddress& hint);
    };

    /// @brief Random allocator that picks address randomly
    ///
    /// @todo: This is a skeleton class for now and is missing implementation.
    class RandomAllocator : public Allocator {
158
    public:
159 160

        /// @brief default constructor (does nothing)
161
        /// @param type - specifies allocation type
162
        RandomAllocator(Lease::Type type);
163 164 165 166 167 168 169 170 171

        /// @brief returns an random address from pool of specified subnet
        ///
        /// @todo: Implement this method
        ///
        /// @param subnet an address will be picked from pool of that subnet
        /// @param duid Client's DUID (ignored)
        /// @param hint the last address that was picked (ignored)
        /// @return a random address from the pool
172
        virtual isc::asiolink::IOAddress
173
        pickAddress(const SubnetPtr& subnet, const DuidPtr& duid,
174 175
                    const isc::asiolink::IOAddress& hint);
    };
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194

    public:

    /// @brief specifies allocation type
    typedef enum {
        ALLOC_ITERATIVE, // iterative - one address after another
        ALLOC_HASHED,    // hashed - client's DUID/client-id is hashed
        ALLOC_RANDOM     // random - an address is randomly selected
    } AllocType;


    /// @brief Default constructor.
    ///
    /// Instantiates necessary services, required to run DHCPv6 server.
    /// In particular, creates IfaceMgr that will be responsible for
    /// network interaction. Will instantiate lease manager, and load
    /// old or create new DUID.
    ///
    /// @param engine_type selects allocation algorithm
195
    /// @param attempts number of attempts for each lease allocation before
196
    ///        we give up (0 means unlimited)
197 198
    /// @param ipv6 specifies if the engine should work for IPv4 or IPv6
    AllocEngine(AllocType engine_type, unsigned int attempts, bool ipv6 = true);
199

200
    /// @brief Returns IPv4 lease.
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
    /// This method finds the appropriate lease for the client using the
    /// following algorithm:
    /// - If lease exists for the combination of the HW address, client id and
    /// subnet, try to renew a lease and return it.
    /// - If lease exists for the combination of the client id and subnet, try
    /// to renew the lease and return it.
    /// - If client supplied an address hint and this address is available,
    /// allocate the new lease with this address.
    /// - If client supplied an address hint and the lease for this address
    /// exists in the database, return this lease if it is expired.
    /// - Pick new address from the pool and try to allocate it for the client,
    /// if expired lease exists for the picked address, try to reuse this lease.
    ///
    /// When a server should do DNS updates, it is required that allocation
    /// returns the information how the lease was obtained by the allocation
    /// engine. In particular, the DHCP server should be able to check whether
    /// existing lease was returned, or new lease was allocated. When existing
    /// lease was returned, server should check whether the FQDN has changed
    /// between the allocation of the old and new lease. If so, server should
    /// perform appropriate DNS update. If not, server may choose to not
    /// perform the update. The information about the old lease is returned via
    /// @c old_lease parameter. If NULL value is returned, it is an indication
    /// that new lease was allocated for the client. If non-NULL value is
    /// returned, it is an indication that allocation engine reused/renewed an
    /// existing lease.
227 228 229
    ///
    /// @param subnet subnet the allocation should come from
    /// @param clientid Client identifier
230 231 232
    /// @param hwaddr Client's hardware address info
    /// @param hint A hint that the client provided
    /// @param fwd_dns_update Indicates whether forward DNS update will be
233
    ///        performed for the client (true) or not (false).
234
    /// @param rev_dns_update Indicates whether reverse DNS update will be
235
    ///        performed for the client (true) or not (false).
236 237
    /// @param hostname A string carrying hostname to be used for DNS updates.
    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
238
    ///        an address for DISCOVER that is not really allocated (true)
239
    /// @param callout_handle A callout handle (used in hooks). A lease callouts
240
    ///        will be executed if this parameter is passed.
241
    /// @param [out] old_lease Holds the pointer to a previous instance of a
242 243
    ///        lease. The NULL pointer indicates that lease didn't exist prior
    ///        to calling this function (e.g. new lease has been allocated).
244
    ///
245 246 247
    /// @return Allocated IPv4 lease (or NULL if allocation failed)
    Lease4Ptr
    allocateAddress4(const SubnetPtr& subnet,
248 249
                     const ClientIdPtr& clientid,
                     const HWAddrPtr& hwaddr,
250
                     const isc::asiolink::IOAddress& hint,
251 252 253
                     const bool fwd_dns_update,
                     const bool rev_dns_update,
                     const std::string& hostname,
254
                     bool fake_allocation,
255 256
                     const isc::hooks::CalloutHandlePtr& callout_handle,
                     Lease4Ptr& old_lease);
257

258 259
    /// @brief Renews a IPv4 lease
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
260 261 262
    /// Since both request and renew are implemented in DHCPv4 as the sending of
    /// a REQUEST packet, it is difficult to easily distinguish between those
    /// cases. Therefore renew for DHCPv4 is done in the allocation engine.
263 264
    /// This method is also used when client crashed/rebooted and tries
    /// to get a new lease. It thinks that it gets a new lease, but in fact
Tomek Mrugalski's avatar
Tomek Mrugalski committed
265
    /// we are only renewing the still valid lease for that client.
266
    ///
267 268 269 270
    /// @param subnet A subnet the client is attached to
    /// @param clientid Client identifier
    /// @param hwaddr Client's hardware address
    /// @param fwd_dns_update Indicates whether forward DNS update will be
271
    ///        performed for the client (true) or not (false).
272
    /// @param rev_dns_update Indicates whether reverse DNS update will be
273
    ///        performed for the client (true) or not (false).
274 275
    /// @param hostname A string carrying hostname to be used for DNS updates.
    /// @param lease A lease to be renewed
276 277
    /// @param callout_handle a callout handle (used in hooks). A lease callouts
    ///        will be executed if this parameter is passed.
278
    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
279
    ///        an address for DISCOVER that is not really allocated (true)
280 281 282 283
    Lease4Ptr
    renewLease4(const SubnetPtr& subnet,
                const ClientIdPtr& clientid,
                const HWAddrPtr& hwaddr,
284 285 286
                const bool fwd_dns_update,
                const bool rev_dns_update,
                const std::string& hostname,
287
                const Lease4Ptr& lease,
288
                const isc::hooks::CalloutHandlePtr& callout_handle,
289 290
                bool fake_allocation /* = false */);

291 292 293 294 295 296 297
    /// @brief Allocates an IPv6 lease
    ///
    /// This method uses currently selected allocator to pick an address from
    /// specified subnet, creates a lease for that address and then inserts
    /// it into LeaseMgr (if this allocation is not fake).
    ///
    /// @param subnet subnet the allocation should come from
298
    /// @param duid Client's DUID
299 300
    /// @param iaid iaid field from the IA_NA container that client sent
    /// @param hint a hint that the client provided
301
    /// @param type lease type (IA, TA or PD)
302
    /// @param fwd_dns_update A boolean value which indicates that server takes
303 304
    ///        responsibility for the forward DNS Update for this lease
    ///        (if true).
305
    /// @param rev_dns_update A boolean value which indicates that server takes
306 307
    ///        responsibility for the reverse DNS Update for this lease
    ///        (if true).
308
    /// @param hostname A fully qualified domain-name of the client.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
309 310
    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
    ///        an address for SOLICIT that is not really allocated (true)
311 312 313
    /// @param callout_handle a callout handle (used in hooks). A lease callouts
    ///        will be executed if this parameter is passed.
    ///
314 315
    /// @return Allocated IPv6 leases (may be empty if allocation failed)
    Lease6Collection
316 317 318
    allocateAddress6(const Subnet6Ptr& subnet,
                     const DuidPtr& duid,
                     uint32_t iaid,
319
                     const isc::asiolink::IOAddress& hint,
320
                     Lease::Type type,
321 322 323
                     const bool fwd_dns_update,
                     const bool rev_dns_update,
                     const std::string& hostname,
324 325
                     bool fake_allocation,
                     const isc::hooks::CalloutHandlePtr& callout_handle);
326 327 328 329 330

    /// @brief Destructor. Used during DHCPv6 service shutdown.
    virtual ~AllocEngine();
private:

Tomek Mrugalski's avatar
Tomek Mrugalski committed
331
    /// @brief Creates a lease and inserts it in LeaseMgr if necessary
332 333
    ///
    /// Creates a lease based on specified parameters and tries to insert it
Tomek Mrugalski's avatar
Tomek Mrugalski committed
334
    /// into the database. That may fail in some cases, e.g. when there is another
335 336
    /// allocation process and we lost a race to a specific lease.
    ///
337 338 339 340 341
    /// @param subnet Subnet the lease is allocated from
    /// @param clientid Client identifier
    /// @param hwaddr Client's hardware address
    /// @param addr An address that was selected and is confirmed to be available
    /// @param fwd_dns_update Indicates whether forward DNS update will be
342
    ///        performed for the client (true) or not (false).
343
    /// @param rev_dns_update Indicates whether reverse DNS update will be
344
    ///        performed for the client (true) or not (false).
345
    /// @param hostname A string carrying hostname to be used for DNS updates.
346
    /// @param callout_handle a callout handle (used in hooks). A lease callouts
Tomek Mrugalski's avatar
Tomek Mrugalski committed
347 348
    ///        will be executed if this parameter is passed (and there are callouts
    ///        registered)
349
    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
350 351 352
    ///        an address for DISCOVER that is not really allocated (true)
    /// @return allocated lease (or NULL in the unlikely case of the lease just
    ///        becomed unavailable)
353 354
    Lease4Ptr createLease4(const SubnetPtr& subnet, const DuidPtr& clientid,
                           const HWAddrPtr& hwaddr,
355
                           const isc::asiolink::IOAddress& addr,
356 357 358
                           const bool fwd_dns_update,
                           const bool rev_dns_update,
                           const std::string& hostname,
359
                           const isc::hooks::CalloutHandlePtr& callout_handle,
360 361
                           bool fake_allocation = false);

362 363 364 365 366 367 368 369 370
    /// @brief creates a lease and inserts it in LeaseMgr if necessary
    ///
    /// Creates a lease based on specified parameters and tries to insert it
    /// into the database. That may fail in some cases, i.e. when there is another
    /// allocation process and we lost a race to a specific lease.
    ///
    /// @param subnet subnet the lease is allocated from
    /// @param duid client's DUID
    /// @param iaid IAID from the IA_NA container the client sent to us
371
    /// @param addr an address that was selected and is confirmed to be
372 373
    ///        available
    /// @param type lease type (IA, TA or PD)
374
    /// @param fwd_dns_update A boolean value which indicates that server takes
375 376
    ///        responsibility for the forward DNS Update for this lease
    ///        (if true).
377
    /// @param rev_dns_update A boolean value which indicates that server takes
378 379
    ///        responsibility for the reverse DNS Update for this lease
    ///        (if true).
380
    /// @param hostname A fully qualified domain-name of the client.
381
    /// @param callout_handle a callout handle (used in hooks). A lease callouts
Tomek Mrugalski's avatar
Tomek Mrugalski committed
382 383
    ///        will be executed if this parameter is passed (and there are callouts
    ///        registered)
Tomek Mrugalski's avatar
Tomek Mrugalski committed
384 385
    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
    ///        an address for SOLICIT that is not really allocated (true)
386
    /// @return allocated lease (or NULL in the unlikely case of the lease just
387
    ///         became unavailable)
388 389
    Lease6Ptr createLease6(const Subnet6Ptr& subnet, const DuidPtr& duid,
                           uint32_t iaid, const isc::asiolink::IOAddress& addr,
390 391
                           Lease::Type type, const bool fwd_dns_update,
                           const bool rev_dns_update,
392
                           const std::string& hostname,
393
                           const isc::hooks::CalloutHandlePtr& callout_handle,
394 395
                           bool fake_allocation = false);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
396
    /// @brief Reuses expired IPv4 lease
397 398 399 400 401
    ///
    /// Updates existing expired lease with new information. Lease database
    /// is updated if this is real (i.e. REQUEST, fake_allocation = false), not
    /// dummy allocation request (i.e. DISCOVER, fake_allocation = true).
    ///
402 403 404 405 406
    /// @param expired Old, expired lease
    /// @param subnet Subnet the lease is allocated from
    /// @param clientid Client identifier
    /// @param hwaddr Client's hardware address
    /// @param fwd_dns_update Indicates whether forward DNS update will be
407
    ///        performed for the client (true) or not (false).
408
    /// @param rev_dns_update Indicates whether reverse DNS update will be
409
    ///        performed for the client (true) or not (false).
410 411
    /// @param hostname A string carrying hostname to be used for DNS updates.
    /// @param callout_handle A callout handle (used in hooks). A lease callouts
412
    ///        will be executed if this parameter is passed.
413
    /// @param fake_allocation Is this real i.e. REQUEST (false) or just picking
414 415 416
    ///        an address for DISCOVER that is not really allocated (true)
    /// @return refreshed lease
    /// @throw BadValue if trying to recycle lease that is still valid
417 418
    Lease4Ptr reuseExpiredLease(Lease4Ptr& expired,
                                const SubnetPtr& subnet,
419 420
                                const ClientIdPtr& clientid,
                                const HWAddrPtr& hwaddr,
421 422 423
                                const bool fwd_dns_update,
                                const bool rev_dns_update,
                                const std::string& hostname,
424
                                const isc::hooks::CalloutHandlePtr& callout_handle,
425
                                bool fake_allocation = false);
426

Tomek Mrugalski's avatar
Tomek Mrugalski committed
427
    /// @brief Reuses expired IPv6 lease
428 429 430 431 432 433 434 435 436
    ///
    /// Updates existing expired lease with new information. Lease database
    /// is updated if this is real (i.e. REQUEST, fake_allocation = false), not
    /// dummy allocation request (i.e. SOLICIT, fake_allocation = true).
    ///
    /// @param expired old, expired lease
    /// @param subnet subnet the lease is allocated from
    /// @param duid client's DUID
    /// @param iaid IAID from the IA_NA container the client sent to us
437
    /// @param fwd_dns_update A boolean value which indicates that server takes
438 439
    ///        responsibility for the forward DNS Update for this lease
    ///        (if true).
440
    /// @param rev_dns_update A boolean value which indicates that server takes
441 442
    ///        responsibility for the reverse DNS Update for this lease
    ///        (if true).
443
    /// @param hostname A fully qualified domain-name of the client.
444 445
    /// @param callout_handle a callout handle (used in hooks). A lease callouts
    ///        will be executed if this parameter is passed.
446 447 448 449 450 451
    /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
    ///        an address for SOLICIT that is not really allocated (true)
    /// @return refreshed lease
    /// @throw BadValue if trying to recycle lease that is still valid
    Lease6Ptr reuseExpiredLease(Lease6Ptr& expired, const Subnet6Ptr& subnet,
                                const DuidPtr& duid, uint32_t iaid,
452 453 454
                                const bool fwd_dns_update,
                                const bool rev_dns_update,
                                const std::string& hostname,
455
                                const isc::hooks::CalloutHandlePtr& callout_handle,
456 457
                                bool fake_allocation = false);

458
    /// @brief a pointer to currently used allocator
Tomek Mrugalski's avatar
Tomek Mrugalski committed
459
    boost::shared_ptr<Allocator> allocator_;
460

461
    /// @brief number of attempts before we give up lease allocation (0=unlimited)
462
    unsigned int attempts_;
463

464 465 466
    // hook name indexes (used in hooks callouts)
    int hook_index_lease4_select_; ///< index for lease4_select hook
    int hook_index_lease6_select_; ///< index for lease6_select hook
467 468 469 470 471
};

}; // namespace isc::dhcp
}; // namespace isc

Tomek Mrugalski's avatar
Tomek Mrugalski committed
472
#endif // ALLOC_ENGINE_H