1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright (C) 2017-2023 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef NETWORK_STATE_H
#define NETWORK_STATE_H

#include <cc/data.h>
#include <dhcpsrv/subnet_id.h>
#include <boost/scoped_ptr.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/shared_ptr.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <set><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <mutex><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace dhcp {

class NetworkStateImpl;

/// @brief Controls the DHCP service enabling status.
///
/// Sometimes, a DHCP server must pause responding to the DHCP queries.
/// Typical cases include a database connection loss when the server tries
/// to reconnect and various cases related to the High Availability operation.
/// It is also possible to explicitly turn the DHCP service on and off via the
/// control channel. This class receives calls from different origins to
/// disable and re-enable the DHCP service.
///
/// The general rule is that the DHCP service must be disabled when the class
/// receives at least one request to disable the service from any origin. The
/// service must be re-enabled when all requestors previously disabling the
/// service re-enabled it. This class also allows for specifying a timeout value
/// for each request, after which the service gets re-enabled automatically. It
/// is particularly useful in HA when there is no guarantee that the HA partner
/// will be able to re-enable the service because it may experience an unexpected
/// outage. In that case, the "max-period" parameter must accompany the "dhcp-disable"
/// command to ensure that the service will eventually be re-enabled.

/// The HA hook library may include several independent relationships. Each
/// relationship is treated as a separate origin by this class. If one relationship
/// disables the DHCP service, the service must remain disabled even when any other
/// relationship requests enabling it. The service is re-enabled after all
/// relationships requested re-enabling it (e.g., they all finished synchronizing
/// the lease database).
///
/// The HA service instances must have unique identifiers they use to specify the
/// origin. For example, an @c HAService with the identifier of 1 should request
/// disabling the local service like this:
///
/// @code
///     NetworkState state;
///     state.disableService(NetworkState::HA_LOCAL_COMMAND + 1);
/// @endcode
///
/// The DHCP state can also be altered by the database recovery mechanism, which
/// disables the service on connection loss and re-enables it after the connection
/// is restored. Unlike in HA, this is implemented using an internal counter. In
/// this case, there is one origin for all database connections. The requests for
/// the @c NetworkState::DB_CONNECTION are counted, and the DHCP service is
/// re-enabled when the counter reaches 0.
///
/// @todo We should consider migrating the database recovery to the same mechanism
///  we use for the HA. The reference counting works because the database connection
/// classes ensure that for each request to disable the DHCP service, there is a
/// corresponding request to enable the service. It prevents the situation that the
/// service remains disabled because there were more requests to disable than to
/// enable the service. It is hard to ensure the same consistency for the HA.
class NetworkState {
public:

    /// @brief DHCP server type.
    enum ServerType {
        DHCPv4,
        DHCPv6
    };

    /// @brief Origin of the network state transition.
    ///
    /// The enumeration indicates the originator of the state transition of the
    /// network state: either user command, HA internal command or DB connection
    /// recovery mechanism.

    /// @brief The network state is being altered by a user command.
    ///
    /// Specify unique origins for different commands by adding a number to this
    /// constant.
    static const unsigned int USER_COMMAND = 1;

    /// @brief The network state is being altered by an HA internal command.
    ///
    /// Specify HA service-specific origins by adding a unique local service
    /// identifier to this constant.
    static const unsigned int HA_LOCAL_COMMAND = 1000;

    /// @brief The network state is being altered by a "dhcp-disable" or "dhcp-enable"
    /// command sent by a HA partner.
    ///
    /// Specify HA service-specific origins by adding a unique remote service
    /// identifier to this constant.
    static const unsigned int HA_REMOTE_COMMAND = 2000;

    /// @brief The network state is being altered by the DB connection
    /// recovery mechanics.
    static const unsigned int DB_CONNECTION = 3000;

    /// @brief Type of the container holding collection of subnet identifiers.
    typedef std::set<SubnetID> Subnets;

    /// @brief Type of the container holding collection of shared network names.
    typedef std::set<std::string> Networks;

    /// @brief Constructor.
    NetworkState(const ServerType& server_type);

    /// @brief Disable the DHCP service state for respective transition origin.
    ///
    /// @note If any of the user commands, HA internal commands or connection
    /// recovery processes disable the dhcp service, the service will remain
    /// disabled until all flags are cleared.
    ///
    /// @param origin The origin of the state transition.
    void disableService(unsigned int origin);

    /// @brief Enable the DHCP service state for respective transition origin.
    ///
    /// @note If any of the user commands, HA internal commands or connection
    /// recovery processes disable the dhcp service, the service will remain
    /// disabled until all flags are cleared.
    ///
    /// @param origin The origin of the state transition.
    void enableService(unsigned int origin);

    /// @brief Reset internal counters for database connection.
    ///
    /// It results in enabling the network service if network service for
    /// all other origins is enabled.
    void resetForDbConnection();

    /// @brief Schedules enabling DHCP service in the future.
    ///
    /// @param seconds Number of seconds after which the service should be enabled
    /// unless @c enableAll is enabled before that time.
    /// @param origin The origin of the state transition.
    void delayedEnableService(const unsigned int seconds,
                              unsigned int origin);

    /// @brief Checks if the DHCP service is globally enabled.
    ///
    /// @return true if the service is globally enabled, false otherwise.
    bool isServiceEnabled() const;

    /// @brief Checks if delayed enabling of DHCP services is scheduled.
    ///
    /// It indicates that the timer is present which counts the time until
    /// @c delayedEnable function will be called automatically.
    ///
    /// @return true if delayed enabling of the DHCP service is scheduled,
    /// false otherwise.
    bool isDelayedEnableService() const;

    /// @name Selective disabling/enabling DHCP service per scopes
    //@{

    /// @brief Disable DHCP service for selected subnets.
    ///
    /// @param subnets Collection of subnet identifiers for which the service
    /// should be disabled.
    ///
    /// @throw isc::NotImplemented
    void selectiveDisable(const NetworkState::Subnets& subnets);

    /// @brief Disable DHCP service for selected networks.
    ///
    /// @param networks Collection of shared network names for which the service
    /// should be disabled.
    ///
    /// @throw isc::NotImplemented
    void selectiveDisable(const NetworkState::Networks& networks);

    /// @brief Enable DHCP service for selected subnets.
    ///
    /// @param subnets Collection of subnet identifiers for which the service
    /// should be disabled.
    ///
    /// @throw isc::NotImplemented
    void selectiveEnable(const NetworkState::Subnets& subnets);

    /// @brief Enable DHCP service for selected networks.
    ///
    /// @param networks Collection of shared network names for which the service
    /// should be enabled.
    ///
    /// @throw isc::NotImplemented
    void selectiveEnable(const NetworkState::Networks& networks);

    //@}

private:

    /// @brief Pointer to the @c NetworkState implementation.
    boost::shared_ptr<NetworkStateImpl> impl_;

    /// @brief The mutex used to protect internal state.
    const boost::scoped_ptr<std::mutex> mutex_;
};

/// @brief Pointer to the @c NetworkState object.
typedef boost::shared_ptr<NetworkState> NetworkStatePtr;

} // end of namespace isc::dhcp
} // end of namespace isc

#endif // NETWORK_STATE_H