Kea 3.1.1
subnet_cmds.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2025 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 <subnet_cmds.h>
10#include <subnet_cmds_log.h>
13#include <dhcpsrv/cfgmgr.h>
22#include <sstream>
23#include <cstdint>
24
25using namespace isc::config;
26using namespace isc::data;
27using namespace isc::dhcp;
28using namespace isc::util;
29using namespace std;
30
31namespace isc {
32namespace subnet_cmds {
33
45
58template <typename SubnetConfigParserType>
60public:
61
65 ConfigDiffManager(std::string space) : space_(space) {
66 if (space != DHCP4_OPTION_SPACE && space != DHCP6_OPTION_SPACE) {
67 isc_throw(BadValue, "wrong dhcp type " << space
68 << ", supported " << DHCP4_OPTION_SPACE << " or "
70 }
71
72 // Define the hierarchy and keys matching functions.
73
76 auto const& subnet_empty = [](ElementPtr& element) {
77 for (auto const& kv : element->mapValue()) {
78 auto const& key = kv.first;
79 if (key != "id" && key != "subnet") {
80 return (false);
81 }
82 }
83 return (true);
84 };
85
89 auto const& pool_empty = [](ElementPtr& element) {
90 for (auto const& kv : element->mapValue()) {
91 auto const& key = kv.first;
92 if (key != "pool") {
93 if (key == "option-data") {
94 if (kv.second->size()) {
95 return (false);
96 }
97 } else {
98 return (false);
99 }
100 }
101 }
102 return (true);
103 };
104
108 auto const& pd_pool_empty = [](ElementPtr& element) {
109 for (auto const& kv : element->mapValue()) {
110 auto const& key = kv.first;
111 if (key != "prefix" && key != "prefix-len" && key != "delegated-len") {
112 if (key == "option-data") {
113 if (kv.second->size()) {
114 return (false);
115 }
116 } else {
117 return (false);
118 }
119 }
120 }
121 return (true);
122 };
123
127 auto const& option_empty = [](ElementPtr& element) {
128 for (auto const& kv : element->mapValue()) {
129 auto const& key = kv.first;
130 if (key != "code" && key != "name" && key != "space") {
131 return (false);
132 }
133 }
134 return (true);
135 };
136
139 auto const& match_any = [](ElementPtr&, ElementPtr&) -> bool { return (true); };
140
143 auto const& subnet_match = [](ElementPtr& left, ElementPtr& right) -> bool {
144 return (left->get("id")->intValue() == right->get("id")->intValue());
145 };
146
149 auto const& pool_match = [](ElementPtr& left, ElementPtr& right) -> bool {
150 return (left->get("pool")->stringValue() == right->get("pool")->stringValue());
151 };
152
155 auto const& pd_pool_match = [](ElementPtr& left, ElementPtr& right) -> bool {
156 return (left->get("prefix")->stringValue() == right->get("prefix")->stringValue() &&
157 left->get("prefix-len")->intValue() == right->get("prefix-len")->intValue() &&
158 left->get("delegated-len")->intValue() == right->get("delegated-len")->intValue());
159 };
160
163 auto const& option_match = [&](ElementPtr& left, ElementPtr& right) -> bool {
164 std::string space = space_;
165 std::string left_space = space;
166 std::string right_space = space;
167 if (left->get("space")) {
168 left_space = left->get("space")->stringValue();
169 }
170 if (right->get("space")) {
171 right_space = right->get("space")->stringValue();
172 }
173 if (left_space == right_space) {
174 if (left->find("code") && right->find("code")) {
175 return (left->get("code")->intValue() == right->get("code")->intValue());
176 } else if (left->find("name") && right->find("name")) {
177 return (left->get("name")->stringValue() == right->get("name")->stringValue());
178 }
179 }
180 return (false);
181 };
182
185 auto const& subnet_is_key = [](const std::string& key) -> bool {
186 return (key == "id" || key == "subnet");
187 };
188
191 auto const& pool_is_key = [](const std::string& key) -> bool {
192 return (key == "pool");
193 };
194
197 auto const& pd_pool_is_key = [](const std::string& key) -> bool {
198 return (key == "prefix" || key == "prefix-len" || key == "delegated-len");
199 };
200
203 auto const& option_is_key = [](const std::string& key) -> bool {
204 return (key == "space" || key == "code" || key == "name");
205 };
206
207 subnet_hierarchy_any_match_ = {
208 { { "subnet", { subnet_match, subnet_empty, subnet_is_key } } },
209 { { "pools", { match_any, pool_empty, pool_is_key } },
210 { "pd-pools", { match_any, pd_pool_empty, pd_pool_is_key } },
211 { "option-data", { option_match, option_empty, option_is_key } } },
212 { { "option-data", { option_match, option_empty, option_is_key } } }
213 };
214
215 subnet_hierarchy_ = {
216 { { "subnet", { subnet_match, subnet_empty, subnet_is_key } } },
217 { { "pools", { pool_match, pool_empty, pool_is_key } },
218 { "pd-pools", { pd_pool_match, pd_pool_empty, pd_pool_is_key } },
219 { "option-data", { option_match, option_empty, option_is_key } } },
220 { { "option-data", { option_match, option_empty, option_is_key } } }
221 };
222 }
223
226
234 void processDelta(UpdateType type, ElementPtr& old_element,
235 ConstElementPtr& subnet_element) {
236 // To be able to have unified format of the key values of pools and
237 // pd-pools, we need to parse the user provided data using one of
238 // the @c Subnet4ConfigParser or @c Subnet6ConfigParser.
239 // This will make keys match when traversing the configuration tree
240 // hierarchy.
241
242 // Save the initial list of keys provided by user.
243 std::set<std::string> initial_keys;
244 for (auto const& key : subnet_element->mapValue()) {
245 initial_keys.insert(key.first);
246 }
247
248 // The merge delete functionality is flexible and permits deleting
249 // entire elements by providing only the keys identifying the
250 // respective element. In the case of options, the space can be a
251 // determined automatically for options inside the default spaces.
252 // The @c Subnet4ConfigParser and @c Subnet6ConfigParser will throw
253 // if the "data" is not provided for specified options, so we must
254 // extend the user input with valid data from the existing
255 // configuration. We don't care about exact pool or pd-pool match as
256 // the data will be removed anyway. A relaxed search for the "data"
257 // value for the specific option space, code and name is done
258 // storing only the valid data so that the parser will not complain.
259 if (type == UPDATE_DELTA_DEL) {
260 ElementPtr extended = boost::const_pointer_cast<Element>(subnet_element);
261 extend("option-data", "data", extended, old_element, subnet_hierarchy_any_match_, "subnet");
262 }
263
264 // The parser is applied on user provided data and then is translated
265 // back to an JSON tree to be able to convert the data to an uniform
266 // internal format: same number of spaces, using prefix or interval
267 // format:
268 // "192.0.2.1-192.0.2.100" and "192.0.2.1 - 192.0.2.100" refer to the
269 // same thing, so does "192.0.2.0/24" and "192.0.2.0 - 192.0.2.255"
270 // "2003:db8::1-2003:db8::10" and "2003:db8::1 - 2003:db8::10" refer
271 // to the same thing, so does "2003:db8::/120" and
272 // "2003:db8:: - 2003:db8::ff"
273 // The Subnet::toElement function adds extra parameters
274 // (e.g. option-data) even if they are empty. This is used for better
275 // matching parameters.
276 SubnetConfigParserType parser;
277 auto new_element = parser.parse(subnet_element)->toElement();
278
279 // The Subnet::toElement function formats the data, but it adds some
280 // undesired elements which will be interpreted as being added by
281 // user, so they must be removed.
282 std::set<std::string> final_keys;
283 for (auto const& key : new_element->mapValue()) {
284 if (initial_keys.find(key.first) == initial_keys.end()) {
285 final_keys.insert(key.first);
286 }
287 }
288 for (auto const& value : final_keys) {
289 new_element->remove(value);
290 }
291
292 if (type == UPDATE_DELTA_ADD) {
293 // Do the merge add.
294 mergeDiffAdd(old_element, new_element, subnet_hierarchy_, "subnet");
295 } else if (type == UPDATE_DELTA_DEL) {
296 // Do the merge del.
297 mergeDiffDel(old_element, new_element, subnet_hierarchy_, "subnet");
298 }
299 };
300
301private:
302
304 std::string space_;
305
308 HierarchyDescriptor subnet_hierarchy_any_match_;
309
312 HierarchyDescriptor subnet_hierarchy_;
313};
314
319public:
320
336 template<typename CfgType>
337 ConstElementPtr getSubnetList(const CfgType& cfg,
338 const std::string& protocol_type) const {
339 // Create a list where we're going to store subnets' information.
340 ElementPtr subnet_list = Element::createList();
341 // Create arguments map and add subnet map.
343 args->set("subnets", subnet_list);
344
345 // Retrieve all subnets from the configuration structure.
346 auto subnets = cfg->getAll();
347
348 // Iterate over all subnets and retrieve the information we're interested in.
349 for (auto const& s : *subnets) {
350 // Information for the individual subnets is held in the map.
351 subnet_list->add(subnetToElement(*s, true));
352 }
353
354 // Generate the status message including the number of subnets found.
355 std::ostringstream s;
356 s << subnets->size() << " " << protocol_type << " subnet";
357
358 // For 0 subnets or more than 1 subnets returned, we use plural form 'subnets'.
359 if (subnets->size() != 1) {
360 s << "s";
361 }
362 s << " found";
363
364 // Log the number of subnets found.
365 if (subnets->size() > 0) {
367 .arg(subnets->size())
368 .arg(protocol_type);
369 return (createAnswer(CONTROL_RESULT_SUCCESS, s.str(), args));
370
371 } else {
372 // No subnets found.
374 .arg(protocol_type);
375 return (createAnswer(CONTROL_RESULT_EMPTY, s.str(), args));
376 }
377 }
378
391 template<typename SubnetTypePtr, typename CfgType>
392 ConstElementPtr getSubnet(const CfgType& cfg,
393 const data::ConstElementPtr& arguments,
394 const std::string& command_name,
395 const std::string& subnet_parameter,
396 const std::string& protocol_version) const {
397 // Arguments are required.
398 if (!arguments) {
399 isc_throw(BadValue, "no arguments specified for the '"
400 << command_name << "' command");
401
402 // Arguments must be a map.
403 } else if (arguments->getType() != Element::map) {
404 isc_throw(BadValue, "arguments specified for the '"
405 << command_name << "' command are not a map");
406
407 // Currently we allow only one parameter in this command: id or
408 // subnet and they are mutually exclusive.
409 } else if (arguments->size() != 1) {
410 isc_throw(BadValue, "invalid number of arguments " << arguments->size()
411 << " for the '" << command_name << "' command. Expecting"
412 " 'id' or 'subnet'");
413 }
414
415 SubnetTypePtr subnet;
416
417 ConstElementPtr subnet_id_param;
418 ConstElementPtr subnet_param = arguments->get("subnet");
419
420 // Check if the 'subnet' parameter has been specified in the command.
421 if (subnet_param) {
422 // This parameter must be a string.
423 if (subnet_param->getType() != Element::string) {
424 isc_throw(BadValue, "'subnet' parameter must be a string");
425 }
426 // Try to find a subnet by prefix.
427 subnet = cfg->getByPrefix(subnet_param->stringValue());
428
429 } else {
430 // Check if the 'id' parameter has been specified in the command.
431 subnet_id_param = arguments->get("id");
432 if (subnet_id_param) {
433 // Subnet identifier must be an integer.
434 if (subnet_id_param->getType() != Element::integer) {
435 isc_throw(BadValue, "'id' parameter must be an integer");
436 }
437 // Try to find a subnet by subnet identifier.
438 subnet = cfg->getBySubnetId(SubnetID(subnet_id_param->intValue()));
439
440 } else {
441 // If neither of these parameters has been specified, signal an error.
442 isc_throw(BadValue, "'id' or 'subnet' parameter required");
443 }
444 }
445
446 ConstElementPtr response;
447
448 // If subnet found, wrap this response in the successful response.
449 if (subnet) {
450 ElementPtr subnets_list = Element::createList();
451 subnets_list->add(subnet->toElement());
452 ElementPtr response_arguments = Element::createMap();
453 response_arguments->set(subnet_parameter, subnets_list);
454
455 std::ostringstream s;
456 s << "Info about " << protocol_version << " subnet " << subnet->toText()
457 << " (id " << subnet->getID() << ") returned";
458 response = createAnswer(CONTROL_RESULT_SUCCESS, s.str(),
459 response_arguments);
460
462 .arg(subnet->toText())
463 .arg(subnet->getID());
464
465 // No subnet found.
466 } else {
467 std::stringstream s;
468 if (subnet_param) {
469 s << "No " << subnet_param->stringValue() << " subnet found";
470 } else {
471 s << "No subnet with id " << subnet_id_param->intValue() << " found";
472 }
473
475 response = createAnswer(CONTROL_RESULT_EMPTY, s.str());
476 }
477
478 return (response);
479 }
480
502 template<typename SimpleParserType, typename SubnetConfigParserType,
503 typename CfgType>
504 ConstElementPtr addSubnet(CfgType& cfg, const ConstElementPtr& arguments,
505 const std::string& command_name,
506 const std::string& subnet_parameter,
507 const std::string& protocol_version) {
508
509 // Arguments are required.
510 if (!arguments) {
511 isc_throw(BadValue, "no arguments specified for the '"
512 << command_name << "' command");
513
514 // Arguments must be a map.
515 } else if (arguments->getType() != Element::map) {
516 isc_throw(BadValue, "arguments specified for the '"
517 << command_name << "' command are not a map");
518
519 } else if (arguments->size() != 1) {
520 isc_throw(BadValue, "invalid number of arguments "
521 << arguments->size() << " for the '"
522 << command_name << "' command. Expecting "
523 "'" << subnet_parameter << "' list");
524 }
525
526 // The map should contain a 'subnet4' or 'subnet6' list.
527 ConstElementPtr subnet_list = arguments->get(subnet_parameter);
528 if (!subnet_list) {
529 isc_throw(BadValue, "missing '" << subnet_parameter << "'"
530 " argument for the '" << command_name << "' command");
531
532 // Make sure it is a list.
533 } else if (subnet_list->getType() != Element::list) {
534 isc_throw(BadValue, "'" << subnet_parameter << "'"
535 " argument specified for the '"
536 << command_name << "' command is not a list");
537
538 // Currently we allow only one subnet in the list.
539 } else if (subnet_list->size() != 1) {
540 isc_throw(BadValue, "invalid number of subnets specified for the"
541 " '" << command_name << "' command. Expected one subnet");
542 }
543
544 // Make sure that the subnet information is a map.
545 ConstElementPtr subnet_element = subnet_list->get(0);
546 if (subnet_element->getType() != Element::map) {
547 isc_throw(BadValue, "invalid subnet information specified for the"
548 "'" << command_name << "' command. Expected a map");
549
550 // Make sure that the subnet doesn't specify any host reservations.
551 // This is only allowed when setting the full server configuration.
552 // In order to add reservations for a subnet a different set of
553 // commands is used.
554 } else if (subnet_element->get("reservations")) {
555 isc_throw(BadValue, "must not specify host reservations with '"
556 << command_name << "'. Use 'reservation-add' to add"
557 " a reservation to a subnet");
558 }
559
560 // The tricky part is that some of the subnet parameters may be
561 // inherited from the global scope. The command itself has no
562 // information about the global parameters' values, so we will
563 // construct a "global" map populated with the server's globals
564 // and add the subnet(s) from the command to that.
565 ElementPtr global_scope;
566
567 // Add in any configured, global parameters from the server
568 global_scope = CfgMgr::instance().getCurrentCfg()->
569 getConfiguredGlobals()->toElement();
570
571 global_scope->set(subnet_parameter, subnet_list);
572
573 // Now, let's specify the default values using SimpleParser4
574 // or SimpleParser6 and derive to the subnet we're adding.
575 SimpleParserType::setAllDefaults(global_scope);
576 SimpleParserType::deriveParameters(global_scope);
577
578 // Finally, let's parse the subnet information extended with the
579 // default values.
580 SubnetConfigParserType parser;
581 auto subnet = parser.parse(subnet_list->get(0));
582
583 // Add this subnet to the current configuration.
584 cfg->add(subnet);
585
586 // Update the statistics. There is no need to remove any existing statistics
587 // because we are not removing any pools, just adding new ones.
588 cfg->updateStatistics();
589
590 // Some allocators require initialization of their state. In particular,
591 // the FLQ allocator needs to populate free leases.
592 subnet->initAllocatorsAfterConfigure();
593
594 // The response contains a subnet prefix and subnet id.
595 ElementPtr subnet_info = Element::createMap();
596 subnet_info->set("id",
597 Element::create(static_cast<long int>(subnet->getID())));
598 subnet_info->set("subnet", Element::create(subnet->toText()));
599
600 // The subnet information is encapsulated in a single element list.
601 ElementPtr subnets_list = Element::createList();
602 subnets_list->add(subnet_info);
603
604 // The list is called subnets just like with 'subnet4-get' and
605 // 'subnet6-get'.
606 ElementPtr response_arguments = Element::createMap();
607 response_arguments->set("subnets", subnets_list);
608
609 // Add text stating that IPv4 or IPv6 subnet has been added.
610 std::ostringstream response_text;
611 response_text << protocol_version << " subnet added";
612
613 // Create the response.
615 response_text.str(),
616 response_arguments);
617
619 .arg(subnet->toText())
620 .arg(subnet->getID());
621
622 return (response);
623 }
624
651 template<typename SimpleParserType, typename SubnetConfigParserType,
652 typename SharedNetworkPtrType, typename SubnetTypePtr,
653 typename CfgType>
655 const ConstElementPtr& arguments,
656 const std::string& command_name,
657 const std::string& subnet_parameter,
658 const std::string& protocol_version,
659 UpdateType type = UPDATE_REPLACE) {
660
661 // Arguments are required.
662 if (!arguments) {
663 isc_throw(BadValue, "no arguments specified for the '"
664 << command_name << "' command");
665
666 // Arguments must be a map.
667 } else if (arguments->getType() != Element::map) {
668 isc_throw(BadValue, "arguments specified for the '"
669 << command_name << "' command are not a map");
670
671 } else if (arguments->size() != 1) {
672 isc_throw(BadValue, "invalid number of arguments "
673 << arguments->size() << " for the '"
674 << command_name << "' command. Expecting "
675 "'" << subnet_parameter << "' list");
676 }
677
678 // The map should contain a 'subnet4' or 'subnet6' list.
679 ConstElementPtr subnet_list = arguments->get(subnet_parameter);
680 if (!subnet_list) {
681 isc_throw(BadValue, "missing '" << subnet_parameter << "'"
682 " argument for the '" << command_name << "' command");
683
684 // Make sure it is a list.
685 } else if (subnet_list->getType() != Element::list) {
686 isc_throw(BadValue, "'" << subnet_parameter << "'"
687 " argument specified for the '"
688 << command_name << "' command is not a list");
689
690 // Currently we allow only one subnet in the list.
691 } else if (subnet_list->size() != 1) {
692 isc_throw(BadValue, "invalid number of subnets specified for the"
693 " '" << command_name << "' command. Expected one subnet");
694 }
695
696 // Make sure that the subnet information is a map.
697 ConstElementPtr subnet_element = subnet_list->get(0);
698 if (subnet_element->getType() != Element::map) {
699 isc_throw(BadValue, "invalid subnet information specified for the"
700 "'" << command_name << "' command. Expected a map");
701
702 // Make sure that the subnet doesn't specify any host reservations.
703 // This is only allowed when setting the full server configuration.
704 } else if (subnet_element->get("reservations")) {
705 isc_throw(BadValue, "must not specify host reservations with '"
706 << command_name << "'.");
707 }
708
709 // Verify that the subnet ID is specified and in 1..max
710 ConstElementPtr id_element = subnet_element->get("id");
711 if (!id_element) {
712 isc_throw(BadValue, "must specify subnet id with '"
713 << command_name << "' command.");
714 }
715 const SubnetID& subnet_id =
716 SimpleParser::getInteger(subnet_element, "id", 1, SUBNET_ID_MAX);
717
718 // Check the subnet with the same ID.
719 auto old_subnet = cfg->getBySubnetId(subnet_id);
720 if (!old_subnet) {
722 "Can't find subnet '" << subnet_id << "' to update");
723 }
724
725 if (type != UPDATE_REPLACE) {
726 auto old_element = old_subnet->toElement();
727
728 std::string space = DHCP4_OPTION_SPACE;
729 if (subnet_parameter == "subnet6") {
730 space = DHCP6_OPTION_SPACE;
731 }
732
734
735 mgr.processDelta(type, old_element, subnet_element);
736
737 // Update the list element with the data after merge add/del.
738 boost::const_pointer_cast<Element>(subnet_list)->set(0, old_element);
739 }
740
741 // The tricky part is that some of the subnet parameters may be
742 // inherited from the global scope. The command itself has no
743 // information about the global parameters' values, so we will
744 // construct a "global" map populated with the server's globals
745 // and replace the subnet(s) from the command to that.
746 ElementPtr global_scope;
747
748 // Add in any configured, global parameters from the server
749 global_scope = CfgMgr::instance().getCurrentCfg()->
750 getConfiguredGlobals()->toElement();
751
752 global_scope->set(subnet_parameter, subnet_list);
753
754 // Now, let's specify the default values using SimpleParser4
755 // or SimpleParser6 and derive to the subnet we're updating.
756 SimpleParserType::setAllDefaults(global_scope);
757 SimpleParserType::deriveParameters(global_scope);
758
759 // Finally, let's parse the subnet information extended with the
760 // default values.
761 SubnetConfigParserType parser;
762 auto subnet = parser.parse(subnet_list->get(0));
763
764 // Subnet update may result in removing some of the pools. Any possibly existing
765 // per-pool statistics should be removed.
766 cfg->removeStatistics();
767
768 try {
769 // Update this subnet to the current configuration.
770 auto old = cfg->replace(subnet);
771 if (!old) {
772 isc_throw(Unexpected, "Unable to update subnet '" << subnet_id
773 << "' in the configuration");
774 }
775
776 // Deal with shared network.
777 SharedNetworkPtrType network;
778 old->getSharedNetwork(network);
779 if (network) {
780 if (!network->replace(subnet)) {
781 // Try to rollback.
782 if (!cfg->replace(old)) {
783 isc_throw(Unexpected, "Unable to rollback subnet '"
784 << subnet_id << "' update. Configuration is "
785 "broken beyond repair.");
786 }
787 isc_throw(Unexpected, "Cancelled subnet '" << subnet_id
788 << "' update: update in shared network '"
789 << network->getName() << "' failed.");
790 }
791 }
792 } catch (...) {
793 // We removed the statistics but we failed to process the command.
794 // We have to add it back before leaving.
795 cfg->updateStatistics();
796 throw;
797 }
798
799 // Update the statistics for all subnets and the pools that left in the
800 // updated subnet.
801 cfg->updateStatistics();
802
803 // Some allocators require initialization of their state. In particular,
804 // the FLQ allocator needs to populate free leases.
805 subnet->initAllocatorsAfterConfigure();
806
807 // The response contains a subnet prefix and subnet id.
808 ElementPtr subnet_info = Element::createMap();
809 subnet_info->set("id",
810 Element::create(static_cast<long int>(subnet->getID())));
811 subnet_info->set("subnet", Element::create(subnet->toText()));
812
813 // The subnet information is encapsulated in a single element list.
814 ElementPtr subnets_list = Element::createList();
815 subnets_list->add(subnet_info);
816
817 // The list is called subnets just like with 'subnet4-get' and
818 // 'subnet6-get'.
819 ElementPtr response_arguments = Element::createMap();
820 response_arguments->set("subnets", subnets_list);
821
822 // Add text stating that IPv4 or IPv6 subnet has been updated.
823 std::ostringstream response_text;
824 response_text << protocol_version << " subnet updated";
825
826 // Create the response.
828 response_text.str(),
829 response_arguments);
830
832 .arg(subnet->toText())
833 .arg(subnet->getID());
834
835 return (response);
836 }
837
852 template<typename CfgType,
853 typename SharedNetworkPtrType>
854 ConstElementPtr delSubnet(CfgType& cfg, const ConstElementPtr& arguments,
855 const std::string& command_name,
856 const std::string& protocol_version) {
857 // Arguments are required.
858 if (!arguments) {
859 isc_throw(BadValue, "no arguments specified for the '"
860 << command_name << "' command");
861
862 // Arguments must be a map.
863 } else if (arguments->getType() != Element::map) {
864 isc_throw(BadValue, "arguments specified for the '"
865 << command_name << "' command are not a map");
866
867 // Currently we only accept one argument, i.e. subnet identifier.
868 } else if (arguments->size() != 1) {
869 isc_throw(BadValue, "invalid number of arguments specified for the '"
870 << command_name << " command. Expected subnet identifier");
871 }
872
873 ConstElementPtr subnet_id_element = arguments->get("id");
874 if (!subnet_id_element) {
875 isc_throw(BadValue, "subnet identifier is required for the '"
876 << command_name << "' command");
877
878 // Subnet identifier must be an integer.
879 } else if (subnet_id_element->getType() != Element::integer) {
880 isc_throw(BadValue, "subnet identifier specified for the '"
881 << command_name << "' is not a number");
882 }
883
884 uint32_t subnet_id = static_cast<uint32_t>(subnet_id_element->intValue());
885 auto subnet = cfg->getBySubnetId(SubnetID(subnet_id));
886
887 // If subnet found, remove it from the configuration.
888 if (!subnet) {
889 // Subnet not found.
890 std::stringstream tmp;
891 tmp << "no subnet with id " << subnet_id << " found";
892 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
893 }
894
895 // Remove existing statistics because we're removing some pools.
896 cfg->removeStatistics();
897
898 try {
899 cfg->del(subnet);
900
901 // Remove subnet from its shared-network (if one).
902 SharedNetworkPtrType network;
903 subnet->getSharedNetwork(network);
904 if (network) {
905 network->del(subnet->getID());
906 }
907
908 // Delete associated host reservations.
909 CfgHostsPtr cfg_hosts = CfgMgr::instance().getCurrentCfg()->getCfgHosts();
910 if (command_name == "subnet4-del") {
911 cfg_hosts->delAll4(subnet_id);
912 } else {
913 cfg_hosts->delAll6(subnet_id);
914 }
915 } catch (...) {
916 // We removed the statistics but we failed to process the command.
917 // We have to add it back before leaving.
918 cfg->updateStatistics();
919 throw;
920 }
921
922 // Update the statistics for the remaning subnets and pools.
923 cfg->updateStatistics();
924
925 std::ostringstream response_text;
926 response_text << protocol_version << " subnet " << subnet->toText()
927 << " (id " << subnet->getID() << ") deleted";
928
929 ElementPtr details = Element::createMap();
931 lst->add(subnetToElement(*subnet, false));
932 details->set("subnets", lst);
933
934 // Create the response.
936 response_text.str(), details);
937
939 .arg(subnet->toText())
940 .arg(subnet->getID());
941
942 return (response);
943 }
944
949 ElementPtr subnetToElement(const Subnet& subnet, bool include_shared_network) const {
950 ElementPtr subnet_element = Element::createMap();
951 subnet_element->set("id",
952 Element::create(static_cast<long int>(subnet.getID())));
953 subnet_element->set("subnet", Element::create(subnet.toText()));
954
955 if (include_shared_network) {
956 std::string sn_name = subnet.getSharedNetworkName();
957 if (!sn_name.empty()) {
958 subnet_element->set("shared-network-name", data::Element::create(sn_name));
959 } else {
960 // Shared network name is null.
961 subnet_element->set("shared-network-name", data::Element::create());
962 }
963 }
964
965 return (subnet_element);
966 }
967
984 template<typename CfgType>
985 ConstElementPtr getNetworkList(const CfgType& networks_cfg,
986 const std::string& protocol_type) const {
987 // Create a list where we're going to store networks' information.
988 ElementPtr network_list = Element::createList();
989 // Create arguments map and add network map.
991 args->set("shared-networks", network_list);
992
993 // Retrieve all networks from the configuration structure.
994 auto networks = networks_cfg->getAll();
995
996 // Iterate over all networks and retrieve the information we're interested in.
997 for (auto const& n : *networks) {
999 json->set("name", Element::create(n->getName()));
1000 // Information for the individual networks is held in the map.
1001 network_list->add(json);
1002 }
1003
1004 // Generate the status message including the number of networks found.
1005 std::ostringstream s;
1006 s << networks->size() << " " << protocol_type << " network";
1007 // For 0 networks or more than 1 networks returned, we use plural form 'networks'.
1008 if (networks->size() != 1) {
1009 s << "s";
1010 }
1011 s << " found";
1012
1013 // Log the number of networks found.
1014 if (networks->size() > 0) {
1016 .arg(networks->size())
1017 .arg(protocol_type);
1018 return (createAnswer(CONTROL_RESULT_SUCCESS, s.str(), args));
1019
1020 } else {
1021 // No networks found.
1023 .arg(protocol_type);
1024 return (createAnswer(CONTROL_RESULT_EMPTY, s.str(), args));
1025 }
1026 }
1027
1039 template<typename NetworkTypePtr, typename CfgType>
1040 ConstElementPtr getNetwork(const CfgType& cfg,
1041 const data::ConstElementPtr& arguments,
1042 const std::string& command_name,
1043 const std::string& protocol_version) const {
1044 // Arguments are required.
1045 if (!arguments) {
1046 isc_throw(BadValue, "no arguments specified for the '"
1047 << command_name << "' command");
1048
1049 // Arguments must be a map.
1050 } else if (arguments->getType() != Element::map) {
1051 isc_throw(BadValue, "arguments specified for the '"
1052 << command_name << "' command are not a map");
1053 }
1054
1055 // Make sure there's name parameter and that it's a string.
1056 ConstElementPtr name = arguments->get("name");
1057 if (!name) {
1058 isc_throw(BadValue, "invalid '" << command_name
1059 << "': missing mandatory 'name' parameter");
1060 }
1061 if (name->getType() != Element::string) {
1062 isc_throw(BadValue, "'name' parameter must be a string");
1063 }
1064
1065 // Try to find the network.
1066 NetworkTypePtr network = cfg->getByName(name->stringValue());
1067
1068 ConstElementPtr response;
1069
1070 // If network found, wrap this response in the successful response.
1071 if (network) {
1072 ElementPtr networks_list = Element::createList();
1073 networks_list->add(network->toElement());
1074 ElementPtr response_arguments = Element::createMap();
1075 response_arguments->set("shared-networks", networks_list);
1076
1077 std::ostringstream s;
1078 s << "Info about " << protocol_version << " shared network '" << network->getName()
1079 << "' returned";
1080 response = createAnswer(CONTROL_RESULT_SUCCESS, s.str(), response_arguments);
1081
1083 .arg(network->getName());
1084
1085 // No network found.
1086 } else {
1087 std::stringstream s;
1088 s << "No '" << name->stringValue() << "' shared network found";
1089
1091 response = createAnswer(CONTROL_RESULT_EMPTY, s.str());
1092 }
1093
1094 return (response);
1095 }
1096
1121 template<typename SimpleParserType, typename SharedNetworkParserType,
1122 typename CfgNetworksType, typename CfgSubnetsType>
1123 ConstElementPtr addNetwork(CfgNetworksType& networks_cfg, CfgSubnetsType& subnets_cfg,
1124 const ConstElementPtr& arguments,
1125 const std::string& command_name,
1126 const std::string& protocol_version) {
1127
1128 // Arguments are required.
1129 if (!arguments) {
1130 isc_throw(BadValue, "no arguments specified for the '"
1131 << command_name << "' command");
1132
1133 // Arguments must be a map.
1134 } else if (arguments->getType() != Element::map) {
1135 isc_throw(BadValue, "arguments specified for the '"
1136 << command_name << "' command are not a map");
1137
1138 }
1139
1140 // The map should contain a 'shared-networks' list.
1141 ConstElementPtr network_list = arguments->get("shared-networks");
1142 if (!network_list) {
1143 isc_throw(BadValue, "missing 'shared-networks'"
1144 " argument for the '" << command_name << "' command");
1145
1146 // Make sure it is a list.
1147 } else if (network_list->getType() != Element::list) {
1148 isc_throw(BadValue, "'shared-networks' argument specified for the '"
1149 << command_name << "' command is not a list");
1150
1151 // Currently we allow only one network in the list.
1152 } else if (network_list->size() != 1) {
1153 isc_throw(BadValue, "invalid number of networks specified for the"
1154 " '" << command_name << "' command. Expected one network");
1155 }
1156
1157 // Make sure that the network information is a map.
1158 ConstElementPtr network_element = network_list->get(0);
1159 if (network_element->getType() != Element::map) {
1160 isc_throw(BadValue, "invalid network information specified for the"
1161 "'" << command_name << "' command. Expected a map");
1162 }
1163
1164 // The tricky part is that some of the network parameters may be
1165 // inherited from the global scope. The command itself has no
1166 // information about the global parameters' values, so we will
1167 // construct a "global" map populated with the server's globals
1168 // and add the network(s) from the command to that.
1169 ElementPtr global_scope;
1170
1171 // Add in any configured, global parameters from the server
1172 global_scope = CfgMgr::instance().getCurrentCfg()->
1173 getConfiguredGlobals()->toElement();
1174
1175 global_scope->set("shared-networks", network_list);
1176
1177 // Now, let's specify the default values using SimpleParser4
1178 // or SimpleParser6 and derive to the network we're adding.
1179 SimpleParserType::setAllDefaults(global_scope);
1180 SimpleParserType::deriveParameters(global_scope);
1181
1182 // Finally, let's parse the network information extended with the
1183 // default values.
1184 SharedNetworkParserType parser;
1185 auto network = parser.parse(network_list->get(0));
1186
1187 // Add this network to the current configuration.
1188 networks_cfg->add(network);
1189
1190 // Also add all subnets to the subnets list.
1191 auto subnets_list = network->getAllSubnets();
1192 if (subnets_list) {
1193 // For each subnet, add it to a list of regular subnets.
1194 for (auto const& subnet : *subnets_list) {
1195 subnets_cfg->add(subnet);
1196 }
1197 }
1198
1199 // Update the statistics for the subnets and pools. There is no need to remove
1200 // any statistics because we're adding new subnets and pools. We remove none.
1201 subnets_cfg->updateStatistics();
1202
1203 // Now that we have successfully added the subnets, let's initialize the
1204 // allocation states for all newly added subnets.
1205 for (auto const& subnet : *subnets_list) {
1206 subnet->initAllocatorsAfterConfigure();
1207 }
1208
1209 // The response contains a network name.
1210 ElementPtr network_info = Element::createMap();
1211 network_info->set("name", Element::create(network->getName()));
1212
1213 // The network information is encapsulated in a single element list.
1214 ElementPtr response_list = Element::createList();
1215 response_list->add(network_info);
1216
1217 ElementPtr response_arguments = Element::createMap();
1218 response_arguments->set("shared-networks", response_list);
1219
1220 // Add text stating that IPv4 or IPv6 network has been added.
1221 std::ostringstream response_text;
1222 response_text << "A new " << protocol_version << " shared network '" << network->getName()
1223 << "' added";
1224
1225 // Create the response.
1227 response_text.str(),
1228 response_arguments);
1229
1231 .arg(network->getName());
1232
1233 return (response);
1234 }
1235
1252 template<typename CfgNetworksType, typename CfgSubnetsType>
1253 ConstElementPtr delNetwork(CfgNetworksType& networks_cfg, CfgSubnetsType& subnets_cfg,
1254 const ConstElementPtr& arguments,
1255 const std::string& command_name,
1256 const std::string& protocol_version) {
1257 // Arguments are required.
1258 if (!arguments) {
1259 isc_throw(BadValue, "no arguments specified for the '"
1260 << command_name << "' command");
1261
1262 // Arguments must be a map.
1263 } else if (arguments->getType() != Element::map) {
1264 isc_throw(BadValue, "arguments specified for the '"
1265 << command_name << "' command are not a map");
1266
1267 // Currently we only accept one argument, i.e. shared network name.
1268 }
1269
1270 // Make sure there's name parameter and that it's a string.
1271 ConstElementPtr name_element = arguments->get("name");
1272 if (!name_element) {
1273 isc_throw(BadValue, "network name ('name') is required for the '"
1274 << command_name << "' command");
1275 } else if (name_element->getType() != Element::string) {
1276 isc_throw(BadValue, "network name ('name') specified for the '"
1277 << command_name << "' is not a string");
1278 }
1279
1280 bool del = false;
1281 ConstElementPtr subnet_action = arguments->get("subnets-action");
1282 if (subnet_action) {
1283 if (subnet_action->getType() != Element::string) {
1284 isc_throw(BadValue, "subnets-action parameter for " << command_name
1285 << " command must be a string. Supported values are: "
1286 << "'keep' and 'delete'.");
1287 }
1288 string tmp = subnet_action->stringValue();
1289 if ( (tmp != "keep") && (tmp != "delete") ) {
1290 isc_throw(BadValue, "Invalid value for subnets-action parameter: "
1291 << tmp << ", Supported values: 'keep' and 'delete'.");
1292 }
1293 if (tmp == "delete") {
1294 del = true;
1295 }
1296 }
1297
1298 std::string name = name_element->stringValue();
1299
1300 auto network = networks_cfg->getByName(name);
1301 if (!network) {
1302 std::stringstream tmp;
1303 tmp << "no shared network with name '" << name << "' found";
1304 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1305 }
1306
1307 // Remove the statistics because some of the subnets will be removed.
1308 // The statistics will be later updated for the remaining subnets.
1309 subnets_cfg->removeStatistics();
1310
1311 try {
1312 // Should we delete all the subnets?
1313 if (del) {
1314
1315 // Get the list of all subnets in this shared network.
1316 auto network_subs = network->getAllSubnets();
1317
1318 // Delete them one by one.
1319 for (auto const& sub : *network_subs) {
1320 subnets_cfg->del(sub);
1321
1322 // Delete associated host reservations.
1323 CfgHostsPtr cfg_hosts = CfgMgr::instance().getCurrentCfg()->getCfgHosts();
1324 if (command_name == "network4-del") {
1325 cfg_hosts->delAll4(sub->getID());
1326
1327 } else if (command_name == "network6-del") {
1328 cfg_hosts->delAll6(sub->getID());
1329 }
1330 }
1331 }
1332 networks_cfg->del(name);
1333
1334 } catch (...) {
1335 // We removed the statistics but we failed to process the command.
1336 // We have to add it back before leaving.
1337 subnets_cfg->updateStatistics();
1338 }
1339
1340 // Recreate the statistics for the remaining subnets.
1341 subnets_cfg->updateStatistics();
1342
1343 std::ostringstream response_text;
1344 response_text << protocol_version << " shared network '"
1345 << name << "' deleted";
1346
1347 ElementPtr details = Element::createMap();
1350 m->set("name", Element::create(name));
1351 lst->add(m);
1352 details->set("shared-networks", lst);
1353
1354 // Create the response.
1356 response_text.str(), details);
1357
1359 .arg(name);
1360
1361 return (response);
1362 }
1363
1383 template<typename CfgNetworksType, typename CfgSubnetsType>
1384 ConstElementPtr addNetworkSubnet(CfgNetworksType& networks, CfgSubnetsType& subnets,
1385 const ConstElementPtr& arguments,
1386 const std::string& command_name,
1387 const std::string& protocol_version) {
1388
1389 // Arguments are required.
1390 if (!arguments) {
1391 isc_throw(BadValue, "no arguments specified for the '"
1392 << command_name << "' command");
1393
1394 // Arguments must be a map.
1395 } else if (arguments->getType() != Element::map) {
1396 isc_throw(BadValue, "arguments specified for the '"
1397 << command_name << "' command are not a map");
1398
1399 }
1400
1401 // The map should contain two parameters: name (string) that identifies a shared network
1402 // and id (int) which identifies a subnet.
1403 ConstElementPtr name_elem = arguments->get("name");
1404 if (!name_elem) {
1405 isc_throw(BadValue, "missing 'name'"
1406 " argument for the '" << command_name << "' command");
1407
1408 // Make sure it is a string.
1409 } else if (name_elem->getType() != Element::string) {
1410 isc_throw(BadValue, "'name' argument specified for the '"
1411 << command_name << "' command is not a string");
1412 }
1413 string name = name_elem->stringValue();
1414
1415 ConstElementPtr id_elem = arguments->get("id");
1416 if (!id_elem) {
1417 isc_throw(BadValue, "missing 'id'"
1418 " argument for the '" << command_name << "' command");
1419
1420 // Make sure it is an integer.
1421 } else if (id_elem->getType() != Element::integer) {
1422 isc_throw(BadValue, "'name' argument specified for the '"
1423 << command_name << "' command is not an integer");
1424 }
1425 SubnetID id(id_elem->intValue());
1426
1427 // Let's check if we have such a shared network
1428 auto network = networks->getByName(name);
1429
1430 if (!network) {
1431 std::stringstream tmp;
1432 tmp << "no " << protocol_version << " shared network with name '" << name << "' found";
1433 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1434 }
1435
1436 auto subnet = subnets->getSubnet(id);
1437 if (!subnet) {
1438 std::stringstream tmp;
1439 tmp << "no " << protocol_version << " subnet with id '" << id << "' found";
1440 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1441 }
1442
1443 // Ok, let's add it. It may throw if the subnet is already part of another network.
1444 // That's ok. The exception will be returned as error code.
1445 network->add(subnet);
1446
1447 // Add text stating that IPv4 or IPv6 subnet has been added.
1448 std::ostringstream response_text;
1449 response_text << protocol_version << " subnet " << subnet->toText() << " (id " <<
1450 id << ") is now part of shared network '" << network->getName()
1451 << "'";
1452
1454 .arg(protocol_version).arg(subnet->toText()).arg(id).arg(network->getName());
1455
1456 // Create the response.
1458 response_text.str());
1459 return (response);
1460 }
1461
1479 template<typename CfgNetworksType>
1480 ConstElementPtr delNetworkSubnet(CfgNetworksType& networks,
1481 const ConstElementPtr& arguments,
1482 const std::string& command_name,
1483 const std::string& protocol_version) {
1484
1485 // Arguments are required.
1486 if (!arguments) {
1487 isc_throw(BadValue, "no arguments specified for the '"
1488 << command_name << "' command");
1489
1490 // Arguments must be a map.
1491 } else if (arguments->getType() != Element::map) {
1492 isc_throw(BadValue, "arguments specified for the '"
1493 << command_name << "' command are not a map");
1494
1495 }
1496
1497 // The map should contain two parameters: name (string) that identifies a shared network
1498 // and id (int) which identifies a subnet.
1499 ConstElementPtr name_elem = arguments->get("name");
1500 if (!name_elem) {
1501 isc_throw(BadValue, "missing 'name'"
1502 " argument for the '" << command_name << "' command");
1503
1504 // Make sure it is a string.
1505 } else if (name_elem->getType() != Element::string) {
1506 isc_throw(BadValue, "'name' argument specified for the '"
1507 << command_name << "' command is not a string");
1508 }
1509 string name = name_elem->stringValue();
1510
1511 ConstElementPtr id_elem = arguments->get("id");
1512 if (!id_elem) {
1513 isc_throw(BadValue, "missing 'id'"
1514 " argument for the '" << command_name << "' command");
1515
1516 // Make sure it is an integer.
1517 } else if (id_elem->getType() != Element::integer) {
1518 isc_throw(BadValue, "'name' argument specified for the '"
1519 << command_name << "' command is not an integer");
1520 }
1521 SubnetID id(id_elem->intValue());
1522
1523 // Let's check if we have such a shared network
1524 auto network = networks->getByName(name);
1525
1526 if (!network) {
1527 std::stringstream tmp;
1528 tmp << "no " << protocol_version << " shared network with name '" << name << "' found";
1529 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1530 }
1531
1532 // Now check if there is such a subnet.
1533 auto subnet = network->getSubnet(id);
1534 if (!subnet) {
1535 std::stringstream tmp;
1536 tmp << "The " << protocol_version << " subnet with id " << id
1537 << " is not part of the shared network with name '" << name << "' found";
1538 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1539 }
1540
1541 // Ok, let's delete it.
1542 network->del(id);
1543
1544 // Add text stating that IPv4 or IPv6 subnet has been added.
1545 std::ostringstream response_text;
1546 response_text << protocol_version << " subnet " << subnet->toText() << " (id " <<
1547 id << ") is now removed from shared network '" << network->getName()
1548 << "'";
1549
1551 .arg(protocol_version).arg(subnet->toText()).arg(id).arg(network->getName());
1552
1553 // Create the response.
1555 response_text.str());
1556 return (response);
1557 }
1558
1559};
1560
1562 : impl_(new SubnetCmdsImpl()) {
1563}
1564
1567 ConstCfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1568 return (impl_->getSubnetList(cfg, "IPv4"));
1569}
1570
1573 ConstCfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1574 return (impl_->getSubnetList(cfg, "IPv6"));
1575}
1576
1579 ConstCfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1580 return (impl_->getSubnet<ConstSubnet4Ptr>(cfg, arguments, "subnet4-get",
1581 "subnet4", "IPv4"));
1582}
1583
1586 ConstCfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1587 return (impl_->getSubnet<ConstSubnet6Ptr>(cfg, arguments, "subnet6-get",
1588 "subnet6", "IPv6"));
1589}
1590
1592
1595 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1597 return (impl_->addSubnet<SimpleParser4, Subnet4ConfigParser>(cfg, arguments,
1598 "subnet4-add",
1599 "subnet4", "IPv4"));
1600}
1601
1604 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1606 return (impl_->addSubnet<SimpleParser6, Subnet6ConfigParser>(cfg, arguments,
1607 "subnet6-add",
1608 "subnet6", "IPv6"));
1609}
1610
1613 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1615 return (impl_->updateSubnet<SimpleParser4, Subnet4ConfigParser,
1616 SharedNetwork4Ptr, Subnet4>(cfg, arguments,
1617 "subnet4-update",
1618 "subnet4", "IPv4"));
1619}
1620
1623 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1625 return (impl_->updateSubnet<SimpleParser6, Subnet6ConfigParser,
1626 SharedNetwork6Ptr, Subnet6>(cfg, arguments,
1627 "subnet6-update",
1628 "subnet6", "IPv6"));
1629}
1630
1633 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1635 return (impl_->delSubnet<CfgSubnets4Ptr, SharedNetwork4Ptr>(cfg, arguments, "subnet4-del", "IPv4"));
1636}
1637
1640 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1642 return (impl_->delSubnet<CfgSubnets6Ptr, SharedNetwork6Ptr>(cfg, arguments, "subnet6-del", "IPv6"));
1643}
1644
1647 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1649 return (impl_->updateSubnet<SimpleParser4, Subnet4ConfigParser,
1650 SharedNetwork4Ptr, Subnet4>(cfg, arguments,
1651 "subnet4-delta-add",
1652 "subnet4", "IPv4",
1654}
1655
1658 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1660 return (impl_->updateSubnet<SimpleParser6, Subnet6ConfigParser,
1661 SharedNetwork6Ptr, Subnet6>(cfg, arguments,
1662 "subnet6-delta-add",
1663 "subnet6", "IPv6",
1665}
1666
1669 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1671 return (impl_->updateSubnet<SimpleParser4, Subnet4ConfigParser,
1672 SharedNetwork4Ptr, Subnet4>(cfg, arguments,
1673 "subnet4-delta-del",
1674 "subnet4", "IPv4",
1676}
1677
1680 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1682 return (impl_->updateSubnet<SimpleParser6, Subnet6ConfigParser,
1683 SharedNetwork6Ptr, Subnet6>(cfg, arguments,
1684 "subnet6-delta-del",
1685 "subnet6", "IPv6",
1687}
1688
1689// =============================================================================
1690// === SHARED NETWORKS =========================================================
1691// =============================================================================
1692
1695 CfgSharedNetworks4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1696 return (impl_->getNetworkList(cfg, "IPv4"));
1697}
1698
1701 CfgSharedNetworks6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1702 return (impl_->getNetworkList(cfg, "IPv6"));
1703}
1704
1707 CfgSharedNetworks4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1708 return (impl_->getNetwork<SharedNetwork4Ptr>(cfg, arguments, "network4-get", "IPv4"));
1709}
1710
1713 CfgSharedNetworks6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1714 return (impl_->getNetwork<SharedNetwork6Ptr>(cfg, arguments, "network6-get", "IPv6"));
1715}
1716
1718
1721 CfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1722 CfgSharedNetworks4Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1724 return (impl_->addNetwork<SimpleParser4, SharedNetwork4Parser>(networks, subnets, arguments,
1725 "network4-add", "IPv4"));
1726}
1727
1730 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1731 CfgSharedNetworks6Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1733 return (impl_->addNetwork<SimpleParser6, SharedNetwork6Parser>(networks, subnets, arguments,
1734 "network6-add", "IPv6"));
1735}
1736
1739 CfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1740 CfgSharedNetworks4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1742 return (impl_->delNetwork(cfg, subnets, arguments, "network4-del", "IPv4"));
1743}
1744
1747 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1748 CfgSharedNetworks6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1750 return (impl_->delNetwork(cfg, subnets, arguments, "network6-del", "IPv6"));
1751}
1752
1755 CfgSharedNetworks4Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1756 CfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1758 return (impl_->addNetworkSubnet(networks, subnets, arguments, "network4-subnet-add",
1759 "IPv4"));
1760}
1761
1764 CfgSharedNetworks6Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1765 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1767 return (impl_->addNetworkSubnet(networks, subnets, arguments, "network6-subnet-add",
1768 "IPv6"));
1769}
1770
1773 CfgSharedNetworks4Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1775 return (impl_->delNetworkSubnet(networks, arguments, "network4-subnet-del", "IPv4"));
1776}
1777
1780 CfgSharedNetworks6Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1782 return (impl_->delNetworkSubnet(networks, arguments, "network6-subnet-del", "IPv6"));
1783}
1784
1785} // end of namespace isc::subnet_cmds
1786} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
@ map
Definition data.h:147
@ integer
Definition data.h:140
@ list
Definition data.h:146
@ string
Definition data.h:144
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an object can not be found.
A generic exception that is thrown when an unexpected error condition occurs.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
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
Implements parser for IPv4 shared networks.
Implements parser for IPv6 shared networks.
A configuration holder for IPv4 subnet.
Definition subnet.h:468
A configuration holder for IPv6 subnet.
Definition subnet.h:633
SubnetID getID() const
Returns unique ID for that subnet.
Definition subnet.h:83
virtual std::string toText() const
Returns textual representation of the subnet (e.g.
Definition subnet.cc:90
std::string getSharedNetworkName() const
Returns shared network name.
Definition subnet.h:250
Manager which handles the delta (differences) between two subnets serialized as a JSON tree (usually ...
void processDelta(UpdateType type, ElementPtr &old_element, ConstElementPtr &subnet_element)
Process the delta between existing configuration and user provided data.
~ConfigDiffManager()=default
Destructor.
ConfigDiffManager(std::string space)
Constructor.
Implementation of the SubnetCmds class.
ConstElementPtr getNetworkList(const CfgType &networks_cfg, const std::string &protocol_type) const
Returns a response to a 'network4-list' and 'network6-list' command.
ConstElementPtr delNetwork(CfgNetworksType &networks_cfg, CfgSubnetsType &subnets_cfg, const ConstElementPtr &arguments, const std::string &command_name, const std::string &protocol_version)
Provides a response to a 'network4-del' and 'network6-del' command.
ElementPtr subnetToElement(const Subnet &subnet, bool include_shared_network) const
Returns essential subnet parameters in Element format.
ConstElementPtr addNetworkSubnet(CfgNetworksType &networks, CfgSubnetsType &subnets, const ConstElementPtr &arguments, const std::string &command_name, const std::string &protocol_version)
Provides a response to a 'network4-subnet-add' and 'network6-subnet-add' command.
ConstElementPtr addSubnet(CfgType &cfg, const ConstElementPtr &arguments, const std::string &command_name, const std::string &subnet_parameter, const std::string &protocol_version)
Provides a response to a 'subnet4-add' and 'subnet6-add' command.
ConstElementPtr delSubnet(CfgType &cfg, const ConstElementPtr &arguments, const std::string &command_name, const std::string &protocol_version)
Provides a response to a 'subnet4-del' and 'subnet6-del' command.
ConstElementPtr addNetwork(CfgNetworksType &networks_cfg, CfgSubnetsType &subnets_cfg, const ConstElementPtr &arguments, const std::string &command_name, const std::string &protocol_version)
Provides a response to a 'network4-add' and 'network6-add' command.
ConstElementPtr delNetworkSubnet(CfgNetworksType &networks, const ConstElementPtr &arguments, const std::string &command_name, const std::string &protocol_version)
Provides a response to a 'network4-subnet-del' and 'network6-subnet-del' command.
ConstElementPtr getSubnet(const CfgType &cfg, const data::ConstElementPtr &arguments, const std::string &command_name, const std::string &subnet_parameter, const std::string &protocol_version) const
Provides a response to a 'subnet4-get' or 'subnet6-get' command.
ConstElementPtr getSubnetList(const CfgType &cfg, const std::string &protocol_type) const
Returns a response to a 'subnet4-list' and 'subnet6-list' command.
ConstElementPtr getNetwork(const CfgType &cfg, const data::ConstElementPtr &arguments, const std::string &command_name, const std::string &protocol_version) const
Provides a response to a 'network4-get' or 'network6-get' command.
ConstElementPtr updateSubnet(CfgType &cfg, const ConstElementPtr &arguments, const std::string &command_name, const std::string &subnet_parameter, const std::string &protocol_version, UpdateType type=UPDATE_REPLACE)
Provides a response to a 'subnet4-update' and 'subnet6-update' command.
data::ConstElementPtr addNetwork4Subnet(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network4-subnet-add' command.
data::ConstElementPtr addSubnet6Delta(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet6-delta-add' command.
data::ConstElementPtr addSubnet4Delta(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet4-delta-add' command.
data::ConstElementPtr addSubnet6(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet6-add' command.
data::ConstElementPtr delNetwork6Subnet(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network6-subnet-del' command.
data::ConstElementPtr getSubnet6(const data::ConstElementPtr &arguments) const
Returns a response to 'subnet6-get' command.
data::ConstElementPtr getNetwork6(const data::ConstElementPtr &arguments) const
Returns a response to 'network6-get' command.
data::ConstElementPtr updateSubnet6(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet6-update' command.
data::ConstElementPtr getSubnet4(const data::ConstElementPtr &arguments) const
Returns a response to 'subnet4-get' command.
data::ConstElementPtr getNetwork4List() const
Returns a response to a 'network4-list' command.
data::ConstElementPtr delNetwork4Subnet(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network4-subnet-del' command.
data::ConstElementPtr getNetwork4(const data::ConstElementPtr &arguments) const
Returns a response to 'network4-get' command.
data::ConstElementPtr getNetwork6List() const
Returns a response to a 'network6-list' command.
data::ConstElementPtr delSubnet6(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet6-del' command.
data::ConstElementPtr delNetwork4(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network4-del' command.
data::ConstElementPtr updateSubnet4(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet4-update' command.
data::ConstElementPtr getSubnet6List() const
Returns a response to a 'subnet6-list' command.
data::ConstElementPtr addNetwork6(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network6-add' command.
data::ConstElementPtr addNetwork4(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network4-add' command.
data::ConstElementPtr delNetwork6(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network6-del' command.
data::ConstElementPtr addSubnet4(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet4-add' command.
data::ConstElementPtr delSubnet4Delta(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet4-delta-del' command.
data::ConstElementPtr addNetwork6Subnet(const data::ConstElementPtr &arguments)
Processes and returns a response to 'network6-subnet-add' command.
data::ConstElementPtr delSubnet6Delta(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet6-delta-del' command.
data::ConstElementPtr getSubnet4List() const
Returns a response to a 'subnet4-list' command.
data::ConstElementPtr delSubnet4(const data::ConstElementPtr &arguments)
Processes and returns a response to 'subnet4-del' command.
RAII class creating a critical section.
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.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
void mergeDiffAdd(ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx)
Merges the diff data by adding the missing elements from 'other' to 'element' (recursively).
Definition data.cc:1217
void mergeDiffDel(ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx)
Merges the diff data by removing the data present in 'other' from 'element' (recursively).
Definition data.cc:1278
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
void extend(const std::string &container, const std::string &extension, ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx, bool alter)
Extends data by adding the specified 'extension' elements from 'other' inside the 'container' element...
Definition data.cc:1368
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
std::vector< FunctionMap > HierarchyDescriptor
Hierarchy descriptor of the containers in a specific Element hierarchy tree.
Definition data.h:924
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:623
boost::shared_ptr< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition subnet.h:458
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
boost::shared_ptr< CfgSharedNetworks6 > CfgSharedNetworks6Ptr
Pointer to the configuration of IPv6 shared networks.
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
boost::shared_ptr< CfgHosts > CfgHostsPtr
Non-const pointer.
Definition cfg_hosts.h:973
boost::shared_ptr< CfgSubnets4 > CfgSubnets4Ptr
Non-const pointer.
boost::shared_ptr< const CfgSubnets4 > ConstCfgSubnets4Ptr
Const pointer.
boost::shared_ptr< const CfgSubnets6 > ConstCfgSubnets6Ptr
Const pointer.
boost::shared_ptr< CfgSharedNetworks4 > CfgSharedNetworks4Ptr
Pointer to the configuration of IPv4 shared networks.
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
const isc::log::MessageID SUBNET_CMDS_NETWORK_LIST
const isc::log::MessageID SUBNET_CMDS_NETWORK_ADD
const isc::log::MessageID SUBNET_CMDS_SUBNET_DEL
const isc::log::MessageID SUBNET_CMDS_SUBNET_ADD
const isc::log::MessageID SUBNET_CMDS_NETWORK_SUBNET_ADD
const isc::log::MessageID SUBNET_CMDS_SUBNET_UPDATE
const isc::log::MessageID SUBNET_CMDS_NETWORK_SUBNET_DEL
const isc::log::MessageID SUBNET_CMDS_SUBNET_LIST_EMPTY
const isc::log::MessageID SUBNET_CMDS_NETWORK_LIST_EMPTY
UpdateType
Type of subnet update.
@ UPDATE_DELTA_DEL
update the old subnet by removing the parameters from the new entry.
@ UPDATE_REPLACE
completely replace old subnet with the new entry.
@ UPDATE_DELTA_ADD
update the old subnet by adding the parameters form the new entry.
const isc::log::MessageID SUBNET_CMDS_SUBNET_GET_EMPTY
const isc::log::MessageID SUBNET_CMDS_NETWORK_GET_EMPTY
const isc::log::MessageID SUBNET_CMDS_SUBNET_GET
const isc::log::MessageID SUBNET_CMDS_NETWORK_DEL
isc::log::Logger subnet_cmds_logger("subnet-cmds-hooks")
const isc::log::MessageID SUBNET_CMDS_NETWORK_GET
const isc::log::MessageID SUBNET_CMDS_SUBNET_LIST
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE