Kea  2.3.3-git
lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-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 
9 #include <dhcp/libdhcp++.h>
10 #include <dhcp/option_custom.h>
11 #include <dhcpsrv/cfgmgr.h>
12 #include <dhcpsrv/dhcpsrv_log.h>
13 #include <dhcpsrv/lease_mgr.h>
14 #include <exceptions/exceptions.h>
15 #include <stats/stats_mgr.h>
16 #include <util/encode/hex.h>
17 
18 #include <boost/foreach.hpp>
19 #include <boost/algorithm/string.hpp>
20 
21 #include <algorithm>
22 #include <iostream>
23 #include <iterator>
24 #include <map>
25 #include <sstream>
26 #include <string>
27 
28 #include <time.h>
29 
30 using namespace isc::asiolink;
31 using namespace isc::data;
32 using namespace isc::db;
33 using namespace isc::dhcp;
34 using namespace isc::util;
35 using namespace std;
36 
37 namespace isc {
38 namespace dhcp {
39 
40 IOServicePtr LeaseMgr::io_service_ = IOServicePtr();
41 
42 LeasePageSize::LeasePageSize(const size_t page_size)
43  : page_size_(page_size) {
44 
45  if (page_size_ == 0) {
46  isc_throw(OutOfRange, "page size of retrieved leases must not be 0");
47  }
48 
49  if (page_size_ > std::numeric_limits<uint32_t>::max()) {
50  isc_throw(OutOfRange, "page size of retrieved leases must not be greater than "
51  << std::numeric_limits<uint32_t>::max());
52  }
53 }
54 
57  uint32_t iaid, SubnetID subnet_id) const {
58  Lease6Collection col = getLeases6(type, duid, iaid, subnet_id);
59 
60  if (col.size() > 1) {
61  isc_throw(MultipleRecords, "More than one lease found for type "
62  << static_cast<int>(type) << ", duid "
63  << duid.toText() << ", iaid " << iaid
64  << " and subnet-id " << subnet_id);
65  }
66  if (col.empty()) {
67  return (Lease6Ptr());
68  }
69  return (*col.begin());
70 }
71 
72 void
74  using namespace stats;
75 
76  StatsMgr& stats_mgr = StatsMgr::instance();
77 
78  LeaseStatsQueryPtr query = startLeaseStatsQuery4();
79  if (!query) {
81  return;
82  }
83 
84  // Zero out the global stats.
85  // Cumulative counters ("reclaimed-declined-addresses", "reclaimed-leases",
86  // "cumulative-assigned-addresses") never get zeroed.
87  int64_t zero = 0;
88  stats_mgr.setValue("declined-addresses", zero);
89 
90  // Create if it does not exit reclaimed declined leases global stats.
91  if (!stats_mgr.getObservation("reclaimed-declined-addresses")) {
92  stats_mgr.setValue("reclaimed-declined-addresses", zero);
93  }
94 
95  // Create if it does not exit reclaimed leases global stats.
96  if (!stats_mgr.getObservation("reclaimed-leases")) {
97  stats_mgr.setValue("reclaimed-leases", zero);
98  }
99 
100  // Create if it does not exit cumulative global stats.
101  if (!stats_mgr.getObservation("cumulative-assigned-addresses")) {
102  stats_mgr.setValue("cumulative-assigned-addresses", zero);
103  }
104 
105  // Clear subnet level stats. This ensures we don't end up with corner
106  // cases that leave stale values in place.
107  const Subnet4Collection* subnets =
108  CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
109 
110  for (Subnet4Collection::const_iterator subnet = subnets->begin();
111  subnet != subnets->end(); ++subnet) {
112  SubnetID subnet_id = (*subnet)->getID();
113  stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
114  "assigned-addresses"),
115  zero);
116 
117  stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
118  "declined-addresses"),
119  zero);
120 
121  if (!stats_mgr.getObservation(
122  StatsMgr::generateName("subnet", subnet_id,
123  "reclaimed-declined-addresses"))) {
124  stats_mgr.setValue(
125  StatsMgr::generateName("subnet", subnet_id,
126  "reclaimed-declined-addresses"),
127  zero);
128  }
129 
130  if (!stats_mgr.getObservation(
131  StatsMgr::generateName("subnet", subnet_id,
132  "reclaimed-leases"))) {
133  stats_mgr.setValue(
134  StatsMgr::generateName("subnet", subnet_id,
135  "reclaimed-leases"),
136  zero);
137  }
138  }
139 
140  // Get counts per state per subnet. Iterate over the result set
141  // updating the subnet and global values.
142  LeaseStatsRow row;
143  while (query->getNextRow(row)) {
144  if (row.lease_state_ == Lease::STATE_DEFAULT) {
145  // Add to subnet level value.
146  stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_,
147  "assigned-addresses"),
148  row.state_count_);
149  } else if (row.lease_state_ == Lease::STATE_DECLINED) {
150  // Set subnet level value.
151  stats_mgr.setValue(StatsMgr::generateName("subnet", row.subnet_id_,
152  "declined-addresses"),
153  row.state_count_);
154 
155  // Add to the global value.
156  stats_mgr.addValue("declined-addresses", row.state_count_);
157 
158  // Add to subnet level value.
159  // Declined leases also count as assigned.
160  stats_mgr.addValue(StatsMgr::generateName("subnet", row.subnet_id_,
161  "assigned-addresses"),
162  row.state_count_);
163  }
164  }
165 }
166 
168  : first_subnet_id_(0), last_subnet_id_(0), select_mode_(ALL_SUBNETS) {
169 }
170 
172  : first_subnet_id_(subnet_id), last_subnet_id_(0),
173  select_mode_(SINGLE_SUBNET) {
174 
175  if (first_subnet_id_ == 0) {
176  isc_throw(BadValue, "LeaseStatsQuery: subnet_id_ must be > 0");
177  }
178 }
179 
181  const SubnetID& last_subnet_id)
182  : first_subnet_id_(first_subnet_id), last_subnet_id_(last_subnet_id),
183  select_mode_(SUBNET_RANGE) {
184 
185  if (first_subnet_id_ == 0) {
186  isc_throw(BadValue, "LeaseStatsQuery: first_subnet_id_ must be > 0");
187  }
188 
189  if (last_subnet_id_ == 0) {
190  isc_throw(BadValue, "LeaseStatsQuery: last_subnet_id_ must be > 0");
191  }
192 
195  "LeaseStatsQuery: last_subnet_id_must be > first_subnet_id_");
196  }
197 }
198 
201  return(LeaseStatsQueryPtr());
202 }
203 
206  return(LeaseStatsQueryPtr());
207 }
208 
211  const SubnetID& /* last_subnet_id */) {
212  return(LeaseStatsQueryPtr());
213 }
214 
215 bool
217  return (false);
218 }
219 
220 void
222  using namespace stats;
223 
224  StatsMgr& stats_mgr = StatsMgr::instance();
225 
226  LeaseStatsQueryPtr query = startLeaseStatsQuery6();
227  if (!query) {
229  return;
230  }
231 
232  // Zero out the global stats.
233  // Cumulative counters ("reclaimed-declined-addresses", "reclaimed-leases",
234  // "cumulative-assigned-nas", "cumulative-assigned-pds") never get zeroed.
235  int64_t zero = 0;
236  stats_mgr.setValue("declined-addresses", zero);
237 
238  if (!stats_mgr.getObservation("reclaimed-declined-addresses")) {
239  stats_mgr.setValue("reclaimed-declined-addresses", zero);
240  }
241 
242  if (!stats_mgr.getObservation("reclaimed-leases")) {
243  stats_mgr.setValue("reclaimed-leases", zero);
244  }
245 
246  // Create if it does not exit cumulative nas global stats.
247  if (!stats_mgr.getObservation("cumulative-assigned-nas")) {
248  stats_mgr.setValue("cumulative-assigned-nas", zero);
249  }
250 
251  // Create if it does not exit cumulative pds global stats.
252  if (!stats_mgr.getObservation("cumulative-assigned-pds")) {
253  stats_mgr.setValue("cumulative-assigned-pds", zero);
254  }
255 
256  // Clear subnet level stats. This ensures we don't end up with corner
257  // cases that leave stale values in place.
258  const Subnet6Collection* subnets =
259  CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
260 
261  for (Subnet6Collection::const_iterator subnet = subnets->begin();
262  subnet != subnets->end(); ++subnet) {
263  SubnetID subnet_id = (*subnet)->getID();
264  stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
265  "assigned-nas"),
266  zero);
267 
268  stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
269  "declined-addresses"),
270  zero);
271 
272  if (!stats_mgr.getObservation(
273  StatsMgr::generateName("subnet", subnet_id,
274  "reclaimed-declined-addresses"))) {
275  stats_mgr.setValue(
276  StatsMgr::generateName("subnet", subnet_id,
277  "reclaimed-declined-addresses"),
278  zero);
279  }
280 
281  stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
282  "assigned-pds"),
283  zero);
284 
285  if (!stats_mgr.getObservation(
286  StatsMgr::generateName("subnet", subnet_id,
287  "reclaimed-leases"))) {
288  stats_mgr.setValue(
289  StatsMgr::generateName("subnet", subnet_id,
290  "reclaimed-leases"),
291  zero);
292  }
293  }
294 
295  // Get counts per state per subnet. Iterate over the result set
296  // updating the subnet and global values.
297  LeaseStatsRow row;
298  while (query->getNextRow(row)) {
299  switch(row.lease_type_) {
300  case Lease::TYPE_NA:
301  if (row.lease_state_ == Lease::STATE_DEFAULT) {
302  // Add to subnet level value.
303  stats_mgr.addValue(StatsMgr::
304  generateName("subnet", row.subnet_id_,
305  "assigned-nas"),
306  row.state_count_);
307  } else if (row.lease_state_ == Lease::STATE_DECLINED) {
308  // Set subnet level value.
309  stats_mgr.setValue(StatsMgr::
310  generateName("subnet", row.subnet_id_,
311  "declined-addresses"),
312  row.state_count_);
313 
314  // Add to the global value.
315  stats_mgr.addValue("declined-addresses", row.state_count_);
316 
317  // Add to subnet level value.
318  // Declined leases also count as assigned.
319  stats_mgr.addValue(StatsMgr::
320  generateName("subnet", row.subnet_id_,
321  "assigned-nas"),
322  row.state_count_);
323  }
324  break;
325 
326  case Lease::TYPE_PD:
327  if (row.lease_state_ == Lease::STATE_DEFAULT) {
328  // Set subnet level value.
329  stats_mgr.setValue(StatsMgr::
330  generateName("subnet", row.subnet_id_,
331  "assigned-pds"),
332  row.state_count_);
333  }
334  break;
335 
336  default:
337  // We dont' support TYPE_TAs yet
338  break;
339  }
340  }
341 }
342 
345  return(LeaseStatsQueryPtr());
346 }
347 
350  return(LeaseStatsQueryPtr());
351 }
352 
355  const SubnetID& /* last_subnet_id */) {
356  return(LeaseStatsQueryPtr());
357 }
358 
359 std::string
361  isc_throw(NotImplemented, "LeaseMgr::getDBVersion() called");
362 }
363 
364 void
366  std::string extended_info_tables;
367  try {
368  extended_info_tables = parameters.at("extended-info-tables");
369  } catch (const exception&) {
370  extended_info_tables = "false";
371  }
372  // If extended_info_tables is 'true' we will enable them.
373  if (extended_info_tables == "true") {
374  setExtendedInfoTablesEnabled(true);
375  }
376 }
377 
378 bool
381  static OptionDefinitionPtr rai_def;
382 
383  bool changed = false;
384  if (!lease) {
385  return (changed);
386  }
387 
389  return (changed);
390  }
391 
392  ConstElementPtr user_context = lease->getContext();
393  if (!user_context) {
394  return (changed);
395  }
396 
397  if (!rai_def) {
400  }
401 
402  if (!rai_def) {
403  // The definition is set when libdhcp++ is loaded so it is impossible
404  // to not be able to get it... so should not happen!
405  isc_throw(Unexpected, "can't find RAI option definition?!");
406  }
407 
409  ConstElementPtr extended_info;
410  ElementPtr mutable_user_context;
411  ElementPtr mutable_isc;
412  string verifying = "";
413  bool removed_extended_info = false;
414 
415  try {
416  verifying = "user context";
417  if (user_context->getType() != Element::map) {
418  isc_throw(BadValue, "user context is not a map");
419  }
420  if (user_context->empty()) {
421  changed = true;
422  lease->setContext(ConstElementPtr());
423  return (changed);
424  }
425 
426  verifying = "isc";
427  isc = user_context->get("ISC");
428  if (!isc) {
429  return (changed);
430  }
431  mutable_user_context =
432  boost::const_pointer_cast<Element>(user_context);
433  if (!mutable_user_context) {
434  // Should not happen...
435  mutable_user_context = copy(user_context, 0);
436  lease->setContext(mutable_user_context);
437  }
438 
439  if (isc->getType() != Element::map) {
440  isc_throw(BadValue, "ISC entry is not a map");
441  }
442  if (isc->empty()) {
443  changed = true;
444  mutable_user_context->remove("ISC");
445  if (mutable_user_context->empty()) {
446  lease->setContext(ConstElementPtr());
447  }
448  return (changed);
449  }
450 
451  verifying = "relay-agent-info";
452  extended_info = isc->get("relay-agent-info");
453  if (!extended_info) {
454  return (changed);
455  }
456  mutable_isc = boost::const_pointer_cast<Element>(isc);
457  if (!mutable_isc) {
458  // Should not happen...
459  mutable_isc = copy(isc, 0);
460  mutable_user_context->set("ISC", mutable_isc);
461  }
462 
463  if (extended_info->getType() == Element::string) {
464  // Upgrade
465  changed = true;
466  ElementPtr upgraded = Element::createMap();
467  upgraded->set("sub-options", extended_info);
468  mutable_isc->set("relay-agent-info", upgraded);
469 
470  // Try to decode sub-options.
471  verifying = "rai";
472  string rai_hex = extended_info->stringValue();
473  vector<uint8_t> rai_data;
474  str::decodeFormattedHexString(rai_hex, rai_data);
475  OptionCustomPtr rai(new OptionCustom(*rai_def, Option::V4, rai_data));
476  if (!rai) {
477  isc_throw(BadValue, "can't create RAI option");
478  }
479 
480  OptionPtr remote_id = rai->getOption(RAI_OPTION_REMOTE_ID);
481  if (remote_id) {
482  vector<uint8_t> bytes = remote_id->toBinary(false);
483  if (bytes.size() > 0) {
484  upgraded->set("remote-id",
486  }
487  }
488 
489  OptionPtr relay_id = rai->getOption(RAI_OPTION_RELAY_ID);
490  if (relay_id) {
491  vector<uint8_t> bytes = relay_id->toBinary(false);
492  if (bytes.size() > 0) {
493  upgraded->set("relay-id",
495  }
496  }
497 
500  .arg(lease->addr_.toText());
501  return (changed);
502  } else if (extended_info->getType() != Element::map) {
503  mutable_isc->remove("relay-agent-info");
504  removed_extended_info = true;
505  isc_throw(BadValue, "relay-agent-info is not a map or a string");
506  }
507 
509  return (changed);
510  }
511 
512  // Try to decode sub-options.
513  ConstElementPtr sub_options = extended_info->get("sub-options");
514  if (sub_options) {
515  verifying = "sub-options";
516  if (sub_options->getType() != Element::string) {
517  mutable_isc->remove("relay-agent-info");
518  removed_extended_info = true;
519  isc_throw(BadValue, "sub-options is not a string");
520  }
521  string rai_hex = sub_options->stringValue();
522  vector<uint8_t> rai_data;
523  str::decodeFormattedHexString(rai_hex, rai_data);
524  }
525 
526  ConstElementPtr remote_id = extended_info->get("remote-id");
527  if (remote_id) {
528  verifying = "remote-id";
529  if (remote_id->getType() != Element::string) {
530  mutable_isc->remove("relay-agent-info");
531  removed_extended_info = true;
532  isc_throw(BadValue, "remote-id is not a string");
533  }
534  string remote_id_hex = remote_id->stringValue();
535  vector<uint8_t> remote_id_data;
536  encode::decodeHex(remote_id_hex, remote_id_data);
537  if (remote_id_data.empty()) {
538  mutable_isc->remove("relay-agent-info");
539  removed_extended_info = true;
540  isc_throw(BadValue, "remote-id is empty");
541  }
542  }
543 
544  ConstElementPtr relay_id = extended_info->get("relay-id");
545  if (relay_id) {
546  verifying = "relay-id";
547  if (relay_id->getType() != Element::string) {
548  mutable_isc->remove("relay-agent-info");
549  removed_extended_info = true;
550  isc_throw(BadValue, "relay-id is not a string");
551  }
552  string relay_id_hex = relay_id->stringValue();
553  vector<uint8_t> relay_id_data;
554  encode::decodeHex(relay_id_hex, relay_id_data);
555  if (relay_id_data.empty()) {
556  mutable_isc->remove("relay-agent-info");
557  removed_extended_info = true;
558  isc_throw(BadValue, "relay-id is empty");
559  }
560  }
561 
563  return (changed);
564  }
565 
566  verifying = "relay-agent-info";
567  for (auto elem : extended_info->mapValue()) {
568  if ((elem.first != "sub-options") &&
569  (elem.first != "remote-id") &&
570  (elem.first != "relay-id") &&
571  (elem.first != "comment")) {
572  mutable_isc->remove("relay-agent-info");
573  removed_extended_info = true;
574  isc_throw(BadValue, "spurious '" << elem.first <<
575  "' entry in relay-agent-info");
576  }
577  }
578 
579  return (changed);
580  } catch (const exception& ex) {
581  ostringstream err;
582  err << "in " << verifying << " a problem was found: " << ex.what();
585  .arg(lease->addr_.toText())
586  .arg(err.str());
587 
588  changed = true;
589  if (verifying == "user context") {
590  lease->setContext(ConstElementPtr());
591  } else if (verifying == "isc") {
592  mutable_user_context->remove("ISC");
593  if (mutable_user_context->empty()) {
594  lease->setContext(ConstElementPtr());
595  }
596  } else {
597  if (!removed_extended_info) {
598  mutable_isc->remove("relay-agent-info");
599  }
600  if (mutable_isc->empty()) {
601  mutable_user_context->remove("ISC");
602  if (mutable_user_context->empty()) {
603  lease->setContext(ConstElementPtr());
604  }
605  }
606  }
607  return (changed);
608  }
609 }
610 
611 bool
614  bool changed = false;
615  if (!lease) {
616  return (changed);
617  }
618 
620  return (changed);
621  }
622 
623  ConstElementPtr user_context = lease->getContext();
624  if (!user_context) {
625  return (changed);
626  }
627 
629  ConstElementPtr relay_info;
630  ElementPtr mutable_user_context;
631  ElementPtr mutable_isc;
632  string verifying = "";
633  bool removed_relay_info = false;
634  bool upgraded = false;
635  bool have_both = false;
636  int i = -1;
637 
638  try {
639  verifying = "user context";
640  if (user_context->getType() != Element::map) {
641  isc_throw(BadValue, "user context is not a map");
642  }
643  if (user_context->empty()) {
644  changed = true;
645  lease->setContext(ConstElementPtr());
646  return (changed);
647  }
648 
649  verifying = "isc";
650  isc = user_context->get("ISC");
651  if (!isc) {
652  return (changed);
653  }
654  mutable_user_context =
655  boost::const_pointer_cast<Element>(user_context);
656  if (!mutable_user_context) {
657  // Should not happen...
658  mutable_user_context = copy(user_context, 0);
659  lease->setContext(mutable_user_context);
660  }
661 
662  if (isc->getType() != Element::map) {
663  isc_throw(BadValue, "ISC entry is not a map");
664  }
665  if (isc->empty()) {
666  changed = true;
667  mutable_user_context->remove("ISC");
668  if (mutable_user_context->empty()) {
669  lease->setContext(ConstElementPtr());
670  }
671  return (changed);
672  }
673  mutable_isc = boost::const_pointer_cast<Element>(isc);
674  if (!mutable_isc) {
675  // Should not happen...
676  mutable_isc = copy(isc, 0);
677  mutable_user_context->set("ISC", mutable_isc);
678  }
679 
680  relay_info = mutable_isc->get("relays");
681  if (relay_info && isc->contains("relay-info")) {
682  changed = true;
683  mutable_isc->remove("relays");
684  have_both = true;
685  relay_info.reset();
686  }
687  if (relay_info) {
688  // Upgrade
689  changed = true;
690  upgraded = true;
691  verifying = "relays";
692  mutable_isc->set("relay-info", relay_info);
693  mutable_isc->remove("relays");
694 
695  if (relay_info->getType() != Element::list) {
696  mutable_isc->remove("relay-info");
697  removed_relay_info = true;
698  isc_throw(BadValue, "relays is not a list");
699  }
700  if (relay_info->empty()) {
701  mutable_isc->remove("relay-info");
702  removed_relay_info = true;
703  isc_throw(BadValue, "relays is empty");
704  }
705 
706  verifying = "relay";
707  for (i = 0; i < relay_info->size(); ++i) {
708  ElementPtr relay = relay_info->getNonConst(i);
709  if (!relay) {
710  mutable_isc->remove("relay-info");
711  removed_relay_info = true;
712  isc_throw(BadValue, "null relay#" << i);
713  }
714  if (relay->getType() != Element::map) {
715  mutable_isc->remove("relay-info");
716  removed_relay_info = true;
717  isc_throw(BadValue, "relay#" << i << " is not a map");
718  }
719 
720  // Try to decode options.
721  ConstElementPtr options = relay->get("options");
722  if (!options) {
723  continue;
724  }
725 
726  verifying = "options";
727  if (options->getType() != Element::string) {
728  mutable_isc->remove("relay-info");
729  removed_relay_info = true;
730  isc_throw(BadValue, "options is not a string");
731  }
732  string options_hex = options->stringValue();
733  vector<uint8_t> options_data;
734  str::decodeFormattedHexString(options_hex, options_data);
735  OptionCollection opts;
736  LibDHCP::unpackOptions6(options_data, DHCP6_OPTION_SPACE, opts);
737 
738  auto remote_id_it = opts.find(D6O_REMOTE_ID);
739  if (remote_id_it != opts.end()) {
740  OptionPtr remote_id = remote_id_it->second;
741  if (remote_id) {
742  vector<uint8_t> bytes = remote_id->toBinary(false);
743  if (bytes.size() > 0) {
744  relay->set("remote-id",
746  }
747  }
748  }
749 
750  auto relay_id_it = opts.find(D6O_RELAY_ID);
751  if (relay_id_it != opts.end()) {
752  OptionPtr relay_id = relay_id_it->second;
753  if (relay_id) {
754  vector<uint8_t> bytes = relay_id->toBinary(false);
755  if (bytes.size() > 0) {
756  relay->set("relay-id",
758  }
759  }
760  }
761  }
762  }
763 
764  verifying = (upgraded ? "relays" : "relay-info");
765  i = -1;
766  relay_info = mutable_isc->get("relay-info");
767  if (!relay_info) {
768  return (changed);
769  }
770  if (!upgraded && (relay_info->getType() != Element::list)) {
771  mutable_isc->remove("relay-info");
772  removed_relay_info = true;
773  isc_throw(BadValue, "relay-info is not a list");
774  }
775  if (!upgraded && relay_info->empty()) {
776  mutable_isc->remove("relay-info");
777  removed_relay_info = true;
778  isc_throw(BadValue, "relay-info is empty");
779  }
780 
781  verifying = "relay";
782  for (i = 0; i < relay_info->size(); ++i) {
783  ElementPtr relay = relay_info->getNonConst(i);
784  if (!upgraded && !relay) {
785  mutable_isc->remove("relay-info");
786  removed_relay_info = true;
787  isc_throw(BadValue, "null relay#" << i);
788  }
789  if (!upgraded && (relay->getType() != Element::map)) {
790  mutable_isc->remove("relay-info");
791  removed_relay_info = true;
792  isc_throw(BadValue, "relay#" << i << " is not a map");
793  }
794 
795  ConstElementPtr options = relay->get("options");
796  if (!upgraded && options) {
797  // Try to decode options.
798  verifying = "options";
799  if (options->getType() != Element::string) {
800  mutable_isc->remove("relay-info");
801  removed_relay_info = true;
802  isc_throw(BadValue, "options is not a string");
803  }
804  string options_hex = options->stringValue();
805  vector<uint8_t> options_data;
806  str::decodeFormattedHexString(options_hex, options_data);
807  OptionCollection opts;
808  LibDHCP::unpackOptions6(options_data, DHCP6_OPTION_SPACE, opts);
809  }
811  continue;
812  }
813 
814  verifying = "link";
815  ConstElementPtr link_addr = relay->get("link");
816  if (!link_addr) {
817  mutable_isc->remove("relay-info");
818  removed_relay_info = true;
819  isc_throw(BadValue, "no link");
820  }
821  if (link_addr->getType() != Element::string) {
822  mutable_isc->remove("relay-info");
823  removed_relay_info = true;
824  isc_throw(BadValue, "link is not a string");
825  }
826  IOAddress laddr(link_addr->stringValue());
827  if (!laddr.isV6()) {
828  mutable_isc->remove("relay-info");
829  removed_relay_info = true;
830  isc_throw(BadValue, "link is not an IPv6 address");
831  }
832 
833  ConstElementPtr remote_id = relay->get("remote-id");
834  if (!upgraded && remote_id) {
835  verifying = "remote-id";
836  if (remote_id->getType() != Element::string) {
837  mutable_isc->remove("relay-info");
838  removed_relay_info = true;
839  isc_throw(BadValue, "remote-id is not a string");
840  }
841  string remote_id_hex = remote_id->stringValue();
842  vector<uint8_t> remote_id_data;
843  encode::decodeHex(remote_id_hex, remote_id_data);
844  if (remote_id_data.empty()) {
845  mutable_isc->remove("relay-info");
846  removed_relay_info = true;
847  isc_throw(BadValue, "remote-id is empty");
848  }
849  }
850 
851  ConstElementPtr relay_id = relay->get("relay-id");
852  if (!upgraded && relay_id) {
853  verifying = "relay-id";
854  if (relay_id->getType() != Element::string) {
855  mutable_isc->remove("relay-info");
856  removed_relay_info = true;
857  isc_throw(BadValue, "relay-id is not a string");
858  }
859  string relay_id_hex = relay_id->stringValue();
860  vector<uint8_t> relay_id_data;
861  encode::decodeHex(relay_id_hex, relay_id_data);
862  if (relay_id_data.empty()) {
863  mutable_isc->remove("relay-info");
864  removed_relay_info = true;
865  isc_throw(BadValue, "relay-id is empty");
866  }
867  }
868 
870  continue;
871  }
872 
873  verifying = "peer";
874  ConstElementPtr peer_addr = relay->get("peer");
875  if (!peer_addr) {
876  mutable_isc->remove("relay-info");
877  removed_relay_info = true;
878  isc_throw(BadValue, "no peer");
879  }
880  if (peer_addr->getType() != Element::string) {
881  mutable_isc->remove("relay-info");
882  removed_relay_info = true;
883  isc_throw(BadValue, "peer is not a string");
884  }
885  IOAddress paddr(peer_addr->stringValue());
886  if (!paddr.isV6()) {
887  mutable_isc->remove("relay-info");
888  removed_relay_info = true;
889  isc_throw(BadValue, "peer is not an IPv6 address");
890  }
891 
892  verifying = "hop";
893  ConstElementPtr hop = relay->get("hop");
894  if (!hop) {
895  mutable_isc->remove("relay-info");
896  removed_relay_info = true;
897  isc_throw(BadValue, "no hop");
898  }
899  if (hop->getType() != Element::integer) {
900  mutable_isc->remove("relay-info");
901  removed_relay_info = true;
902  isc_throw(BadValue, "hop is not an integer");
903  }
904 
905  verifying = (upgraded ? "relays" : "relay-info");
906  for (auto elem : relay->mapValue()) {
907  if ((elem.first != "hop") &&
908  (elem.first != "link") &&
909  (elem.first != "peer") &&
910  (elem.first != "options") &&
911  (elem.first != "remote-id") &&
912  (elem.first != "relay-id") &&
913  (elem.first != "comment")) {
914  mutable_isc->remove("relay-info");
915  removed_relay_info = true;
916  isc_throw(BadValue, "spurious '" << elem.first << "' entry");
917  }
918  }
919  }
920 
921  if (upgraded) {
924  .arg(lease->addr_.toText());
925  }
926 
927  return (changed);
928  } catch (const exception& ex) {
929  ostringstream err;
930  err << "in " << verifying;
931  if (i >= 0) {
932  err << " [relay#" << i << "]";
933  }
934  err << " a problem was found: " << ex.what();
937  .arg(lease->addr_.toText())
938  .arg(err.str());
939 
940  changed = true;
941  have_both = !have_both;
942  if (verifying == "user context") {
943  lease->setContext(ConstElementPtr());
944  } else if (verifying == "isc") {
945  mutable_user_context->remove("ISC");
946  if (mutable_user_context->empty()) {
947  lease->setContext(ConstElementPtr());
948  }
949  } else {
950  if (!removed_relay_info) {
951  mutable_isc->remove("relay-info");
952  }
953  if (mutable_isc->empty()) {
954  mutable_user_context->remove("ISC");
955  if (mutable_user_context->empty()) {
956  lease->setContext(ConstElementPtr());
957  }
958  }
959  }
960  return (changed);
961  }
962 }
963 
964 bool
966 
967  bool added = false;
968  if (!lease) {
969  return (added);
970  }
971 
972  ConstElementPtr user_context = lease->getContext();
973  if (!user_context || (user_context->getType() != Element::map) ||
974  user_context->empty()) {
975  return (added);
976  }
977 
978  ConstElementPtr isc = user_context->get("ISC");
979  if (!isc || (isc->getType() != Element::map) || isc->empty()) {
980  return (added);
981  }
982 
983  ConstElementPtr relay_info = isc->get("relay-info");
984  if (!relay_info || (relay_info->getType() != Element::list) ||
985  relay_info->empty()) {
986  return (added);
987  }
988 
989  for (int i = 0; i < relay_info->size(); ++i) {
990  ConstElementPtr relay = relay_info->get(i);
991  if (!relay || (relay->getType() != Element::map) || relay->empty()) {
992  continue;
993  }
994  try {
995  ConstElementPtr relay_id = relay->get("relay-id");
996  if (relay_id) {
997  string relay_id_hex = relay_id->stringValue();
998  vector<uint8_t> relay_id_data;
999  encode::decodeHex(relay_id_hex, relay_id_data);
1000  if (relay_id_data.empty()) {
1001  continue;
1002  }
1003  addRelayId6(lease->addr_, relay_id_data);
1004  added = true;
1005  }
1006 
1007  ConstElementPtr remote_id = relay->get("remote-id");
1008  if (remote_id) {
1009  string remote_id_hex = remote_id->stringValue();
1010  vector<uint8_t> remote_id_data;
1011  encode::decodeHex(remote_id_hex, remote_id_data);
1012  if (remote_id_data.empty()) {
1013  continue;
1014  }
1015  addRemoteId6(lease->addr_, remote_id_data);
1016  added = true;
1017  }
1018  } catch (const exception&) {
1019  continue;
1020  }
1021  }
1022  return (added);
1023 }
1024 
1025 } // namespace isc::dhcp
1026 } // namespace isc
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
Definition: lease_mgr.cc:349
const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:210
A generic exception that is thrown when a function is not implemented.
virtual void setExtendedInfoTablesEnabled(const bool enabled)
Extended information / Bulk Lease Query shared interface.
Definition: lease_mgr.h:983
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
Definition: lease_mgr.cc:354
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query for all subnets.
Definition: lease_mgr.cc:200
LeaseStatsQuery()
Default constructor The query created will return statistics for all subnets.
Definition: lease_mgr.cc:167
An abstract API for lease database.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:49
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
STL namespace.
static bool upgradeLease4ExtendedInfo(const Lease4Ptr &lease, CfgConsistency::ExtendedInfoSanity check=CfgConsistency::EXTENDED_INFO_CHECK_FIX)
The following queries are used to fulfill Bulk Lease Query queries.
Definition: lease_mgr.cc:379
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:291
void decodeFormattedHexString(const std::string &hex_string, std::vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition: strutil.cc:273
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
static std::string getDBVersion()
Class method to return extended version info This class method must be redeclared and redefined in de...
Definition: lease_mgr.cc:360
static size_t unpackOptions6(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, size_t *relay_msg_offset=0, size_t *relay_msg_len=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition: libdhcp++.cc:309
static bool upgradeLease6ExtendedInfo(const Lease6Ptr &lease, CfgConsistency::ExtendedInfoSanity check=CfgConsistency::EXTENDED_INFO_CHECK_FIX)
Upgrade a V6 lease user context to the new extended info entry.
Definition: lease_mgr.cc:612
Multiple lease records found where one expected.
Definition: db_exceptions.h:16
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
Definition: lease_mgr.cc:205
#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...
Definition: edns.h:19
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:56
boost::multi_index_container< Subnet4Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetServerIdIndexTag >, boost::multi_index::const_mem_fun< Network4, asiolink::IOAddress, &Network4::getServerId > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > >> Subnet4Collection
A collection of Subnet4 objects.
Definition: subnet.h:835
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1360
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:294
virtual bool addExtendedInfo6(const Lease6Ptr &lease)
Extract extended info from a lease6 and add it into tables.
Definition: lease_mgr.cc:965
SubnetID last_subnet_id_
Last subnet_id in the selection criteria when a range is given.
Definition: lease_mgr.h:202
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 (&#39;hex&#39;) format into the original data.
Definition: base_n.cc:474
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:117
void recountLeaseStats4()
Recalculates per-subnet and global stats for IPv4 leases.
Definition: lease_mgr.cc:73
A generic exception that is thrown when an unexpected error condition occurs.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:671
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition: option.h:40
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:123
the lease contains non-temporary IPv6 address
Definition: lease.h:47
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > >> Subnet6Collection
A collection of Subnet6 objects.
Definition: subnet.h:906
const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
Definition: lease_mgr.cc:210
Defines the logger used by the top-level component of kea-lfc.
ExtendedInfoSanity
Values for extended info sanity checks done for leases.
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 (&#39;hex&#39;) format.
Definition: base_n.cc:469
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query for all subnets.
Definition: lease_mgr.cc:344
const isc::log::MessageID DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
#define DHCP6_OPTION_SPACE
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:121
Type
Type of lease or pool.
Definition: lease.h:46
#define DHCP4_OPTION_SPACE
global std option spaces
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:70
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
static const uint32_t STATE_DEFAULT
A lease in the default state.
Definition: lease.h:69
SubnetID first_subnet_id_
First (or only) subnet_id in the selection criteria.
Definition: lease_mgr.h:195
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:123
void recountLeaseStats6()
Recalculates per-subnet and global stats for IPv6 leases.
Definition: lease_mgr.cc:221
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
static const uint32_t STATE_DECLINED
Declined lease.
Definition: lease.h:72
Contains a single row of lease statistical data.
Definition: lease_mgr.h:64
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:75
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:119
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
virtual bool getNextRow(LeaseStatsRow &row)
Fetches the next row of data.
Definition: lease_mgr.cc:216
Option with defined data fields represented as buffers that can be accessed using data field index...
Definition: option_custom.h:32
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:513
const isc::log::MessageID DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25