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