1 // Copyright (C) 2014-2019 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 CFG_SUBNETS4_H 8 #define CFG_SUBNETS4_H 9 10 #include <asiolink/io_address.h> 11 #include <cc/cfg_to_element.h> 12 #include <dhcp/pkt4.h> 13 #include <dhcpsrv/cfg_shared_networks.h> 14 #include <dhcpsrv/subnet.h> 15 #include <dhcpsrv/subnet_id.h> 16 #include <dhcpsrv/subnet_selector.h> 17 #include <boost/shared_ptr.hpp> 18 #include <string> 19 20 namespace isc { 21 namespace dhcp { 22 23 /// @brief Holds subnets configured for the DHCPv4 server. 24 /// 25 /// This class holds a collection of subnets configured for the DHCPv4 server. 26 /// It allows for retrieving a subnet for the particular client using various 27 /// parameters extracted from the DHCPv4 message. These parameters must be 28 /// assigned to the appropriate members of the @c CfgSubnets4::Selector 29 /// structure. 30 /// 31 /// See @c CfgSubnets4::selectSubnet documentation for more details on how the 32 /// subnet is selected for the client. 33 class CfgSubnets4 : public isc::data::CfgToElement { 34 public: 35 36 /// @brief Adds new subnet to the configuration. 37 /// 38 /// @param subnet Pointer to the subnet being added. 39 /// 40 /// @throw isc::DuplicateSubnetID If the subnet id for the new subnet 41 /// duplicates id of an existing subnet. 42 void add(const Subnet4Ptr& subnet); 43 44 /// @brief Replaces subnet in the configuration. 45 /// 46 /// This method replaces a subnet by another subnet with the same ID. 47 /// The prefix should be the same too. 48 /// 49 /// @param subnet Pointer to the subnet being updated. 50 /// @throw BadValue if the subnet to update does not exit. 51 /// @return Pointer to the replaced subnet or NULL if it failed. 52 Subnet4Ptr replace(const Subnet4Ptr& subnet); 53 54 /// @brief Removes subnet from the configuration. 55 /// 56 /// @param subnet Pointer to the subnet to be removed. 57 /// 58 /// @throw isc::BadValue if such subnet doesn't exist. 59 void del(const ConstSubnet4Ptr& subnet); 60 61 /// @brief Removes subnet from the configuration. 62 /// 63 /// @param subnet_id Identifier of the subnet to be removed. 64 /// 65 /// @throw isc::BadValue if such subnet doesn't exist. 66 void del(const SubnetID& subnet_id); 67 68 /// @brief Merges specified subnet configuration into this configuration. 69 /// 70 /// This method merges subnets from the @c other configuration into this 71 /// configuration. The general rule is that existing subnets are replaced 72 /// by the subnets from @c other. If there is no corresponding subnet in 73 /// this configuration the subnet from @c other configuration is inserted. 74 /// 75 /// The complexity of the merge process stems from the associations between 76 /// the subnets and shared networks. It is assumed that subnets in @c other 77 /// are the authority on their shared network assignments. It is also 78 /// assumed that @ networks is the list of shared networks that should be 79 /// used in making assignments. The general concept is that the overarching 80 /// merge process will first merge shared networks and then pass that list 81 /// of networks into this method. Subnets from @c other are then merged 82 /// into this configuration as follows: 83 /// 84 /// For each subnet in @c other: 85 /// 86 /// - If a subnet of the same ID already exists in this configuration: 87 /// -# If it belongs to a shared network, remove it from that network 88 /// -# Remove the subnet from this configuration and discard it 89 /// 90 /// - Create the subnet's option instance, as well as any options 91 /// that belong to any of the subnet's pools. 92 /// - Add the subnet from @c other to this configuration. 93 /// - If that subnet is associated to shared network, find that network 94 /// in @ networks and add that subnet to it. 95 /// 96 /// @warning The merge operation affects the @c other configuration. 97 /// Therefore, the caller must not rely on the data held in the @c other 98 /// object after the call to @c merge. Also, the data held in @c other must 99 /// not be modified after the call to @c merge because it may affect the 100 /// merged configuration. 101 /// 102 /// @param cfg_def set of of user-defined option definitions to use 103 /// when creating option instances. 104 /// @param networks collection of shared networks that to which assignments 105 /// should be added. In other words, the list of shared networks that belong 106 /// to the same SrvConfig instance we are merging into. 107 /// @param other the subnet configuration to be merged into this 108 /// configuration. 109 void merge(CfgOptionDefPtr cfg_def, CfgSharedNetworks4Ptr networks, 110 CfgSubnets4& other); 111 112 /// @brief Returns pointer to the collection of all IPv4 subnets. 113 /// 114 /// This is used in a hook (subnet4_select), where the hook is able 115 /// to choose a different subnet. Server code has to offer a list 116 /// of possible choices (i.e. all subnets). 117 /// 118 /// @return A pointer to const Subnet4 collection getAll()119 const Subnet4Collection* getAll() const { 120 return (&subnets_); 121 } 122 123 /// @brief Returns const pointer to a subnet identified by the specified 124 /// subnet identifier. 125 /// 126 /// The const pointer is returned by this method to prevent a caller from 127 /// modifying the subnet configuration. Modifications to subnet configuration 128 /// is dangerous and must be done carefully. The subnets' configuration is 129 /// held in the multi index container and any modifications to the subnet 130 /// id or subnet prefix must trigger re-indexing of multi index container. 131 /// There is no possibility to enforce this when the non-const pointer is 132 /// returned. 133 /// 134 /// @param subnet_id Subnet identifier. 135 /// 136 /// @return Pointer to the @c Subnet4 object or null pointer if such 137 /// subnet doesn't exist. 138 ConstSubnet4Ptr getBySubnetId(const SubnetID& subnet_id) const; 139 140 /// @brief Returns const pointer to a subnet which matches the specified 141 /// prefix in the canonical form. 142 /// 143 /// The const pointer is returned by this method to prevent a caller from 144 /// modifying the subnet configuration. Modifications to subnet configuration 145 /// is dangerous and must be done carefully. The subnets' configuration is 146 /// held in the multi index container and any modifications to the subnet 147 /// id or subnet prefix must trigger re-indexing of multi index container. 148 /// There is no possibility to enforce this when the non-const pointer is 149 /// returned. 150 /// 151 /// @param subnet_prefix Subnet prefix, e.g. 10.2.3.0/24 152 /// 153 /// @return Pointer to the @c Subnet4 object or null pointer if such 154 /// subnet doesn't exist. 155 ConstSubnet4Ptr getByPrefix(const std::string& subnet_prefix) const; 156 157 /// @brief Checks if specified server identifier has been specified for 158 /// any subnet. 159 /// 160 /// @param server_id Server identifier. 161 /// 162 /// @return true if there is a subnet with a specified server identifier. 163 bool hasSubnetWithServerId(const asiolink::IOAddress& server_id) const; 164 165 /// @brief Build selector from a client's message. 166 /// 167 /// @note: code moved from server. 168 /// 169 /// @param query client's message. 170 /// @return filled selector. 171 static SubnetSelector initSelector(const Pkt4Ptr& query); 172 173 /// @brief Returns a pointer to the selected subnet. 174 /// 175 /// This method tries to retrieve the subnet for the client using various 176 /// parameters extracted from the client's message using the following 177 /// logic. 178 /// 179 /// First when link select suboption of relay agent information option 180 /// or subnet select option in this order exists the address is used 181 /// 182 /// If the giaddr value is set in the selector it means that the client's 183 /// message was relayed. The subnet configuration allows for setting the 184 /// relay address for each subnet to indicate that the subnet must be 185 /// assigned when the packet was transmitted over the particular relay. 186 /// This method first tries to match the giaddr with the relay addresses 187 /// specified for all subnets. If the relay address for the subnet is equal 188 /// to the address of the relay through which the message was transmitted, 189 /// the particular subnet is returned. 190 /// 191 /// If the giaddr is not matched with any of the relay addresses in any 192 /// subnet or the message was not relayed, the method will need to try to 193 /// match one of the addresses in the client's message with the prefixes 194 /// of the existing subnets. Depending whether it is a relayed message, 195 /// message from the renewing client or a new allocation, the server will 196 /// pick one of the following addresses for this matching: 197 /// - giaddr - for relayed message 198 /// - ciaddr - for renewing or rebinding client 199 /// - source address - for the renewing client which didn't provide ciaddr 200 /// - address on the local server's interface if this is a new allocation 201 /// requested by the directly connected client 202 /// 203 /// If the address matches with a subnet, the subnet is returned. 204 /// 205 /// @todo This method requires performance improvement! It currently 206 /// iterates over all existing subnets (possibly a couple of times) 207 /// to find the one which fulfills the search criteria. The subnet storage 208 /// is implemented as a simple STL vector which precludes fast searches 209 /// using specific keys. Hence, full scan is required. To improve the 210 /// search performance a different container type is required, e.g. 211 /// multi-index container, or something of a similar functionality. 212 /// 213 /// @param selector Const reference to the selector structure which holds 214 /// various information extracted from the client's packet which are used 215 /// to find appropriate subnet. 216 /// 217 /// @return Pointer to the selected subnet or NULL if no subnet found. 218 /// @throw isc::BadValue if the values in the subnet selector are invalid 219 /// or they are insufficient to select a subnet. 220 Subnet4Ptr selectSubnet(const SubnetSelector& selector) const; 221 222 /// @brief Returns subnet with specified subnet-id value 223 /// 224 /// Warning: this method uses full scan. Its use is not recommended for 225 /// packet processing. 226 /// 227 /// @return Subnet (or NULL) 228 Subnet4Ptr getSubnet(const SubnetID id) const; 229 230 /// @brief Returns a pointer to a subnet if provided address is in its range. 231 /// 232 /// This method returns a pointer to the subnet if the address passed in 233 /// parameter is in range with this subnet. This is mainly used for unit 234 /// testing. This method is also called by the 235 /// @c selectSubnet(SubnetSelector). 236 /// 237 /// @todo This method requires performance improvement! It currently 238 /// iterates over all existing subnets to find the one which fulfills 239 /// the search criteria. The subnet storage is implemented as a simple 240 /// STL vector which precludes fast searches using specific keys. 241 /// Hence, full scan is required. To improve the search performance a 242 /// different container type is required, e.g. multi-index container, 243 /// or something of a similar functionality. 244 /// 245 /// @param address Address for which the subnet is searched. 246 /// @param client_classes Optional parameter specifying the classes that 247 /// the client belongs to. 248 /// 249 /// @return Pointer to the selected subnet or NULL if no subnet found. 250 Subnet4Ptr selectSubnet(const asiolink::IOAddress& address, 251 const ClientClasses& client_classes 252 = ClientClasses()) const; 253 254 /// @brief Returns a pointer to a subnet if provided interface name matches. 255 /// 256 /// This method returns a pointer to the subnet if the interface name passed 257 /// in parameter iface matches that of a subnet. This is mainly used for matching 258 /// local incoming traffic, even when the addresses on local interfaces do 259 /// not match a subnet definition. This method is also called by the 260 /// @c selectSubnet(SubnetSelector). 261 /// 262 /// @todo This method requires performance improvement! It currently 263 /// iterates over all existing subnets to find the one which fulfills 264 /// the search criteria. The subnet storage is implemented as a simple 265 /// STL vector which precludes fast searches using specific keys. 266 /// Hence, full scan is required. To improve the search performance a 267 /// different container type is required, e.g. multi-index container, 268 /// or something of a similar functionality. 269 /// 270 /// @param iface name of the interface to be matched. 271 /// @param client_classes Optional parameter specifying the classes that 272 /// the client belongs to. 273 /// 274 /// @return Pointer to the selected subnet or NULL if no subnet found. 275 Subnet4Ptr selectSubnet(const std::string& iface, 276 const ClientClasses& client_classes) const; 277 278 /// @brief Attempts to do subnet selection based on DHCP4o6 information 279 /// 280 /// The algorithm implemented is as follows: 281 /// 282 /// - First: try to match IPv6 subnet (4o6-subnet parameter) with the 283 /// remote IPv6 address of the incoming packet 284 /// - Second: try to match interface-id (4o6-interface-id parameter) 285 /// with the interface-id option in the incoming 4o6 packet 286 /// - Third: try to match interface-name (4o6-interface parameter) 287 /// with the name of the interface the incoming 4o6 packet was 288 /// received over. 289 /// 290 /// @todo: Add additional selection criteria. See 291 /// https://gitlab.isc.org/isc-projects/kea/wikis/designs/dhcpv4o6-design for details. 292 /// 293 /// @param selector Const reference to the selector structure which holds 294 /// various information extracted from the client's packet which are used 295 /// to find appropriate subnet. 296 /// @return Pointer to the selected subnet or NULL if no subnet found. 297 Subnet4Ptr 298 selectSubnet4o6(const SubnetSelector& selector) const; 299 300 /// @brief Updates statistics. 301 /// 302 /// This method updates statistics that are affected by the newly committed 303 /// configuration. In particular, it updates the number of available addresses 304 /// in each subnet. Other statistics may be added in the future. In general, 305 /// these are statistics that are dependent only on configuration, so they are 306 /// not expected to change until the next reconfiguration event. 307 void updateStatistics(); 308 309 /// @brief Removes statistics. 310 /// 311 /// During commitment of a new configuration, we need to get rid of the old 312 /// statistics for the old configuration. In particular, we need to remove 313 /// anything related to subnets, as there may be fewer subnets in the new 314 /// configuration and also subnet-ids may change. 315 void removeStatistics(); 316 317 /// @brief Unparse a configuration object 318 /// 319 /// @return a pointer to unparsed configuration 320 virtual isc::data::ElementPtr toElement() const; 321 322 private: 323 324 /// @brief A container for IPv4 subnets. 325 Subnet4Collection subnets_; 326 327 }; 328 329 /// @name Pointer to the @c CfgSubnets4 objects. 330 //@{ 331 /// @brief Non-const pointer. 332 typedef boost::shared_ptr<CfgSubnets4> CfgSubnets4Ptr; 333 334 /// @brief Const pointer. 335 typedef boost::shared_ptr<const CfgSubnets4> ConstCfgSubnets4Ptr; 336 337 //@} 338 339 } 340 } 341 342 #endif // CFG_SUBNETS4_H 343