1 // Copyright (C) 2017-2020 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 SHARED_NETWORK_H 8 #define SHARED_NETWORK_H 9 10 #include <asiolink/io_address.h> 11 #include <cc/data.h> 12 #include <dhcpsrv/subnet.h> 13 #include <dhcpsrv/subnet_id.h> 14 #include <boost/enable_shared_from_this.hpp> 15 #include <boost/multi_index/mem_fun.hpp> 16 #include <boost/multi_index/hashed_index.hpp> 17 #include <boost/multi_index/indexed_by.hpp> 18 #include <boost/multi_index/ordered_index.hpp> 19 #include <boost/multi_index/random_access_index.hpp> 20 #include <boost/multi_index_container.hpp> 21 #include <boost/shared_ptr.hpp> 22 #include <string> 23 24 namespace isc { 25 namespace dhcp { 26 27 /// @brief A tag for accessing random access index. 28 struct SharedNetworkRandomAccessIndexTag { }; 29 30 /// @brief A tag for accessing index by id. 31 struct SharedNetworkIdIndexTag { }; 32 33 /// @brief A tag for accessing index by shared network name. 34 struct SharedNetworkNameIndexTag { }; 35 36 /// @brief A tag for accessing index by server identifier. 37 struct SharedNetworkServerIdIndexTag { }; 38 39 /// @brief Tag for the index for searching by shared network modification 40 /// time. 41 struct SharedNetworkModificationTimeIndexTag { }; 42 43 class SharedNetwork4; 44 45 /// @brief Pointer to @ref SharedNetwork4 object. 46 typedef boost::shared_ptr<SharedNetwork4> SharedNetwork4Ptr; 47 48 /// @brief Shared network holding IPv4 subnets. 49 /// 50 /// Specialization of the @ref Network4 class for IPv4 shared networks. 51 class SharedNetwork4 : public virtual Network4, 52 public boost::enable_shared_from_this<SharedNetwork4> { 53 public: 54 55 /// @brief Constructor. 56 /// 57 /// Sets name of the shared network. 58 /// 59 /// @param name Name of the shared network. SharedNetwork4(const std::string & name)60 explicit SharedNetwork4(const std::string& name) 61 : name_(name), subnets_() { 62 } 63 64 /// @brief Factory function creating an instance of the @c SharedNetwork4. 65 /// 66 /// This function should be used to create an instance of the shared 67 /// network within a hooks library in cases when the library may be 68 /// unloaded before the object is destroyed. This ensures that the 69 /// ownership of the object by the Kea process is retained. 70 /// 71 /// @param name Name of the shared network. 72 /// 73 /// @return Pointer to the @c SharedNetwork4 instance. 74 static SharedNetwork4Ptr create(const std::string& name); 75 76 /// @brief Returns a name of the shared network. getName()77 std::string getName() const { 78 return (name_); 79 } 80 81 /// @brief Sets new name for the shared network. 82 /// 83 /// @param name New name for the shared network. setName(const std::string & name)84 void setName(const std::string& name) { 85 name_ = name; 86 } 87 88 /// @brief Adds IPv4 subnet to a shared network. 89 /// 90 /// @param subnet Pointer to a subnet being added to this shared network. 91 /// 92 /// @throw isc::BadValue if subnet is null. 93 /// @throw isc::DuplicateSubnetID if a subnet with the given subnet id 94 /// already exists in this shared network. 95 /// @throw InvalidOperation if a subnet is already associated with some 96 /// shared network. 97 void add(const Subnet4Ptr& subnet); 98 99 /// @brief Replaces IPv4 subnet in a shared network. 100 /// 101 /// This method replaces a subnet by another subnet with the same ID. 102 /// The prefix should be the same too. 103 /// 104 /// @param subnet Pointer to a subnet replacing the subnet with the same ID 105 /// in this shared network. 106 /// @throw isc::BadValue if subnet is null. 107 /// @throw InvalidOperation if a subnet is already associated with some 108 /// shared network. 109 /// @return true if the operation succeeded, false otherwise. 110 bool replace(const Subnet4Ptr& subnet); 111 112 /// @brief Removes subnet from a shared network. 113 /// 114 /// @param subnet_id Identifier of a subnet to be removed. 115 /// 116 /// @throw BadValue When specified subnet doesn't exist. 117 void del(const SubnetID& subnet_id); 118 119 /// @brief Removes all subnets from a shared network. 120 void delAll(); 121 122 /// @brief Returns a pointer to the collection of subnets within this 123 /// shared network. getAllSubnets()124 const Subnet4Collection* getAllSubnets() const { 125 return (&subnets_); 126 } 127 128 /// @brief Returns a subnet for a specified subnet id. 129 /// 130 /// @param subnet_id Subnet identifier. 131 /// 132 /// @return Shared pointer to a subnet using this id or null pointer 133 /// if such subnet doesn't exist within shared network. 134 Subnet4Ptr getSubnet(const SubnetID& subnet_id) const; 135 136 /// @brief Returns a subnet for a specified subnet prefix. 137 /// 138 /// @param subnet_prefix Subnet prefix. 139 /// 140 /// @return Shared pointer to a subnet using this prefix or null pointer 141 /// if such subnet doesn't exist within shared network. 142 Subnet4Ptr getSubnet(const std::string& subnet_prefix) const; 143 144 /// @brief Retrieves next available IPv4 subnet within shared network. 145 /// 146 /// See documentation for @ref SharedNetwork4::getNextSubnet. 147 /// 148 /// @param first_subnet Pointer to a subnet from which the caller is 149 /// iterating over subnets within shared network. This is typically a 150 /// subnet selected during "subnet selection" step. 151 /// @param current_subnet Identifier of a subnet for which next subnet is 152 /// to be found. 153 /// 154 /// @return Pointer to next subnet or null pointer if no more subnets found. 155 /// 156 /// @throw isc::BadValue if invalid arguments specified, e.g. unable to 157 /// find first or current subnet within shared network. 158 Subnet4Ptr getNextSubnet(const Subnet4Ptr& first_subnet, 159 const SubnetID& current_subnet) const; 160 161 /// @brief Attempts to find a subnet which is more likely to include available 162 /// leases than selected subnet. 163 /// 164 /// When allocating unreserved leases from a shared network it is important to 165 /// remember from which subnet within the shared network we have been recently 166 /// handing out leases. The allocation engine can use that information to start 167 /// trying allocation of the leases from that subnet rather than from the default 168 /// subnet selected for this client. Starting from the default subnet causes a 169 /// risk of having to walk over many subnets with exhausted address pools before 170 /// getting to the subnet with available leases. This method attempts to find 171 /// such subnet by inspecting "last allocation" timestamps. The one with most 172 /// recent timestamp is selected. 173 /// 174 /// The preferred subnet must also fulfil the condition of equal client classes 175 /// with the @c selected_subnet. 176 /// 177 /// @todo Need extensions to this logic when we support more than one client 178 /// class for a subnet. 179 /// 180 /// @param selected_subnet Pointer to a currently selected subnet. 181 /// 182 /// @return Pointer to a preferred subnet. It may be the same as @c selected_subnet 183 /// if no better subnet was found. 184 Subnet4Ptr getPreferredSubnet(const Subnet4Ptr& selected_subnet) const; 185 186 /// @brief Checks if the shared network includes a subnet with 187 /// the match client ID flag set to true. 188 /// 189 /// @param first_subnet Pointer to the subnet from which iteration starts. 190 /// @param client_classes List of classes that the client belongs to. 191 /// @return true if the shared network includes at least one subnet 192 /// guarded by a given class with the match client ID flag set to true. 193 /// False otherwise. 194 static 195 bool subnetsIncludeMatchClientId(const Subnet4Ptr& first_subnet, 196 const ClientClasses& client_classes); 197 198 /// @brief Unparses shared network object. 199 /// 200 /// @return A pointer to unparsed shared network configuration. 201 virtual data::ElementPtr toElement() const; 202 203 private: 204 205 /// @brief Holds a name of a shared network. 206 std::string name_; 207 208 /// @brief Collection of IPv4 subnets within shared network. 209 Subnet4Collection subnets_; 210 }; 211 212 /// @brief Multi index container holding shared networks. 213 /// 214 /// This is multi index container can hold pointers to @ref SharedNetwork4 215 /// objects. It provides indexes for shared network lookups using properties 216 /// such as shared network's name. 217 typedef boost::multi_index_container< 218 // Multi index container holds pointers to the shared networks. 219 SharedNetwork4Ptr, 220 boost::multi_index::indexed_by< 221 // First is the random access index allowing for accessing objects 222 // just like we'd do with vector. 223 boost::multi_index::random_access< 224 boost::multi_index::tag<SharedNetworkRandomAccessIndexTag> 225 >, 226 // Second index allows for access by shared network id. 227 boost::multi_index::hashed_non_unique< 228 boost::multi_index::tag<SharedNetworkIdIndexTag>, 229 boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t, 230 &data::BaseStampedElement::getId> 231 >, 232 // Third index allows for access by shared network's name. 233 boost::multi_index::ordered_unique< 234 boost::multi_index::tag<SharedNetworkNameIndexTag>, 235 boost::multi_index::const_mem_fun<SharedNetwork4, std::string, 236 &SharedNetwork4::getName> 237 >, 238 // Fourth index allows for access by server identifier specified for the 239 // network. 240 boost::multi_index::ordered_non_unique< 241 boost::multi_index::tag<SharedNetworkServerIdIndexTag>, 242 boost::multi_index::const_mem_fun<Network4, asiolink::IOAddress, 243 &Network4::getServerId> 244 >, 245 // Fifth index allows for searching using subnet modification time. 246 boost::multi_index::ordered_non_unique< 247 boost::multi_index::tag<SharedNetworkModificationTimeIndexTag>, 248 boost::multi_index::const_mem_fun<data::BaseStampedElement, 249 boost::posix_time::ptime, 250 &data::BaseStampedElement::getModificationTime> 251 > 252 > 253 > SharedNetwork4Collection; 254 255 class SharedNetwork6; 256 257 /// @brief Pointer to @ref SharedNetwork6 object. 258 typedef boost::shared_ptr<SharedNetwork6> SharedNetwork6Ptr; 259 260 /// @brief Shared network holding IPv6 subnets. 261 /// 262 /// Specialization of the @ref Network6 class for IPv6 shared networks. 263 class SharedNetwork6 : public virtual Network6, 264 public boost::enable_shared_from_this<SharedNetwork6> { 265 public: 266 267 /// @brief Constructor. 268 /// 269 /// Sets name of the shared network. SharedNetwork6(const std::string & name)270 explicit SharedNetwork6(const std::string& name) 271 : name_(name), subnets_() { 272 } 273 274 /// @brief Factory function creating an instance of the @c SharedNetwork6. 275 /// 276 /// This function should be used to create an instance of the shared 277 /// network within a hooks library in cases when the library may be 278 /// unloaded before the object is destroyed. This ensures that the 279 /// ownership of the object by the Kea process is retained. 280 /// 281 /// @param name Name of the shared network. 282 /// 283 /// @return Pointer to the @c SharedNetwork6 instance. 284 static SharedNetwork6Ptr create(const std::string& name); 285 286 /// @brief Returns a name of the shared network. getName()287 std::string getName() const { 288 return (name_); 289 } 290 291 /// @brief Sets new name for the shared network. 292 /// 293 /// @param name New name for the shared network. setName(const std::string & name)294 void setName(const std::string& name) { 295 name_ = name; 296 } 297 298 /// @brief Adds IPv6 subnet to a shared network. 299 /// 300 /// @param subnet Pointer to a subnet being added to this shared network. 301 /// 302 /// @throw isc::BadValue if subnet is null. 303 /// @throw isc::DuplicateSubnetID if a subnet with the given subnet id 304 /// already exists in this shared network. 305 /// @throw InvalidOperation if a subnet is already associated with some 306 /// shared network. 307 void add(const Subnet6Ptr& subnet); 308 309 /// @brief Replaces IPv6 subnet in a shared network. 310 /// 311 /// This method replaces a subnet by another subnet with the same ID. 312 /// The prefix should be the same too. 313 /// 314 /// @param subnet Pointer to a subnet replacing the subnet with the same ID 315 /// in this shared network. 316 /// @throw isc::BadValue if subnet is null. 317 /// @throw InvalidOperation if a subnet is already associated with some 318 /// shared network. 319 /// @return true if the operation succeeded, false otherwise. 320 bool replace(const Subnet6Ptr& subnet); 321 322 /// @brief Removes subnet from a shared network. 323 /// 324 /// @param subnet_id Identifier of a subnet to be removed. 325 /// 326 /// @throw BadValue When specified subnet doesn't exist. 327 void del(const SubnetID& subnet_id); 328 329 /// @brief Removes all subnets from a shared network. 330 void delAll(); 331 332 /// @brief Returns a pointer to the collection of subnets within this 333 /// shared network. getAllSubnets()334 const Subnet6Collection* getAllSubnets() const { 335 return (&subnets_); 336 } 337 338 /// @brief Returns a subnet for a specified subnet id. 339 /// 340 /// @param subnet_id Subnet identifier. 341 /// 342 /// @return Shared pointer to a subnet using this id or null pointer 343 /// if such subnet doesn't exist within shared network. 344 Subnet6Ptr getSubnet(const SubnetID& subnet_id) const; 345 346 /// @brief Returns a subnet for a specified subnet prefix. 347 /// 348 /// @param subnet_prefix Subnet prefix. 349 /// 350 /// @return Shared pointer to a subnet using this prefix or null pointer 351 /// if such subnet doesn't exist within shared network. 352 Subnet6Ptr getSubnet(const std::string& subnet_prefix) const; 353 354 /// @brief Retrieves next available IPv6 subnet within shared network. 355 /// 356 /// See documentation for @ref SharedNetwork6::getNextSubnet. 357 /// 358 /// @param first_subnet Pointer to a subnet from which the caller is 359 /// iterating over subnets within shared network. This is typically a 360 /// subnet selected during "subnet selection" step. 361 /// @param current_subnet Identifier of a subnet for which next subnet is 362 /// to be found. 363 /// 364 /// @return Pointer to next subnet or null pointer if no more subnets found. 365 /// 366 /// @throw isc::BadValue if invalid arguments specified, e.g. unable to 367 /// find first or current subnet within shared network. 368 Subnet6Ptr getNextSubnet(const Subnet6Ptr& first_subnet, 369 const SubnetID& current_subnet) const; 370 371 /// @brief Attempts to find a subnet which is more likely to include available 372 /// leases than selected subnet. 373 /// 374 /// When allocating unreserved leases from a shared network it is important to 375 /// remember from which subnet within the shared network we have been recently 376 /// handing out leases. The allocation engine can use that information to start 377 /// trying allocation of the leases from that subnet rather than from the default 378 /// subnet selected for this client. Starting from the default subnet causes a 379 /// risk of having to walk over many subnets with exhausted address pools before 380 /// getting to the subnet with available leases. This method attempts to find 381 /// such subnet by inspecting "last allocation" timestamps. The one with most 382 /// recent timestamp is selected. 383 /// 384 /// The preferred subnet must also fulfil the condition of equal client classes 385 /// with the @c selected_subnet. 386 /// 387 /// @param selected_subnet Pointer to a currently selected subnet. 388 /// @param lease_type Type of the lease for which preferred subnet should be 389 /// returned. 390 /// 391 /// @return Pointer to a preferred subnet. It may be the same as @c selected_subnet 392 /// if no better subnet was found. 393 Subnet6Ptr getPreferredSubnet(const Subnet6Ptr& selected_subnet, 394 const Lease::Type& lease_type) const; 395 396 /// @brief Unparses shared network object. 397 /// 398 /// @return A pointer to unparsed shared network configuration. 399 virtual data::ElementPtr toElement() const; 400 401 private: 402 403 /// @brief Holds a name of a shared network. 404 std::string name_; 405 406 /// @brief Collection of IPv6 subnets within shared network. 407 Subnet6Collection subnets_; 408 }; 409 410 /// @brief Multi index container holding shared networks. 411 /// 412 /// This is multi index container can hold pointers to @ref SharedNetwork6 413 /// objects. It provides indexes for shared network lookups using properties 414 /// such as shared network's name. 415 typedef boost::multi_index_container< 416 // Multi index container holds pointers to the shared networks. 417 SharedNetwork6Ptr, 418 boost::multi_index::indexed_by< 419 // First is the random access index allowing for accessing objects 420 // just like we'd do with vector. 421 boost::multi_index::random_access< 422 boost::multi_index::tag<SharedNetworkRandomAccessIndexTag> 423 >, 424 // Second index allows for access by shared network id. 425 boost::multi_index::hashed_non_unique< 426 boost::multi_index::tag<SharedNetworkIdIndexTag>, 427 boost::multi_index::const_mem_fun<data::BaseStampedElement, uint64_t, 428 &data::BaseStampedElement::getId> 429 >, 430 // Third index allows for access by shared network's name. 431 boost::multi_index::ordered_unique< 432 boost::multi_index::tag<SharedNetworkNameIndexTag>, 433 boost::multi_index::const_mem_fun<SharedNetwork6, std::string, 434 &SharedNetwork6::getName> 435 >, 436 // Fourth index allows for searching using subnet modification time. 437 boost::multi_index::ordered_non_unique< 438 boost::multi_index::tag<SharedNetworkModificationTimeIndexTag>, 439 boost::multi_index::const_mem_fun<data::BaseStampedElement, 440 boost::posix_time::ptime, 441 &data::BaseStampedElement::getModificationTime> 442 > 443 > 444 > SharedNetwork6Collection; 445 446 /// @brief A class containing static convenience methods to fetch the shared 447 /// networks from the containers. 448 /// 449 /// @tparam ReturnPtrType Type of the returned object, i.e. @c SharedNetwork4Ptr 450 /// or @c SharedNetwork6Ptr. 451 /// @tparam CollectionType One of the @c SharedNetwork4Collection or 452 /// @c SharedNetwork6Collection. 453 template<typename ReturnPtrType, typename CollectionType> 454 class SharedNetworkFetcher { 455 public: 456 457 /// @brief Fetches shared network by name. 458 /// 459 /// @param collection Const reference to the collection from which the shared 460 /// network is to be fetched. 461 /// @param name Name of the shared network to be fetched. 462 /// @return Pointer to the fetched shared network or null if no such shared 463 /// network could be found. get(const CollectionType & collection,const std::string & name)464 static ReturnPtrType get(const CollectionType& collection, const std::string& name) { 465 auto& index = collection.template get<SharedNetworkNameIndexTag>(); 466 auto sn = index.find(name); 467 if (sn != index.end()) { 468 return (*sn); 469 } 470 // No network found. Return null pointer. 471 return (ReturnPtrType()); 472 } 473 }; 474 475 /// @brief Type of the @c SharedNetworkFetcher used for IPv4. 476 using SharedNetworkFetcher4 = SharedNetworkFetcher<SharedNetwork4Ptr, SharedNetwork4Collection>; 477 478 /// @brief Type of the @c SharedNetworkFetcher used for IPv6. 479 using SharedNetworkFetcher6 = SharedNetworkFetcher<SharedNetwork6Ptr, SharedNetwork6Collection>; 480 481 } // end of namespace isc::dhcp 482 } // end of namespace isc 483 484 #endif // SHARED_NETWORK_H 485