Kea 3.3.1
lease_cmds.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2026 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>
9#include <config/cmds_impl.h>
11#include <cc/data.h>
12#include <asiolink/io_address.h>
14#include <dhcpsrv/cfgmgr.h>
16#include <dhcpsrv/lease_mgr.h>
20#include <dhcpsrv/subnet_id.h>
22#include <dhcp/duid.h>
23#include <hooks/hooks.h>
25#include <lease_cmds.h>
27#include <lease_parser.h>
28#include <lease_cmds_log.h>
29#include <stats/stats_mgr.h>
30#include <util/encode/encode.h>
31#include <util/filesystem.h>
33
34#include <boost/scoped_ptr.hpp>
35#include <boost/algorithm/string.hpp>
36#include <limits>
37#include <string>
38#include <sstream>
39
40using namespace isc::dhcp;
41using namespace isc::data;
42using namespace isc::dhcp_ddns;
43using namespace isc::config;
44using namespace isc::asiolink;
45using namespace isc::hooks;
46using namespace isc::stats;
47using namespace isc::util;
48using namespace isc::util::file;
49using namespace isc::log;
50using namespace std;
51
52namespace isc {
53namespace lease_cmds {
54
55namespace {
56
57const int128_t uint32_min = numeric_limits<uint32_t>::min();
58const int128_t uint32_max = numeric_limits<uint32_t>::max();
59
60}
61
63class LeaseCmdsImpl : private CmdsImpl {
64public:
65
67 class Parameters {
68 public:
69
77
80
83
86
89
92
102 static Type txtToType(const std::string& txt) {
103 if (txt == "hw-address") {
105 } else if (txt == "duid") {
106 return (Parameters::TYPE_DUID);
107 } else if (txt == "client-id") {
109 } else {
110 isc_throw(BadValue, "Incorrect identifier type: "
111 << txt << ", the only supported values are: "
112 "hw-address, duid, client-id");
113 }
114 }
115
118
121
123 uint32_t iaid;
124
127
130 : subnet_id(0), addr("::"), query_type(TYPE_ADDR),
131 lease_type(Lease::TYPE_NA), iaid(0), updateDDNS(false) {
132 }
133 };
134
135public:
136
145 int
147
157 int
159
168 int
170
182 int
184
200 int
202
212 int
214
224 int
226
236 int
238
248 int
250
261 int
263
272 int
274
283 int
285
294 int
296
305 int
307
316 int
318
327 int
329
339
349
358 int
360
372 Parameters getParameters(bool v6, const ConstElementPtr& args);
373
391 Lease6Ptr getIPv6LeaseForDelete(const Parameters& parameters) const;
392
408 const IOAddress& lease_address,
409 const DuidPtr& duid,
410 const int control_result,
411 const std::string& error_message) const;
412
423 IOAddress getAddressParam(ConstElementPtr params, const std::string name,
424 short family = AF_INET) const;
433 static bool addOrUpdate4(Lease4Ptr lease, bool force_create);
434
443 static bool addOrUpdate6(Lease6Ptr lease, bool force_create);
444
449 inline static ConstElementPtr getExtendedInfo6(const Lease6Ptr& lease) {
450 ConstElementPtr user_context = lease->getContext();
451 if (!user_context || (user_context->getType() != Element::map)) {
452 return (ConstElementPtr());
453 }
454 ConstElementPtr isc = user_context->get("ISC");
455 if (!isc || (isc->getType() != Element::map)) {
456 return (ConstElementPtr());
457 }
458 return (isc->get("relay-info"));
459 }
460
474 static void lease4Offer(CalloutHandle& callout_handle,
476
488 static void leases4Committed(CalloutHandle& callout_handle,
490
502 static void leases6Committed(CalloutHandle& callout_handle,
504};
505
506bool
507LeaseCmdsImpl::addOrUpdate4(Lease4Ptr lease, bool force_create) {
508 if (lease->stateRegistered()) {
509 isc_throw(BadValue, "DHCPv4 leases do not support registered state");
510 }
511
512 Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(lease->addr_);
513 if (force_create && !existing) {
514 // lease does not exist
515 if (!LeaseMgrFactory::instance().addLease(lease)) {
517 "lost race between calls to get and add");
518 }
520 return (true);
521 }
522 if (existing) {
523 // Update lease current expiration time with value received from the
524 // database. Some database backends reject operations on the lease if
525 // the current expiration time value does not match what is stored.
526 Lease::syncCurrentExpirationTime(*existing, *lease);
527 }
528 try {
530 } catch (const NoSuchLease&) {
531 isc_throw(LeaseCmdsConflict, "failed to update the lease with address "
532 << lease->addr_ << " either because the lease has been "
533 "deleted or it has changed in the database, in both cases a "
534 "retry might succeed");
535 }
536
537 LeaseMgr::updateStatsOnUpdate(existing, lease);
538 return (false);
539}
540
541bool
542LeaseCmdsImpl::addOrUpdate6(Lease6Ptr lease, bool force_create) {
543 Lease6Ptr existing =
544 LeaseMgrFactory::instance().getLease6(lease->type_, lease->addr_);
545 if (force_create && !existing) {
546 // lease does not exist
547 if (!LeaseMgrFactory::instance().addLease(lease)) {
549 "lost race between calls to get and add");
550 }
552 return (true);
553 }
554 if (existing) {
555 // Refuse used <-> registered transitions.
556 if (existing->stateRegistered() && !lease->stateRegistered()) {
557 isc_throw(BadValue, "illegal reuse of registered address "
558 << lease->addr_);
559 } else if (!existing->stateRegistered() && lease->stateRegistered()) {
560 isc_throw(BadValue, "address in use: " << lease->addr_
561 << " can't be registered");
562 }
563
564 // Update lease current expiration time with value received from the
565 // database. Some database backends reject operations on the lease if
566 // the current expiration time value does not match what is stored.
567 Lease::syncCurrentExpirationTime(*existing, *lease);
568
569 // Check what is the action about extended info.
570 ConstElementPtr old_extended_info = getExtendedInfo6(existing);
571 ConstElementPtr extended_info = getExtendedInfo6(lease);
572 if ((!old_extended_info && !extended_info) ||
573 (old_extended_info && extended_info &&
574 (*old_extended_info == *extended_info))) {
575 // Leave the default Lease6::ACTION_IGNORE.
576 } else {
577 lease->extended_info_action_ = Lease6::ACTION_UPDATE;
578 }
579 }
580 try {
582 } catch (const NoSuchLease&) {
583 isc_throw(LeaseCmdsConflict, "failed to update the lease with address "
584 << lease->addr_ << " either because the lease has been "
585 "deleted or it has changed in the database, in both cases a "
586 "retry might succeed");
587 }
588
589 LeaseMgr::updateStatsOnUpdate(existing, lease);
590 return (false);
591}
592
593int
595 // Arbitrary defaulting to DHCPv4 or with other words extractCommand
596 // below is not expected to throw...
597 bool v4 = true;
598 stringstream resp;
599 string lease_address = "unknown";
600 try {
601 extractCommand(handle);
602 v4 = (cmd_name_ == "lease4-add");
603 if (!cmd_args_) {
604 isc_throw(isc::BadValue, "no parameters specified for the command");
605 }
606
608
609 // This parameter is ignored for the commands adding the lease.
610 bool force_create = false;
611 Lease4Ptr lease4;
612 Lease6Ptr lease6;
613 if (v4) {
614 Lease4Parser parser;
615 lease4 = parser.parse(config, cmd_args_, force_create);
616 if (lease4) {
617 lease_address = lease4->addr_.toText();
618 bool success;
619 if (!MultiThreadingMgr::instance().getMode()) {
620 // Not multi-threading.
621 success = LeaseMgrFactory::instance().addLease(lease4);
622 } else {
623 // Multi-threading, try to lock first to avoid a race.
624 ResourceHandler4 resource_handler;
625 if (resource_handler.tryLock4(lease4->addr_)) {
626 success = LeaseMgrFactory::instance().addLease(lease4);
627 } else {
629 "ResourceBusy: IP address:" << lease4->addr_
630 << " could not be added.");
631 }
632 }
633
634 if (!success) {
635 isc_throw(LeaseCmdsConflict, "IPv4 lease already exists.");
636 }
637
639 resp << "Lease for address " << lease4->addr_.toText()
640 << ", subnet-id " << lease4->subnet_id_ << " added.";
641 }
642 } else {
643 Lease6Parser parser;
644 lease6 = parser.parse(config, cmd_args_, force_create);
645 if (lease6) {
646 lease_address = lease6->addr_.toText();
647 bool success;
648 if (!MultiThreadingMgr::instance().getMode()) {
649 // Not multi-threading.
650 success = LeaseMgrFactory::instance().addLease(lease6);
651 } else {
652 // Multi-threading, try to lock first to avoid a race.
653 ResourceHandler resource_handler;
654 if (resource_handler.tryLock(lease6->type_, lease6->addr_)) {
655 success = LeaseMgrFactory::instance().addLease(lease6);
656 } else {
658 "ResourceBusy: IP address:" << lease6->addr_
659 << " could not be added.");
660 }
661 }
662
663 if (!success) {
664 isc_throw(LeaseCmdsConflict, "IPv6 lease already exists.");
665 }
666
668 if (lease6->type_ == Lease::TYPE_NA) {
669 resp << "Lease for address " << lease6->addr_.toText()
670 << ", subnet-id " << lease6->subnet_id_ << " added.";
671 } else {
672 resp << "Lease for prefix " << lease6->addr_.toText()
673 << "/" << static_cast<int>(lease6->prefixlen_)
674 << ", subnet-id " << lease6->subnet_id_ << " added.";
675 }
676 }
677 }
678 } catch (const LeaseCmdsConflict& ex) {
680 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
681 .arg(ex.what());
683 return (0);
684
685 } catch (const std::exception& ex) {
687 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
688 .arg(ex.what());
689 setErrorResponse(handle, ex.what());
690 return (1);
691 }
692
695 .arg(lease_address);
696 setSuccessResponse(handle, resp.str());
697 return (0);
698}
699
702 Parameters x;
703
704 if (!params || params->getType() != Element::map) {
705 isc_throw(BadValue, "Parameters missing or are not a map.");
706 }
707
708 if (params->contains("update-ddns")) {
709 ConstElementPtr tmp = params->get("update-ddns");
710 if (tmp->getType() != Element::boolean) {
711 isc_throw(BadValue, "'update-ddns' is not a boolean");
712 } else {
713 x.updateDDNS = tmp->boolValue();
714 }
715 }
716
717 // We support several sets of parameters for leaseX-get/lease-del:
718 // lease-get(type, address)
719 // lease-get(type, subnet-id, identifier-type, identifier)
720
721 if (params->contains("type")) {
722 string t = params->get("type")->stringValue();
723 if (t == "IA_NA" || t == "0") {
725 } else if (t == "IA_PD" || t == "2") {
727 } else if (t == "V4" || t == "3") {
729 } else {
730 isc_throw(BadValue, "Invalid lease type specified: " << t
731 << ", only supported values are: IA_NA, IA_PD and V4");
732 }
733 }
734
735 ConstElementPtr tmp = params->get("ip-address");
736 if (tmp) {
737 if (tmp->getType() != Element::string) {
738 isc_throw(BadValue, "'ip-address' is not a string.");
739 }
740
741 x.addr = IOAddress(tmp->stringValue());
742
743 if ((v6 && !x.addr.isV6()) || (!v6 && !x.addr.isV4())) {
744 stringstream txt;
745 txt << "Invalid " << (v6 ? "IPv6" : "IPv4")
746 << " address specified: " << tmp->stringValue();
747 isc_throw(BadValue, txt.str());
748 }
749
751 return (x);
752 }
753
754 tmp = params->get("subnet-id");
755 if (!tmp) {
756 isc_throw(BadValue, "Mandatory 'subnet-id' parameter missing.");
757 }
758 if (tmp->getType() != Element::integer) {
759 isc_throw(BadValue, "'subnet-id' parameter is not integer.");
760 }
761 int128_t tmp128 = tmp->intValue();
762 if ((tmp128 < uint32_min) || (tmp128 > uint32_max)) {
763 isc_throw(BadValue, "'subnet-id' parameter is not a 32 bit unsigned integer.");
764 }
765 x.subnet_id = static_cast<SubnetID>(tmp128);
766
767 tmp = params->get("iaid");
768 if (tmp) {
769 if (!v6) {
770 isc_throw(BadValue, "'iaid' parameter is specific to DHCPv6.");
771 }
772 if (tmp->getType() != Element::integer) {
773 isc_throw(BadValue, "'iaid' parameter is not integer.");
774 }
775 tmp128 = tmp->intValue();
776 if ((tmp128 < uint32_min) || (tmp128 > uint32_max)) {
777 isc_throw(BadValue, "'iaid' parameter is not a 32 bit unsigned integer.");
778 }
779 x.iaid = static_cast<uint32_t>(tmp128);
780 }
781
782 // No address specified. Ok, so it must be identifier based query.
783 // "identifier-type": "duid",
784 // "identifier": "aa:bb:cc:dd:ee:..."
785
786 ConstElementPtr type = params->get("identifier-type");
787 ConstElementPtr ident = params->get("identifier");
788 if (!type || type->getType() != Element::string) {
789 isc_throw(BadValue, "No 'ip-address' provided"
790 " and 'identifier-type' is either missing or not a string.");
791 }
792 if (!ident || ident->getType() != Element::string) {
793 isc_throw(BadValue, "No 'ip-address' provided"
794 " and 'identifier' is either missing or not a string.");
795 }
796
797 // Got the parameters. Let's see if their values make sense.
798 // Try to convert identifier-type
799 x.query_type = Parameters::txtToType(type->stringValue());
800
801 switch (x.query_type) {
803 try {
804 HWAddr hw = HWAddr::fromText(ident->stringValue());
805 x.hwaddr = HWAddrPtr(new HWAddr(hw));
806 } catch (const std::exception& ex) {
807 isc_throw(BadValue, "Bad 'hw-address' identifier: " << ex.what());
808 }
809 break;
811 try {
812 x.client_id = ClientId::fromText(ident->stringValue());
813 } catch (const std::exception& ex) {
814 isc_throw(BadValue, "Bad 'client-id' identifier: " << ex.what());
815 }
816 break;
818 try {
819 DUID duid = DUID::fromText(ident->stringValue());
820 x.duid = DuidPtr(new DUID(duid));
821 } catch (const std::exception& ex) {
822 isc_throw(BadValue, "Bad 'duid' identifier: " << ex.what());
823 }
824 break;
825 default:
826 isc_throw(BadValue, "Identifier type " << type->stringValue() <<
827 " is not supported.");
828 }
829
830 return (x);
831}
832
833int
835 Parameters p;
836 Lease4Ptr lease4;
837 Lease6Ptr lease6;
838 bool v4 = true;
839 try {
840 extractCommand(handle);
841 v4 = (cmd_name_ == "lease4-get");
842 p = getParameters(!v4, cmd_args_);
843 switch (p.query_type) {
845 // Query by address
846 if (v4) {
848 } else {
850 }
851 break;
852 }
854 if (v4) {
855 if (!p.hwaddr) {
856 isc_throw(InvalidParameter, "Program error: Query by hw-address "
857 "requires hwaddr to be specified");
858 }
859
861 } else {
862 isc_throw(isc::InvalidParameter, "Query by hw-address is not allowed in v6.");
863 }
864 break;
865
867 if (!v4) {
868 if (!p.duid) {
869 isc_throw(InvalidParameter, "Program error: Query by duid "
870 "requires duid to be specified");
871 }
872
874 p.iaid, p.subnet_id);
875 } else {
876 isc_throw(InvalidParameter, "Query by duid is not allowed in v4.");
877 }
878 break;
879
881 if (v4) {
882 if (!p.client_id) {
883 isc_throw(InvalidParameter, "Program error: Query by client-id "
884 "requires client-id to be specified");
885 }
886
888 } else {
889 isc_throw(isc::InvalidParameter, "Query by client-id is not allowed in v6.");
890 }
891 break;
892
893 default: {
894 isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
895 break;
896 }
897 }
898 } catch (const std::exception& ex) {
900 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
901 .arg(ex.what());
902 setErrorResponse(handle, ex.what());
903 return (1);
904 }
905
906 ElementPtr lease_json;
907 if (v4 && lease4) {
908 lease_json = lease4->toElement();
910 "IPv4 lease found.", lease_json);
911 setResponse(handle, response);
912 } else if (!v4 && lease6) {
913 lease_json = lease6->toElement();
915 "IPv6 lease found.", lease_json);
916 setResponse(handle, response);
917 } else {
918 // If we got here, the lease has not been found.
919 setErrorResponse(handle, "Lease not found.", CONTROL_RESULT_EMPTY);
920 }
921
922 return (0);
923}
924
925int
927 bool v4 = true;
928 try {
929 extractCommand(handle);
930 v4 = (cmd_name_ == "lease4-get-all");
931
932 ElementPtr leases_json = Element::createList();
933
934 // The argument may contain a list of subnets for which leases should
935 // be returned.
936 if (cmd_args_) {
937 ConstElementPtr subnets = cmd_args_->get("subnets");
938 if (!subnets) {
939 isc_throw(BadValue, "'subnets' parameter not specified");
940 }
941 if (subnets->getType() != Element::list) {
942 isc_throw(BadValue, "'subnets' parameter must be a list");
943 }
944
945 const std::vector<ElementPtr>& subnet_ids = subnets->listValue();
946 for (auto const& subnet_id : subnet_ids) {
947 if (subnet_id->getType() != Element::integer) {
948 isc_throw(BadValue, "listed subnet identifiers must be numbers");
949 }
950 auto subnet_id_ = subnet_id->intValue();
951 if ((subnet_id_ < uint32_min) || (subnet_id_ > uint32_max)) {
952 isc_throw(BadValue, "out of range subnet identifier "
953 << subnet_id_);
954 }
955
956 if (v4) {
957 Lease4Collection leases =
959 for (auto const& lease : leases) {
960 ElementPtr lease_json = lease->toElement();
961 leases_json->add(lease_json);
962 }
963 } else {
964 Lease6Collection leases =
966 for (auto const& lease : leases) {
967 ElementPtr lease_json = lease->toElement();
968 leases_json->add(lease_json);
969 }
970 }
971 }
972
973 } else {
974 // There is no 'subnets' argument so let's return all leases.
975 if (v4) {
977 for (auto const& lease : leases) {
978 ElementPtr lease_json = lease->toElement();
979 leases_json->add(lease_json);
980 }
981 } else {
983 for (auto const& lease : leases) {
984 ElementPtr lease_json = lease->toElement();
985 leases_json->add(lease_json);
986 }
987 }
988 }
989
990 std::ostringstream s;
991 s << leases_json->size()
992 << " IPv" << (v4 ? "4" : "6")
993 << " lease(s) found.";
995 args->set("leases", leases_json);
996 ConstElementPtr response =
997 createAnswer(leases_json->size() > 0 ?
1000 s.str(), args);
1001 setResponse(handle, response);
1002
1003 } catch (const std::exception& ex) {
1004 setErrorResponse(handle, ex.what());
1005 return (CONTROL_RESULT_ERROR);
1006 }
1007
1008 return (0);
1009}
1010
1011int
1013 bool v4 = true;
1014 try {
1015 extractCommand(handle);
1016 v4 = (cmd_name_ == "lease4-get-page");
1017
1018 // arguments must always be present
1019 if (!cmd_args_) {
1020 isc_throw(BadValue, "no parameters specified for the " << cmd_name_
1021 << " command");
1022 }
1023
1024 // The 'from' argument denotes from which lease we should start the
1025 // results page. The results page excludes this lease.
1026 ConstElementPtr from = cmd_args_->get("from");
1027 if (!from) {
1028 isc_throw(BadValue, "'from' parameter not specified");
1029 }
1030
1031 // The 'from' argument is a string. It may contain a 'start' keyword or
1032 // an IP address.
1033 if (from->getType() != Element::string) {
1034 isc_throw(BadValue, "'from' parameter must be a string");
1035 }
1036
1037 boost::scoped_ptr<IOAddress> from_address;
1038 try {
1039 if (from->stringValue() == "start") {
1040 from_address.reset(new IOAddress(v4 ? "0.0.0.0" : "::"));
1041
1042 } else {
1043 // Conversion of a string to an IP address may throw.
1044 from_address.reset(new IOAddress(from->stringValue()));
1045 }
1046
1047 } catch (...) {
1048 isc_throw(BadValue, "'from' parameter value is neither 'start' keyword nor "
1049 "a valid IPv" << (v4 ? "4" : "6") << " address");
1050 }
1051
1052 // It must be either IPv4 address for lease4-get-page or IPv6 address for
1053 // lease6-get-page.
1054 if (v4 && (!from_address->isV4())) {
1055 isc_throw(BadValue, "'from' parameter value " << from_address->toText()
1056 << " is not an IPv4 address");
1057
1058 } else if (!v4 && from_address->isV4()) {
1059 isc_throw(BadValue, "'from' parameter value " << from_address->toText()
1060 << " is not an IPv6 address");
1061 }
1062
1063 // The 'limit' is a desired page size. It must always be present.
1064 ConstElementPtr page_limit = cmd_args_->get("limit");
1065 if (!page_limit) {
1066 isc_throw(BadValue, "'limit' parameter not specified");
1067 }
1068
1069 // The 'limit' must be a number.
1070 if (page_limit->getType() != Element::integer) {
1071 isc_throw(BadValue, "'limit' parameter must be a number");
1072 }
1073
1074 auto tmp128 = page_limit->intValue();
1075 if ((tmp128 < uint32_min) || (tmp128 > uint32_max)) {
1076 isc_throw(BadValue, "'limit' parameter is not a 32 bit unsigned integer.");
1077 }
1078
1079 if (tmp128 == 0) {
1080 isc_throw(BadValue, "'limit' parameter must not be 0.");
1081 }
1082
1083 // Retrieve the desired page size.
1084 size_t page_limit_value = static_cast<size_t>(tmp128);
1085
1086 ElementPtr leases_json = Element::createList();
1087
1088 if (v4) {
1089 // Get page of IPv4 leases.
1090 Lease4Collection leases =
1091 LeaseMgrFactory::instance().getLeases4(*from_address,
1092 LeasePageSize(page_limit_value));
1093
1094 // Convert leases into JSON list.
1095 for (auto const& lease : leases) {
1096 ElementPtr lease_json = lease->toElement();
1097 leases_json->add(lease_json);
1098 }
1099
1100 } else {
1101 // Get page of IPv6 leases.
1102 Lease6Collection leases =
1103 LeaseMgrFactory::instance().getLeases6(*from_address,
1104 LeasePageSize(page_limit_value));
1105 // Convert leases into JSON list.
1106 for (auto const& lease : leases) {
1107 ElementPtr lease_json = lease->toElement();
1108 leases_json->add(lease_json);
1109 }
1110 }
1111
1112 // Prepare textual status.
1113 std::ostringstream s;
1114 s << leases_json->size()
1115 << " IPv" << (v4 ? "4" : "6")
1116 << " lease(s) found.";
1118
1119 // Put gathered data into arguments map.
1120 args->set("leases", leases_json);
1121 args->set("count", Element::create(static_cast<int64_t>(leases_json->size())));
1122
1123 // Create the response.
1124 ConstElementPtr response =
1125 createAnswer(leases_json->size() > 0 ?
1128 s.str(), args);
1129 setResponse(handle, response);
1130
1131 } catch (const std::exception& ex) {
1132 setErrorResponse(handle, ex.what());
1133 return (CONTROL_RESULT_ERROR);
1134 }
1135
1136 return (CONTROL_RESULT_SUCCESS);
1137}
1138
1139int
1141 bool v4 = true;
1142 try {
1143 extractCommand(handle);
1144 v4 = (cmd_name_ == "lease4-get-by-hw-address");
1145
1146 // arguments must always be present
1147 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1148 isc_throw(BadValue, "Command arguments missing or a not a map.");
1149 }
1150
1151 // the hw-address parameter is mandatory.
1152 ConstElementPtr hw_address = cmd_args_->get("hw-address");
1153 if (!hw_address) {
1154 isc_throw(BadValue, "'hw-address' parameter not specified");
1155 }
1156
1157 // The 'hw-address' argument is a string.
1158 if (hw_address->getType() != Element::string) {
1159 isc_throw(BadValue, "'hw-address' parameter must be a string");
1160 }
1161
1162 if (hw_address->stringValue().empty()) {
1163 isc_throw(BadValue, "'hw-address' parameter must not be empty");
1164 }
1165
1166 HWAddr hwaddr;
1167 try {
1168 hwaddr = HWAddr::fromText(hw_address->stringValue());
1169 } catch (const std::exception& ex) {
1170 isc_throw(BadValue, "bad 'hw-address' parameter: " << ex.what());
1171 }
1172
1173 ElementPtr leases_json = Element::createList();
1174 if (v4) {
1175 Lease4Collection leases =
1177 for (auto const& lease : leases) {
1178 ElementPtr lease_json = lease->toElement();
1179 leases_json->add(lease_json);
1180 }
1181 } else {
1182 Lease6Collection leases =
1184 for (auto const& lease : leases) {
1185 ElementPtr lease_json = lease->toElement();
1186 leases_json->add(lease_json);
1187 }
1188 }
1189
1190 std::ostringstream s;
1191 s << leases_json->size()
1192 << " IPv" << (v4 ? "4" : "6")
1193 << " lease(s) found.";
1195 args->set("leases", leases_json);
1196 ConstElementPtr response =
1197 createAnswer(leases_json->size() > 0 ?
1200 s.str(), args);
1201 setResponse(handle, response);
1202
1203 } catch (const std::exception& ex) {
1204 setErrorResponse(handle, ex.what());
1205 return (CONTROL_RESULT_ERROR);
1206 }
1207
1208 return (0);
1209}
1210
1211int
1213 try {
1214 extractCommand(handle);
1215
1216 // arguments must always be present
1217 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1218 isc_throw(BadValue, "Command arguments missing or a not a map.");
1219 }
1220
1221 // the client-id parameter is mandatory.
1222 ConstElementPtr client_id = cmd_args_->get("client-id");
1223 if (!client_id) {
1224 isc_throw(BadValue, "'client-id' parameter not specified");
1225 }
1226
1227 // The 'client-id' argument is a string.
1228 if (client_id->getType() != Element::string) {
1229 isc_throw(BadValue, "'client-id' parameter must be a string");
1230 }
1231
1232 ClientIdPtr clientid;
1233 try {
1234 clientid = ClientId::fromText(client_id->stringValue());
1235 } catch (const std::exception& ex) {
1236 isc_throw(BadValue, "bad 'client-id' parameter: " << ex.what());
1237 }
1238
1239 Lease4Collection leases =
1241 ElementPtr leases_json = Element::createList();
1242 for (auto const& lease : leases) {
1243 ElementPtr lease_json = lease->toElement();
1244 leases_json->add(lease_json);
1245 }
1246
1247 std::ostringstream s;
1248 s << leases_json->size() << " IPv4 lease(s) found.";
1250 args->set("leases", leases_json);
1251 ConstElementPtr response =
1252 createAnswer(leases_json->size() > 0 ?
1255 s.str(), args);
1256 setResponse(handle, response);
1257
1258 } catch (const std::exception& ex) {
1259 setErrorResponse(handle, ex.what());
1260 return (CONTROL_RESULT_ERROR);
1261 }
1262
1263 return (0);
1264}
1265
1266int
1268 try {
1269 extractCommand(handle);
1270
1271 // arguments must always be present
1272 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1273 isc_throw(BadValue, "Command arguments missing or a not a map.");
1274 }
1275
1276 // the duid parameter is mandatory.
1277 ConstElementPtr duid = cmd_args_->get("duid");
1278 if (!duid) {
1279 isc_throw(BadValue, "'duid' parameter not specified");
1280 }
1281
1282 // The 'duid' argument is a string.
1283 if (duid->getType() != Element::string) {
1284 isc_throw(BadValue, "'duid' parameter must be a string");
1285 }
1286
1287 DUID duid_ = DUID::EMPTY();
1288 try {
1289 duid_ = DUID::fromText(duid->stringValue());
1290 } catch (const std::exception& ex) {
1291 isc_throw(BadValue, "bad 'duid' parameter: " << ex.what());
1292 }
1293
1294 Lease6Collection leases =
1296 ElementPtr leases_json = Element::createList();
1297 for (auto const& lease : leases) {
1298 ElementPtr lease_json = lease->toElement();
1299 leases_json->add(lease_json);
1300 }
1301
1302 std::ostringstream s;
1303 s << leases_json->size() << " IPv6 lease(s) found.";
1305 args->set("leases", leases_json);
1306 ConstElementPtr response =
1307 createAnswer(leases_json->size() > 0 ?
1310 s.str(), args);
1311 setResponse(handle, response);
1312
1313 } catch (const std::exception& ex) {
1314 setErrorResponse(handle, ex.what());
1315 return (CONTROL_RESULT_ERROR);
1316 }
1317
1318 return (0);
1319}
1320
1321int
1323 bool v4 = true;
1324 try {
1325 extractCommand(handle);
1326 v4 = (cmd_name_ == "lease4-get-by-state");
1327
1328 // arguments must always be present
1329 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1330 isc_throw(BadValue, "Command arguments missing or a not a map.");
1331 }
1332
1333 // the state parameter is mandatory.
1334 ConstElementPtr state = cmd_args_->get("state");
1335 if (!state) {
1336 isc_throw(BadValue, "'state' parameter not specified");
1337 }
1338
1339 uint32_t state_ = 0;
1340 // We accept string (nicknames) and integer values.
1341 if (state->getType() == Element::string) {
1342 std::string state_str = state->stringValue();
1343 if (state_str.empty()) {
1344 isc_throw(BadValue, "'state' parameter is empty");
1345 } else if ((state_str == "default") || (state_str == "assigned")) {
1346 state_ = Lease::STATE_DEFAULT;;
1347 } else if (state_str == "declined") {
1348 state_ = Lease::STATE_DECLINED;
1349 } else if (state_str == "expired-reclaimed") {
1351 } else if (state_str == "released") {
1352 state_ = Lease::STATE_RELEASED;
1353 } else if (state_str == "registered") {
1354 state_ = Lease::STATE_REGISTERED;
1355 } else {
1356 isc_throw(BadValue, "'state' parameter value (" << state_str
1357 << ") is not recognized");
1358 }
1359 } else if (state->getType() == Element::integer) {
1360 state_ = state->intValue();
1361 } else {
1362 isc_throw(BadValue, "'state' parameter must be a number or a string");
1363 }
1364
1365 SubnetID subnet_id_ = 0;
1366 ConstElementPtr subnet = cmd_args_->get("subnet-id");
1367 if (subnet) {
1368 if (subnet->getType() != Element::integer) {
1369 isc_throw(BadValue, "'subnet-id' parameter must be a number");
1370 }
1371 auto id128 = subnet->intValue();
1372 if ((id128 < uint32_min) || (id128 > uint32_max)) {
1373 isc_throw(BadValue, "'subnet-id' parameter must be a 32 bit unsigned integer");
1374 }
1375 subnet_id_ = static_cast<SubnetID>(id128);
1376 }
1377
1378 ElementPtr leases_json = Element::createList();
1379 if (v4) {
1380 Lease4Collection leases =
1381 LeaseMgrFactory::instance().getLeases4(state_, subnet_id_);
1382
1383 for (auto const& lease : leases) {
1384 ElementPtr lease_json = lease->toElement();
1385 leases_json->add(lease_json);
1386 }
1387 } else {
1388 Lease6Collection leases =
1389 LeaseMgrFactory::instance().getLeases6(state_, subnet_id_);
1390
1391 for (auto const& lease : leases) {
1392 ElementPtr lease_json = lease->toElement();
1393 leases_json->add(lease_json);
1394 }
1395 }
1396
1397 std::ostringstream s;
1398 s << leases_json->size()
1399 << " IPv" << (v4 ? "4" : "6")
1400 << " lease(s) found with state ";
1401 if (state_ <= Lease::STATE_REGISTERED) {
1402 s << Lease::basicStatesToText(state_) << " (" << state_ << ")";
1403 } else {
1404 s << state_;
1405 }
1406 if (subnet_id_ != 0) {
1407 s << " in subnet " << subnet_id_;
1408 }
1409 s << ".";
1411 args->set("leases", leases_json);
1412 ConstElementPtr response =
1413 createAnswer(leases_json->size() > 0 ?
1416 s.str(), args);
1417 setResponse(handle, response);
1418
1419 } catch (const std::exception& ex) {
1420 setErrorResponse(handle, ex.what());
1421 return (CONTROL_RESULT_ERROR);
1422 }
1423
1424 return (0);
1425}
1426
1427int
1429 bool v4 = true;
1430 try {
1431 extractCommand(handle);
1432 v4 = (cmd_name_ == "lease4-get-by-hostname");
1433
1434 // arguments must always be present
1435 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1436 isc_throw(BadValue, "Command arguments missing or a not a map.");
1437 }
1438
1439 // the hostname parameter is mandatory.
1440 ConstElementPtr hostname = cmd_args_->get("hostname");
1441 if (!hostname) {
1442 isc_throw(BadValue, "'hostname' parameter not specified");
1443 }
1444
1445 // The 'hostname' argument is a string.
1446 if (hostname->getType() != Element::string) {
1447 isc_throw(BadValue, "'hostname' parameter must be a string");
1448 }
1449
1450 std::string hostname_ = hostname->stringValue();
1452 if (hostname_.empty()) {
1453 isc_throw(BadValue, "'hostname' parameter is empty");
1454 }
1455 boost::algorithm::to_lower(hostname_);
1456
1457 ElementPtr leases_json = Element::createList();
1458 if (v4) {
1459 Lease4Collection leases =
1461
1462 for (auto const& lease : leases) {
1463 ElementPtr lease_json = lease->toElement();
1464 leases_json->add(lease_json);
1465 }
1466 } else {
1467 Lease6Collection leases =
1469
1470 for (auto const& lease : leases) {
1471 ElementPtr lease_json = lease->toElement();
1472 leases_json->add(lease_json);
1473 }
1474 }
1475
1476 std::ostringstream s;
1477 s << leases_json->size()
1478 << " IPv" << (v4 ? "4" : "6")
1479 << " lease(s) found.";
1481 args->set("leases", leases_json);
1482 ConstElementPtr response =
1483 createAnswer(leases_json->size() > 0 ?
1486 s.str(), args);
1487 setResponse(handle, response);
1488
1489 } catch (const std::exception& ex) {
1490 setErrorResponse(handle, ex.what());
1491 return (CONTROL_RESULT_ERROR);
1492 }
1493
1494 return (0);
1495}
1496
1497int
1499 Parameters p;
1500 Lease4Ptr lease4;
1501 try {
1502 extractCommand(handle);
1503 p = getParameters(false, cmd_args_);
1504 switch (p.query_type) {
1505 case Parameters::TYPE_ADDR: {
1506 // If address was specified explicitly, let's use it as is.
1508 if (!lease4) {
1509 setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1510 return (0);
1511 }
1512 break;
1513 }
1515 if (!p.hwaddr) {
1516 isc_throw(InvalidParameter, "Program error: Query by hw-address "
1517 "requires hwaddr to be specified");
1518 }
1519
1520 // Let's see if there's such a lease at all.
1522 if (!lease4) {
1523 setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1524 return (0);
1525 }
1526 break;
1527 }
1529 if (!p.client_id) {
1530 isc_throw(InvalidParameter, "Program error: Query by client-id "
1531 "requires client-id to be specified");
1532 }
1533
1534 // Let's see if there's such a lease at all.
1536 if (!lease4) {
1537 setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1538 return (0);
1539 }
1540 break;
1541 }
1542 case Parameters::TYPE_DUID: {
1543 isc_throw(InvalidParameter, "Delete by duid is not allowed in v4.");
1544 break;
1545 }
1546 default: {
1547 isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1548 break;
1549 }
1550 }
1551
1552 if (LeaseMgrFactory::instance().deleteLease(lease4)) {
1553 setSuccessResponse(handle, "IPv4 lease deleted.");
1555 } else {
1556 setErrorResponse (handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1557 }
1558
1559 // Queue an NCR to remove DNS if configured and the lease has it.
1560 if (p.updateDDNS) {
1561 queueNCR(CHG_REMOVE, lease4);
1562 }
1563
1564 } catch (const std::exception& ex) {
1566 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1567 .arg(ex.what());
1568 setErrorResponse(handle, ex.what());
1569 return (1);
1570 }
1572 .arg(lease4->addr_.toText());
1573 return (0);
1574}
1575
1576int
1578 try {
1579 extractCommand(handle);
1580
1581 // Arguments are mandatory.
1582 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1583 isc_throw(BadValue, "Command arguments missing or a not a map.");
1584 }
1585
1586 // At least one of the 'deleted-leases' or 'leases' must be present.
1587 auto deleted_leases = cmd_args_->get("deleted-leases");
1588 auto leases = cmd_args_->get("leases");
1589
1590 if (!deleted_leases && !leases) {
1591 isc_throw(BadValue, "neither 'deleted-leases' nor 'leases' parameter"
1592 " specified");
1593 }
1594
1595 // Make sure that 'deleted-leases' is a list, if present.
1596 if (deleted_leases && (deleted_leases->getType() != Element::list)) {
1597 isc_throw(BadValue, "the 'deleted-leases' parameter must be a list");
1598 }
1599
1600 // Make sure that 'leases' is a list, if present.
1601 if (leases && (leases->getType() != Element::list)) {
1602 isc_throw(BadValue, "the 'leases' parameter must be a list");
1603 }
1604
1605 // Parse deleted leases without deleting them from the database
1606 // yet. If any of the deleted leases or new leases appears to be
1607 // malformed we can easily rollback.
1608 std::list<std::pair<Parameters, Lease6Ptr> > parsed_deleted_list;
1609 if (deleted_leases) {
1610 auto leases_list = deleted_leases->listValue();
1611
1612 // Iterate over leases to be deleted.
1613 for (auto const& lease_params : leases_list) {
1614 // Parsing the lease may throw and it means that the lease
1615 // information is malformed.
1616 Parameters p = getParameters(true, lease_params);
1617 auto lease = getIPv6LeaseForDelete(p);
1618 parsed_deleted_list.push_back(std::make_pair(p, lease));
1619 }
1620 }
1621
1622 // Parse new/updated leases without affecting the database to detect
1623 // any errors that should cause an error response.
1624 std::list<Lease6Ptr> parsed_leases_list;
1625 if (leases) {
1627
1628 // Iterate over all leases.
1629 auto leases_list = leases->listValue();
1630 for (auto const& lease_params : leases_list) {
1631
1632 Lease6Parser parser;
1633 bool force_update;
1634
1635 // If parsing the lease fails we throw, as it indicates that the
1636 // command is malformed.
1637 Lease6Ptr lease6 = parser.parse(config, lease_params, force_update);
1638 parsed_leases_list.push_back(lease6);
1639 }
1640 }
1641
1642 // Count successful deletions and updates.
1643 size_t success_count = 0;
1644
1645 ElementPtr failed_deleted_list;
1646 if (!parsed_deleted_list.empty()) {
1647
1648 // Iterate over leases to be deleted.
1649 for (auto const& lease_params_pair : parsed_deleted_list) {
1650
1651 // This part is outside of the try-catch because an exception
1652 // indicates that the command is malformed.
1653 Parameters p = lease_params_pair.first;
1654 auto lease = lease_params_pair.second;
1655
1656 try {
1657 if (lease) {
1658 // This may throw if the lease couldn't be deleted for
1659 // any reason, but we still want to proceed with other
1660 // leases.
1661 if (LeaseMgrFactory::instance().deleteLease(lease)) {
1662 ++success_count;
1664
1665 } else {
1666 // Lazy creation of the list of leases which failed to delete.
1667 if (!failed_deleted_list) {
1668 failed_deleted_list = Element::createList();
1669 }
1670
1671 // If the lease doesn't exist we also want to put it
1672 // on the list of leases which failed to delete. That
1673 // corresponds to the lease6-del command which returns
1674 // an error when the lease doesn't exist.
1675 failed_deleted_list->add(createFailedLeaseMap(p.lease_type,
1676 p.addr, p.duid,
1678 "lease not found"));
1679 }
1680 }
1681
1682 } catch (const std::exception& ex) {
1683 // Lazy creation of the list of leases which failed to delete.
1684 if (!failed_deleted_list) {
1685 failed_deleted_list = Element::createList();
1686 }
1687 failed_deleted_list->add(createFailedLeaseMap(p.lease_type,
1688 p.addr, p.duid,
1690 ex.what()));
1691 }
1692 }
1693 }
1694
1695 // Process leases to be added or/and updated.
1696 ElementPtr failed_leases_list;
1697 if (!parsed_leases_list.empty()) {
1699
1700 // Iterate over all leases.
1701 for (auto const& lease : parsed_leases_list) {
1702
1703 auto result = CONTROL_RESULT_SUCCESS;
1704 std::ostringstream text;
1705 try {
1706 if (!MultiThreadingMgr::instance().getMode()) {
1707 // Not multi-threading.
1708 addOrUpdate6(lease, true);
1709 } else {
1710 // Multi-threading, try to lock first to avoid a race.
1711 ResourceHandler resource_handler;
1712 if (resource_handler.tryLock(lease->type_, lease->addr_)) {
1713 addOrUpdate6(lease, true);
1714 } else {
1716 "ResourceBusy: IP address:" << lease->addr_
1717 << " could not be updated.");
1718 }
1719 }
1720
1721 ++success_count;
1722 } catch (const LeaseCmdsConflict& ex) {
1723 result = CONTROL_RESULT_CONFLICT;
1724 text << ex.what();
1725
1726 } catch (const std::exception& ex) {
1727 result = CONTROL_RESULT_ERROR;
1728 text << ex.what();
1729 }
1730 // Handle an error.
1731 if (result != CONTROL_RESULT_SUCCESS) {
1732 // Lazy creation of the list of leases which failed to add/update.
1733 if (!failed_leases_list) {
1734 failed_leases_list = Element::createList();
1735 }
1736 failed_leases_list->add(createFailedLeaseMap(lease->type_,
1737 lease->addr_,
1738 lease->duid_,
1739 result,
1740 text.str()));
1741 }
1742 }
1743 }
1744
1745 // Start preparing the response.
1746 ElementPtr args;
1747
1748 if (failed_deleted_list || failed_leases_list) {
1749 // If there are any failed leases, let's include them in the response.
1750 args = Element::createMap();
1751
1752 // failed-deleted-leases
1753 if (failed_deleted_list) {
1754 args->set("failed-deleted-leases", failed_deleted_list);
1755 }
1756
1757 // failed-leases
1758 if (failed_leases_list) {
1759 args->set("failed-leases", failed_leases_list);
1760 }
1761 }
1762
1763 // Send the success response and include failed leases.
1764 std::ostringstream resp_text;
1765 resp_text << "Bulk apply of " << success_count << " IPv6 leases completed.";
1766 auto answer = createAnswer(success_count > 0 ? CONTROL_RESULT_SUCCESS :
1767 CONTROL_RESULT_EMPTY, resp_text.str(), args);
1768 setResponse(handle, answer);
1769
1772 .arg(success_count);
1773
1774 } catch (const std::exception& ex) {
1775 // Unable to parse the command and similar issues.
1777 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1778 .arg(ex.what());
1779 setErrorResponse(handle, ex.what());
1780 return (CONTROL_RESULT_ERROR);
1781 }
1782
1783 return (0);
1784}
1785
1786int
1788 Parameters p;
1789 Lease6Ptr lease6;
1791 try {
1792 extractCommand(handle);
1793 p = getParameters(true, cmd_args_);
1794
1795 switch (p.query_type) {
1796 case Parameters::TYPE_ADDR: {
1797 // If address was specified explicitly, let's use it as is.
1798
1799 // Let's see if there's such a lease at all.
1801 if (!lease6) {
1802 setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
1803 return (0);
1804 }
1805 break;
1806 }
1808 isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6.");
1809 break;
1810 }
1811 case Parameters::TYPE_DUID: {
1812 if (!p.duid) {
1813 isc_throw(InvalidParameter, "Program error: Query by duid "
1814 "requires duid to be specified");
1815 }
1816
1817 // Let's see if there's such a lease at all.
1819 p.iaid, p.subnet_id);
1820 if (!lease6) {
1821 setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
1822 return (0);
1823 }
1824 break;
1825 }
1826 default: {
1827 isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1828 break;
1829 }
1830 }
1831
1832 if (LeaseMgrFactory::instance().deleteLease(lease6)) {
1833 setSuccessResponse(handle, "IPv6 lease deleted.");
1835 } else {
1836 setErrorResponse (handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
1837 }
1838
1839 // Queue an NCR to remove DNS if configured and the lease has it.
1840 if (p.updateDDNS) {
1841 queueNCR(CHG_REMOVE, lease6);
1842 }
1843
1844 } catch (const std::exception& ex) {
1846 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1847 .arg(ex.what());
1848 setErrorResponse(handle, ex.what());
1849 return (1);
1850 }
1851
1853 .arg(lease6->addr_.toText());
1854 return (0);
1855}
1856
1857int
1859 try {
1860 extractCommand(handle);
1861
1862 // We need the lease to be specified.
1863 if (!cmd_args_) {
1864 isc_throw(isc::BadValue, "no parameters specified for lease4-update command");
1865 }
1866
1867 // Get the parameters specified by the user first.
1869 Lease4Ptr lease4;
1870 Lease4Parser parser;
1871 bool force_create = false;
1872
1873 // The parser does sanity checks (if the address is in scope, if
1874 // subnet-id is valid, etc)
1875 lease4 = parser.parse(config, cmd_args_, force_create);
1876 bool added = false;
1877 if (!MultiThreadingMgr::instance().getMode()) {
1878 // Not multi-threading.
1879 added = addOrUpdate4(lease4, force_create);
1880 } else {
1881 // Multi-threading, try to lock first to avoid a race.
1882 ResourceHandler4 resource_handler;
1883 if (resource_handler.tryLock4(lease4->addr_)) {
1884 added = addOrUpdate4(lease4, force_create);
1885 } else {
1887 "ResourceBusy: IP address:" << lease4->addr_
1888 << " could not be updated.");
1889 }
1890 }
1891
1892 if (added) {
1893 setSuccessResponse(handle, "IPv4 lease added.");
1894 } else {
1895 setSuccessResponse(handle, "IPv4 lease updated.");
1896 }
1899 .arg(lease4->addr_.toText());
1900
1901 } catch (const LeaseCmdsConflict& ex) {
1903 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1904 .arg(ex.what());
1906 return (0);
1907
1908 } catch (const std::exception& ex) {
1910 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1911 .arg(ex.what());
1912 setErrorResponse(handle, ex.what());
1913 return (1);
1914 }
1915
1916 return (0);
1917}
1918
1919int
1921 try {
1922 extractCommand(handle);
1923
1924 // We need the lease to be specified.
1925 if (!cmd_args_) {
1926 isc_throw(isc::BadValue, "no parameters specified for lease6-update command");
1927 }
1928
1929 // Get the parameters specified by the user first.
1931 Lease6Ptr lease6;
1932 Lease6Parser parser;
1933 bool force_create = false;
1934
1935 // The parser does sanity checks (if the address is in scope, if
1936 // subnet-id is valid, etc)
1937 lease6 = parser.parse(config, cmd_args_, force_create);
1938 bool added = false;
1939 if (!MultiThreadingMgr::instance().getMode()) {
1940 // Not multi-threading.
1941 added = addOrUpdate6(lease6, force_create);
1942 } else {
1943 // Multi-threading, try to lock first to avoid a race.
1944 ResourceHandler resource_handler;
1945 if (resource_handler.tryLock(lease6->type_, lease6->addr_)) {
1946 added = addOrUpdate6(lease6, force_create);
1947 } else {
1949 "ResourceBusy: IP address:" << lease6->addr_
1950 << " could not be updated.");
1951 }
1952 }
1953
1954 if (added) {
1955 setSuccessResponse(handle, "IPv6 lease added.");
1956 } else {
1957 setSuccessResponse(handle, "IPv6 lease updated.");
1958 }
1961 .arg(lease6->addr_.toText());
1962
1963 } catch (const LeaseCmdsConflict& ex) {
1965 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1966 .arg(ex.what());
1968 return (0);
1969
1970 } catch (const std::exception& ex) {
1972 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1973 .arg(ex.what());
1974 setErrorResponse(handle, ex.what());
1975 return (1);
1976 }
1977
1978 return (0);
1979}
1980
1981int
1983 try {
1984 extractCommand(handle);
1985
1986 SimpleParser parser;
1987 SubnetID id = 0;
1988
1989 size_t num = 0; // number of leases deleted
1990 stringstream ids; // a text with subnet-ids being wiped
1991
1992 // The subnet-id parameter is now optional.
1993 if (cmd_args_ && cmd_args_->contains("subnet-id")) {
1994 id = parser.getUint32(cmd_args_, "subnet-id");
1995 }
1996
1997 if (id) {
1998 // Wipe a single subnet.
2000 ids << " " << id;
2001
2002 auto assigned_observation = StatsMgr::instance().getObservation(
2003 StatsMgr::generateName("subnet", id, "assigned-addresses"));
2004
2005 int64_t previous_assigned = 0;
2006
2007 if (assigned_observation) {
2008 previous_assigned = assigned_observation->getInteger().first;
2009 }
2010
2011 auto declined_observation = StatsMgr::instance().getObservation(
2012 StatsMgr::generateName("subnet", id, "declined-addresses"));
2013
2014 int64_t previous_declined = 0;
2015
2016 if (declined_observation) {
2017 previous_declined = declined_observation->getInteger().first;
2018 }
2019
2021 StatsMgr::generateName("subnet", id, "assigned-addresses"),
2022 static_cast<int64_t>(0));
2023
2025 StatsMgr::generateName("subnet", id, "declined-addresses"),
2026 static_cast<int64_t>(0));
2027
2028 auto const& sub = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(id);
2029 if (sub) {
2030 for (auto const& pool : sub->getPools(Lease::TYPE_V4)) {
2031 const std::string& name_aa(StatsMgr::generateName("subnet", sub->getID(),
2032 StatsMgr::generateName("pool", pool->getID(),
2033 "assigned-addresses")));
2034 if (!StatsMgr::instance().getObservation(name_aa)) {
2035 StatsMgr::instance().setValue(name_aa, static_cast<int64_t>(0));
2036 }
2037
2038 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2039 StatsMgr::generateName("pool", pool->getID(),
2040 "declined-addresses")));
2041 if (!StatsMgr::instance().getObservation(name_da)) {
2042 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2043 }
2044 }
2045 }
2046
2047 StatsMgr::instance().addValue("assigned-addresses", -previous_assigned);
2048
2049 StatsMgr::instance().addValue("declined-addresses", -previous_declined);
2050 } else {
2051 // Wipe them all!
2053 ConstCfgSubnets4Ptr subnets = config->getCfgSubnets4();
2054 const Subnet4Collection* subs = subnets->getAll();
2055
2056 // Go over all subnets and wipe leases in each of them.
2057 for (auto const& sub : *subs) {
2058 num += LeaseMgrFactory::instance().wipeLeases4(sub->getID());
2059 ids << " " << sub->getID();
2061 StatsMgr::generateName("subnet", sub->getID(), "assigned-addresses"),
2062 static_cast<int64_t>(0));
2063
2065 StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
2066 static_cast<int64_t>(0));
2067
2068 for (auto const& pool : sub->getPools(Lease::TYPE_V4)) {
2069 const std::string& name_aa(StatsMgr::generateName("subnet", sub->getID(),
2070 StatsMgr::generateName("pool", pool->getID(),
2071 "assigned-addresses")));
2072 if (!StatsMgr::instance().getObservation(name_aa)) {
2073 StatsMgr::instance().setValue(name_aa, static_cast<int64_t>(0));
2074 }
2075
2076 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2077 StatsMgr::generateName("pool", pool->getID(),
2078 "declined-addresses")));
2079 if (!StatsMgr::instance().getObservation(name_da)) {
2080 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2081 }
2082 }
2083 }
2084
2085 StatsMgr::instance().setValue("assigned-addresses", static_cast<int64_t>(0));
2086
2087 StatsMgr::instance().setValue("declined-addresses", static_cast<int64_t>(0));
2088 }
2089
2090 stringstream tmp;
2091 tmp << "Deleted " << num << " IPv4 lease(s) from subnet(s)" << ids.str();
2093 : CONTROL_RESULT_EMPTY, tmp.str());
2094 setResponse(handle, response);
2095 } catch (const std::exception& ex) {
2097 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2098 .arg(ex.what());
2099 setErrorResponse(handle, ex.what());
2100 return (1);
2101 }
2102
2104 .arg(cmd_args_ ? cmd_args_->str() : "<no args>");
2105 return (0);
2106}
2107
2108int
2110 try {
2111 extractCommand(handle);
2112
2113 SimpleParser parser;
2114 SubnetID id = 0;
2115
2116 size_t num = 0; // number of leases deleted
2117 stringstream ids; // a text with subnet-ids being wiped
2118
2123
2124 // The subnet-id parameter is now optional.
2125 if (cmd_args_ && cmd_args_->contains("subnet-id")) {
2126 id = parser.getUint32(cmd_args_, "subnet-id");
2127 }
2128
2129 if (id) {
2130 // Wipe a single subnet.
2132 ids << " " << id;
2133
2134 auto assigned_na_observation = StatsMgr::instance().getObservation(
2135 StatsMgr::generateName("subnet", id, "assigned-nas"));
2136
2137 int64_t previous_assigned_na = 0;
2138
2139 if (assigned_na_observation) {
2140 previous_assigned_na = assigned_na_observation->getInteger().first;
2141 }
2142
2143 auto assigned_pd_observation = StatsMgr::instance().getObservation(
2144 StatsMgr::generateName("subnet", id, "assigned-pds"));
2145
2146 int64_t previous_assigned_pd = 0;
2147
2148 if (assigned_pd_observation) {
2149 previous_assigned_pd = assigned_pd_observation->getInteger().first;
2150 }
2151
2152 auto declined_observation = StatsMgr::instance().getObservation(
2153 StatsMgr::generateName("subnet", id, "declined-addresses"));
2154
2155 int64_t previous_declined = 0;
2156
2157 if (declined_observation) {
2158 previous_declined = declined_observation->getInteger().first;
2159 }
2160
2162 StatsMgr::generateName("subnet", id, "assigned-nas" ),
2163 static_cast<int64_t>(0));
2164
2166 StatsMgr::generateName("subnet", id, "assigned-pds"),
2167 static_cast<int64_t>(0));
2168
2170 StatsMgr::generateName("subnet", id, "declined-addresses"),
2171 static_cast<int64_t>(0));
2172
2174 StatsMgr::generateName("subnet", id, "registered-nas"),
2175 static_cast<int64_t>(0));
2176
2177 auto const& sub = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(id);
2178 if (sub) {
2179 for (auto const& pool : sub->getPools(Lease::TYPE_NA)) {
2180 const std::string& name_anas(StatsMgr::generateName("subnet", sub->getID(),
2181 StatsMgr::generateName("pool", pool->getID(),
2182 "assigned-nas")));
2183 if (!StatsMgr::instance().getObservation(name_anas)) {
2184 StatsMgr::instance().setValue(name_anas, static_cast<int64_t>(0));
2185 }
2186
2187 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2188 StatsMgr::generateName("pool", pool->getID(),
2189 "declined-addresses")));
2190 if (!StatsMgr::instance().getObservation(name_da)) {
2191 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2192 }
2193 }
2194
2195 for (auto const& pool : sub->getPools(Lease::TYPE_PD)) {
2196 const std::string& name_apds(StatsMgr::generateName("subnet", sub->getID(),
2197 StatsMgr::generateName("pd-pool", pool->getID(),
2198 "assigned-pds")));
2199 if (!StatsMgr::instance().getObservation(name_apds)) {
2200 StatsMgr::instance().setValue(name_apds, static_cast<int64_t>(0));
2201 }
2202 }
2203 }
2204
2205 StatsMgr::instance().addValue("assigned-nas", -previous_assigned_na);
2206
2207 StatsMgr::instance().addValue("assigned-pds", -previous_assigned_pd);
2208
2209 StatsMgr::instance().addValue("declined-addresses", -previous_declined);
2210 } else {
2211 // Wipe them all!
2213 ConstCfgSubnets6Ptr subnets = config->getCfgSubnets6();
2214 const Subnet6Collection* subs = subnets->getAll();
2215
2216 // Go over all subnets and wipe leases in each of them.
2217 for (auto const& sub : *subs) {
2218 num += LeaseMgrFactory::instance().wipeLeases6(sub->getID());
2219 ids << " " << sub->getID();
2221 StatsMgr::generateName("subnet", sub->getID(), "assigned-nas" ),
2222 static_cast<int64_t>(0));
2223
2225 StatsMgr::generateName("subnet", sub->getID(), "assigned-pds"),
2226 static_cast<int64_t>(0));
2227
2229 StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
2230 static_cast<int64_t>(0));
2231
2233 StatsMgr::generateName("subnet", sub->getID(), "registered-nas"),
2234 static_cast<int64_t>(0));
2235
2236 for (auto const& pool : sub->getPools(Lease::TYPE_NA)) {
2237 const std::string& name_anas(StatsMgr::generateName("subnet", sub->getID(),
2238 StatsMgr::generateName("pool", pool->getID(),
2239 "assigned-nas")));
2240 if (!StatsMgr::instance().getObservation(name_anas)) {
2241 StatsMgr::instance().setValue(name_anas, static_cast<int64_t>(0));
2242 }
2243
2244 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2245 StatsMgr::generateName("pool", pool->getID(),
2246 "declined-addresses")));
2247 if (!StatsMgr::instance().getObservation(name_da)) {
2248 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2249 }
2250 }
2251
2252 for (auto const& pool : sub->getPools(Lease::TYPE_PD)) {
2253 const std::string& name_apds(StatsMgr::generateName("subnet", sub->getID(),
2254 StatsMgr::generateName("pd-pool", pool->getID(),
2255 "assigned-pds")));
2256 if (!StatsMgr::instance().getObservation(name_apds)) {
2257 StatsMgr::instance().setValue(name_apds, static_cast<int64_t>(0));
2258 }
2259 }
2260 }
2261
2262 StatsMgr::instance().setValue("assigned-nas", static_cast<int64_t>(0));
2263
2264 StatsMgr::instance().setValue("assigned-pds", static_cast<int64_t>(0));
2265
2266 StatsMgr::instance().setValue("declined-addresses", static_cast<int64_t>(0));
2267 }
2268
2269 stringstream tmp;
2270 tmp << "Deleted " << num << " IPv6 lease(s) from subnet(s)" << ids.str();
2272 : CONTROL_RESULT_EMPTY, tmp.str());
2273 setResponse(handle, response);
2274 } catch (const std::exception& ex) {
2276 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2277 .arg(ex.what());
2278 setErrorResponse(handle, ex.what());
2279 return (1);
2280 }
2281
2283 .arg(cmd_args_ ? cmd_args_->str() : "<no args>");
2284 return (0);
2285}
2286
2289 Lease6Ptr lease6;
2290
2291 switch (parameters.query_type) {
2292 case Parameters::TYPE_ADDR: {
2293 // If address was specified explicitly, let's use it as is.
2294
2295 // Let's see if there's such a lease at all.
2296 lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type,
2297 parameters.addr);
2298 if (!lease6) {
2299 lease6.reset(new Lease6());
2300 lease6->addr_ = parameters.addr;
2301 }
2302 break;
2303 }
2305 isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6.");
2306 break;
2307 }
2308 case Parameters::TYPE_DUID: {
2309 if (!parameters.duid) {
2310 isc_throw(InvalidParameter, "Program error: Query by duid "
2311 "requires duid to be specified");
2312 }
2313
2314 // Let's see if there's such a lease at all.
2315 lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type,
2316 *parameters.duid,
2317 parameters.iaid,
2318 parameters.subnet_id);
2319 break;
2320 }
2321 default:
2322 isc_throw(InvalidOperation, "Unknown query type: "
2323 << static_cast<int>(parameters.query_type));
2324 }
2325
2326 return (lease6);
2327}
2328
2331 short family) const {
2332 ConstElementPtr param = params->get(name);
2333 if (!param) {
2334 isc_throw(BadValue, "'" << name << "' parameter is missing.");
2335 }
2336
2337 if (param->getType() != Element::string) {
2338 isc_throw(BadValue, "'" << name << "' is not a string.");
2339 }
2340
2341 IOAddress addr(0);
2342 try {
2343 addr = IOAddress(param->stringValue());
2344 } catch (const std::exception& ex) {
2345 isc_throw(BadValue, "'" << param->stringValue()
2346 << "' is not a valid IP address.");
2347 }
2348
2349 if (addr.getFamily() != family) {
2350 isc_throw(BadValue, "Invalid "
2351 << (family == AF_INET6 ? "IPv6" : "IPv4")
2352 << " address specified: " << param->stringValue());
2353 }
2354
2355 return (addr);
2356}
2357
2358int
2360 std::stringstream ss;
2361 int resp_code = CONTROL_RESULT_ERROR;
2362
2363 try {
2364 extractCommand(handle);
2365
2366 // Get the target lease address. Invalid value will throw.
2367 IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET);
2368
2369 if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
2370 ss << "DDNS updating is not enabled";
2371 resp_code = CONTROL_RESULT_CONFLICT;
2372 } else {
2373 // Find the lease.
2375 if (!lease) {
2376 ss << "No lease found for: " << addr.toText();
2377 resp_code = CONTROL_RESULT_EMPTY;
2378 } else if (lease->hostname_.empty()) {
2379 ss << "Lease for: " << addr.toText()
2380 << ", has no hostname, nothing to update";
2381 resp_code = CONTROL_RESULT_CONFLICT;
2382 } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
2383 ss << "Neither forward nor reverse updates enabled for lease for: "
2384 << addr.toText();
2385 resp_code = CONTROL_RESULT_CONFLICT;
2386 } else {
2387 // We have a lease with a hostname and updates in at least
2388 // one direction enabled. Queue an NCR for it.
2389 queueNCR(CHG_ADD, lease);
2390 ss << "NCR generated for: " << addr.toText()
2391 << ", hostname: " << lease->hostname_;
2392 setSuccessResponse(handle, ss.str());
2394 return (0);
2395 }
2396 }
2397 } catch (const std::exception& ex) {
2398 ss << ex.what();
2399 }
2400
2402 setErrorResponse(handle, ss.str(), resp_code);
2403 return (resp_code == CONTROL_RESULT_EMPTY || resp_code == CONTROL_RESULT_CONFLICT ? 0 : 1);
2404}
2405
2406int
2408 std::stringstream ss;
2409 int resp_code = CONTROL_RESULT_ERROR;
2410
2411 try {
2412 extractCommand(handle);
2413
2414 // Get the target lease address. Invalid value will throw.
2415 IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET6);
2416
2417 if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
2418 ss << "DDNS updating is not enabled";
2419 resp_code = CONTROL_RESULT_CONFLICT;
2420 } else {
2421 // Find the lease.
2423 if (!lease) {
2424 ss << "No lease found for: " << addr.toText();
2425 resp_code = CONTROL_RESULT_EMPTY;
2426 } else if (lease->hostname_.empty()) {
2427 ss << "Lease for: " << addr.toText()
2428 << ", has no hostname, nothing to update";
2429 resp_code = CONTROL_RESULT_CONFLICT;
2430 } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
2431 ss << "Neither forward nor reverse updates enabled for lease for: "
2432 << addr.toText();
2433 resp_code = CONTROL_RESULT_CONFLICT;
2434 } else {
2435 // We have a lease with a hostname and updates in at least
2436 // one direction enabled. Queue an NCR for it.
2437 queueNCR(CHG_ADD, lease);
2438 ss << "NCR generated for: " << addr.toText()
2439 << ", hostname: " << lease->hostname_;
2440 setSuccessResponse(handle, ss.str());
2442 return (0);
2443 }
2444 }
2445 } catch (const std::exception& ex) {
2446 ss << ex.what();
2447 }
2448
2450 setErrorResponse(handle, ss.str(), resp_code);
2451 return (resp_code == CONTROL_RESULT_EMPTY ? 0 : 1);
2452}
2453
2456 const IOAddress& lease_address,
2457 const DuidPtr& duid,
2458 const int control_result,
2459 const std::string& error_message) const {
2460 auto failed_lease_map = Element::createMap();
2461 failed_lease_map->set("type", Element::create(Lease::typeToText(lease_type)));
2462
2463 if (!lease_address.isV6Zero()) {
2464 failed_lease_map->set("ip-address", Element::create(lease_address.toText()));
2465
2466 } else if (duid) {
2467 failed_lease_map->set("duid", Element::create(duid->toText()));
2468 }
2469
2470 // Associate the result with the lease.
2471 failed_lease_map->set("result", Element::create(control_result));
2472 failed_lease_map->set("error-message", Element::create(error_message));
2473
2474 return (failed_lease_map);
2475}
2476
2477int
2479 bool v4 = true;
2480 try {
2481 extractCommand(handle);
2482 v4 = (cmd_name_ == "lease4-write");
2483
2484 if (!cmd_args_) {
2485 isc_throw(isc::BadValue, "no parameters specified for the command");
2486 }
2487
2488 ConstElementPtr file = cmd_args_->get("filename");
2489 if (!file) {
2490 isc_throw(BadValue, "'filename' parameter not specified");
2491 }
2492 if (file->getType() != Element::string) {
2493 isc_throw(BadValue, "'filename' parameter must be a string");
2494 }
2495
2496 std::string filename;
2497 try {
2498 filename = CfgMgr::instance().validatePath(file->stringValue());
2499 } catch (const SecurityWarn& ex) {
2501 .arg(ex.what());
2502 filename = file->stringValue();
2503 } catch (const std::exception& ex) {
2504 isc_throw(BadValue, "'filename' parameter is invalid: " << ex.what());
2505 }
2506
2507 if (v4) {
2509 } else {
2511 }
2512
2513 ostringstream s;
2514 s << (v4 ? "IPv4" : "IPv6")
2515 << " lease database into '"
2516 << filename << "'.";
2518 setResponse(handle, response);
2519 } catch (const std::exception& ex) {
2520 setErrorResponse(handle, ex.what());
2521 return (CONTROL_RESULT_ERROR);
2522 }
2523
2524 return (0);
2525}
2526
2527void
2530 uint32_t offer_lifetime;
2531 callout_handle.getArgument("offer_lifetime", offer_lifetime);
2532 if (!offer_lifetime) {
2533 // Offers leases are not being persisted, nothing to do.
2534 return;
2535 }
2536
2537 // Get the remaining arguments we need.
2538 Pkt4Ptr query;
2539 Pkt4Ptr response;
2540 Lease4CollectionPtr leases;
2541
2542 callout_handle.getArgument("query4", query);
2543 callout_handle.getArgument("response4", response);
2544 callout_handle.getArgument("leases4", leases);
2545
2546 if (!leases || leases->empty() || !((*leases)[0])) {
2547 isc_throw(Unexpected, "lease4Offer - no lease!");
2548 }
2549
2550 Lease4Ptr lease = (*leases)[0];
2551 try {
2552 if (mgr->evaluateVariables(query, response, lease)) {
2554 }
2555 } catch (const NoSuchLease&) {
2556 isc_throw(LeaseCmdsConflict, "failed to update"
2557 " the lease with address " << lease->addr_ <<
2558 " either because the lease has been"
2559 " deleted or it has changed in the database");
2560 } catch (const std::exception& ex) {
2561 isc_throw(Unexpected, "evaluating binding variables failed for: "
2562 << query->getLabel() << ", :" << ex.what());
2563 }
2564}
2565
2566void
2569 Pkt4Ptr query;
2570 Pkt4Ptr response;
2571 Lease4CollectionPtr leases;
2572
2573 // Get the necessary arguments.
2574 callout_handle.getArgument("query4", query);
2575 callout_handle.getArgument("response4", response);
2576 callout_handle.getArgument("leases4", leases);
2577
2578 if (!leases) {
2579 isc_throw(Unexpected, "leases4Committed - leases is null");
2580 }
2581
2582 // In some cases we may have no lease, e.g. DHCPNAK,
2583 // or no response e.g. DHCPRELEASE.
2584 if (leases->empty() || !response || (response->getType() != DHCPACK)) {
2585 return;
2586 }
2587
2588 Lease4Ptr lease = (*leases)[0];
2589 if (!lease) {
2590 isc_throw(Unexpected, "leases4Committed - lease is null");
2591 }
2592
2593 try {
2594 if (mgr->evaluateVariables(query, response, lease)) {
2596 }
2597 } catch (const NoSuchLease&) {
2598 isc_throw(LeaseCmdsConflict, "failed to update"
2599 " the lease with address " << lease->addr_ <<
2600 " either because the lease has been"
2601 " deleted or it has changed in the database");
2602 } catch (const std::exception& ex) {
2603 isc_throw(Unexpected, "evaluating binding variables failed for: "
2604 << query->getLabel() << ", :" << ex.what());
2605 }
2606}
2607
2608void
2611 Pkt6Ptr query;
2612 Pkt6Ptr response;
2613 Lease6CollectionPtr leases;
2614
2615 // Get the necessary arguments.
2616 callout_handle.getArgument("query6", query);
2617 callout_handle.getArgument("response6", response);
2618 callout_handle.getArgument("leases6", leases);
2619
2620 if (!leases) {
2621 isc_throw(Unexpected, "leases6Committed - leases is null");
2622 }
2623
2624 // In some cases we may have no active leases or no response.
2625 if (leases->empty() || !response) {
2626 return;
2627 }
2628
2629 int attempted = 0;
2630 int failed = 0;
2631 for (auto lease : *leases) {
2632 try {
2633 if (!lease) {
2634 isc_throw(Unexpected, "leases6Committed - lease is null");
2635 }
2636
2642 // Only update a lease if its active.
2643 if (lease->valid_lft_) {
2644 ++attempted;
2645 if (mgr->evaluateVariables(query, response, lease)) {
2647 }
2648 }
2649 } catch (const NoSuchLease&) {
2650 ++failed;
2652 .arg(lease->addr_.toText())
2653 .arg(query->getLabel());
2654 } catch (const std::exception& ex) {
2655 ++failed;
2657 .arg(query->getLabel())
2658 .arg(lease->addr_.toText())
2659 .arg(ex.what());
2660 }
2661 }
2662
2663 if (failed) {
2664 isc_throw(Unexpected, failed << " out of " << attempted
2665 << " leases failed to update for "
2666 << query->getLabel());
2667 }
2668}
2669
2670int
2672 return (impl_->leaseAddHandler(handle));
2673}
2674
2675int
2677 return (impl_->lease6BulkApplyHandler(handle));
2678}
2679
2680int
2682 return (impl_->leaseGetHandler(handle));
2683}
2684
2685int
2687 return (impl_->leaseGetAllHandler(handle));
2688}
2689
2690int
2692 return (impl_->leaseGetPageHandler(handle));
2693}
2694
2695int
2697 return (impl_->leaseGetByHwAddressHandler(handle));
2698}
2699
2700int
2702 return (impl_->leaseGetByClientIdHandler(handle));
2703}
2704
2705int
2707 return (impl_->leaseGetByDuidHandler(handle));
2708}
2709
2710int
2712 return (impl_->leaseGetByStateHandler(handle));
2713}
2714
2715int
2717 return (impl_->leaseGetByHostnameHandler(handle));
2718}
2719
2720int
2722 return (impl_->lease4DelHandler(handle));
2723}
2724
2725int
2727 return (impl_->lease6DelHandler(handle));
2728}
2729
2730int
2732 return (impl_->lease4UpdateHandler(handle));
2733}
2734
2735int
2737 return (impl_->lease6UpdateHandler(handle));
2738}
2739
2740int
2743 return (impl_->lease4WipeHandler(handle));
2744}
2745
2746int
2749 return (impl_->lease6WipeHandler(handle));
2750}
2751
2752int
2754 return (impl_->lease4ResendDdnsHandler(handle));
2755}
2756
2757int
2759 return (impl_->lease6ResendDdnsHandler(handle));
2760}
2761
2762int
2764 return (impl_->leaseWriteHandler(handle));
2765}
2766
2768}
2769
2770
2771void
2774 impl_->lease4Offer(callout_handle, mgr);
2775}
2776
2777void
2780 impl_->leases4Committed(callout_handle, mgr);
2781}
2782
2783void
2786 impl_->leases6Committed(callout_handle, mgr);
2787}
2788
2789} // end of namespace lease_cmds
2790} // end of namespace isc
static DUID fromText(const std::string &text)
Create DUID from the textual format.
Definition duid.cc:50
static const DUID & EMPTY()
Defines the constant "empty" DUID.
Definition duid.cc:55
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:300
@ map
Definition data.h:160
@ integer
Definition data.h:153
@ boolean
Definition data.h:155
@ list
Definition data.h:159
@ string
Definition data.h:157
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:350
Exception thrown when a command failed due to a conflict.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown when an unexpected error condition occurs.
Base class that command handler implementers may use for common tasks.
Definition cmds_impl.h:21
std::string cmd_name_
Stores the command name extracted by a call to extractCommand.
Definition cmds_impl.h:69
void setErrorResponse(hooks::CalloutHandle &handle, const std::string &text, int status=CONTROL_RESULT_ERROR)
Set the callout argument "response" to indicate an error.
Definition cmds_impl.h:54
data::ConstElementPtr cmd_args_
Stores the command arguments extracted by a call to extractCommand.
Definition cmds_impl.h:72
void extractCommand(hooks::CalloutHandle &handle)
Extracts the command name and arguments from a Callout handle.
Definition cmds_impl.h:29
void setSuccessResponse(hooks::CalloutHandle &handle, const std::string &text)
Set the callout argument "response" to indicate success.
Definition cmds_impl.h:43
void setResponse(hooks::CalloutHandle &handle, data::ConstElementPtr &response)
Set the callout argument "response" to the given response.
Definition cmds_impl.h:64
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
std::string validatePath(const std::string data_path) const
Validates a file path against the supported directory for DHCP data.
Definition cfgmgr.cc:40
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
static ClientIdPtr fromText(const std::string &text)
Create client identifier from the textual format.
Definition duid.cc:73
Holds DUID (DHCPv6 Unique Identifier).
Definition duid.h:142
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual Lease6Collection getLeases6(Lease::Type type, const DUID &duid, uint32_t iaid) const =0
Returns existing IPv6 leases for a given DUID+IA combination.
virtual size_t wipeLeases6(const SubnetID &subnet_id)=0
Virtual method which removes specified leases.
static void updateStatsOnAdd(const Lease4Ptr &lease)
Update in-memory stats when adding a v4 lease.
virtual Lease4Collection getLeases4(SubnetID subnet_id) const =0
Returns all IPv4 leases for the particular subnet identifier.
virtual void writeLeases6(const std::string &filename)=0
Write V6 leases to a file.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const =0
Returns an IPv4 lease for specified IPv4 address.
static void updateStatsOnUpdate(const Lease4Ptr &existing, const Lease4Ptr &lease)
Update in-memory stats when updating a v4 lease.
virtual bool addLease(const Lease4Ptr &lease)=0
Adds an IPv4 lease.
virtual size_t wipeLeases4(const SubnetID &subnet_id)=0
Virtual method which removes specified leases.
virtual void updateLease4(const Lease4Ptr &lease4)=0
Updates IPv4 lease.
virtual void writeLeases4(const std::string &filename)=0
Write V4 leases to a file.
static void updateStatsOnDelete(const Lease4Ptr &lease)
Update in-memory stats when deleting a v4 lease.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
virtual void updateLease6(const Lease6Ptr &lease6)=0
Updates IPv6 lease.
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
Attempt to update lease that was not there.
Resource race avoidance RAII handler for DHCPv4.
bool tryLock4(const asiolink::IOAddress &addr)
Tries to acquires a resource.
Resource race avoidance RAII handler.
bool tryLock(Lease::Type type, const asiolink::IOAddress &addr)
Tries to acquires a resource.
Per-packet callout handle.
void getArgument(const std::string &name, T &value) const
Get argument.
Parser for Lease4 structure.
virtual isc::dhcp::Lease4Ptr parse(isc::dhcp::ConstSrvConfigPtr &cfg, const isc::data::ConstElementPtr &lease_info, bool &force_create)
Parses Element tree and tries to convert to Lease4.
Parser for Lease6 structure.
virtual isc::dhcp::Lease6Ptr parse(isc::dhcp::ConstSrvConfigPtr &cfg, const isc::data::ConstElementPtr &lease_info, bool &force_create)
Parses Element tree and tries to convert to Lease4.
Parameters specified for lease commands.
Definition lease_cmds.cc:67
uint32_t iaid
IAID identifier used for v6 leases.
HWAddrPtr hwaddr
Specifies hardware address (used when query_type is TYPE_HWADDR).
Definition lease_cmds.cc:85
Lease::Type lease_type
Lease type (NA,TA or PD) used for v6 leases.
Type query_type
specifies parameter types
Type
specifies type of query (by IP addr, by hwaddr, by DUID)
Definition lease_cmds.cc:71
@ TYPE_CLIENT_ID
query by client identifier (v4 only).
Definition lease_cmds.cc:75
@ TYPE_HWADDR
query by hardware address (v4 only)
Definition lease_cmds.cc:73
@ TYPE_ADDR
query by IP address (either v4 or v6)
Definition lease_cmds.cc:72
isc::dhcp::ClientIdPtr client_id
Specifies identifier value (used when query_type is TYPE_CLIENT_ID).
Definition lease_cmds.cc:91
static Type txtToType(const std::string &txt)
Attempts to covert text to one of specified types.
bool updateDDNS
Indicates whether or not DNS should be updated.
IOAddress addr
Specifies IPv4/v6 address (used when query_type is TYPE_ADDR).
Definition lease_cmds.cc:82
SubnetID subnet_id
Specifies subnet-id (always used).
Definition lease_cmds.cc:79
isc::dhcp::DuidPtr duid
Specifies identifier value (used when query_type is TYPE_DUID).
Definition lease_cmds.cc:88
Wrapper class around reservation command handlers.
Definition lease_cmds.cc:63
int lease4DelHandler(CalloutHandle &handle)
lease4-del command handler
IOAddress getAddressParam(ConstElementPtr params, const std::string name, short family=AF_INET) const
static void lease4Offer(CalloutHandle &callout_handle, BindingVariableMgrPtr mgr)
lease4_offer hookpoint handler.
ElementPtr createFailedLeaseMap(const Lease::Type &lease_type, const IOAddress &lease_address, const DuidPtr &duid, const int control_result, const std::string &error_message) const
Returns a map holding brief information about a lease which failed to be deleted, updated or added.
int leaseGetByStateHandler(hooks::CalloutHandle &handle)
lease4-get-by-state and lease6-get-by-state commands handler
static bool addOrUpdate6(Lease6Ptr lease, bool force_create)
Add or update lease.
int lease6BulkApplyHandler(CalloutHandle &handle)
lease6-bulk-apply command handler
int leaseGetByDuidHandler(hooks::CalloutHandle &handle)
lease6-get-by-duid command handler
int lease6UpdateHandler(CalloutHandle &handle)
lease6-update handler
int leaseGetPageHandler(hooks::CalloutHandle &handle)
lease4-get-page, lease6-get-page commands handler
Lease6Ptr getIPv6LeaseForDelete(const Parameters &parameters) const
Convenience function fetching IPv6 address to be used to delete a lease.
int leaseGetByHostnameHandler(hooks::CalloutHandle &handle)
lease4-get-by-hostname and lease6-get-by-hostname commands handler
int lease6DelHandler(CalloutHandle &handle)
lease6-del command handler
int leaseGetByHwAddressHandler(hooks::CalloutHandle &handle)
lease4-get-by-hw-address, lease6-get-by-hw-address command handler
static ConstElementPtr getExtendedInfo6(const Lease6Ptr &lease)
Get DHCPv6 extended info.
int leaseGetHandler(CalloutHandle &handle)
lease4-get, lease6-get command handler
static bool addOrUpdate4(Lease4Ptr lease, bool force_create)
Add or update lease.
static void leases4Committed(CalloutHandle &callout_handle, BindingVariableMgrPtr mgr)
leases4_committed hookpoint handler.
int lease6WipeHandler(CalloutHandle &handle)
lease6-wipe handler
int leaseGetByClientIdHandler(hooks::CalloutHandle &handle)
lease4-get-by-client-id command handler
int lease6ResendDdnsHandler(CalloutHandle &handle)
lease6-resend-ddns handler
int leaseAddHandler(CalloutHandle &handle)
lease4-add, lease6-add command handler
int lease4ResendDdnsHandler(CalloutHandle &handle)
lease4-resend-ddns handler
Parameters getParameters(bool v6, const ConstElementPtr &args)
Extracts parameters required for reservation-get and reservation-del.
static void leases6Committed(CalloutHandle &callout_handle, BindingVariableMgrPtr mgr)
leases6_committed hookpoint handler.
int lease4UpdateHandler(CalloutHandle &handle)
lease4-update handler
int lease4WipeHandler(CalloutHandle &handle)
lease4-wipe handler
int leaseGetAllHandler(CalloutHandle &handle)
lease4-get-all, lease6-get-all commands handler
int leaseWriteHandler(CalloutHandle &handle)
lease4-write handler, lease6-write handler
int lease4ResendDdnsHandler(hooks::CalloutHandle &handle)
lease4-resend-ddns command handler
int leaseGetByStateHandler(hooks::CalloutHandle &handle)
lease4-get-by-state and lease6-get-by-state commands handler
int lease6WipeHandler(hooks::CalloutHandle &handle)
lease6-wipe handler
int leaseGetPageHandler(hooks::CalloutHandle &handle)
lease4-get-page, lease6-get-page commands handler
int lease6DelHandler(hooks::CalloutHandle &handle)
lease6-del command handler
int leaseGetAllHandler(hooks::CalloutHandle &handle)
lease4-get-all, lease6-get-all commands handler
int leaseGetByHostnameHandler(hooks::CalloutHandle &handle)
lease4-get-by-hostname and lease6-get-by-hostname commands handler
void leases4Committed(hooks::CalloutHandle &callout_handle, BindingVariableMgrPtr mgr)
leases4_committed hookpoint handler.
int lease4DelHandler(hooks::CalloutHandle &handle)
lease4-del command handler
int leaseWriteHandler(hooks::CalloutHandle &handle)
lease4-write handler, lease6-write handler
int leaseAddHandler(hooks::CalloutHandle &handle)
lease4-add, lease6-add command handler
int leaseGetByClientIdHandler(hooks::CalloutHandle &handle)
lease4-get-by-client-id command handler
void lease4Offer(hooks::CalloutHandle &callout_handle, BindingVariableMgrPtr mgr)
lease4_offer hookpoint handler.
int lease4UpdateHandler(hooks::CalloutHandle &handle)
lease4-update handler
int leaseGetHandler(hooks::CalloutHandle &handle)
lease4-get, lease6-get command handler
int leaseGetByHwAddressHandler(hooks::CalloutHandle &handle)
lease4-get-by-hw-address, lease6-get-by-hw-address command handler
int lease6UpdateHandler(hooks::CalloutHandle &handle)
lease6-update handler
void leases6Committed(hooks::CalloutHandle &callout_handle, BindingVariableMgrPtr mgr)
leases6_committed hookpoint handler.
int leaseGetByDuidHandler(hooks::CalloutHandle &handle)
lease6-get-by-duid command handler
int lease6BulkApplyHandler(hooks::CalloutHandle &handle)
lease6-bulk-apply command handler
int lease4WipeHandler(hooks::CalloutHandle &handle)
lease4-wipe handler
int lease6ResendDdnsHandler(hooks::CalloutHandle &handle)
lease6-resend-ddns command handler
ObservationPtr getObservation(const std::string &name) const
Returns an observation.
static StatsMgr & instance()
Statistics Manager accessor method.
static std::string generateName(const std::string &context, Type index, const std::string &stat_name)
Generates statistic name in a given context.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
A generic exception that is thrown if a parameter given violates security check but enforcement is la...
Definition filesystem.h:22
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void setValue(const std::string &name, const int64_t value)
Records absolute integer observation.
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
const isc::log::MessageID LEASE_CMDS_DEL4
const isc::log::MessageID LEASE_CMDS_WIPE4_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE4_FAILED
const isc::log::MessageID LEASE_CMDS_WIPE6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE6_CONFLICT
const isc::log::MessageID LEASE_CMDS_UPDATE4_CONFLICT
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4_FAILED
const isc::log::MessageID LEASE_CMDS_DEL6
const isc::log::MessageID LEASE_CMDS_ADD4_FAILED
const isc::log::MessageID LEASE_CMDS_LEASES6_COMMITTED_LEASE_ERROR
const isc::log::MessageID LEASE_CMDS_PATH_SECURITY_WARNING
const isc::log::MessageID LEASE_CMDS_ADD6
const isc::log::MessageID LEASE_CMDS_ADD4
const isc::log::MessageID LEASE_CMDS_WIPE6
const isc::log::MessageID LEASE_CMDS_ADD6_CONFLICT
const isc::log::MessageID LEASE_CMDS_BULK_APPLY6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE6
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4
const isc::log::MessageID LEASE_CMDS_GET6_FAILED
const isc::log::MessageID LEASE_CMDS_WIPE4
const isc::log::MessageID LEASE_CMDS_BULK_APPLY6
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6_FAILED
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6
const isc::log::MessageID LEASE_CMDS_GET4_FAILED
const isc::log::MessageID LEASE_CMDS_ADD4_CONFLICT
const isc::log::MessageID LEASE_CMDS_LEASES6_COMMITTED_CONFLICT
const isc::log::MessageID LEASE_CMDS_DEL4_FAILED
const isc::log::MessageID LEASE_CMDS_ADD6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE4
const isc::log::MessageID LEASE_CMDS_DEL6_FAILED
An abstract API for lease database.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_CONFLICT
Status code indicating that the command was unsuccessful due to a conflict between the command argume...
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
boost::shared_ptr< Lease4Collection > Lease4CollectionPtr
A shared pointer to the collection of IPv4 leases.
Definition lease.h:523
boost::shared_ptr< const SrvConfig > ConstSrvConfigPtr
Const pointer to the SrvConfig.
void queueNCR(const NameChangeType &chg_type, const Lease4Ptr &lease)
Creates name change request from the DHCPv4 lease.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:528
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition lease.h:693
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:934
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
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:863
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition duid.h:216
@ DHCPACK
Definition dhcp4.h:239
boost::shared_ptr< const CfgSubnets4 > ConstCfgSubnets4Ptr
Const pointer.
boost::shared_ptr< const CfgSubnets6 > ConstCfgSubnets6Ptr
Const pointer.
boost::shared_ptr< Lease6Collection > Lease6CollectionPtr
A shared pointer to the collection of IPv6 leases.
Definition lease.h:696
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition lease.h:520
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:315
const int LEASE_CMDS_DBG_COMMAND_DATA
Logging level used to log successful commands.
isc::log::Logger lease_cmds_logger("lease-cmds-hooks")
boost::shared_ptr< BindingVariableMgr > BindingVariableMgrPtr
Defines a shared pointer to a BindingVariableMgr.
boost::multiprecision::checked_int128_t int128_t
Definition bigints.h:19
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition hwaddr.h:20
static HWAddr fromText(const std::string &text, const uint16_t htype=HTYPE_ETHER)
Creates instance of the hardware address from textual format.
Definition hwaddr.cc:62
Structure that holds a lease for IPv6 address and/or prefix.
Definition lease.h:536
@ ACTION_UPDATE
update extended info tables.
Definition lease.h:576
a common structure for IPv4 and IPv6 leases
Definition lease.h:31
static constexpr uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69
static constexpr uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition lease.h:75
static constexpr uint32_t STATE_DECLINED
Declined lease.
Definition lease.h:72
static constexpr uint32_t STATE_REGISTERED
Registered self-generated lease.
Definition lease.h:81
static std::string basicStatesToText(const uint32_t state)
Returns name(s) of the basic lease state(s).
Definition lease.cc:89
static constexpr uint32_t STATE_RELEASED
Released lease held in the database for lease affinity.
Definition lease.h:78
static void syncCurrentExpirationTime(const Lease &from, Lease &to)
Sync lease current expiration time with new value from another lease, so that additional operations c...
Definition lease.cc:316
Type
Type of lease or pool.
Definition lease.h:46
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
@ TYPE_V4
IPv4 lease.
Definition lease.h:50
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
static std::string typeToText(Type type)
returns text representation of a lease type
Definition lease.cc:56