Kea  1.5.0
shared_network.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-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 
10 #include <dhcpsrv/shared_network.h>
11 
12 using namespace isc;
13 using namespace isc::data;
14 using namespace isc::dhcp;
15 
16 namespace {
17 
24 class Impl {
25 public:
26 
44  template<typename SubnetPtrType, typename SubnetCollectionType>
45  static void add(SubnetCollectionType& subnets, const SubnetPtrType& subnet) {
46  // Subnet must be non-null.
47  if (!subnet) {
48  isc_throw(BadValue, "null pointer specified when adding a subnet"
49  " to a shared network");
50  }
51 
52  // Check if a subnet with this id already exists.
53  if (getSubnet<SubnetPtrType>(subnets, subnet->getID())) {
54  isc_throw(DuplicateSubnetID, "attempted to add subnet with a"
55  " duplicated subnet identifier " << subnet->getID());
56  }
57 
58  // Check if the subnet is already associated with some network.
59  NetworkPtr network;
60  subnet->getSharedNetwork(network);
61  if (network) {
62  isc_throw(InvalidOperation, "subnet " << subnet->getID()
63  << " being added to a shared network"
64  " already belongs to a shared network");
65  }
66 
67  // Add a subnet to the collection of subnets for this shared network.
68  subnets.push_back(subnet);
69  }
70 
81  template<typename SubnetPtrType, typename SubnetCollectionType>
82  static SubnetPtrType del(SubnetCollectionType& subnets,
83  const SubnetID& subnet_id) {
84  auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
85  auto subnet_it = index.find(subnet_id);
86  if (subnet_it == index.end()) {
87  isc_throw(BadValue, "unable to delete subnet " << subnet_id
88  << " from shared network. Subnet doesn't belong"
89  " to this shared network");
90  }
91  auto subnet = *subnet_it;
92  index.erase(subnet_it);
93  return (subnet);
94  }
95 
107  template<typename SubnetPtrType, typename SubnetCollectionType>
108  static SubnetPtrType getSubnet(const SubnetCollectionType& subnets,
109  const SubnetID& subnet_id) {
110  const auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
111  auto subnet_it = index.find(subnet_id);
112  if (subnet_it != index.cend()) {
113  return (*subnet_it);
114  }
115 
116  // Subnet not found.
117  return (SubnetPtrType());
118  }
119 
159  template<typename SubnetPtrType, typename SubnetCollectionType>
160  static SubnetPtrType getNextSubnet(const SubnetCollectionType& subnets,
161  const SubnetPtrType& first_subnet,
162  const SubnetID& current_subnet) {
163  // It is ok to have a shared network without any subnets, but in this
164  // case there is nothing else we can return but null pointer.
165  if (subnets.empty()) {
166  return (SubnetPtrType());
167  }
168 
169  // Need to retrieve an iterator to the current subnet first. The
170  // subnet must exist in this container, thus we throw if the iterator
171  // is not found.
172  const auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
173  auto subnet_id_it = index.find(current_subnet);
174  if (subnet_id_it == index.cend()) {
175  isc_throw(BadValue, "no such subnet " << current_subnet
176  << " within shared network");
177  }
178 
179  // We need to transform this iterator (by subnet id) to a random access
180  // index iterator. Multi index container has a nice way of doing it.
181  auto subnet_it = subnets.template project<SubnetRandomAccessIndexTag>(subnet_id_it);
182 
183  // Step to a next subnet within random access index.
184  if (++subnet_it == subnets.cend()) {
185  // If we reached the end of the container, start over from the
186  // beginning.
187  subnet_it = subnets.cbegin();
188  }
189 
190  // Check if we have made a full circle. If we did, return a null pointer
191  // to indicate that there are no more subnets.
192  if ((*subnet_it)->getID() == first_subnet->getID()) {
193  return (SubnetPtrType());
194  }
195 
196  // Got the next subnet, so return it.
197  return (*subnet_it);
198  }
199 
224  template<typename SubnetPtrType, typename SubnetCollectionType>
225  static SubnetPtrType getPreferredSubnet(const SubnetCollectionType& subnets,
226  const SubnetPtrType& selected_subnet,
227  const Lease::Type& lease_type) {
228 
229  auto preferred_subnet = selected_subnet;
230  for (auto s = subnets.begin(); s != subnets.end(); ++s) {
231  if (((*s)->getClientClass() == selected_subnet->getClientClass()) &&
232  ((*s)->getLastAllocatedTime(lease_type) >
233  selected_subnet->getLastAllocatedTime(lease_type))) {
234  preferred_subnet = (*s);
235  }
236  }
237 
238  return (preferred_subnet);
239  }
240 };
241 
242 } // end of anonymous namespace
243 
244 namespace isc {
245 namespace dhcp {
246 
248 SharedNetwork4::sharedFromThis() {
249  return (shared_from_this());
250 }
251 
252 void
253 SharedNetwork4::add(const Subnet4Ptr& subnet) {
254  Impl::add(subnets_, subnet);
255  // Associate the subnet with this network.
256  setSharedNetwork(subnet);
257 }
258 
259 void
260 SharedNetwork4::del(const SubnetID& subnet_id) {
261  Subnet4Ptr subnet = Impl::del<Subnet4Ptr>(subnets_, subnet_id);
262  clearSharedNetwork(subnet);
263 }
264 
265 void
266 SharedNetwork4::delAll() {
267  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
268  clearSharedNetwork(*subnet);
269  }
270  subnets_.clear();
271 }
272 
274 SharedNetwork4::getSubnet(const SubnetID& subnet_id) const {
275  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_id));
276 }
277 
279 SharedNetwork4::getNextSubnet(const Subnet4Ptr& first_subnet,
280  const SubnetID& current_subnet) const {
281  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
282 }
283 
285 SharedNetwork4::getPreferredSubnet(const Subnet4Ptr& selected_subnet) const {
286  return (Impl::getPreferredSubnet<Subnet4Ptr>(subnets_, selected_subnet,
287  Lease::TYPE_V4));
288 }
289 
291 SharedNetwork4::toElement() const {
292  ElementPtr map = Network4::toElement();
293 
294  // Set shared network name.
295  if (!name_.empty()) {
296  map->set("name", Element::create(name_));
297  }
298 
299  ElementPtr subnet4 = Element::createList();
300  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
301  subnet4->add((*subnet)->toElement());
302  }
303 
304  map->set("subnet4", subnet4);
305 
306  return (map);
307 }
308 
310 SharedNetwork6::sharedFromThis() {
311  return (shared_from_this());
312 }
313 
314 void
315 SharedNetwork6::add(const Subnet6Ptr& subnet) {
316  Impl::add(subnets_, subnet);
317  // Associate the subnet with this network.
318  setSharedNetwork(subnet);
319 }
320 
321 void
322 SharedNetwork6::del(const SubnetID& subnet_id) {
323  Subnet6Ptr subnet = Impl::del<Subnet6Ptr>(subnets_, subnet_id);
324  clearSharedNetwork(subnet);
325 }
326 
327 void
328 SharedNetwork6::delAll() {
329  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
330  clearSharedNetwork(*subnet);
331  }
332  subnets_.clear();
333 }
335 SharedNetwork6::getSubnet(const SubnetID& subnet_id) const {
336  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_id));
337 }
338 
340 SharedNetwork6::getNextSubnet(const Subnet6Ptr& first_subnet,
341  const SubnetID& current_subnet) const {
342  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
343 }
344 
346 SharedNetwork6::getPreferredSubnet(const Subnet6Ptr& selected_subnet,
347  const Lease::Type& lease_type) const {
348  return (Impl::getPreferredSubnet(subnets_, selected_subnet, lease_type));
349 }
350 
352 SharedNetwork6::toElement() const {
353  ElementPtr map = Network6::toElement();
354 
355  // Set shared network name.
356  if (!name_.empty()) {
357  map->set("name", Element::create(name_));
358  }
359 
360  ElementPtr subnet6 = Element::createList();
361  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
362  subnet6->add((*subnet)->toElement());
363  }
364 
365  map->set("subnet6", subnet6);
366 
367  return (map);
368 }
369 
370 } // end of namespace isc::dhcp
371 } // end of namespace isc
isc::dhcp::DuplicateSubnetID
Exception thrown upon attempt to add subnet with an ID that belongs to the subnet that already exists...
Definition: subnet_id.h:34
isc::dhcp::Lease::Type
Type
Type of lease or pool.
Definition: lease.h:38
isc::data
Definition: cfg_to_element.h:25
shared_network.h
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::InvalidOperation
A generic exception that is thrown if a function is called in a prohibited way.
Definition: exceptions/exceptions.h:143
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp
Definition: ctrl_dhcp4_srv.cc:75
isc::dhcp::Subnet4Ptr
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:464
isc::data::Element::createList
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
isc::dhcp::Subnet6Ptr
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:629
exceptions.h
name_
const Name & name_
Definition: dns/message.cc:693
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
isc::dhcp::SubnetID
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
isc::data::Element::create
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:223
isc::dhcp::NetworkPtr
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:360