1 // Copyright (C) 2012-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 CFGMGR_H 8 #define CFGMGR_H 9 10 #include <asiolink/io_address.h> 11 #include <dhcp/option.h> 12 #include <dhcp/option_space.h> 13 #include <dhcp/classify.h> 14 #include <dhcpsrv/d2_client_mgr.h> 15 #include <dhcpsrv/pool.h> 16 #include <dhcpsrv/srv_config.h> 17 #include <util/buffer.h> 18 #include <util/optional.h> 19 20 #include <boost/shared_ptr.hpp> 21 #include <boost/noncopyable.hpp> 22 23 #include <map> 24 #include <string> 25 #include <vector> 26 #include <list> 27 28 namespace isc { 29 namespace dhcp { 30 31 /// @brief Exception thrown when the same interface has been specified twice. 32 /// 33 /// In particular, this exception is thrown when adding interface to the set 34 /// of interfaces on which server is supposed to listen. 35 class DuplicateListeningIface : public Exception { 36 public: DuplicateListeningIface(const char * file,size_t line,const char * what)37 DuplicateListeningIface(const char* file, size_t line, const char* what) : 38 isc::Exception(file, line, what) { }; 39 }; 40 41 /// @brief Configuration Manager 42 /// 43 /// This singleton class holds the whole configuration for DHCPv4 and DHCPv6 44 /// servers. 45 /// 46 /// Below is a sketch of configuration inheritance. 47 /// Let's investigate the following configuration: 48 /// 49 /// @code 50 /// preferred-lifetime 500; 51 /// valid-lifetime 1000; 52 /// subnet6 2001:db8:1::/48 { 53 /// pool6 2001::db8:1::1 - 2001::db8:1::ff; 54 /// }; 55 /// subnet6 2001:db8:2::/48 { 56 /// valid-lifetime 2000; 57 /// pool6 2001::db8:2::1 - 2001::db8:2::ff; 58 /// }; 59 /// @endcode 60 /// 61 /// Parameters defined in a global scope are applicable to everything until 62 /// they are overwritten in a smaller scope, in this case subnet6. 63 /// In the example above, the first subnet6 has preferred lifetime of 500s 64 /// and a valid lifetime of 1000s. The second subnet has preferred lifetime 65 /// of 500s, but valid lifetime of 2000s. 66 /// 67 /// Parameter inheritance is implemented in dedicated classes. See 68 /// @ref isc::dhcp::SimpleParser4::deriveParameters and 69 /// @ref isc::dhcp::SimpleParser6::deriveParameters. 70 class CfgMgr : public boost::noncopyable { 71 public: 72 73 /// @brief A number of configurations held by @c CfgMgr. 74 /// 75 /// @todo Make it configurable. 76 static const size_t CONFIG_LIST_SIZE; 77 78 /// @brief returns a single instance of Configuration Manager 79 /// 80 /// CfgMgr is a singleton and this method is the only way of 81 /// accessing it. 82 static CfgMgr& instance(); 83 84 /// @brief returns path do the data directory 85 /// 86 /// This method returns a path to writable directory that DHCP servers 87 /// can store data in. 88 /// @return data directory 89 util::Optional<std::string> getDataDir() const; 90 91 /// @brief Sets new data directory. 92 /// 93 /// @param datadir New data directory. 94 /// @param unspecified Initial state. Default is "unspecified". 95 void setDataDir(const std::string& datadir, bool unspecified = true); 96 97 /// @brief Updates the DHCP-DDNS client configuration to the given value. 98 /// 99 /// Passes the new configuration to the D2ClientMgr instance, 100 /// d2_client_mgr_, which will attempt to apply the new configuration 101 /// by shutting down its sender and opening a new connection per the new 102 /// configuration (see @c D2ClientMgr::setD2ClientConfig()). 103 /// 104 /// @param new_config pointer to the new client configuration. 105 /// 106 /// @throw Underlying method(s) will throw D2ClientError if given an empty 107 /// pointer. 108 void setD2ClientConfig(D2ClientConfigPtr& new_config); 109 110 /// @brief Convenience method for checking if DHCP-DDNS updates are enabled. 111 /// 112 /// @return True if the D2 configuration is enabled. 113 bool ddnsEnabled(); 114 115 /// @brief Fetches the DHCP-DDNS configuration pointer. 116 /// 117 /// @return a reference to the current configuration pointer. 118 const D2ClientConfigPtr& getD2ClientConfig() const; 119 120 /// @brief Fetches the DHCP-DDNS manager. 121 /// 122 /// @return a reference to the DHCP-DDNS manager. 123 D2ClientMgr& getD2ClientMgr(); 124 125 /// @name Methods managing the collection of configurations. 126 /// 127 /// The following methods manage the process of preparing a configuration 128 /// without affecting a currently used configuration and then committing 129 /// the configuration to replace current configuration atomically. 130 /// They also allow for keeping a history of previous configurations so 131 /// as the @c CfgMgr can revert to the historical configuration when 132 /// required. 133 /// 134 /// @todo Migrate all configuration parameters to use the model supported 135 /// by these functions. 136 /// 137 /// @todo Make the size of the configurations history configurable. 138 /// 139 //@{ 140 141 /// @brief Removes current, staging and all previous configurations. 142 /// 143 /// This function removes all configurations, including current, 144 /// staging and external configurations. It creates a new current 145 /// configuration with default settings. 146 /// 147 /// This function is exception safe. 148 void clear(); 149 150 /// @brief Commits the staging configuration. 151 /// 152 /// The staging configuration becomes current configuration when this 153 /// function is called. It removes the oldest configuration held in the 154 /// history so as the size of the list of configuration does not exceed 155 /// the @c CONFIG_LIST_SIZE. 156 /// 157 /// This function is exception safe. 158 void commit(); 159 160 /// @brief Removes staging configuration. 161 /// 162 /// This function should be called when there is a staging configuration 163 /// (likely created in the previous configuration attempt) but the entirely 164 /// new configuration should be created. It removes the existing staging 165 /// configuration and the next call to @c CfgMgr::getStagingCfg will return a 166 /// fresh (default) configuration. 167 /// 168 /// This function is exception safe. 169 void rollback(); 170 171 /// @brief Reverts to one of the previous configurations. 172 /// 173 /// This function reverts to selected previous configuration. The previous 174 /// configuration is entirely copied to a new @c SrvConfig instance. This 175 /// new instance has a unique sequence id (sequence id is not copied). The 176 /// previous configuration (being copied) is not modified by this operation. 177 /// 178 /// The configuration to be copied is identified by the index value which 179 /// is the distance between the current (most recent) and desired 180 /// configuration. If the index is out of range an exception is thrown. 181 /// 182 /// @warning Revert operation will rollback any changes to the staging 183 /// configuration (if it exists). 184 /// 185 /// @warning This function requires that the entire previous configuration 186 /// is copied to the new configuration object. This is not working for 187 /// some of the complex configuration objects, e.g. subnets. Hence, the 188 /// "revert" operation is not really usable at this point. 189 /// 190 /// @param index A distance from the current configuration to the 191 /// past configuration to be reverted. The minimal value is 1 which points 192 /// to the nearest configuration. 193 /// 194 /// @throw isc::OutOfRange if the specified index is out of range. 195 void revert(const size_t index); 196 197 /// @brief Returns a pointer to the current configuration. 198 /// 199 /// This function returns pointer to the current configuration. If the 200 /// current configuration is not set it will create a default configuration 201 /// and return it. 202 /// 203 /// In the previous Kea releases this method used to return a const pointer 204 /// to the current configuration to ensure that it is not accidentally 205 /// modified while the server is running. This has been changed in Kea 1.3 206 /// release and now this function returns a non-const pointer. The reason 207 /// is that there are certain use cases when current configuration must 208 /// be modified without going through a full cycle of server 209 /// reconfiguration, e.g. add a subnet to the current configuration as 210 /// a result of receiving a command over control API. In such case the 211 /// performance of processing such command is critical and rebuilding the 212 /// whole configuration just for this small configuration change is out 213 /// of question. 214 /// 215 /// Nevertheless, such configuration updates should always be made with 216 /// caution and one has to make sure that the configuration data integrity 217 /// is preserved. 218 /// 219 /// @return Non-null pointer to the current configuration. 220 SrvConfigPtr getCurrentCfg(); 221 222 /// @brief Returns a pointer to the staging configuration. 223 /// 224 /// The staging configuration is used by the configuration parsers to 225 /// create new configuration. The staging configuration doesn't affect the 226 /// server's operation until it is committed. The staging configuration 227 /// is a non-const object which can be modified by the caller. 228 /// 229 /// Multiple consecutive calls to this function return the same object 230 /// which can be modified from various places of the code (e.g. various 231 /// configuration parsers). 232 /// 233 /// @return non-null pointer to the staging configuration. 234 SrvConfigPtr getStagingCfg(); 235 236 /// @brief Creates an external configuration and returns pointer to it. 237 /// 238 /// External configurations are those that come from other sources than 239 /// from the configuration file, e.g. a database or a command. They 240 /// are created aside and merged into the staging or current configuration. 241 /// External configurations are accessed by their sequence numbers. The 242 /// sequence numbers are autogenerated when the external configuration 243 /// instance is created. 244 /// 245 /// @return non-null pointer to created external configuration. 246 SrvConfigPtr createExternalCfg(); 247 248 /// @brief Merges external configuration with the given sequence number 249 /// into the staging configuration. 250 /// 251 /// After the merge, the source configuration is discarded from the 252 /// @c CfgMgr as it should not be used anymore. 253 /// 254 /// @param seq Source configuration sequence number. 255 /// 256 /// @throw BadValue if the external configuration with the given sequence 257 /// number doesn't exist. 258 void mergeIntoStagingCfg(const uint32_t seq); 259 260 /// @brief Merges external configuration with the given sequence number 261 /// into the current configuration. 262 /// 263 /// After the merge, the source configuration is discarded from the 264 /// @c CfgMgr as it should not be used anymore. 265 /// 266 /// @param seq Source configuration sequence number. 267 /// 268 /// @throw BadValue if the external configuration with the given sequence 269 /// number doesn't exist. 270 void mergeIntoCurrentCfg(const uint32_t seq); 271 272 //@} 273 274 /// @brief Sets address family (AF_INET or AF_INET6) setFamily(uint16_t family)275 void setFamily(uint16_t family) { 276 family_ = family == AF_INET ? AF_INET : AF_INET6; 277 } 278 279 /// @brief Returns address family. getFamily()280 uint16_t getFamily() const { 281 return (family_); 282 } 283 284 //@} 285 286 protected: 287 288 /// @brief Protected constructor. 289 /// 290 /// This constructor is protected for 2 reasons. First, it forbids any 291 /// instantiations of this class (CfgMgr is a singleton). Second, it 292 /// allows derived class to instantiate it. That is useful for testing 293 /// purposes. 294 CfgMgr(); 295 296 /// @brief virtual destructor 297 virtual ~CfgMgr(); 298 299 private: 300 301 /// @brief Checks if current configuration is created and creates it if needed. 302 /// 303 /// This private method is called to ensure that the current configuration 304 /// is created. If current configuration is not set, it creates the 305 /// default current configuration. 306 void ensureCurrentAllocated(); 307 308 309 /// @brief Merges external configuration with the given sequence number 310 /// into the specified configuration. 311 /// 312 /// @param target_config Pointer to the configuration into which the 313 /// external configuration should be merged. 314 /// @param seq Source configuration sequence number. 315 void mergeIntoCfg(const SrvConfigPtr& taget_config, const uint32_t seq); 316 317 /// @brief directory where data files (e.g. server-id) are stored 318 util::Optional<std::string> datadir_; 319 320 /// @brief Manages the DHCP-DDNS client and its configuration. 321 D2ClientMgr d2_client_mgr_; 322 323 /// @brief Server configuration 324 /// 325 /// This is a structure that will hold all configuration. 326 /// @todo: migrate all other parameters to that structure. 327 SrvConfigPtr configuration_; 328 329 /// @name Configuration List. 330 /// 331 //@{ 332 /// @brief Server configuration list type. 333 typedef std::list<SrvConfigPtr> SrvConfigList; 334 335 /// @brief Container holding all previous and current configurations. 336 SrvConfigList configs_; 337 //@} 338 339 /// @name Map of external configurations. 340 /// 341 //@{ 342 /// @brief Server configuration map type. 343 typedef std::map<uint32_t, SrvConfigPtr> SrvConfigMap; 344 345 /// @brief Map of external configurations with sequence numbers used 346 /// as keys. 347 SrvConfigMap external_configs_; 348 //@} 349 350 /// @brief Address family. 351 uint16_t family_; 352 }; 353 354 } // namespace isc::dhcp 355 } // namespace isc 356 357 #endif // CFGMGR_H 358