Kea  2.3.5-git
shared_network.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2023 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 
300  template<typename SubnetPtrType, typename SubnetCollectionType>
301  static SubnetPtrType getPreferredSubnet(const SubnetCollectionType& subnets,
302  const SubnetPtrType& selected_subnet,
303  const Lease::Type& lease_type) {
304 
305  auto preferred_subnet = selected_subnet;
306  for (auto s = subnets.begin(); s != subnets.end(); ++s) {
307  // It doesn't make sense to check the subnet against itself.
308  if (preferred_subnet == (*s)) {
309  continue;
310  }
311  if ((*s)->getClientClass().get() != selected_subnet->getClientClass().get()) {
312  continue;
313  }
314  auto current_subnet_state = (*s)->getAllocationState(lease_type);
315  if (!current_subnet_state) {
316  continue;
317  }
318  auto preferred_subnet_state = preferred_subnet->getAllocationState(lease_type);
319  if (!preferred_subnet_state) {
320  continue;
321  }
322  // The currently checked subnet has more recent time than the
323  // currently preferred subnet. Update the preferred subnet
324  // instance.
325  if (current_subnet_state->getLastAllocatedTime() >
326  preferred_subnet_state->getLastAllocatedTime()) {
327  preferred_subnet = (*s);
328  }
329  }
330  return (preferred_subnet);
331  }
332 };
333 
334 } // end of anonymous namespace
335 
336 namespace isc {
337 namespace dhcp {
338 
340 SharedNetwork4::create(const std::string& name) {
341  return (boost::make_shared<SharedNetwork4>(name));
342 }
343 
344 void
345 SharedNetwork4::add(const Subnet4Ptr& subnet) {
346  Impl::add(subnets_, subnet);
347  // Associate the subnet with this network.
348  subnet->setSharedNetwork(shared_from_this());
349  subnet->setSharedNetworkName(name_);
350 }
351 
352 bool
353 SharedNetwork4::replace(const Subnet4Ptr& subnet) {
354  // Subnet must be non-null.
355  if (!subnet) {
356  isc_throw(BadValue, "null pointer specified when adding a subnet"
357  " to a shared network");
358  }
359  const Subnet4Ptr& old = getSubnet(subnet->getID());
360  bool ret = Impl::replace(subnets_, subnet);
361  if (ret) {
362  // Associate the subnet with this network.
363  subnet->setSharedNetwork(shared_from_this());
364  subnet->setSharedNetworkName(name_);
365  // Deassociate the previous subnet.
366  old->setSharedNetwork(NetworkPtr());
367  old->setSharedNetworkName("");
368  }
369  return (ret);
370 }
371 
372 void
373 SharedNetwork4::del(const SubnetID& subnet_id) {
374  Subnet4Ptr subnet = Impl::del<Subnet4Ptr>(subnets_, subnet_id);
375  subnet->setSharedNetwork(NetworkPtr());
376  subnet->setSharedNetworkName("");
377 }
378 
379 void
380 SharedNetwork4::delAll() {
381  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
382  (*subnet)->setSharedNetwork(NetworkPtr());
383  (*subnet)->setSharedNetworkName("");
384  }
385  subnets_.clear();
386 }
387 
389 SharedNetwork4::getSubnet(const SubnetID& subnet_id) const {
390  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_id));
391 }
392 
394 SharedNetwork4::getSubnet(const std::string& subnet_prefix) const {
395  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_prefix));
396 }
397 
399 SharedNetwork4::getNextSubnet(const Subnet4Ptr& first_subnet,
400  const SubnetID& current_subnet) const {
401  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
402 }
403 
405 SharedNetwork4::getPreferredSubnet(const Subnet4Ptr& selected_subnet) const {
406  return (Impl::getPreferredSubnet<Subnet4Ptr>(subnets_, selected_subnet,
407  Lease::TYPE_V4));
408 }
409 
410 bool
411 SharedNetwork4::subnetsIncludeMatchClientId(const Subnet4Ptr& first_subnet,
412  const ClientClasses& client_classes) {
413  for (Subnet4Ptr subnet = first_subnet; subnet;
414  subnet = subnet->getNextSubnet(first_subnet, client_classes)) {
415  if (subnet->getMatchClientId()) {
416  return (true);
417  }
418  }
419  return (false);
420 }
421 
423 SharedNetwork4::toElement() const {
424  ElementPtr map = Network4::toElement();
425 
426  // Set shared network name.
427  if (!name_.empty()) {
428  map->set("name", Element::create(name_));
429  }
430 
431  ElementPtr subnet4 = Element::createList();
432  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
433  subnet4->add((*subnet)->toElement());
434  }
435 
436  map->set("subnet4", subnet4);
437 
438  return (map);
439 }
440 
442 SharedNetwork6::create(const std::string& name) {
443  return (boost::make_shared<SharedNetwork6>(name));
444 }
445 
446 void
447 SharedNetwork6::add(const Subnet6Ptr& subnet) {
448  Impl::add(subnets_, subnet);
449  // Associate the subnet with this network.
450  subnet->setSharedNetwork(shared_from_this());
451  subnet->setSharedNetworkName(name_);
452 }
453 
454 bool
455 SharedNetwork6::replace(const Subnet6Ptr& subnet) {
456  // Subnet must be non-null.
457  if (!subnet) {
458  isc_throw(BadValue, "null pointer specified when adding a subnet"
459  " to a shared network");
460  }
461  const Subnet6Ptr& old = getSubnet(subnet->getID());
462  bool ret = Impl::replace(subnets_, subnet);
463  if (ret) {
464  // Associate the subnet with this network.
465  subnet->setSharedNetwork(shared_from_this());
466  subnet->setSharedNetworkName(name_);
467  // Deassociate the previous subnet.
468  old->setSharedNetwork(NetworkPtr());
469  old->setSharedNetworkName("");
470  }
471  return (ret);
472 }
473 
474 void
475 SharedNetwork6::del(const SubnetID& subnet_id) {
476  Subnet6Ptr subnet = Impl::del<Subnet6Ptr>(subnets_, subnet_id);
477  subnet->setSharedNetwork(NetworkPtr());
478  subnet->setSharedNetworkName("");
479 }
480 
481 void
482 SharedNetwork6::delAll() {
483  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
484  (*subnet)->setSharedNetwork(NetworkPtr());
485  }
486  subnets_.clear();
487 }
488 
490 SharedNetwork6::getSubnet(const SubnetID& subnet_id) const {
491  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_id));
492 }
493 
495 SharedNetwork6::getSubnet(const std::string& subnet_prefix) const {
496  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_prefix));
497 }
498 
500 SharedNetwork6::getNextSubnet(const Subnet6Ptr& first_subnet,
501  const SubnetID& current_subnet) const {
502  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
503 }
504 
506 SharedNetwork6::getPreferredSubnet(const Subnet6Ptr& selected_subnet,
507  const Lease::Type& lease_type) const {
508  return (Impl::getPreferredSubnet(subnets_, selected_subnet, lease_type));
509 }
510 
512 SharedNetwork6::toElement() const {
513  ElementPtr map = Network6::toElement();
514 
515  // Set shared network name.
516  if (!name_.empty()) {
517  map->set("name", Element::create(name_));
518  }
519 
520  ElementPtr subnet6 = Element::createList();
521  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
522  subnet6->add((*subnet)->toElement());
523  }
524 
525  map->set("subnet6", subnet6);
526 
527  return (map);
528 }
529 
530 } // end of namespace isc::dhcp
531 } // 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:36
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:70
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:477
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:286
#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-lfc.
const Name & name_
Definition: dns/message.cc:693
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
Type
Type of lease or pool.
Definition: lease.h:46
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:635
Container for storing client class names.
Definition: classify.h:108
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25