Kea  1.9.9-git
shared_network.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2020 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 #include <boost/make_shared.hpp>
12 
13 using namespace isc;
14 using namespace isc::data;
15 using namespace isc::dhcp;
16 
17 namespace {
18 
25 class Impl {
26 public:
27 
45  template<typename SubnetPtrType, typename SubnetCollectionType>
46  static void add(SubnetCollectionType& subnets, const SubnetPtrType& subnet) {
47  // Subnet must be non-null.
48  if (!subnet) {
49  isc_throw(BadValue, "null pointer specified when adding a subnet"
50  " to a shared network");
51  }
52 
53  // Check if a subnet with this id already exists.
54  if (getSubnet<SubnetPtrType>(subnets, subnet->getID())) {
55  isc_throw(DuplicateSubnetID, "attempted to add subnet with a"
56  " duplicated subnet identifier " << subnet->getID());
57  } else if (getSubnet<SubnetPtrType>(subnets, subnet->toText())) {
58  isc_throw(DuplicateSubnetID, "attempted to add subnet with a"
59  " duplicated subnet prefix " << subnet->toText());
60  }
61 
62  // Check if the subnet is already associated with some network.
63  NetworkPtr network;
64  subnet->getSharedNetwork(network);
65  if (network) {
66  isc_throw(InvalidOperation, "subnet " << subnet->getID()
67  << " being added to a shared network"
68  " already belongs to a shared network");
69  }
70 
71  // Add a subnet to the collection of subnets for this shared network.
72  static_cast<void>(subnets.insert(subnet));
73  }
74 
95  template<typename SubnetPtrType, typename SubnetCollectionType>
96  static bool replace(SubnetCollectionType& subnets,
97  const SubnetPtrType& subnet) {
98 
99  // Check if the new subnet is already associated with some network.
100  NetworkPtr network;
101  subnet->getSharedNetwork(network);
102  if (network) {
103  isc_throw(InvalidOperation, "subnet " << subnet->getID()
104  << " being replaced in a shared network"
105  " already belongs to a shared network");
106  }
107 
108  // Get the subnet with the same ID.
109  const SubnetID& subnet_id = subnet->getID();
110  auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
111  auto subnet_it = index.find(subnet_id);
112  if (subnet_it == index.end()) {
113  // Nothing to replace: return false to get the whole operation
114  // to be rollbacked.
115  return (false);
116  }
117 
118  // Replace it.
119  return (index.replace(subnet_it, subnet));
120  }
121 
132  template<typename SubnetPtrType, typename SubnetCollectionType>
133  static SubnetPtrType del(SubnetCollectionType& subnets,
134  const SubnetID& subnet_id) {
135  auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
136  auto subnet_it = index.find(subnet_id);
137  if (subnet_it == index.end()) {
138  isc_throw(BadValue, "unable to delete subnet " << subnet_id
139  << " from shared network. Subnet doesn't belong"
140  " to this shared network");
141  }
142  auto subnet = *subnet_it;
143  index.erase(subnet_it);
144  return (subnet);
145  }
146 
158  template<typename SubnetPtrType, typename SubnetCollectionType>
159  static SubnetPtrType getSubnet(const SubnetCollectionType& subnets,
160  const SubnetID& subnet_id) {
161  const auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
162  auto subnet_it = index.find(subnet_id);
163  if (subnet_it != index.cend()) {
164  return (*subnet_it);
165  }
166 
167  // Subnet not found.
168  return (SubnetPtrType());
169  }
170 
183  template<typename SubnetPtrType, typename SubnetCollectionType>
184  static SubnetPtrType getSubnet(const SubnetCollectionType& subnets,
185  const std::string& subnet_prefix) {
186  const auto& index = subnets.template get<SubnetPrefixIndexTag>();
187  auto subnet_it = index.find(subnet_prefix);
188  if (subnet_it != index.cend()) {
189  return (*subnet_it);
190  }
191 
192  // Subnet not found.
193  return (SubnetPtrType());
194  }
195 
235  template<typename SubnetPtrType, typename SubnetCollectionType>
236  static SubnetPtrType getNextSubnet(const SubnetCollectionType& subnets,
237  const SubnetPtrType& first_subnet,
238  const SubnetID& current_subnet) {
239  // It is ok to have a shared network without any subnets, but in this
240  // case there is nothing else we can return but null pointer.
241  if (subnets.empty()) {
242  return (SubnetPtrType());
243  }
244 
245  // Need to retrieve an iterator to the current subnet first. The
246  // subnet must exist in this container, thus we throw if the iterator
247  // is not found.
248  const auto& index = subnets.template get<SubnetSubnetIdIndexTag>();
249  auto subnet_it = index.find(current_subnet);
250  if (subnet_it == index.cend()) {
251  isc_throw(BadValue, "no such subnet " << current_subnet
252  << " within shared network");
253  }
254 
255  // Step to a next subnet.
256  if (++subnet_it == subnets.cend()) {
257  // If we reached the end of the container, start over from the
258  // beginning.
259  subnet_it = subnets.cbegin();
260  }
261 
262  // Check if we have made a full circle. If we did, return a null pointer
263  // to indicate that there are no more subnets.
264  if ((*subnet_it)->getID() == first_subnet->getID()) {
265  return (SubnetPtrType());
266  }
267 
268  // Got the next subnet, so return it.
269  return (*subnet_it);
270  }
271 
296  template<typename SubnetPtrType, typename SubnetCollectionType>
297  static SubnetPtrType getPreferredSubnet(const SubnetCollectionType& subnets,
298  const SubnetPtrType& selected_subnet,
299  const Lease::Type& lease_type) {
300 
301  auto preferred_subnet = selected_subnet;
302  for (auto s = subnets.begin(); s != subnets.end(); ++s) {
303  if (((*s)->getClientClass() == selected_subnet->getClientClass()) &&
304  ((*s)->getLastAllocatedTime(lease_type) >
305  selected_subnet->getLastAllocatedTime(lease_type))) {
306  preferred_subnet = (*s);
307  }
308  }
309 
310  return (preferred_subnet);
311  }
312 };
313 
314 } // end of anonymous namespace
315 
316 namespace isc {
317 namespace dhcp {
318 
320 SharedNetwork4::create(const std::string& name) {
321  return (boost::make_shared<SharedNetwork4>(name));
322 }
323 
324 void
325 SharedNetwork4::add(const Subnet4Ptr& subnet) {
326  Impl::add(subnets_, subnet);
327  // Associate the subnet with this network.
328  subnet->setSharedNetwork(shared_from_this());
329  subnet->setSharedNetworkName(name_);
330 }
331 
332 bool
333 SharedNetwork4::replace(const Subnet4Ptr& subnet) {
334  // Subnet must be non-null.
335  if (!subnet) {
336  isc_throw(BadValue, "null pointer specified when adding a subnet"
337  " to a shared network");
338  }
339  const Subnet4Ptr& old = getSubnet(subnet->getID());
340  bool ret = Impl::replace(subnets_, subnet);
341  if (ret) {
342  // Associate the subnet with this network.
343  subnet->setSharedNetwork(shared_from_this());
344  subnet->setSharedNetworkName(name_);
345  // Deassociate the previous subnet.
346  old->setSharedNetwork(NetworkPtr());
347  old->setSharedNetworkName("");
348  }
349  return (ret);
350 }
351 
352 void
353 SharedNetwork4::del(const SubnetID& subnet_id) {
354  Subnet4Ptr subnet = Impl::del<Subnet4Ptr>(subnets_, subnet_id);
355  subnet->setSharedNetwork(NetworkPtr());
356  subnet->setSharedNetworkName("");
357 }
358 
359 void
360 SharedNetwork4::delAll() {
361  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
362  (*subnet)->setSharedNetwork(NetworkPtr());
363  (*subnet)->setSharedNetworkName("");
364  }
365  subnets_.clear();
366 }
367 
369 SharedNetwork4::getSubnet(const SubnetID& subnet_id) const {
370  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_id));
371 }
372 
374 SharedNetwork4::getSubnet(const std::string& subnet_prefix) const {
375  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_prefix));
376 }
377 
379 SharedNetwork4::getNextSubnet(const Subnet4Ptr& first_subnet,
380  const SubnetID& current_subnet) const {
381  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
382 }
383 
385 SharedNetwork4::getPreferredSubnet(const Subnet4Ptr& selected_subnet) const {
386  return (Impl::getPreferredSubnet<Subnet4Ptr>(subnets_, selected_subnet,
387  Lease::TYPE_V4));
388 }
389 
390 bool
391 SharedNetwork4::subnetsIncludeMatchClientId(const Subnet4Ptr& first_subnet,
392  const ClientClasses& client_classes) {
393  for (Subnet4Ptr subnet = first_subnet; subnet;
394  subnet = subnet->getNextSubnet(first_subnet, client_classes)) {
395  if (subnet->getMatchClientId()) {
396  return (true);
397  }
398  }
399  return (false);
400 }
401 
403 SharedNetwork4::toElement() const {
404  ElementPtr map = Network4::toElement();
405 
406  // Set shared network name.
407  if (!name_.empty()) {
408  map->set("name", Element::create(name_));
409  }
410 
411  ElementPtr subnet4 = Element::createList();
412  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
413  subnet4->add((*subnet)->toElement());
414  }
415 
416  map->set("subnet4", subnet4);
417 
418  return (map);
419 }
420 
422 SharedNetwork6::create(const std::string& name) {
423  return (boost::make_shared<SharedNetwork6>(name));
424 }
425 
426 void
427 SharedNetwork6::add(const Subnet6Ptr& subnet) {
428  Impl::add(subnets_, subnet);
429  // Associate the subnet with this network.
430  subnet->setSharedNetwork(shared_from_this());
431  subnet->setSharedNetworkName(name_);
432 }
433 
434 bool
435 SharedNetwork6::replace(const Subnet6Ptr& subnet) {
436  // Subnet must be non-null.
437  if (!subnet) {
438  isc_throw(BadValue, "null pointer specified when adding a subnet"
439  " to a shared network");
440  }
441  const Subnet6Ptr& old = getSubnet(subnet->getID());
442  bool ret = Impl::replace(subnets_, subnet);
443  if (ret) {
444  // Associate the subnet with this network.
445  subnet->setSharedNetwork(shared_from_this());
446  subnet->setSharedNetworkName(name_);
447  // Deassociate the previous subnet.
448  old->setSharedNetwork(NetworkPtr());
449  old->setSharedNetworkName("");
450  }
451  return (ret);
452 }
453 
454 void
455 SharedNetwork6::del(const SubnetID& subnet_id) {
456  Subnet6Ptr subnet = Impl::del<Subnet6Ptr>(subnets_, subnet_id);
457  subnet->setSharedNetwork(NetworkPtr());
458  subnet->setSharedNetworkName("");
459 }
460 
461 void
462 SharedNetwork6::delAll() {
463  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
464  (*subnet)->setSharedNetwork(NetworkPtr());
465  }
466  subnets_.clear();
467 }
468 
470 SharedNetwork6::getSubnet(const SubnetID& subnet_id) const {
471  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_id));
472 }
473 
475 SharedNetwork6::getSubnet(const std::string& subnet_prefix) const {
476  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_prefix));
477 }
478 
480 SharedNetwork6::getNextSubnet(const Subnet6Ptr& first_subnet,
481  const SubnetID& current_subnet) const {
482  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
483 }
484 
486 SharedNetwork6::getPreferredSubnet(const Subnet6Ptr& selected_subnet,
487  const Lease::Type& lease_type) const {
488  return (Impl::getPreferredSubnet(subnets_, selected_subnet, lease_type));
489 }
490 
492 SharedNetwork6::toElement() const {
493  ElementPtr map = Network6::toElement();
494 
495  // Set shared network name.
496  if (!name_.empty()) {
497  map->set("name", Element::create(name_));
498  }
499 
500  ElementPtr subnet6 = Element::createList();
501  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
502  subnet6->add((*subnet)->toElement());
503  }
504 
505  map->set("subnet6", subnet6);
506 
507  return (map);
508 }
509 
510 } // end of namespace isc::dhcp
511 } // end of namespace isc
Exception thrown upon attempt to add subnet with an ID that belongs to the subnet that already exists...
Definition: subnet_id.h:35
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:40
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:522
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:262
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
Defines the logger used by the top-level component of kea-dhcp-ddns.
const Name & name_
Definition: dns/message.cc:693
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:222
Type
Type of lease or pool.
Definition: lease.h:50
A generic exception that is thrown if a function is called in a prohibited way.
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:670
Container for storing client class names.
Definition: classify.h:43
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24