cfgmgr.h 15 KB
Newer Older
1
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef CFGMGR_H
#define CFGMGR_H

#include <asiolink/io_address.h>
19
#include <dhcp/option.h>
20
#include <dhcp/option_definition.h>
21
#include <dhcp/option_space.h>
22
#include <dhcpsrv/option_space_container.h>
23 24 25 26 27 28 29 30 31 32
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet.h>
#include <util/buffer.h>

#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>

#include <map>
#include <string>
#include <vector>
33
#include <list>
34 35 36 37

namespace isc {
namespace dhcp {

38 39 40 41 42 43 44 45 46 47
/// @brief Exception thrown when the same interface has been specified twice.
///
/// In particular, this exception is thrown when adding interface to the set
/// of interfaces on which server is supposed to listen.
class DuplicateListeningIface : public Exception {
public:
    DuplicateListeningIface(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

48

49 50 51 52 53
/// @brief Configuration Manager
///
/// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
/// servers. It currently holds information about zero or more subnets6.
/// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
54
/// basic "chunk" of configuration. It contains a range of assignable
55 56
/// addresses.
///
57
/// Below is a sketch of configuration inheritance (not implemented yet).
58 59
/// Let's investigate the following configuration:
///
60
/// @code
61
/// preferred-lifetime 500;
62 63 64 65 66 67 68 69
/// valid-lifetime 1000;
/// subnet6 2001:db8:1::/48 {
///     pool6 2001::db8:1::1 - 2001::db8:1::ff;
/// };
/// subnet6 2001:db8:2::/48 {
///     valid-lifetime 2000;
///     pool6 2001::db8:2::1 - 2001::db8:2::ff;
/// };
70 71
/// @endcode
///
72
/// Parameters defined in a global scope are applicable to everything until
73
/// they are overwritten in a smaller scope, in this case subnet6.
74 75 76 77 78 79 80
/// In the example above, the first subnet6 has preferred lifetime of 500s
/// and a valid lifetime of 1000s. The second subnet has preferred lifetime
/// of 500s, but valid lifetime of 2000s.
///
/// Parameter inheritance is likely to be implemented in configuration handling
/// routines, so there is no storage capability in a global scope for
/// subnet-specific parameters.
81 82 83
///
/// @todo: Implement Subnet4 support (ticket #2237)
/// @todo: Implement option definition support
84
/// @todo: Implement parameter inheritance
85 86
class CfgMgr : public boost::noncopyable {
public:
87 88 89 90 91

    /// @brief returns a single instance of Configuration Manager
    ///
    /// CfgMgr is a singleton and this method is the only way of
    /// accessing it.
92 93
    static CfgMgr& instance();

94 95 96
    /// @brief Add new option definition.
    ///
    /// @param def option definition to be added.
97
    /// @param option_space name of the option space to add definition to.
98 99 100
    ///
    /// @throw isc::dhcp::DuplicateOptionDefinition when the particular
    /// option definition already exists.
101 102
    /// @throw isc::dhcp::MalformedOptionDefinition when the pointer to
    /// an option definition is NULL.
103
    /// @throw isc::BadValue when the option space name is empty or
104 105
    /// when trying to override the standard option (in dhcp4 or dhcp6
    /// option space).
106 107 108 109 110 111 112
    void addOptionDef(const OptionDefinitionPtr& def,
                      const std::string& option_space);

    /// @brief Return option definitions for particular option space.
    ///
    /// @param option_space option space.
    ///
113 114 115 116
    /// @return pointer to the collection of option definitions for
    /// the particular option space. The option collection is empty
    /// if no option exists for the option space specified.
    OptionDefContainerPtr
117 118 119 120 121 122 123 124 125 126 127 128
    getOptionDefs(const std::string& option_space) const;

    /// @brief Return option definition for a particular option space and code.
    ///
    /// @param option_space option space.
    /// @param option_code option code.
    ///
    /// @return an option definition or NULL pointer if option definition
    /// has not been found.
    OptionDefinitionPtr getOptionDef(const std::string& option_space,
                                     const uint16_t option_code) const;

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    /// @brief Adds new DHCPv4 option space to the collection.
    ///
    /// @param space option space to be added.
    ///
    /// @throw isc::dhcp::InvalidOptionSpace invalid option space
    /// has been specified.
    void addOptionSpace4(const OptionSpacePtr& space);

    /// @brief Adds new DHCPv6 option space to the collection.
    ///
    /// @param space option space to be added.
    ///
    /// @throw isc::dhcp::InvalidOptionSpace invalid option space
    /// has been specified.
    void addOptionSpace6(const OptionSpacePtr& space);

    /// @brief Return option spaces for DHCPv4.
    ///
    /// @return A collection of option spaces.
    const OptionSpaceCollection& getOptionSpaces4() const {
        return (spaces4_);
    }

    /// @brief Return option spaces for DHCPv6.
    ///
    /// @return A collection of option spaces.
    const OptionSpaceCollection& getOptionSpaces6() const {
        return (spaces6_);
    }

159
    /// @brief get IPv6 subnet by address
160 161 162 163 164 165
    ///
    /// Finds a matching subnet, based on an address. This can be used
    /// in two cases: when trying to find an appropriate lease based on
    /// a) relay link address (that must be the address that is on link)
    /// b) our global address on the interface the message was received on
    ///    (for directly connected clients)
166 167
    ///
    /// @param hint an address that belongs to a searched subnet
168
    ///
169
    /// @return a subnet object (or NULL if no suitable match was fount)
170 171
    Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);

172 173 174 175 176 177 178 179 180
    /// @brief get IPv6 subnet by interface name
    ///
    /// Finds a matching local subnet, based on interface name. This
    /// is used for selecting subnets that were explicitly marked by the
    /// user as reachable over specified network interface.
    /// @param iface_name interface name
    /// @return a subnet object (or NULL if no suitable match was fount)
    Subnet6Ptr getSubnet6(const std::string& iface_name);

181
    /// @brief get IPv6 subnet by interface-id
182
    ///
183 184 185
    /// Another possibility to find a subnet is based on interface-id.
    ///
    /// @param interface_id content of interface-id option returned by a relay
186 187
    ///
    /// @return a subnet object
188
    Subnet6Ptr getSubnet6(OptionPtr interface_id);
189

190
    /// @brief adds an IPv6 subnet
191 192
    ///
    /// @param subnet new subnet to be added.
193 194
    void addSubnet6(const Subnet6Ptr& subnet);

195 196 197
    /// @brief Delete all option definitions.
    void deleteOptionDefs();

198 199 200 201
    /// @todo: Add subnet6 removal routines. Currently it is not possible
    /// to remove subnets. The only case where subnet6 removal would be
    /// needed is a dynamic server reconfiguration - a use case that is not
    /// planned to be supported any time soon.
202

203
    /// @brief removes all IPv6 subnets
204
    ///
205
    /// This method removes all existing IPv6 subnets. It is used during
206 207 208 209 210 211 212
    /// reconfiguration - old configuration is wiped and new definitions
    /// are used to recreate subnets.
    ///
    /// @todo Implement more intelligent approach. Note that comparison
    /// between old and new configuration is tricky. For example: is
    /// 2000::/64 and 2000::/48 the same subnet or is it something
    /// completely new?
213
    void deleteSubnets6();
214

215 216 217 218 219 220 221 222 223
    /// @brief returns const reference to all subnets6
    ///
    /// This is used in a hook (subnet4_select), where the hook is able
    /// to choose a different subnet. Server code has to offer a list
    /// of possible choices (i.e. all subnets).
    /// @return a pointer to const Subnet6 collection
    const Subnet4Collection* getSubnets4() {
        return (&subnets4_);
    }
224 225 226 227 228 229

    /// @brief returns const reference to all subnets6
    ///
    /// This is used in a hook (subnet6_select), where the hook is able
    /// to choose a different subnet. Server code has to offer a list
    /// of possible choices (i.e. all subnets).
230 231 232
    /// @return a pointer to const Subnet6 collection
    const Subnet6Collection* getSubnets6() {
        return (&subnets6_);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
233
    }
Tomek Mrugalski's avatar
Tomek Mrugalski committed
234

235 236 237 238 239 240 241 242 243
    /// @brief get IPv4 subnet by address
    ///
    /// Finds a matching subnet, based on an address. This can be used
    /// in two cases: when trying to find an appropriate lease based on
    /// a) relay link address (that must be the address that is on link)
    /// b) our global address on the interface the message was received on
    ///    (for directly connected clients)
    ///
    /// @param hint an address that belongs to a searched subnet
244 245
    ///
    /// @return a subnet object
246 247 248 249 250 251
    Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint);

