1 // Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef SUBNET_H
8 #define SUBNET_H
9 
10 #include <asiolink/io_address.h>
11 #include <cc/data.h>
12 #include <cc/user_context.h>
13 #include <dhcp/option_space_container.h>
14 #include <dhcpsrv/lease.h>
15 #include <dhcpsrv/network.h>
16 #include <dhcpsrv/pool.h>
17 #include <dhcpsrv/subnet_id.h>
18 #include <dhcpsrv/triplet.h>
19 #include <boost/multi_index/mem_fun.hpp>
20 #include <boost/multi_index/indexed_by.hpp>
21 #include <boost/multi_index/ordered_index.hpp>
22 #include <boost/multi_index/random_access_index.hpp>
23 #include <boost/multi_index_container.hpp>
24 #include <boost/date_time/posix_time/posix_time.hpp>
25 #include <boost/pointer_cast.hpp>
26 #include <boost/scoped_ptr.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <cstdint>
29 #include <map>
30 #include <mutex>
31 #include <utility>
32 
33 namespace isc {
34 namespace dhcp {
35 
36 class Subnet : public virtual Network {
37 public:
38 
39     /// @brief checks if specified address is in range.
40     ///
41     /// @param addr this address will be checked if it is included in a specific
42     ///        range
43     /// @return true if address is in range, false otherwise
44     bool inRange(const isc::asiolink::IOAddress& addr) const;
45 
46     /// @brief checks if the specified address is in pools.
47     ///
48     /// Note the difference between inRange() and inPool() for addresses
49     /// (i.e. *not* prefixes). For a given subnet (e.g. 2001::/64) there
50     /// may be one or more pools defined that may or may not cover
51     /// entire subnet, e.g. pool 2001::1-2001::10). inPool() returning
52     /// true implies inRange(), but the reverse implication is not
53     /// always true. For the given example, 2001::1234:abcd would return
54     /// true for inRange(), but false for inPool() check.
55     ///
56     /// @param type type of pools to iterate over
57     /// @param addr this address will be checked if it belongs to any pools in
58     ///        that subnet
59     /// @return true if the address is in any of the pools
60     bool inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const;
61 
62     /// @brief checks if the specified address is in allowed pools.
63     ///
64     /// This takes also into account client classes
65     ///
66     /// @param type type of pools to iterate over
67     /// @param addr this address will be checked if it belongs to any pools in
68     ///        that subnet
69     /// @param client_classes client class list which must be allowed
70     /// @return true if the address is in any of the allowed pools
71     bool inPool(Lease::Type type,
72                 const isc::asiolink::IOAddress& addr,
73                 const ClientClasses& client_classes) const;
74 
75     /// @brief returns the last address that was tried from this subnet.
76     ///
77     /// This method returns the last address that was attempted to be allocated
78     /// from this subnet. This is used as helper information for the next
79     /// iteration of the allocation algorithm.
80     ///
81     /// @note: this routine is Kea thread safe.
82     ///
83     /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
84     ///        AllocEngine::IterativeAllocator and keep the data there
85     ///
86     /// @param type lease type to be returned
87     /// @return address/prefix that was last tried from this subnet
88     isc::asiolink::IOAddress getLastAllocated(Lease::Type type) const;
89 
90     /// @brief Returns the timestamp when the @c setLastAllocated function
91     /// was called.
92     ///
93     /// @note: this routine is Kea thread safe.
94     ///
95     /// @param lease_type Lease type for which last allocation timestamp should
96     /// be returned.
97     ///
98     /// @return Time when a lease of a specified type has been allocated from
99     /// this subnet. The negative infinity time is returned if a lease type is
100     /// not recognized (which is unlikely).
101     boost::posix_time::ptime
102     getLastAllocatedTime(const Lease::Type& lease_type) const;
103 
104     /// @brief sets the last address that was tried from this subnet.
105     ///
106     /// This method sets the last address that was attempted to be allocated
107     /// from this subnet. This is used as helper information for the next
108     /// iteration of the allocation algorithm.
109     ///
110     /// @note: this routine is Kea thread safe.
111     ///
112     /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
113     ///        AllocEngine::IterativeAllocator and keep the data there
114     /// @param addr address/prefix to that was tried last
115     /// @param type lease type to be set
116     void setLastAllocated(Lease::Type type,
117                           const isc::asiolink::IOAddress& addr);
118 
119     /// @brief Returns unique ID for that subnet.
120     ///
121     /// @return unique ID for that subnet
getID()122     SubnetID getID() const { return (id_); }
123 
124     /// @brief Returns subnet parameters (prefix and prefix length).
125     ///
126     /// @return (prefix, prefix length) pair
get()127     std::pair<isc::asiolink::IOAddress, uint8_t> get() const {
128         return (std::make_pair(prefix_, prefix_len_));
129     }
130 
131     /// @brief Adds a new pool for the subnet.
132     ///
133     /// This method checks that the address range represented by the pool
134     /// matches the subnet prefix, if the pool type is different than
135     /// IA_PD. The prefixes from the IA_PD pools don't need to match the
136     /// prefix from the subnet from which they are handed out to the
137     /// requesting router because the requesting router may use the
138     /// delegated prefixes in different networks (using different subnets).
139     ///
140     /// A DHCPv4 pool being added must not overlap with any existing DHCPv4
141     /// pool. A DHCPv6 pool being added must not overlap with any existing
142     /// DHCPv6 pool.
143     ///
144     /// Pools held within a subnet are sorted by first pool address/prefix
145     /// from the lowest to the highest.
146     ///
147     /// @param pool pool to be added
148     ///
149     /// @throw isc::BadValue if the pool type is invalid, the pool
150     /// is not an IA_PD pool and the address range of this pool does not
151     /// match the subnet prefix, or the pool overlaps with an existing pool
152     /// within the subnet.
153     void addPool(const PoolPtr& pool);
154 
155     /// @brief Deletes all pools of specified type.
156     ///
157     /// This method is used for testing purposes only
158     ///
159     /// @param type type of pools to be deleted
160     void delPools(Lease::Type type);
161 
162     /// @brief Returns a pool that specified address belongs to.
163     ///
164     /// This method uses binary search to retrieve the pool. Thus, the number
165     /// of comparisons performed by this method is logarithmic in the number
166     /// of pools belonging to a subnet.
167     ///
168     /// If there is no pool that the address belongs to (hint is invalid), other
169     /// pool of specified type will be returned.
170     ///
171     /// With anypool set to true, this is means give me a pool, preferably
172     /// the one that addr belongs to. With anypool set to false, it means
173     /// give me a pool that addr belongs to (or NULL if here is no such pool)
174     ///
175     /// @param type pool type that the pool is looked for
176     /// @param addr address that the returned pool should cover (optional)
177     /// @param anypool other pool may be returned as well, not only the one
178     ///        that addr belongs to
179     /// @return found pool (or NULL)
180     const PoolPtr getPool(Lease::Type type, const isc::asiolink::IOAddress& addr,
181                           bool anypool = true) const;
182 
183     /// @brief Returns a pool that specified address belongs to with classes.
184     ///
185     /// Variant using only pools allowing given classes.
186     ///
187     /// @param type pool type that the pool is looked for
188     /// @param client_classes client class list which must be allowed
189     /// @param addr address that the returned pool should cover (optional)
190     const PoolPtr getPool(Lease::Type type,
191                           const ClientClasses& client_classes,
192                           const isc::asiolink::IOAddress& addr) const;
193 
194     /// @brief Returns a pool without any address specified.
195     ///
196     /// @param type pool type that the pool is looked for
197     /// @return returns one of the pools defined
getAnyPool(Lease::Type type)198     PoolPtr getAnyPool(Lease::Type type) {
199         return (getPool(type, default_pool()));
200     }
201 
202     /// @brief Returns the default address that will be used for pool selection.
203     ///
204     /// It must be implemented in derived classes (should return :: for Subnet6
205     /// and 0.0.0.0 for Subnet4).
206     virtual isc::asiolink::IOAddress default_pool() const = 0;
207 
208     /// @brief Returns all pools (const variant).
209     ///
210     /// The reference is only valid as long as the object that returned it.
211     ///
212     /// @param type lease type to be set
213     /// @return a collection of all pools
214     const PoolCollection& getPools(Lease::Type type) const;
215 
216     /// @brief Returns the number of possible leases for specified lease type.
217     ///
218     /// @param type type of the lease
219     uint64_t getPoolCapacity(Lease::Type type) const;
220 
221     /// @brief Returns the number of possible leases for specified lease type
222     /// allowed for a client which belongs to classes.
223     ///
224     /// @param type type of the lease
225     /// @param client_classes list of classes the client belongs to
226     /// @return number of leases matching lease type and classes
227     uint64_t getPoolCapacity(Lease::Type type,
228                              const ClientClasses& client_classes) const;
229 
230     /// @brief Returns textual representation of the subnet (e.g.
231     /// "2001:db8::/64").
232     ///
233     /// @return textual representation
234     virtual std::string toText() const;
235 
236     /// @brief Resets subnet-id counter to its initial value (1).
237     ///
238     /// This should be called during reconfiguration, before any new
239     /// subnet objects are created. It will ensure that the subnet_id will
240     /// be consistent between reconfigures.
resetSubnetID()241     static void resetSubnetID() {
242         static_id_ = 1;
243     }
244 
245     /// @brief Retrieves pointer to a shared network associated with a subnet.
246     ///
247     /// By implementing it as a template function we overcome a need to
248     /// include shared_network.h header file to specify return type explicitly.
249     /// The header can't be included because it would cause circular dependency
250     /// between subnet.h and shared_network.h.
251     ///
252     /// This method uses an argument to hold a return value to allow the compiler
253     /// to infer the return type without a need to call this function with an
254     /// explicit return type as template argument.
255     ///
256     /// @param [out] shared_network Pointer to the shared network where returned
257     /// value should be assigned.
258     ///
259     /// @tparam Type of the shared network, i.e. @ref SharedNetwork4 or a
260     /// @ref SharedNetwork6.
261     template<typename SharedNetworkPtrType>
getSharedNetwork(SharedNetworkPtrType & shared_network)262     void getSharedNetwork(SharedNetworkPtrType& shared_network) const {
263         shared_network = boost::dynamic_pointer_cast<
264             typename SharedNetworkPtrType::element_type>(parent_network_.lock());
265     }
266 
267     /// @brief Assigns shared network to a subnet.
268     ///
269     /// This method replaces any shared network associated with a subnet with
270     /// a new shared network.
271     ///
272     /// @param shared_network Pointer to a new shared network to be associated
273     /// with the subnet.
setSharedNetwork(const NetworkPtr & shared_network)274     void setSharedNetwork(const NetworkPtr& shared_network) {
275         parent_network_ = shared_network;
276     }
277 
278     /// @brief Returns shared network name.
279     ///
280     /// @return shared network name
getSharedNetworkName()281     std::string getSharedNetworkName() const {
282         return (shared_network_name_);
283     }
284 
285     /// @brief Sets new shared network name.
286     ///
287     /// In certain cases the subnet must be associated with the shared network
288     /// but the shared network object is not available. In particular, subnets
289     /// are returned from the configuration database with only names of the
290     /// shared networks. The actual shared networks must be fetched from the
291     /// database using a separate query. In order to not loose associations
292     /// of subnets with shared networks, the configuration backends will use
293     /// this method to store the shared network names. The servers will later
294     /// use those names to associate subnets with shared network instances.
295     ///
296     /// @param shared_network_name New shared network name.
setSharedNetworkName(const std::string & shared_network_name)297     void setSharedNetworkName(const std::string& shared_network_name) {
298         shared_network_name_ = shared_network_name;
299     }
300 
301     /// @brief Returns all pools (non-const variant).
302     ///
303     /// The reference is only valid as long as the object that returned it.
304     ///
305     /// @param type lease type to be set
306     /// @return a collection of all pools
307     PoolCollection& getPoolsWritable(Lease::Type type);
308 
309 protected:
310 
311     /// @brief Protected constructor.
312     //
313     /// By making the constructor protected, we make sure that no one will
314     /// ever instantiate that class. Subnet4 and Subnet6 should be used instead.
315     ///
316     /// This constructor assigns a new subnet-id (see @ref generateNextID).
317     /// This subnet-id has unique value that is strictly monotonously increasing
318     /// for each subnet, until it is explicitly reset back to 1 during
319     /// reconfiguration process.
320     ///
321     /// @param prefix subnet prefix
322     /// @param len prefix length for the subnet
323     /// @param id arbitrary subnet id, value of 0 triggers autogeneration
324     /// of subnet id
325     Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
326            const SubnetID id);
327 
328     /// @brief virtual destructor.
329     ///
330     /// A virtual destructor is needed because other classes
331     /// derive from this class.
~Subnet()332     virtual ~Subnet() { };
333 
334     /// @brief keeps the subnet-id value.
335     ///
336     /// It is incremented every time a new Subnet object is created. It is reset
337     /// (@ref resetSubnetID) every time reconfiguration
338     /// occurs.
339     ///
340     /// Static value initialized in subnet.cc.
341     static SubnetID static_id_;
342 
343     /// @brief returns the next unique Subnet-ID.
344     ///
345     /// This method generates and returns the next unique subnet-id.
346     /// It is a strictly monotonously increasing value (1,2,3,...) for
347     /// each new Subnet object created. It can be explicitly reset
348     /// back to 1 during reconfiguration (@ref resetSubnetID).
349     ///
350     /// @return the next unique Subnet-ID
generateNextID()351     static SubnetID generateNextID() {
352         if (static_id_ == SUBNET_ID_MAX) {
353             resetSubnetID();
354         }
355 
356         return (static_id_++);
357     }
358 
359     /// @brief Checks if used pool type is valid.
360     ///
361     /// Allowed type for Subnet4 is Pool::TYPE_V4.
362     /// Allowed types for Subnet6 are Pool::TYPE_{IA,TA,PD}.
363     /// This method is implemented in derived classes.
364     ///
365     /// @param type type to be checked
366     /// @throw BadValue if invalid value is used
367     virtual void checkType(Lease::Type type) const = 0;
368 
369     /// @brief Returns a sum of possible leases in all pools.
370     ///
371     /// @param pools list of pools
372     /// @return sum of possible leases
373     uint64_t sumPoolCapacity(const PoolCollection& pools) const;
374 
375     /// @brief Returns a sum of possible leases in all pools allowing classes.
376     ///
377     /// @param pools list of pools
378     /// @param client_classes list of classes
379     /// @return sum of possible/allowed leases
380     uint64_t sumPoolCapacity(const PoolCollection& pools,
381                              const ClientClasses& client_classes) const;
382 
383     /// @brief Checks if the specified pool overlaps with an existing pool.
384     ///
385     /// @param pool_type Pool type.
386     /// @param pool Pointer to a pool for which the method should check if
387     /// it overlaps with any existing pool within this subnet.
388     ///
389     /// @return true if pool overlaps with an existing pool of a specified
390     /// type, false otherwise
391     bool poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const;
392 
393     /// @brief Unparse a subnet object.
394     ///
395     /// @return A pointer to unparsed subnet configuration.
396     virtual data::ElementPtr toElement() const;
397 
398     /// @brief Converts subnet prefix to a pair of prefix/length pair.
399     ///
400     /// IPv4 and IPv6 specific conversion functions should apply extra checks
401     /// on the returned values, i.e. whether length is in range and the IP
402     /// address has a valid type.
403     ///
404     /// @param prefix Prefix to be parsed.
405     /// @throw BadValue if provided prefix is not valid.
406     static std::pair<asiolink::IOAddress, uint8_t>
407     parsePrefixCommon(const std::string& prefix);
408 
409     /// @brief subnet-id
410     ///
411     /// Subnet-id is a unique value that can be used to find or identify
412     /// a Subnet4 or Subnet6.
413     SubnetID id_;
414 
415     /// @brief collection of IPv4 or non-temporary IPv6 pools in that subnet.
416     PoolCollection pools_;
417 
418     /// @brief collection of IPv6 temporary address pools in that subnet.
419     PoolCollection pools_ta_;
420 
421     /// @brief collection of IPv6 prefix pools in that subnet.
422     PoolCollection pools_pd_;
423 
424     /// @brief a prefix of the subnet.
425     isc::asiolink::IOAddress prefix_;
426 
427     /// @brief a prefix length of the subnet.
428     uint8_t prefix_len_;
429 
430     /// @brief last allocated address.
431     ///
432     /// This is the last allocated address that was previously allocated from
433     /// this particular subnet. Some allocation algorithms (e.g. iterative) use
434     /// that value, others do not. It should be noted that although the value
435     /// is usually correct, there are cases when it is invalid, e.g. after
436     /// removing a pool, restarting or changing allocation algorithms. For
437     /// that purpose it should be only considered a help that should not be
438     /// fully trusted.
439     isc::asiolink::IOAddress last_allocated_ia_;
440 
441     /// @brief last allocated temporary address.
442     ///
443     /// See @ref last_allocated_ia_ for details.
444     isc::asiolink::IOAddress last_allocated_ta_;
445 
446     /// @brief last allocated IPv6 prefix.
447     ///
448     /// See @ref last_allocated_ia_ for details.
449     isc::asiolink::IOAddress last_allocated_pd_;
450 
451     /// @brief Timestamp indicating when a lease of a specified type has been
452     /// last allocated from this subnet.
453     ///
454     /// @note: This map is protected by the mutex.
455     std::map<Lease::Type, boost::posix_time::ptime> last_allocated_time_;
456 
457     /// @brief Shared network name.
458     std::string shared_network_name_;
459 
460 private:
461 
462     /// @brief returns the last address that was tried from this subnet.
463     ///
464     /// Should be called in a thread safe context.
465     ///
466     /// This method returns the last address that was attempted to be allocated
467     /// from this subnet. This is used as helper information for the next
468     /// iteration of the allocation algorithm.
469     ///
470     /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
471     ///        AllocEngine::IterativeAllocator and keep the data there
472     ///
473     /// @param type lease type to be returned
474     /// @return address/prefix that was last tried from this subnet
475     isc::asiolink::IOAddress getLastAllocatedInternal(Lease::Type type) const;
476 
477     /// @brief Returns the timestamp when the @c setLastAllocated function
478     /// was called.
479     ///
480     /// Should be called in a thread safe context.
481     ///
482     /// @param lease_type Lease type for which last allocation timestamp should
483     /// be returned.
484     ///
485     /// @return Time when a lease of a specified type has been allocated from
486     /// this subnet. The negative infinity time is returned if a lease type is
487     /// not recognized (which is unlikely).
488     boost::posix_time::ptime
489     getLastAllocatedTimeInternal(const Lease::Type& lease_type) const;
490 
491     /// @brief sets the last address that was tried from this subnet.
492     ///
493     /// Should be called in a thread safe context.
494     ///
495     /// This method sets the last address that was attempted to be allocated
496     /// from this subnet. This is used as helper information for the next
497     /// iteration of the allocation algorithm.
498     ///
499     /// @note: this routine is Kea thread safe.
500     ///
501     /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
502     ///        AllocEngine::IterativeAllocator and keep the data there
503     /// @param addr address/prefix to that was tried last
504     /// @param type lease type to be set
505     void setLastAllocatedInternal(Lease::Type type,
506                                   const isc::asiolink::IOAddress& addr);
507 
508     /// @brief Mutex to protect the internal state.
509     boost::scoped_ptr<std::mutex> mutex_;
510 };
511 
512 /// @brief A generic pointer to either Subnet4 or Subnet6 object
513 typedef boost::shared_ptr<Subnet> SubnetPtr;
514 
515 
516 class Subnet4;
517 
518 /// @brief A const pointer to a @c Subnet4 object.
519 typedef boost::shared_ptr<const Subnet4> ConstSubnet4Ptr;
520 
521 /// @brief A pointer to a @c Subnet4 object.
522 typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
523 
524 /// @brief A configuration holder for IPv4 subnet.
525 ///
526 /// This class represents an IPv4 subnet.
527 /// @note Subnet and Network use virtual inheritance to avoid
528 /// a diamond issue with UserContext
529 class Subnet4 : public Subnet, public Network4 {
530 public:
531 
532     /// @brief Constructor with all parameters.
533     ///
534     /// This constructor calls Subnet::Subnet, where subnet-id is generated.
535     ///
536     /// @param prefix Subnet4 prefix
537     /// @param length prefix length
538     /// @param t1 renewal timer (in seconds)
539     /// @param t2 rebind timer (in seconds)
540     /// @param valid_lifetime preferred lifetime of leases (in seconds)
541     /// @param id arbitrary subnet id, default value of 0 triggers
542     /// autogeneration of subnet id
543     Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
544             const Triplet<uint32_t>& t1,
545             const Triplet<uint32_t>& t2,
546             const Triplet<uint32_t>& valid_lifetime,
547             const SubnetID id = 0);
548 
549     /// @brief Factory function creating an instance of the @c Subnet4.
550     ///
551     /// This function should be used to create an instance of the subnet
552     /// object within a hooks library in cases when the library may be
553     /// unloaded before the object is destroyed. This ensures that the
554     /// ownership of the object by the Kea process is retained.
555     ///
556     /// @param prefix Subnet4 prefix
557     /// @param length prefix length
558     /// @param t1 renewal timer (in seconds)
559     /// @param t2 rebind timer (in seconds)
560     /// @param valid_lifetime preferred lifetime of leases (in seconds)
561     /// @param id arbitrary subnet id, default value of 0 triggers
562     /// autogeneration of subnet id
563     ///
564     /// @return Pointer to the @c Subnet4 instance.
565     static Subnet4Ptr
566     create(const isc::asiolink::IOAddress& prefix, uint8_t length,
567            const Triplet<uint32_t>& t1,
568            const Triplet<uint32_t>& t2,
569            const Triplet<uint32_t>& valid_lifetime,
570            const SubnetID id = 0);
571 
572     /// @brief Returns next subnet within shared network.
573     ///
574     /// If the current subnet doesn't belong to any shared network or if
575     /// the next subnet is the same as first subnet (specified in the
576     /// argument) a NULL pointer is returned.
577     ///
578     /// @param first_subnet Pointer to the subnet from which iterations have
579     /// started.
580     ///
581     /// @return Pointer to the next subnet or NULL pointer if the next subnet
582     /// is the first subnet or if the current subnet doesn't belong to a
583     /// shared network.
584     Subnet4Ptr getNextSubnet(const Subnet4Ptr& first_subnet) const;
585 
586     /// @brief Returns next subnet within shared network that matches
587     /// client classes.
588     ///
589     /// @param first_subnet Pointer to the subnet from which iterations have
590     /// started.
591     /// @param client_classes List of classes that the client belongs to.
592     /// The subnets not matching the classes aren't returned by this
593     /// method.
594     ///
595     /// @return Pointer to the next subnet or NULL pointer if the next subnet
596     /// is the first subnet or if the current subnet doesn't belong to a
597     /// shared network.
598     Subnet4Ptr getNextSubnet(const Subnet4Ptr& first_subnet,
599                              const ClientClasses& client_classes) const;
600 
601     /// @brief Checks whether this subnet and parent shared network supports
602     /// the client that belongs to specified classes.
603     ///
604     /// This method extends the @ref Network::clientSupported method with
605     /// additional checks whether shared network owning this class supports
606     /// the client belonging to specified classes. If the class doesn't
607     /// belong to a shared network this method only checks if the subnet
608     /// supports specified classes.
609     ///
610     /// @param client_classes List of classes the client belongs to.
611     /// @return true if client can be supported, false otherwise.
612     virtual bool
613     clientSupported(const isc::dhcp::ClientClasses& client_classes) const;
614 
615     /// @brief Returns DHCP4o6 configuration parameters.
616     ///
617     /// This structure is always available. If the 4o6 is not enabled, its
618     /// enabled_ field will be set to false.
get4o6()619     Cfg4o6& get4o6() {
620         return (dhcp4o6_);
621     }
622 
623     /// @brief Returns const DHCP4o6 configuration parameters.
624     ///
625     /// This structure is always available. If the 4o6 is not enabled, its
626     /// enabled_ field will be set to false.
get4o6()627     const Cfg4o6& get4o6() const {
628         return (dhcp4o6_);
629     }
630 
631     /// @brief Unparse a subnet object.
632     ///
633     /// @return A pointer to unparsed subnet configuration.
634     virtual data::ElementPtr toElement() const;
635 
636     /// @brief Converts subnet prefix to a pair of prefix/length pair.
637     ///
638     /// @param prefix Prefix to be parsed.
639     /// @throw BadValue if provided invalid IPv4 prefix.
640     static std::pair<asiolink::IOAddress, uint8_t>
641     parsePrefix(const std::string& prefix);
642 
643 private:
644 
645     /// @brief Returns default address for pool selection.
646     ///
647     /// @return ANY IPv4 address
default_pool()648     virtual isc::asiolink::IOAddress default_pool() const {
649         return (isc::asiolink::IOAddress("0.0.0.0"));
650     }
651 
652     /// @brief Checks if used pool type is valid.
653     ///
654     /// Allowed type for Subnet4 is Pool::TYPE_V4.
655     ///
656     /// @param type type to be checked
657     /// @throw BadValue if invalid value is used
658     virtual void checkType(Lease::Type type) const;
659 
660     /// @brief All the information related to DHCP4o6
661     Cfg4o6 dhcp4o6_;
662 };
663 
664 class Subnet6;
665 
666 /// @brief A const pointer to a @c Subnet6 object.
667 typedef boost::shared_ptr<const Subnet6> ConstSubnet6Ptr;
668 
669 /// @brief A pointer to a Subnet6 object
670 typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
671 
672 /// @brief A configuration holder for IPv6 subnet.
673 ///
674 /// This class represents an IPv6 subnet.
675 /// @note Subnet and Network use virtual inheritance to avoid
676 /// a diamond issue with UserContext
677 class Subnet6 : public Subnet, public Network6 {
678 public:
679 
680     /// @brief Constructor with all parameters.
681     ///
682     /// This constructor calls Subnet::Subnet, where subnet-id is generated.
683     ///
684     /// @param prefix Subnet6 prefix
685     /// @param length prefix length
686     /// @param t1 renewal timer (in seconds)
687     /// @param t2 rebind timer (in seconds)
688     /// @param preferred_lifetime preferred lifetime of leases (in seconds)
689     /// @param valid_lifetime preferred lifetime of leases (in seconds)
690     /// @param id arbitrary subnet id, default value of 0 triggers
691     /// autogeneration of subnet id
692     Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
693             const Triplet<uint32_t>& t1,
694             const Triplet<uint32_t>& t2,
695             const Triplet<uint32_t>& preferred_lifetime,
696             const Triplet<uint32_t>& valid_lifetime,
697             const SubnetID id = 0);
698 
699     /// @brief Factory function creating an instance of the @c Subnet4.
700     ///
701     /// This function should be used to create an instance of the subnet
702     /// object within a hooks library in cases when the library may be
703     /// unloaded before the object is destroyed. This ensures that the
704     /// ownership of the object by the Kea process is retained.
705     ///
706     /// @param prefix Subnet6 prefix
707     /// @param length prefix length
708     /// @param t1 renewal timer (in seconds)
709     /// @param t2 rebind timer (in seconds)
710     /// @param preferred_lifetime preferred lifetime of leases (in seconds)
711     /// @param valid_lifetime preferred lifetime of leases (in seconds)
712     /// @param id arbitrary subnet id, default value of 0 triggers
713     /// autogeneration of subnet id
714     ///
715     /// @return Pointer to the @c Subnet6 instance.
716     static Subnet6Ptr
717     create(const isc::asiolink::IOAddress& prefix, uint8_t length,
718            const Triplet<uint32_t>& t1,
719            const Triplet<uint32_t>& t2,
720            const Triplet<uint32_t>& preferred_lifetime,
721            const Triplet<uint32_t>& valid_lifetime,
722            const SubnetID id = 0);
723 
724     /// @brief Returns next subnet within shared network.
725     ///
726     /// If the current subnet doesn't belong to any shared network or if
727     /// the next subnet is the same as first subnet (specified in the
728     /// arguments) a NULL pointer is returned.
729     ///
730     /// @param first_subnet Pointer to the subnet from which iterations have
731     /// started.
732     ///
733     /// @return Pointer to the next subnet or NULL pointer if the next subnet
734     /// is the first subnet or if the current subnet doesn't belong to a
735     /// shared network.
736     Subnet6Ptr getNextSubnet(const Subnet6Ptr& first_subnet) const;
737 
738     /// @brief Returns next subnet within shared network that matches
739     /// client classes.
740     ///
741     /// @param first_subnet Pointer to the subnet from which iterations have
742     /// started.
743     /// @param client_classes List of classes that the client belongs to.
744     /// The subnets not matching the classes aren't returned by this
745     /// method.
746     ///
747     /// @return Pointer to the next subnet or NULL pointer if the next subnet
748     /// is the first subnet or if the current subnet doesn't belong to a
749     /// shared network.
750     Subnet6Ptr getNextSubnet(const Subnet6Ptr& first_subnet,
751                              const ClientClasses& client_classes) const;
752 
753     /// @brief Checks whether this subnet and parent shared network supports
754     /// the client that belongs to specified classes.
755     ///
756     /// This method extends the @ref Network::clientSupported method with
757     /// additional checks whether shared network owning this class supports
758     /// the client belonging to specified classes. If the class doesn't
759     /// belong to a shared network this method only checks if the subnet
760     /// supports specified classes.
761     ///
762     /// @param client_classes List of classes the client belongs to.
763     /// @return true if client can be supported, false otherwise.
764     virtual bool
765     clientSupported(const isc::dhcp::ClientClasses& client_classes) const;
766 
767     /// @brief Unparse a subnet object.
768     ///
769     /// @return A pointer to unparsed subnet configuration.
770     virtual data::ElementPtr toElement() const;
771 
772     /// @brief Converts subnet prefix to a pair of prefix/length pair.
773     ///
774     /// @param prefix Prefix to be parsed.
775     /// @throw BadValue if provided invalid IPv4 prefix.
776     static std::pair<asiolink::IOAddress, uint8_t>
777     parsePrefix(const std::string& prefix);
778 
779 private:
780 
781     /// @brief Returns default address for pool selection
782     /// @return ANY IPv6 address
default_pool()783     virtual isc::asiolink::IOAddress default_pool() const {
784         return (isc::asiolink::IOAddress("::"));
785     }
786 
787     /// @brief Checks if used pool type is valid
788     ///
789     /// allowed types for Subnet6 are Pool::TYPE_{IA,TA,PD}.
790     ///
791     /// @param type type to be checked
792     /// @throw BadValue if invalid value is used
793     virtual void checkType(Lease::Type type) const;
794 
795 };
796 
797 /// @name Definition of the multi index container holding subnet information
798 ///
799 //@{
800 
801 /// @brief Tag for the index for searching by subnet identifier.
802 struct SubnetSubnetIdIndexTag { };
803 
804 /// @brief Tag for the index for searching by subnet prefix.
805 struct SubnetPrefixIndexTag { };
806 
807 /// @brief Tag for the index for searching by server identifier.
808 struct SubnetServerIdIndexTag { };
809 
810 /// @brief Tag for the index for searching by subnet modification time.
811 struct SubnetModificationTimeIndexTag { };
812 
813 /// @brief A collection of @c Subnet4 objects.
814 ///
815 /// This container provides a set of indexes which can be used to retrieve
816 /// subnets by various properties.
817 ///
818 /// This multi index container can hold pointers to @ref Subnet4
819 /// objects representing subnets. It provides indexes for subnet lookups
820 /// using subnet properties such as: subnet identifier,
821 /// subnet prefix or server identifier specified for a subnet. It also
822 /// provides a random access index which allows for using the container
823 /// like a vector.
824 ///
825 /// The random access index is used by the DHCP servers which perform
826 /// a full scan on subnets to find the one that matches some specific
827 /// criteria for subnet selection.
828 ///
829 /// The remaining indexes are used for searching for a specific subnet
830 /// as a result of receiving a command over the control API, e.g.
831 /// when 'subnet-get' command is received.
832 ///
833 /// @todo We should consider optimizing subnet selection by leveraging
834 /// the indexing capabilities of this container, e.g. searching for
835 /// a subnet by interface name, relay address etc.
836 typedef boost::multi_index_container<
837     // Multi index container holds pointers to the subnets.
838     Subnet4Ptr,
839     // The following holds all indexes.
840     boost::multi_index::indexed_by<
841         // First index allows for searching using subnet identifier.
842         boost::multi_index::ordered_unique<
843             boost::multi_index::tag<SubnetSubnetIdIndexTag>,
844             boost::multi_index::const_mem_fun<Subnet, SubnetID, &Subnet::getID>
845         >,
846         // Second index allows for searching using an output from toText function.
847         boost::multi_index::ordered_unique<
848             boost::multi_index::tag<SubnetPrefixIndexTag>,
849             boost::multi_index::const_mem_fun<Subnet, std::string, &Subnet::toText>
850         >,
851 
852         // Third index allows for searching using an output from getServerId.
853         boost::multi_index::ordered_non_unique<
854             boost::multi_index::tag<SubnetServerIdIndexTag>,
855             boost::multi_index::const_mem_fun<Network4, asiolink::IOAddress,
856                                               &Network4::getServerId>
857         >,
858 
859         // Forth index allows for searching using subnet modification time.
860         boost::multi_index::ordered_non_unique<
861             boost::multi_index::tag<SubnetModificationTimeIndexTag>,
862             boost::multi_index::const_mem_fun<data::BaseStampedElement,
863                                               boost::posix_time::ptime,
864                                               &data::BaseStampedElement::getModificationTime>
865         >
866     >
867 > Subnet4Collection;
868 
869 /// @brief A collection of @c Subnet6 objects
870 ///
871 /// This container provides a set of indexes which can be used to retrieve
872 /// subnets by various properties.
873 ///
874 /// This multi index container can hold pointers to @ref Subnet6 objects
875 /// representing subnets. It provides indexes for subnet lookups using
876 /// subnet properties such as: subnet identifier or subnet prefix. It
877 /// also provides a random access index which allows for using the
878 /// container like a vector.
879 ///
880 /// The random access index is used by the DHCP servers which perform
881 /// a full scan on subnets to find the one that matches some specific
882 /// criteria for subnet selection.
883 ///
884 /// The remaining indexes are used for searching for a specific subnet
885 /// as a result of receiving a command over the control API, e.g.
886 /// when 'subnet-get' command is received.
887 ///
888 /// @todo We should consider optimizing subnet selection by leveraging
889 /// the indexing capabilities of this container, e.g. searching for
890 /// a subnet by interface name, relay address etc.
891 typedef boost::multi_index_container<
892     // Multi index container holds pointers to the subnets.
893     Subnet6Ptr,
894     // The following holds all indexes.
895     boost::multi_index::indexed_by<
896         // First index allows for searching using subnet identifier.
897         boost::multi_index::ordered_unique<
898             boost::multi_index::tag<SubnetSubnetIdIndexTag>,
899             boost::multi_index::const_mem_fun<Subnet, SubnetID, &Subnet::getID>
900         >,
901         // Second index allows for searching using an output from toText function.
902         boost::multi_index::ordered_unique<
903             boost::multi_index::tag<SubnetPrefixIndexTag>,
904             boost::multi_index::const_mem_fun<Subnet, std::string, &Subnet::toText>
905         >,
906         // Third index allows for searching using subnet modification time.
907         boost::multi_index::ordered_non_unique<
908             boost::multi_index::tag<SubnetModificationTimeIndexTag>,
909             boost::multi_index::const_mem_fun<data::BaseStampedElement,
910                                               boost::posix_time::ptime,
911                                               &data::BaseStampedElement::getModificationTime>
912         >
913     >
914 > Subnet6Collection;
915 
916 /// @brief A class containing static convenience methods to fetch the subnets
917 /// from the containers.
918 ///
919 /// @tparam ReturnPtrType Type of the returned object, i.e. @c Subnet4Ptr
920 /// or @c Subnet6Ptr.
921 /// @tparam CollectionType One of the @c Subnet4Collection or @c Subnet6Collection.
922 template<typename ReturnPtrType, typename CollectionType>
923 class SubnetFetcher {
924 public:
925 
926     /// @brief Fetches subnets by id.
927     ///
928     /// @param collection Const reference to the collection from which the
929     /// subnet is to be fetched.
930     /// @param subnet_id Id of the subnet to be fetched.
931     /// @return Pointer to the fetched subnet or null if no such subnet
932     /// could be found.
get(const CollectionType & collection,const SubnetID & subnet_id)933     static ReturnPtrType get(const CollectionType& collection,
934                              const SubnetID& subnet_id) {
935         auto& index = collection.template get<SubnetSubnetIdIndexTag>();
936         auto s = index.find(subnet_id);
937         if (s != index.end()) {
938             return (*s);
939         }
940         // No subnet found. Return null pointer.
941         return (ReturnPtrType());
942     }
943 };
944 
945 /// @brief Type of the @c SubnetFetcher used for IPv4.
946 using SubnetFetcher4 = SubnetFetcher<Subnet4Ptr, Subnet4Collection>;
947 
948 /// @brief Type of the @c SubnetFetcher used for IPv6.
949 using SubnetFetcher6 = SubnetFetcher<Subnet6Ptr, Subnet6Collection>;
950 
951 
952 //@}
953 
954 } // end of isc::dhcp namespace
955 } // end of isc namespace
956 
957 #endif // SUBNET_H
958