Kea 1.5.0
cfg_subnets6.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2018 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#include <config.h>
8#include <dhcp/dhcp6.h>
12#include <dhcpsrv/dhcpsrv_log.h>
14#include <dhcpsrv/subnet_id.h>
15#include <stats/stats_mgr.h>
16#include <boost/foreach.hpp>
17#include <string.h>
18#include <sstream>
19
20using namespace isc::asiolink;
21using namespace isc::data;
22
23namespace isc {
24namespace dhcp {
25
26void
28 if (getBySubnetId(subnet->getID())) {
29 isc_throw(isc::dhcp::DuplicateSubnetID, "ID of the new IPv6 subnet '"
30 << subnet->getID() << "' is already in use");
31
32 } else if (getByPrefix(subnet->toText())) {
35 isc_throw(isc::dhcp::DuplicateSubnetID, "subnet with the prefix of '"
36 << subnet->toText() << "' already exists");
37 }
38
39 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_ADD_SUBNET6)
40 .arg(subnet->toText());
41 subnets_.push_back(subnet);
42}
43
44void
46 auto& index = subnets_.get<SubnetSubnetIdIndexTag>();
47 auto subnet_it = index.find(subnet->getID());
48 if (subnet_it == index.end()) {
49 isc_throw(BadValue, "no subnet with ID of '" << subnet->getID()
50 << "' found");
51 }
52 index.erase(subnet_it);
53
54 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_DEL_SUBNET6)
55 .arg(subnet->toText());
56}
57
59CfgSubnets6::getBySubnetId(const SubnetID& subnet_id) const {
60 const auto& index = subnets_.get<SubnetSubnetIdIndexTag>();
61 auto subnet_it = index.find(subnet_id);
62 return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet6Ptr());
63}
64
66CfgSubnets6::getByPrefix(const std::string& subnet_text) const {
67 const auto& index = subnets_.get<SubnetPrefixIndexTag>();
68 auto subnet_it = index.find(subnet_text);
69 return ((subnet_it != index.cend()) ? (*subnet_it) : ConstSubnet6Ptr());
70}
71
74 // Initialize subnet selector with the values used to select the subnet.
75 SubnetSelector selector;
76 selector.iface_name_ = query->getIface();
77 selector.remote_address_ = query->getRemoteAddr();
78 selector.first_relay_linkaddr_ = IOAddress("::");
79 selector.client_classes_ = query->classes_;
80
81 // Initialize fields specific to relayed messages.
82 if (!query->relay_info_.empty()) {
83 BOOST_REVERSE_FOREACH(Pkt6::RelayInfo relay, query->relay_info_) {
84 if (!relay.linkaddr_.isV6Zero() &&
85 !relay.linkaddr_.isV6LinkLocal()) {
86 selector.first_relay_linkaddr_ = relay.linkaddr_;
87 break;
88 }
89 }
90 selector.interface_id_ =
91 query->getAnyRelayOption(D6O_INTERFACE_ID,
93 }
94
95 return (selector);
96}
97
100 Subnet6Ptr subnet;
101
102 // If relay agent link address is set to zero it means that we're dealing
103 // with a directly connected client.
104 if (selector.first_relay_linkaddr_ == IOAddress("::")) {
105 // If interface name is known try to match it with interface names
106 // specified for configured subnets.
107 if (!selector.iface_name_.empty()) {
108 subnet = selectSubnet(selector.iface_name_,
109 selector.client_classes_);
110 }
111
112 // If interface name didn't match, try the client's address.
113 if (!subnet && selector.remote_address_ != IOAddress("::")) {
114 subnet = selectSubnet(selector.remote_address_,
115 selector.client_classes_);
116 }
117
118 // If relay agent link address is set, we're dealing with a relayed message.
119 } else {
120
121 // Find the subnet using the Interface Id option, if present.
122 subnet = selectSubnet(selector.interface_id_, selector.client_classes_);
123
124 // If Interface ID option could not be matched for any subnet, try
125 // the relay agent link address.
126 if (!subnet) {
127 subnet = selectSubnet(selector.first_relay_linkaddr_,
128 selector.client_classes_,
129 true);
130 }
131 }
132
133 // Return subnet found, or NULL if not found.
134 return (subnet);
135}
136
139 const ClientClasses& client_classes,
140 const bool is_relay_address) const {
141
142 // If the specified address is a relay address we first need to match
143 // it with the relay addresses specified for all subnets.
144 if (is_relay_address) {
145 for (Subnet6Collection::const_iterator subnet = subnets_.begin();
146 subnet != subnets_.end(); ++subnet) {
147
148 // If the specified address matches a relay address, return this
149 // subnet.
150 if (is_relay_address &&
151 ((*subnet)->hasRelayAddress(address)) &&
152 (*subnet)->clientSupported(client_classes)) {
154 DHCPSRV_CFGMGR_SUBNET6_RELAY)
155 .arg((*subnet)->toText()).arg(address.toText());
156 return (*subnet);
157 }
158
159 }
160 }
161
162 // No success so far. Check if the specified address is in range
163 // with any subnet.
164 for (Subnet6Collection::const_iterator subnet = subnets_.begin();
165 subnet != subnets_.end(); ++subnet) {
166 if ((*subnet)->inRange(address) &&
167 (*subnet)->clientSupported(client_classes)) {
168 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, DHCPSRV_CFGMGR_SUBNET6)
169 .arg((*subnet)->toText()).arg(address.toText());
170 return (*subnet);
171 }
172 }
173
174 // Nothing found.
175 return (Subnet6Ptr());
176}
177
178
180CfgSubnets6::selectSubnet(const std::string& iface_name,
181 const ClientClasses& client_classes) const {
182
183 // If empty interface specified, we can't select subnet by interface.
184 if (!iface_name.empty()) {
185 for (Subnet6Collection::const_iterator subnet = subnets_.begin();
186 subnet != subnets_.end(); ++subnet) {
187
188 // If interface name matches with the one specified for the subnet
189 // and the client is not rejected based on the classification,
190 // return the subnet.
191 if ((iface_name == (*subnet)->getIface()) &&
192 (*subnet)->clientSupported(client_classes)) {
193
195 DHCPSRV_CFGMGR_SUBNET6_IFACE)
196 .arg((*subnet)->toText()).arg(iface_name);
197 return (*subnet);
198 }
199 }
200 }
201
202 // No subnet found for this interface name.
203 return (Subnet6Ptr());
204}
205
207CfgSubnets6::selectSubnet(const OptionPtr& interface_id,
208 const ClientClasses& client_classes) const {
209 // We can only select subnet using an interface id, if the interface
210 // id is known.
211 if (interface_id) {
212 for (Subnet6Collection::const_iterator subnet = subnets_.begin();
213 subnet != subnets_.end(); ++subnet) {
214
215 // If interface id matches for the subnet and the subnet is not
216 // rejected based on the classification.
217 if ((*subnet)->getInterfaceId() &&
218 (*subnet)->getInterfaceId()->equals(interface_id) &&
219 (*subnet)->clientSupported(client_classes)) {
220
222 DHCPSRV_CFGMGR_SUBNET6_IFACE_ID)
223 .arg((*subnet)->toText());
224 return (*subnet);
225 }
226 }
227 }
228 // No subnet found.
229 return (Subnet6Ptr());
230}
231
234
237 for (auto subnet = subnets_.begin(); subnet != subnets_.end(); ++subnet) {
238 if ((*subnet)->getID() == id) {
239 return (*subnet);
240 }
241 }
242 return (Subnet6Ptr());
243}
244
245void
247 using namespace isc::stats;
248
249 StatsMgr& stats_mgr = StatsMgr::instance();
250 // For each v6 subnet currently configured, remove the statistics.
251 for (Subnet6Collection::const_iterator subnet6 = subnets_.begin();
252 subnet6 != subnets_.end(); ++subnet6) {
253 SubnetID subnet_id = (*subnet6)->getID();
254 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id, "total-nas"));
255
256 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
257 "assigned-nas"));
258
259 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id, "total-pds"));
260
261 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
262 "assigned-pds"));
263
264 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
265 "declined-addresses"));
266
267 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
268 "declined-reclaimed-addresses"));
269
270 stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
271 "reclaimed-leases"));
272 }
273}
274
275void
277 using namespace isc::stats;
278
279 StatsMgr& stats_mgr = StatsMgr::instance();
280 // For each v6 subnet currently configured, calculate totals
281 for (Subnet6Collection::const_iterator subnet6 = subnets_.begin();
282 subnet6 != subnets_.end(); ++subnet6) {
283 SubnetID subnet_id = (*subnet6)->getID();
284
285 stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
286 "total-nas"),
287 static_cast<int64_t>
288 ((*subnet6)->getPoolCapacity(Lease::TYPE_NA)));
289
290 stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
291 "total-pds"),
292 static_cast<int64_t>
293 ((*subnet6)->getPoolCapacity(Lease::TYPE_PD)));
294 }
295
296 // Only recount the stats if we have subnets.
297 if (subnets_.begin() != subnets_.end()) {
299 }
300}
301
305 // Iterate subnets
306 for (Subnet6Collection::const_iterator subnet = subnets_.cbegin();
307 subnet != subnets_.cend(); ++subnet) {
308 result->add((*subnet)->toElement());
309 }
310 return (result);
311}
312
313} // end of namespace isc::dhcp
314} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
void updateStatistics()
Updates statistics.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Subnet6Ptr selectSubnet(const SubnetSelector &selector) const
Selects a subnet using parameters specified in the selector.
Definition: cfg_subnets6.cc:99
Subnet6Ptr getSubnet(const SubnetID id) const
Returns subnet with specified subnet-id value.
void removeStatistics()
Removes statistics.
void add(const Subnet6Ptr &subnet)
Adds new subnet to the configuration.
Definition: cfg_subnets6.cc:27
static SubnetSelector initSelector(const Pkt6Ptr &query)
Build selector from a client's message.
Definition: cfg_subnets6.cc:73
void del(const ConstSubnet6Ptr &subnet)
Removes subnet from the configuration.
Definition: cfg_subnets6.cc:45
ConstSubnet6Ptr getByPrefix(const std::string &subnet_prefix) const
Returns const pointer to a subnet which matches the specified prefix in the canonical form.
Definition: cfg_subnets6.cc:66
ConstSubnet6Ptr getBySubnetId(const SubnetID &subnet_id) const
Returns const pointer to a subnet identified by the specified subnet identifier.
Definition: cfg_subnets6.cc:59
Container for storing client class names.
Definition: classify.h:43
Exception thrown upon attempt to add subnet with an ID that belongs to the subnet that already exists...
Definition: subnet_id.h:34
static LeaseMgr & instance()
Return current lease manager.
void recountLeaseStats6()
Recalculates per-subnet and global stats for IPv6 leases.
Definition: lease_mgr.cc:182
@ RELAY_GET_FIRST
Definition: pkt6.h:77
Statistics Manager class.
@ D6O_INTERFACE_ID
Definition: dhcp6.h:38
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
bool del(const std::string &name)
Removes specified statistic.
Definition: stats_mgr.cc:99
void setValue(const std::string &name, const int64_t value)
Records absolute integer observation.
Definition: stats_mgr.cc:31
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< Element > ElementPtr
Definition: data.h:22
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition: subnet.h:626
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:629
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:31
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
boost::shared_ptr< Option > OptionPtr
Definition: option.h:38
Defines the logger used by the top-level component of kea-dhcp-ddns.
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:39
structure that describes a single relay information
Definition: pkt6.h:85
isc::asiolink::IOAddress linkaddr_
fixed field in relay-forw/relay-reply
Definition: pkt6.h:96
Tag for the index for searching by subnet prefix.
Definition: subnet.h:742
Subnet selector used to specify parameters used to select a subnet.
std::string iface_name_
Name of the interface on which the message was received.
ClientClasses client_classes_
Classes that the client belongs to.
asiolink::IOAddress remote_address_
Source address of the message.
OptionPtr interface_id_
Interface id option.
asiolink::IOAddress first_relay_linkaddr_
First relay link address.
Tag for the index for searching by subnet identifier.
Definition: subnet.h:739