    /// @brief adds a subnet4
    void addSubnet4(const Subnet4Ptr& subnet);

    /// @brief removes all IPv4 subnets
252 253 254 255 256 257 258 259 260 261
    ///
    /// This method removes all existing IPv4 subnets. It is used during
    /// reconfiguration - old configuration is wiped and new definitions
    /// are used to recreate subnets.
    ///
    /// @todo Implement more intelligent approach. Note that comparison
    /// between old and new configuration is tricky. For example: is
    /// 192.0.2.0/23 and 192.0.2.0/24 the same subnet or is it something
    /// completely new?
    void deleteSubnets4();
262

263 264 265 266 267 268 269 270

    /// @brief returns path do the data directory
    ///
    /// This method returns a path to writeable directory that DHCP servers
    /// can store data in.
    /// @return data directory
    std::string getDataDir();

271 272 273 274
    /// @brief Adds the name of the interface to the set of interfaces on which
    /// server should listen.
    ///
    /// @param iface A name of the interface being added to the listening set.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
275
    void addActiveIface(const std::string& iface);
276

277 278
    /// @brief Sets the flag which indicates that server is supposed to listen
    /// on all available interfaces.
279
    ///
280 281 282 283
    /// This function does not close or open sockets. It simply marks that
    /// server should start to listen on all interfaces the next time sockets
    /// are reopened. Server should examine this flag when it gets reconfigured
    /// and configuration changes the interfaces that server should listen on.
284 285
    void activateAllIfaces();

286 287
    /// @brief Clear the collection of the interfaces that server should listen
    /// on.
288 289 290
    ///
    /// Apart from clearing the list of interfaces specified with
    /// @c CfgMgr::addListeningInterface, it also disables listening on all
291 292 293 294 295 296
    /// interfaces if it has been enabled using
    /// @c CfgMgr::activateAllInterfaces.
    /// Likewise @c CfgMgr::activateAllIfaces, this function does not close or
    /// open sockets. It marks all interfaces inactive for DHCP traffic.
    /// Server should examine this new setting when it attempts to
    /// reopen sockets (as a result of reconfiguration).
297 298
    void deleteActiveIfaces();

299 300
    /// @brief Check if specified interface should be used to listen to DHCP
    /// traffic.
301 302 303 304 305 306 307
    ///
    /// @param iface A name of the interface to be checked.
    ///
    /// @return true if the specified interface belongs to the set of the
    /// interfaces on which server is configured to listen.
    bool isActiveIface(const std::string& iface) const;

308 309 310
    /// @brief returns unicast a given interface should listen on (or NULL)
    ///
    /// This method will return an address for a specified interface, if the
Tomek Mrugalski's avatar
Tomek Mrugalski committed
311 312 313
    /// server is supposed to listen on unicast address. This address is
    /// intended to be used immediately. This pointer is valid only until
    /// the next configuration change.
314 315 316 317 318
    ///
    /// @return IOAddress pointer (or NULL if none)
    const isc::asiolink::IOAddress*
    getUnicast(const std::string& iface) const;

319 320 321
protected:

