Kea  2.1.7-git
shared_network.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2022 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  if (((*s)->getClientClass() == selected_subnet->getClientClass()) &&
308  ((*s)->getLastAllocatedTime(lease_type) >
309  selected_subnet->getLastAllocatedTime(lease_type))) {
310  preferred_subnet = (*s);
311  }
312  }
313 
314  return (preferred_subnet);
315  }
316 };
317 
318 } // end of anonymous namespace
319 
320 namespace isc {
321 namespace dhcp {
322 
324 SharedNetwork4::create(const std::string& name) {
325  return (boost::make_shared<SharedNetwork4>(name));
326 }
327 
328 void
329 SharedNetwork4::add(const Subnet4Ptr& subnet) {
330  Impl::add(subnets_, subnet);
331  // Associate the subnet with this network.
332  subnet->setSharedNetwork(shared_from_this());
333  subnet->setSharedNetworkName(name_);
334 }
335 
336 bool
337 SharedNetwork4::replace(const Subnet4Ptr& subnet) {
338  // Subnet must be non-null.
339  if (!subnet) {
340  isc_throw(BadValue, "null pointer specified when adding a subnet"
341  " to a shared network");
342  }
343  const Subnet4Ptr& old = getSubnet(subnet->getID());
344  bool ret = Impl::replace(subnets_, subnet);
345  if (ret) {
346  // Associate the subnet with this network.
347  subnet->setSharedNetwork(shared_from_this());
348  subnet->setSharedNetworkName(name_);
349  // Deassociate the previous subnet.
350  old->setSharedNetwork(NetworkPtr());
351  old->setSharedNetworkName("");
352  }
353  return (ret);
354 }
355 
356 void
357 SharedNetwork4::del(const SubnetID& subnet_id) {
358  Subnet4Ptr subnet = Impl::del<Subnet4Ptr>(subnets_, subnet_id);
359  subnet->setSharedNetwork(NetworkPtr());
360  subnet->setSharedNetworkName("");
361 }
362 
363 void
364 SharedNetwork4::delAll() {
365  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
366  (*subnet)->setSharedNetwork(NetworkPtr());
367  (*subnet)->setSharedNetworkName("");
368  }
369  subnets_.clear();
370 }
371 
373 SharedNetwork4::getSubnet(const SubnetID& subnet_id) const {
374  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_id));
375 }
376 
378 SharedNetwork4::getSubnet(const std::string& subnet_prefix) const {
379  return (Impl::getSubnet<Subnet4Ptr>(subnets_, subnet_prefix));
380 }
381 
383 SharedNetwork4::getNextSubnet(const Subnet4Ptr& first_subnet,
384  const SubnetID& current_subnet) const {
385  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
386 }
387 
389 SharedNetwork4::getPreferredSubnet(const Subnet4Ptr& selected_subnet) const {
390  return (Impl::getPreferredSubnet<Subnet4Ptr>(subnets_, selected_subnet,
391  Lease::TYPE_V4));
392 }
393 
394 bool
395 SharedNetwork4::subnetsIncludeMatchClientId(const Subnet4Ptr& first_subnet,
396  const ClientClasses& client_classes) {
397  for (Subnet4Ptr subnet = first_subnet; subnet;
398  subnet = subnet->getNextSubnet(first_subnet, client_classes)) {
399  if (subnet->getMatchClientId()) {
400  return (true);
401  }
402  }
403  return (false);
404 }
405 
407 SharedNetwork4::toElement() const {
408  ElementPtr map = Network4::toElement();
409 
410  // Set shared network name.
411  if (!name_.empty()) {
412  map->set("name", Element::create(name_));
413  }
414 
415  ElementPtr subnet4 = Element::createList();
416  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
417  subnet4->add((*subnet)->toElement());
418  }
419 
420  map->set("subnet4", subnet4);
421 
422  return (map);
423 }
424 
426 SharedNetwork6::create(const std::string& name) {
427  return (boost::make_shared<SharedNetwork6>(name));
428 }
429 
430 void
431 SharedNetwork6::add(const Subnet6Ptr& subnet) {
432  Impl::add(subnets_, subnet);
433  // Associate the subnet with this network.
434  subnet->setSharedNetwork(shared_from_this());
435  subnet->setSharedNetworkName(name_);
436 }
437 
438 bool
439 SharedNetwork6::replace(const Subnet6Ptr& subnet) {
440  // Subnet must be non-null.
441  if (!subnet) {
442  isc_throw(BadValue, "null pointer specified when adding a subnet"
443  " to a shared network");
444  }
445  const Subnet6Ptr& old = getSubnet(subnet->getID());
446  bool ret = Impl::replace(subnets_, subnet);
447  if (ret) {
448  // Associate the subnet with this network.
449  subnet->setSharedNetwork(shared_from_this());
450  subnet->setSharedNetworkName(name_);
451  // Deassociate the previous subnet.
452  old->setSharedNetwork(NetworkPtr());
453  old->setSharedNetworkName("");
454  }
455  return (ret);
456 }
457 
458 void
459 SharedNetwork6::del(const SubnetID& subnet_id) {
460  Subnet6Ptr subnet = Impl::del<Subnet6Ptr>(subnets_, subnet_id);
461  subnet->setSharedNetwork(NetworkPtr());
462  subnet->setSharedNetworkName("");
463 }
464 
465 void
466 SharedNetwork6::delAll() {
467  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
468  (*subnet)->setSharedNetwork(NetworkPtr());
469  }
470  subnets_.clear();
471 }
472 
474 SharedNetwork6::getSubnet(const SubnetID& subnet_id) const {
475  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_id));
476 }
477 
479 SharedNetwork6::getSubnet(const std::string& subnet_prefix) const {
480  return (Impl::getSubnet<Subnet6Ptr>(subnets_, subnet_prefix));
481 }
482 
484 SharedNetwork6::getNextSubnet(const Subnet6Ptr& first_subnet,
485  const SubnetID& current_subnet) const {
486  return (Impl::getNextSubnet(subnets_, first_subnet, current_subnet));
487 }
488 
490 SharedNetwork6::getPreferredSubnet(const Subnet6Ptr& selected_subnet,
491  const Lease::Type& lease_type) const {
492  return (Impl::getPreferredSubnet(subnets_, selected_subnet, lease_type));
493 }
494 
496 SharedNetwork6::toElement() const {
497  ElementPtr map = Network6::toElement();
498 
499  // Set shared network name.
500  if (!name_.empty()) {
501  map->set("name", Element::create(name_));
502  }
503 
504  ElementPtr subnet6 = Element::createList();
505  for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
506  subnet6->add((*subnet)->toElement());
507  }
508 
509  map->set("subnet6", subnet6);
510 
511  return (map);
512 }
513 
514 } // end of namespace isc::dhcp
515 } // 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:41
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:524
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:281
#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:45
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:672
Container for storing client class names.
Definition: classify.h:68
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24