    /// @brief Protected constructor.
322 323 324 325 326
    ///
    /// This constructor is protected for 2 reasons. First, it forbids any
    /// instantiations of this class (CfgMgr is a singleton). Second, it
    /// allows derived class to instantiate it. That is useful for testing
    /// purposes.
327 328
    CfgMgr();

329
    /// @brief virtual destructor
330 331
    virtual ~CfgMgr();

332
    /// @brief a container for IPv6 subnets.
333 334 335 336 337
    ///
    /// That is a simple vector of pointers. It does not make much sense to
    /// optimize access time (e.g. using a map), because typical search
    /// pattern will use calling inRange() method on each subnet until
    /// a match is found.
338
    Subnet6Collection subnets6_;
339 340 341 342 343 344 345 346

    /// @brief a container for IPv4 subnets.
    ///
    /// That is a simple vector of pointers. It does not make much sense to
    /// optimize access time (e.g. using a map), because typical search
    /// pattern will use calling inRange() method on each subnet until
    /// a match is found.
    Subnet4Collection subnets4_;
347 348 349

private:

350 351 352 353 354 355 356 357 358 359 360 361 362 363
    /// @brief Checks if the specified interface is listed as active.
    ///
    /// This function searches for the specified interface name on the list of
    /// active interfaces: @c CfgMgr::active_ifaces_. It does not take into
    /// account @c CfgMgr::all_ifaces_active_ flag. If this flag is set to true
    /// but the specified interface does not belong to
    /// @c CfgMgr::active_ifaces_, it will return false.
    ///
    /// @param iface interface name.
    ///
    /// @return true if specified interface belongs to
    /// @c CfgMgr::active_ifaces_.
    bool isIfaceListedActive(const std::string& iface) const;

364 365 366 367 368 369
    /// @brief A collection of option definitions.
    ///
    /// A collection of option definitions that can be accessed
    /// using option space name they belong to.
    OptionSpaceContainer<OptionDefContainer,
                         OptionDefinitionPtr> option_def_spaces_;
370

371 372 373 374 375
    /// @brief Container for defined DHCPv6 option spaces.
    OptionSpaceCollection spaces6_;

    /// @brief Container for defined DHCPv4 option spaces.
    OptionSpaceCollection spaces4_;
376

377 378
    /// @brief directory where data files (e.g. server-id) are stored
    std::string datadir_;
379 380 381 382 383 384 385

    /// @name A collection of interface names on which server listens.
    //@{
    typedef std::list<std::string> ActiveIfacesCollection;
    std::list<std::string> active_ifaces_;
    //@}

386 387 388 389 390 391
    /// @name a collection of unicast addresses and the interfaces names the
    //        server is supposed to listen on
    //@{
    typedef std::map<std::string, isc::asiolink::IOAddress> UnicastIfacesCollection;
    UnicastIfacesCollection unicast_addrs_;

392 393 394
    /// A flag which indicates that server should listen on all available
    /// interfaces.
    bool all_ifaces_active_;
395
};
396 397 398 399

} // namespace isc::dhcp
} // namespace isc

400
#endif // CFGMGR_H