Kea 3.1.4
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 left_space = space_;
165 std::string right_space = space_;
166 if (left->get("space")) {
167 left_space = left->get("space")->stringValue();
168 }
169 if (right->get("space")) {
170 right_space = right->get("space")->stringValue();
171 }
172 if (left_space == right_space) {
173 if (left->find("code") && right->find("code")) {
174 return (left->get("code")->intValue() == right->get("code")->intValue());
175 } else if (left->find("name") && right->find("name")) {
176 return (left->get("name")->stringValue() == right->get("name")->stringValue());
177 }
178 }
179 return (false);
180 };
181
184 auto const& subnet_is_key = [](const std::string& key) -> bool {
185 return (key == "id" || key == "subnet");
186 };
187
190 auto const& pool_is_key = [](const std::string& key) -> bool {
191 return (key == "pool");
192 };
193
196 auto const& pd_pool_is_key = [](const std::string& key) -> bool {
197 return (key == "prefix" || key == "prefix-len" || key == "delegated-len");
198 };
199
202 auto const& option_is_key = [](const std::string& key) -> bool {
203 return (key == "space" || key == "code" || key == "name");
204 };
205
206 subnet_hierarchy_any_match_ = {
207 { { "subnet", { subnet_match, subnet_empty, subnet_is_key } } },
208 { { "pools", { match_any, pool_empty, pool_is_key } },
209 { "pd-pools", { match_any, pd_pool_empty, pd_pool_is_key } },
210 { "option-data", { option_match, option_empty, option_is_key } } },
211 { { "option-data", { option_match, option_empty, option_is_key } } }
212 };
213
214 subnet_hierarchy_ = {
215 { { "subnet", { subnet_match, subnet_empty, subnet_is_key } } },
216 { { "pools", { pool_match, pool_empty, pool_is_key } },
217 { "pd-pools", { pd_pool_match, pd_pool_empty, pd_pool_is_key } },
218 { "option-data", { option_match, option_empty, option_is_key } } },
219 { { "option-data", { option_match, option_empty, option_is_key } } }
220 };
221 }
222
225
233 void processDelta(UpdateType type, ElementPtr& old_element,
234 ConstElementPtr& subnet_element) {
235 // To be able to have unified format of the key values of pools and
236 // pd-pools, we need to parse the user provided data using one of
237 // the @c Subnet4ConfigParser or @c Subnet6ConfigParser.
238 // This will make keys match when traversing the configuration tree
239 // hierarchy.
240
241 // Save the initial list of keys provided by user.
242 std::set<std::string> initial_keys;
243 for (auto const& key : subnet_element->mapValue()) {
244 initial_keys.insert(key.first);
245 }
246
247 // The merge delete functionality is flexible and permits deleting
248 // entire elements by providing only the keys identifying the
249 // respective element. In the case of options, the space can be a
250 // determined automatically for options inside the default spaces.
251 // The @c Subnet4ConfigParser and @c Subnet6ConfigParser will throw
252 // if the "data" is not provided for specified options, so we must
253 // extend the user input with valid data from the existing
254 // configuration. We don't care about exact pool or pd-pool match as
255 // the data will be removed anyway. A relaxed search for the "data"
256 // value for the specific option space, code and name is done
257 // storing only the valid data so that the parser will not complain.
258 if (type == UPDATE_DELTA_DEL) {
259 ElementPtr extended = boost::const_pointer_cast<Element>(subnet_element);
260 extend("option-data", "data", extended, old_element, subnet_hierarchy_any_match_, "subnet");
261 }
262
263 // The parser is applied on user provided data and then is translated
264 // back to an JSON tree to be able to convert the data to an uniform
265 // internal format: same number of spaces, using prefix or interval
266 // format:
267 // "192.0.2.1-192.0.2.100" and "192.0.2.1 - 192.0.2.100" refer to the
268 // same thing, so does "192.0.2.0/24" and "192.0.2.0 - 192.0.2.255"
269 // "2003:db8::1-2003:db8::10" and "2003:db8::1 - 2003:db8::10" refer
270 // to the same thing, so does "2003:db8::/120" and
271 // "2003:db8:: - 2003:db8::ff"
272 // The Subnet::toElement function adds extra parameters
273 // (e.g. option-data) even if they are empty. This is used for better
274 // matching parameters.
275 SubnetConfigParserType parser;
276 auto new_element = parser.parse(subnet_element)->toElement();
277
278 // The Subnet::toElement function formats the data, but it adds some
279 // undesired elements which will be interpreted as being added by
280 // user, so they must be removed.
281 std::set<std::string> final_keys;
282 for (auto const& key : new_element->mapValue()) {
283 if (initial_keys.find(key.first) == initial_keys.end()) {
284 final_keys.insert(key.first);
285 }
286 }
287 for (auto const& value : final_keys) {
288 new_element->remove(value);
289 }
290
291 if (type == UPDATE_DELTA_ADD) {
292 // Do the merge add.
293 mergeDiffAdd(old_element, new_element, subnet_hierarchy_, "subnet");
294 } else if (type == UPDATE_DELTA_DEL) {
295 // Do the merge del.
296 mergeDiffDel(old_element, new_element, subnet_hierarchy_, "subnet");
297 }
298 };
299
300private:
301
303 std::string space_;
304
307 HierarchyDescriptor subnet_hierarchy_any_match_;
308
311 HierarchyDescriptor subnet_hierarchy_;
312};
313
318public:
319
335 template<typename CfgType>
336 ConstElementPtr getSubnetList(const CfgType& cfg,
337 const std::string& protocol_type) const {
338 // Create a list where we're going to store subnets' information.
339 ElementPtr subnet_list = Element::createList();
340 // Create arguments map and add subnet map.
342 args->set("subnets", subnet_list);
343
344 // Retrieve all subnets from the configuration structure.
345 auto subnets = cfg->getAll();
346
347 // Iterate over all subnets and retrieve the information we're interested in.
348 for (auto const& s : *subnets) {
349 // Information for the individual subnets is held in the map.
350 subnet_list->add(subnetToElement(*s, true));
351 }
352
353 // Generate the status message including the number of subnets found.
354 std::ostringstream s;
355 s << subnets->size() << " " << protocol_type << " subnet";
356
357 // For 0 subnets or more than 1 subnets returned, we use plural form 'subnets'.
358 if (subnets->size() != 1) {
359 s << "s";
360 }
361 s << " found";
362
363 // Log the number of subnets found.
364 if (subnets->size() > 0) {
366 .arg(subnets->size())
367 .arg(protocol_type);
368 return (createAnswer(CONTROL_RESULT_SUCCESS, s.str(), args));
369
370 } else {
371 // No subnets found.
373 .arg(protocol_type);
374 return (createAnswer(CONTROL_RESULT_EMPTY, s.str(), args));
375 }
376 }
377
390 template<typename SubnetTypePtr, typename CfgType>
391 ConstElementPtr getSubnet(const CfgType& cfg,
392 const data::ConstElementPtr& arguments,
393 const std::string& command_name,
394 const std::string& subnet_parameter,
395 const std::string& protocol_version) const {
396 // Arguments are required.
397 if (!arguments) {
398 isc_throw(BadValue, "no arguments specified for the '"
399 << command_name << "' command");
400
401 // Arguments must be a map.
402 } else if (arguments->getType() != Element::map) {
403 isc_throw(BadValue, "arguments specified for the '"
404 << command_name << "' command are not a map");
405
406 // Currently we allow only one parameter in this command: id or
407 // subnet and they are mutually exclusive.
408 } else if (arguments->size() != 1) {
409 isc_throw(BadValue, "invalid number of arguments " << arguments->size()
410 << " for the '" << command_name << "' command. Expecting"
411 " 'id' or 'subnet'");
412 }
413
414 SubnetTypePtr subnet;
415
416 ConstElementPtr subnet_id_param;
417 ConstElementPtr subnet_param = arguments->get("subnet");
418
419 // Check if the 'subnet' parameter has been specified in the command.
420 if (subnet_param) {
421 // This parameter must be a string.
422 if (subnet_param->getType() != Element::string) {
423 isc_throw(BadValue, "'subnet' parameter must be a string");
424 }
425 // Try to find a subnet by prefix.
426 subnet = cfg->getByPrefix(subnet_param->stringValue());
427
428 } else {
429 // Check if the 'id' parameter has been specified in the command.
430 subnet_id_param = arguments->get("id");
431 if (subnet_id_param) {
432 // Subnet identifier must be an integer.
433 if (subnet_id_param->getType() != Element::integer) {
434 isc_throw(BadValue, "'id' parameter must be an integer");
435 }
436 // Try to find a subnet by subnet identifier.
437 subnet = cfg->getBySubnetId(SubnetID(subnet_id_param->intValue()));
438
439 } else {
440 // If neither of these parameters has been specified, signal an error.
441 isc_throw(BadValue, "'id' or 'subnet' parameter required");
442 }
443 }
444
445 ConstElementPtr response;
446
447 // If subnet found, wrap this response in the successful response.
448 if (subnet) {
449 ElementPtr subnets_list = Element::createList();
450 subnets_list->add(subnet->toElement());
451 ElementPtr response_arguments = Element::createMap();
452 response_arguments->set(subnet_parameter, subnets_list);
453
454 std::ostringstream s;
455 s << "Info about " << protocol_version << " subnet " << subnet->toText()
456 << " (id " << subnet->getID() << ") returned";
457 response = createAnswer(CONTROL_RESULT_SUCCESS, s.str(),
458 response_arguments);
459
461 .arg(subnet->toText())
462 .arg(subnet->getID());
463
464 // No subnet found.
465 } else {
466 std::stringstream s;
467 if (subnet_param) {
468 s << "No " << subnet_param->stringValue() << " subnet found";
469 } else {
470 s << "No subnet with id " << subnet_id_param->intValue() << " found";
471 }
472
474 response = createAnswer(CONTROL_RESULT_EMPTY, s.str());
475 }
476
477 return (response);
478 }
479
501 template<typename SimpleParserType, typename SubnetConfigParserType,
502 typename CfgType>
503 ConstElementPtr addSubnet(CfgType& cfg, const ConstElementPtr& arguments,
504 const std::string& command_name,
505 const std::string& subnet_parameter,
506 const std::string& protocol_version) {
507
508 // Arguments are required.
509 if (!arguments) {
510 isc_throw(BadValue, "no arguments specified for the '"
511 << command_name << "' command");
512
513 // Arguments must be a map.
514 } else if (arguments->getType() != Element::map) {
515 isc_throw(BadValue, "arguments specified for the '"
516 << command_name << "' command are not a map");
517
518 } else if (arguments->size() != 1) {
519 isc_throw(BadValue, "invalid number of arguments "
520 << arguments->size() << " for the '"
521 << command_name << "' command. Expecting "
522 "'" << subnet_parameter << "' list");
523 }
524
525 // The map should contain a 'subnet4' or 'subnet6' list.
526 ConstElementPtr subnet_list = arguments->get(subnet_parameter);
527 if (!subnet_list) {
528 isc_throw(BadValue, "missing '" << subnet_parameter << "'"
529 " argument for the '" << command_name << "' command");
530
531 // Make sure it is a list.
532 } else if (subnet_list->getType() != Element::list) {
533 isc_throw(BadValue, "'" << subnet_parameter << "'"
534 " argument specified for the '"
535 << command_name << "' command is not a list");
536
537 // Currently we allow only one subnet in the list.
538 } else if (subnet_list->size() != 1) {
539 isc_throw(BadValue, "invalid number of subnets specified for the"
540 " '" << command_name << "' command. Expected one subnet");
541 }
542
543 // Make sure that the subnet information is a map.
544 ConstElementPtr subnet_element = subnet_list->get(0);
545 if (subnet_element->getType() != Element::map) {
546 isc_throw(BadValue, "invalid subnet information specified for the"
547 "'" << command_name << "' command. Expected a map");
548
549 // Make sure that the subnet doesn't specify any host reservations.
550 // This is only allowed when setting the full server configuration.
551 // In order to add reservations for a subnet a different set of
552 // commands is used.
553 } else if (subnet_element->get("reservations")) {
554 isc_throw(BadValue, "must not specify host reservations with '"
555 << command_name << "'. Use 'reservation-add' to add"
556 " a reservation to a subnet");
557 }
558
559 // The tricky part is that some of the subnet parameters may be
560 // inherited from the global scope. The command itself has no
561 // information about the global parameters' values, so we will
562 // construct a "global" map populated with the server's globals
563 // and add the subnet(s) from the command to that.
564 ElementPtr global_scope;
565
566 // Add in any configured, global parameters from the server
567 global_scope = CfgMgr::instance().getCurrentCfg()->
568 getConfiguredGlobals()->toElement();
569
570 global_scope->set(subnet_parameter, subnet_list);
571
572 // Now, let's specify the default values using SimpleParser4
573 // or SimpleParser6 and derive to the subnet we're adding.
574 SimpleParserType::setAllDefaults(global_scope);
575 SimpleParserType::deriveParameters(global_scope);
576
577 // Finally, let's parse the subnet information extended with the
578 // default values.
579 SubnetConfigParserType parser;
580 auto subnet = parser.parse(subnet_list->get(0));
581
582 // Add this subnet to the current configuration.
583 cfg->add(subnet);
584
585 // Update the statistics. There is no need to remove any existing statistics
586 // because we are not removing any pools, just adding new ones.
587 cfg->updateStatistics();
588
589 // Some allocators require initialization of their state. In particular,
590 // the FLQ allocator needs to populate free leases.
591 subnet->initAllocatorsAfterConfigure();
592
593 // The response contains a subnet prefix and subnet id.
594 ElementPtr subnet_info = Element::createMap();
595 subnet_info->set("id",
596 Element::create(static_cast<long int>(subnet->getID())));
597 subnet_info->set("subnet", Element::create(subnet->toText()));
598
599 // The subnet information is encapsulated in a single element list.
600 ElementPtr subnets_list = Element::createList();
601 subnets_list->add(subnet_info);
602
603 // The list is called subnets just like with 'subnet4-get' and
604 // 'subnet6-get'.
605 ElementPtr response_arguments = Element::createMap();
606 response_arguments->set("subnets", subnets_list);
607
608 // Add text stating that IPv4 or IPv6 subnet has been added.
609 std::ostringstream response_text;
610 response_text << protocol_version << " subnet added";
611
612 // Create the response.
614 response_text.str(),
615 response_arguments);
616
618 .arg(subnet->toText())
619 .arg(subnet->getID());
620
621 return (response);
622 }
623
650 template<typename SimpleParserType, typename SubnetConfigParserType,
651 typename SharedNetworkPtrType, typename SubnetTypePtr,
652 typename CfgType>
654 const ConstElementPtr& arguments,
655 const std::string& command_name,
656 const std::string& subnet_parameter,
657 const std::string& protocol_version,
658 UpdateType type = UPDATE_REPLACE) {
659
660 // Arguments are required.
661 if (!arguments) {
662 isc_throw(BadValue, "no arguments specified for the '"
663 << command_name << "' command");
664
665 // Arguments must be a map.
666 } else if (arguments->getType() != Element::map) {
667 isc_throw(BadValue, "arguments specified for the '"
668 << command_name << "' command are not a map");
669
670 } else if (arguments->size() != 1) {
671 isc_throw(BadValue, "invalid number of arguments "
672 << arguments->size() << " for the '"
673 << command_name << "' command. Expecting "
674 "'" << subnet_parameter << "' list");
675 }
676
677 // The map should contain a 'subnet4' or 'subnet6' list.
678 ConstElementPtr subnet_list = arguments->get(subnet_parameter);
679 if (!subnet_list) {
680 isc_throw(BadValue, "missing '" << subnet_parameter << "'"
681 " argument for the '" << command_name << "' command");
682
683 // Make sure it is a list.
684 } else if (subnet_list->getType() != Element::list) {
685 isc_throw(BadValue, "'" << subnet_parameter << "'"
686 " argument specified for the '"
687 << command_name << "' command is not a list");
688
689 // Currently we allow only one subnet in the list.
690 } else if (subnet_list->size() != 1) {
691 isc_throw(BadValue, "invalid number of subnets specified for the"
692 " '" << command_name << "' command. Expected one subnet");
693 }
694
695 // Make sure that the subnet information is a map.
696 ConstElementPtr subnet_element = subnet_list->get(0);
697 if (subnet_element->getType() != Element::map) {
698 isc_throw(BadValue, "invalid subnet information specified for the"
699 "'" << command_name << "' command. Expected a map");
700
701 // Make sure that the subnet doesn't specify any host reservations.
702 // This is only allowed when setting the full server configuration.
703 } else if (subnet_element->get("reservations")) {
704 isc_throw(BadValue, "must not specify host reservations with '"
705 << command_name << "'.");
706 }
707
708 // Verify that the subnet ID is specified and in 1..max
709 ConstElementPtr id_element = subnet_element->get("id");
710 if (!id_element) {
711 isc_throw(BadValue, "must specify subnet id with '"
712 << command_name << "' command.");
713 }
714 const SubnetID& subnet_id =
715 SimpleParser::getInteger(subnet_element, "id", 1, SUBNET_ID_MAX);
716
717 // Check the subnet with the same ID.
718 auto old_subnet = cfg->getBySubnetId(subnet_id);
719 if (!old_subnet) {
721 "Can't find subnet '" << subnet_id << "' to update");
722 }
723
724 if (type != UPDATE_REPLACE) {
725 auto old_element = old_subnet->toElement();
726
727 std::string space = DHCP4_OPTION_SPACE;
728 if (subnet_parameter == "subnet6") {
729 space = DHCP6_OPTION_SPACE;
730 }
731
733
734 mgr.processDelta(type, old_element, subnet_element);
735
736 // Update the list element with the data after merge add/del.
737 boost::const_pointer_cast<Element>(subnet_list)->set(0, old_element);
738 }
739
740 // The tricky part is that some of the subnet parameters may be
741 // inherited from the global scope. The command itself has no
742 // information about the global parameters' values, so we will
743 // construct a "global" map populated with the server's globals
744 // and replace the subnet(s) from the command to that.
745 ElementPtr global_scope;
746
747 // Add in any configured, global parameters from the server
748 global_scope = CfgMgr::instance().getCurrentCfg()->
749 getConfiguredGlobals()->toElement();
750
751 global_scope->set(subnet_parameter, subnet_list);
752
753 // Now, let's specify the default values using SimpleParser4
754 // or SimpleParser6 and derive to the subnet we're updating.
755 SimpleParserType::setAllDefaults(global_scope);
756 SimpleParserType::deriveParameters(global_scope);
757
758 // Finally, let's parse the subnet information extended with the
759 // default values.
760 SubnetConfigParserType parser;
761 auto subnet = parser.parse(subnet_list->get(0));
762
763 // Subnet update may result in removing some of the pools. Any possibly existing
764 // per-pool statistics should be removed.
765 cfg->removeStatistics();
766
767 try {
768 // Update this subnet to the current configuration.
769 auto old = cfg->replace(subnet);
770 if (!old) {
771 isc_throw(Unexpected, "Unable to update subnet '" << subnet_id
772 << "' in the configuration");
773 }
774
775 // Deal with shared network.
776 SharedNetworkPtrType network;
777 old->getSharedNetwork(network);
778 if (network) {
779 if (!network->replace(subnet)) {
780 // Try to rollback.
781 if (!cfg->replace(old)) {
782 isc_throw(Unexpected, "Unable to rollback subnet '"
783 << subnet_id << "' update. Configuration is "
784 "broken beyond repair.");
785 }
786 isc_throw(Unexpected, "Cancelled subnet '" << subnet_id
787 << "' update: update in shared network '"
788 << network->getName() << "' failed.");
789 }
790 }
791 } catch (...) {
792 // We removed the statistics but we failed to process the command.
793 // We have to add it back before leaving.
794 cfg->updateStatistics();
795 throw;
796 }
797
798 // Update the statistics for all subnets and the pools that left in the
799 // updated subnet.
800 cfg->updateStatistics();
801
802 // Some allocators require initialization of their state. In particular,
803 // the FLQ allocator needs to populate free leases.
804 subnet->initAllocatorsAfterConfigure();
805
806 // The response contains a subnet prefix and subnet id.
807 ElementPtr subnet_info = Element::createMap();
808 subnet_info->set("id",
809 Element::create(static_cast<long int>(subnet->getID())));
810 subnet_info->set("subnet", Element::create(subnet->toText()));
811
812 // The subnet information is encapsulated in a single element list.
813 ElementPtr subnets_list = Element::createList();
814 subnets_list->add(subnet_info);
815
816 // The list is called subnets just like with 'subnet4-get' and
817 // 'subnet6-get'.
818 ElementPtr response_arguments = Element::createMap();
819 response_arguments->set("subnets", subnets_list);
820
821 // Add text stating that IPv4 or IPv6 subnet has been updated.
822 std::ostringstream response_text;
823 response_text << protocol_version << " subnet updated";
824
825 // Create the response.
827 response_text.str(),
828 response_arguments);
829
831 .arg(subnet->toText())
832 .arg(subnet->getID());
833
834 return (response);
835 }
836
851 template<typename CfgType,
852 typename SharedNetworkPtrType>
853 ConstElementPtr delSubnet(CfgType& cfg, const ConstElementPtr& arguments,
854 const std::string& command_name,
855 const std::string& protocol_version) {
856 // Arguments are required.
857 if (!arguments) {
858 isc_throw(BadValue, "no arguments specified for the '"
859 << command_name << "' command");
860
861 // Arguments must be a map.
862 } else if (arguments->getType() != Element::map) {
863 isc_throw(BadValue, "arguments specified for the '"
864 << command_name << "' command are not a map");
865
866 // Currently we only accept one argument, i.e. subnet identifier.
867 } else if (arguments->size() != 1) {
868 isc_throw(BadValue, "invalid number of arguments specified for the '"
869 << command_name << " command. Expected subnet identifier");
870 }
871
872 ConstElementPtr subnet_id_element = arguments->get("id");
873 if (!subnet_id_element) {
874 isc_throw(BadValue, "subnet identifier is required for the '"
875 << command_name << "' command");
876
877 // Subnet identifier must be an integer.
878 } else if (subnet_id_element->getType() != Element::integer) {
879 isc_throw(BadValue, "subnet identifier specified for the '"
880 << command_name << "' is not a number");
881 }
882
883 uint32_t subnet_id = static_cast<uint32_t>(subnet_id_element->intValue());
884 auto subnet = cfg->getBySubnetId(SubnetID(subnet_id));
885
886 // If subnet found, remove it from the configuration.
887 if (!subnet) {
888 // Subnet not found.
889 std::stringstream tmp;
890 tmp << "no subnet with id " << subnet_id << " found";
891 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
892 }
893
894 // Remove existing statistics because we're removing some pools.
895 cfg->removeStatistics();
896
897 try {
898 cfg->del(subnet);
899
900 // Remove subnet from its shared-network (if one).
901 SharedNetworkPtrType network;
902 subnet->getSharedNetwork(network);
903 if (network) {
904 network->del(subnet->getID());
905 }
906
907 // Delete associated host reservations.
908 CfgHostsPtr cfg_hosts = CfgMgr::instance().getCurrentCfg()->getCfgHosts();
909 if (command_name == "subnet4-del") {
910 cfg_hosts->delAll4(subnet_id);
911 } else {
912 cfg_hosts->delAll6(subnet_id);
913 }
914 } catch (...) {
915 // We removed the statistics but we failed to process the command.
916 // We have to add it back before leaving.
917 cfg->updateStatistics();
918 throw;
919 }
920
921 // Update the statistics for the remaning subnets and pools.
922 cfg->updateStatistics();
923
924 std::ostringstream response_text;
925 response_text << protocol_version << " subnet " << subnet->toText()
926 << " (id " << subnet->getID() << ") deleted";
927
928 ElementPtr details = Element::createMap();
930 lst->add(subnetToElement(*subnet, false));
931 details->set("subnets", lst);
932
933 // Create the response.
935 response_text.str(), details);
936
938 .arg(subnet->toText())
939 .arg(subnet->getID());
940
941 return (response);
942 }
943
948 ElementPtr subnetToElement(const Subnet& subnet, bool include_shared_network) const {
949 ElementPtr subnet_element = Element::createMap();
950 subnet_element->set("id",
951 Element::create(static_cast<long int>(subnet.getID())));
952 subnet_element->set("subnet", Element::create(subnet.toText()));
953
954 if (include_shared_network) {
955 std::string sn_name = subnet.getSharedNetworkName();
956 if (!sn_name.empty()) {
957 subnet_element->set("shared-network-name", data::Element::create(sn_name));
958 } else {
959 // Shared network name is null.
960 subnet_element->set("shared-network-name", data::Element::create());
961 }
962 }
963
964 return (subnet_element);
965 }
966
983 template<typename CfgType>
984 ConstElementPtr getNetworkList(const CfgType& networks_cfg,
985 const std::string& protocol_type) const {
986 // Create a list where we're going to store networks' information.
987 ElementPtr network_list = Element::createList();
988 // Create arguments map and add network map.
990 args->set("shared-networks", network_list);
991
992 // Retrieve all networks from the configuration structure.
993 auto networks = networks_cfg->getAll();
994
995 // Iterate over all networks and retrieve the information we're interested in.
996 for (auto const& n : *networks) {
998 json->set("name", Element::create(n->getName()));
999 // Information for the individual networks is held in the map.
1000 network_list->add(json);
1001 }
1002
1003 // Generate the status message including the number of networks found.
1004 std::ostringstream s;
1005 s << networks->size() << " " << protocol_type << " network";
1006 // For 0 networks or more than 1 networks returned, we use plural form 'networks'.
1007 if (networks->size() != 1) {
1008 s << "s";
1009 }
1010 s << " found";
1011
1012 // Log the number of networks found.
1013 if (networks->size() > 0) {
1015 .arg(networks->size())
1016 .arg(protocol_type);
1017 return (createAnswer(CONTROL_RESULT_SUCCESS, s.str(), args));
1018
1019 } else {
1020 // No networks found.
1022 .arg(protocol_type);
1023 return (createAnswer(CONTROL_RESULT_EMPTY, s.str(), args));
1024 }
1025 }
1026
1038 template<typename NetworkTypePtr, typename CfgType>
1039 ConstElementPtr getNetwork(const CfgType& cfg,
1040 const data::ConstElementPtr& arguments,
1041 const std::string& command_name,
1042 const std::string& protocol_version) const {
1043 // Arguments are required.
1044 if (!arguments) {
1045 isc_throw(BadValue, "no arguments specified for the '"
1046 << command_name << "' command");
1047
1048 // Arguments must be a map.
1049 } else if (arguments->getType() != Element::map) {
1050 isc_throw(BadValue, "arguments specified for the '"
1051 << command_name << "' command are not a map");
1052 }
1053
1054 // Make sure there's name parameter and that it's a string.
1055 ConstElementPtr name = arguments->get("name");
1056 if (!name) {
1057 isc_throw(BadValue, "invalid '" << command_name
1058 << "': missing mandatory 'name' parameter");
1059 }
1060 if (name->getType() != Element::string) {
1061 isc_throw(BadValue, "'name' parameter must be a string");
1062 }
1063
1064 // Try to find the network.
1065 NetworkTypePtr network = cfg->getByName(name->stringValue());
1066
1067 ConstElementPtr response;
1068
1069 // If network found, wrap this response in the successful response.
1070 if (network) {
1071 ElementPtr networks_list = Element::createList();
1072 networks_list->add(network->toElement());
1073 ElementPtr response_arguments = Element::createMap();
1074 response_arguments->set("shared-networks", networks_list);
1075
1076 std::ostringstream s;
1077 s << "Info about " << protocol_version << " shared network '" << network->getName()
1078 << "' returned";
1079 response = createAnswer(CONTROL_RESULT_SUCCESS, s.str(), response_arguments);
1080
1082 .arg(network->getName());
1083
1084 // No network found.
1085 } else {
1086 std::stringstream s;
1087 s << "No '" << name->stringValue() << "' shared network found";
1088
1090 response = createAnswer(CONTROL_RESULT_EMPTY, s.str());
1091 }
1092
1093 return (response);
1094 }
1095
1120 template<typename SimpleParserType, typename SharedNetworkParserType,
1121 typename CfgNetworksType, typename CfgSubnetsType>
1122 ConstElementPtr addNetwork(CfgNetworksType& networks_cfg, CfgSubnetsType& subnets_cfg,
1123 const ConstElementPtr& arguments,
1124 const std::string& command_name,
1125 const std::string& protocol_version) {
1126
1127 // Arguments are required.
1128 if (!arguments) {
1129 isc_throw(BadValue, "no arguments specified for the '"
1130 << command_name << "' command");
1131
1132 // Arguments must be a map.
1133 } else if (arguments->getType() != Element::map) {
1134 isc_throw(BadValue, "arguments specified for the '"
1135 << command_name << "' command are not a map");
1136
1137 }
1138
1139 // The map should contain a 'shared-networks' list.
1140 ConstElementPtr network_list = arguments->get("shared-networks");
1141 if (!network_list) {
1142 isc_throw(BadValue, "missing 'shared-networks'"
1143 " argument for the '" << command_name << "' command");
1144
1145 // Make sure it is a list.
1146 } else if (network_list->getType() != Element::list) {
1147 isc_throw(BadValue, "'shared-networks' argument specified for the '"
1148 << command_name << "' command is not a list");
1149
1150 // Currently we allow only one network in the list.
1151 } else if (network_list->size() != 1) {
1152 isc_throw(BadValue, "invalid number of networks specified for the"
1153 " '" << command_name << "' command. Expected one network");
1154 }
1155
1156 // Make sure that the network information is a map.
1157 ConstElementPtr network_element = network_list->get(0);
1158 if (network_element->getType() != Element::map) {
1159 isc_throw(BadValue, "invalid network information specified for the"
1160 "'" << command_name << "' command. Expected a map");
1161 }
1162
1163 // The tricky part is that some of the network parameters may be
1164 // inherited from the global scope. The command itself has no
1165 // information about the global parameters' values, so we will
1166 // construct a "global" map populated with the server's globals
1167 // and add the network(s) from the command to that.
1168 ElementPtr global_scope;
1169
1170 // Add in any configured, global parameters from the server
1171 global_scope = CfgMgr::instance().getCurrentCfg()->
1172 getConfiguredGlobals()->toElement();
1173
1174 global_scope->set("shared-networks", network_list);
1175
1176 // Now, let's specify the default values using SimpleParser4
1177 // or SimpleParser6 and derive to the network we're adding.
1178 SimpleParserType::setAllDefaults(global_scope);
1179 SimpleParserType::deriveParameters(global_scope);
1180
1181 // Finally, let's parse the network information extended with the
1182 // default values.
1183 SharedNetworkParserType parser;
1184 auto network = parser.parse(network_list->get(0));
1185
1186 // Add this network to the current configuration.
1187 networks_cfg->add(network);
1188
1189 // Also add all subnets to the subnets list.
1190 auto subnets_list = network->getAllSubnets();
1191 if (subnets_list) {
1192 // For each subnet, add it to a list of regular subnets.
1193 for (auto const& subnet : *subnets_list) {
1194 subnets_cfg->add(subnet);
1195 }
1196 }
1197
1198 // Update the statistics for the subnets and pools. There is no need to remove
1199 // any statistics because we're adding new subnets and pools. We remove none.
1200 subnets_cfg->updateStatistics();
1201
1202 // Now that we have successfully added the subnets, let's initialize the
1203 // allocation states for all newly added subnets.
1204 for (auto const& subnet : *subnets_list) {
1205 subnet->initAllocatorsAfterConfigure();
1206 }
1207
1208 // The response contains a network name.
1209 ElementPtr network_info = Element::createMap();
1210 network_info->set("name", Element::create(network->getName()));
1211
1212 // The network information is encapsulated in a single element list.
1213 ElementPtr response_list = Element::createList();
1214 response_list->add(network_info);
1215
1216 ElementPtr response_arguments = Element::createMap();
1217 response_arguments->set("shared-networks", response_list);
1218
1219 // Add text stating that IPv4 or IPv6 network has been added.
1220 std::ostringstream response_text;
1221 response_text << "A new " << protocol_version << " shared network '" << network->getName()
1222 << "' added";
1223
1224 // Create the response.
1226 response_text.str(),
1227 response_arguments);
1228
1230 .arg(network->getName());
1231
1232 return (response);
1233 }
1234
1251 template<typename CfgNetworksType, typename CfgSubnetsType>
1252 ConstElementPtr delNetwork(CfgNetworksType& networks_cfg, CfgSubnetsType& subnets_cfg,
1253 const ConstElementPtr& arguments,
1254 const std::string& command_name,
1255 const std::string& protocol_version) {
1256 // Arguments are required.
1257 if (!arguments) {
1258 isc_throw(BadValue, "no arguments specified for the '"
1259 << command_name << "' command");
1260
1261 // Arguments must be a map.
1262 } else if (arguments->getType() != Element::map) {
1263 isc_throw(BadValue, "arguments specified for the '"
1264 << command_name << "' command are not a map");
1265
1266 // Currently we only accept one argument, i.e. shared network name.
1267 }
1268
1269 // Make sure there's name parameter and that it's a string.
1270 ConstElementPtr name_element = arguments->get("name");
1271 if (!name_element) {
1272 isc_throw(BadValue, "network name ('name') is required for the '"
1273 << command_name << "' command");
1274 } else if (name_element->getType() != Element::string) {
1275 isc_throw(BadValue, "network name ('name') specified for the '"
1276 << command_name << "' is not a string");
1277 }
1278
1279 bool del = false;
1280 ConstElementPtr subnet_action = arguments->get("subnets-action");
1281 if (subnet_action) {
1282 if (subnet_action->getType() != Element::string) {
1283 isc_throw(BadValue, "subnets-action parameter for " << command_name
1284 << " command must be a string. Supported values are: "
1285 << "'keep' and 'delete'.");
1286 }
1287 string tmp = subnet_action->stringValue();
1288 if ( (tmp != "keep") && (tmp != "delete") ) {
1289 isc_throw(BadValue, "Invalid value for subnets-action parameter: "
1290 << tmp << ", Supported values: 'keep' and 'delete'.");
1291 }
1292 if (tmp == "delete") {
1293 del = true;
1294 }
1295 }
1296
1297 std::string name = name_element->stringValue();
1298
1299 auto network = networks_cfg->getByName(name);
1300 if (!network) {
1301 std::stringstream tmp;
1302 tmp << "no shared network with name '" << name << "' found";
1303 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1304 }
1305
1306 // Remove the statistics because some of the subnets will be removed.
1307 // The statistics will be later updated for the remaining subnets.
1308 subnets_cfg->removeStatistics();
1309
1310 try {
1311 // Should we delete all the subnets?
1312 if (del) {
1313
1314 // Get the list of all subnets in this shared network.
1315 auto network_subs = network->getAllSubnets();
1316
1317 // Delete them one by one.
1318 for (auto const& sub : *network_subs) {
1319 subnets_cfg->del(sub);
1320
1321 // Delete associated host reservations.
1322 CfgHostsPtr cfg_hosts = CfgMgr::instance().getCurrentCfg()->getCfgHosts();
1323 if (command_name == "network4-del") {
1324 cfg_hosts->delAll4(sub->getID());
1325
1326 } else if (command_name == "network6-del") {
1327 cfg_hosts->delAll6(sub->getID());
1328 }
1329 }
1330 }
1331 networks_cfg->del(name);
1332
1333 } catch (...) {
1334 // We removed the statistics but we failed to process the command.
1335 // We have to add it back before leaving.
1336 subnets_cfg->updateStatistics();
1337 }
1338
1339 // Recreate the statistics for the remaining subnets.
1340 subnets_cfg->updateStatistics();
1341
1342 std::ostringstream response_text;
1343 response_text << protocol_version << " shared network '"
1344 << name << "' deleted";
1345
1346 ElementPtr details = Element::createMap();
1349 m->set("name", Element::create(name));
1350 lst->add(m);
1351 details->set("shared-networks", lst);
1352
1353 // Create the response.
1355 response_text.str(), details);
1356
1358 .arg(name);
1359
1360 return (response);
1361 }
1362
1382 template<typename CfgNetworksType, typename CfgSubnetsType>
1383 ConstElementPtr addNetworkSubnet(CfgNetworksType& networks, CfgSubnetsType& subnets,
1384 const ConstElementPtr& arguments,
1385 const std::string& command_name,
1386 const std::string& protocol_version) {
1387
1388 // Arguments are required.
1389 if (!arguments) {
1390 isc_throw(BadValue, "no arguments specified for the '"
1391 << command_name << "' command");
1392
1393 // Arguments must be a map.
1394 } else if (arguments->getType() != Element::map) {
1395 isc_throw(BadValue, "arguments specified for the '"
1396 << command_name << "' command are not a map");
1397
1398 }
1399
1400 // The map should contain two parameters: name (string) that identifies a shared network
1401 // and id (int) which identifies a subnet.
1402 ConstElementPtr name_elem = arguments->get("name");
1403 if (!name_elem) {
1404 isc_throw(BadValue, "missing 'name'"
1405 " argument for the '" << command_name << "' command");
1406
1407 // Make sure it is a string.
1408 } else if (name_elem->getType() != Element::string) {
1409 isc_throw(BadValue, "'name' argument specified for the '"
1410 << command_name << "' command is not a string");
1411 }
1412 string name = name_elem->stringValue();
1413
1414 ConstElementPtr id_elem = arguments->get("id");
1415 if (!id_elem) {
1416 isc_throw(BadValue, "missing 'id'"
1417 " argument for the '" << command_name << "' command");
1418
1419 // Make sure it is an integer.
1420 } else if (id_elem->getType() != Element::integer) {
1421 isc_throw(BadValue, "'name' argument specified for the '"
1422 << command_name << "' command is not an integer");
1423 }
1424 SubnetID id(id_elem->intValue());
1425
1426 // Let's check if we have such a shared network
1427 auto network = networks->getByName(name);
1428
1429 if (!network) {
1430 std::stringstream tmp;
1431 tmp << "no " << protocol_version << " shared network with name '" << name << "' found";
1432 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1433 }
1434
1435 auto subnet = subnets->getSubnet(id);
1436 if (!subnet) {
1437 std::stringstream tmp;
1438 tmp << "no " << protocol_version << " subnet with id '" << id << "' found";
1439 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1440 }
1441
1442 // Ok, let's add it. It may throw if the subnet is already part of another network.
1443 // That's ok. The exception will be returned as error code.
1444 network->add(subnet);
1445
1446 // Add text stating that IPv4 or IPv6 subnet has been added.
1447 std::ostringstream response_text;
1448 response_text << protocol_version << " subnet " << subnet->toText() << " (id " <<
1449 id << ") is now part of shared network '" << network->getName()
1450 << "'";
1451
1453 .arg(protocol_version).arg(subnet->toText()).arg(id).arg(network->getName());
1454
1455 // Create the response.
1457 response_text.str());
1458 return (response);
1459 }
1460
1478 template<typename CfgNetworksType>
1479 ConstElementPtr delNetworkSubnet(CfgNetworksType& networks,
1480 const ConstElementPtr& arguments,
1481 const std::string& command_name,
1482 const std::string& protocol_version) {
1483
1484 // Arguments are required.
1485 if (!arguments) {
1486 isc_throw(BadValue, "no arguments specified for the '"
1487 << command_name << "' command");
1488
1489 // Arguments must be a map.
1490 } else if (arguments->getType() != Element::map) {
1491 isc_throw(BadValue, "arguments specified for the '"
1492 << command_name << "' command are not a map");
1493
1494 }
1495
1496 // The map should contain two parameters: name (string) that identifies a shared network
1497 // and id (int) which identifies a subnet.
1498 ConstElementPtr name_elem = arguments->get("name");
1499 if (!name_elem) {
1500 isc_throw(BadValue, "missing 'name'"
1501 " argument for the '" << command_name << "' command");
1502
1503 // Make sure it is a string.
1504 } else if (name_elem->getType() != Element::string) {
1505 isc_throw(BadValue, "'name' argument specified for the '"
1506 << command_name << "' command is not a string");
1507 }
1508 string name = name_elem->stringValue();
1509
1510 ConstElementPtr id_elem = arguments->get("id");
1511 if (!id_elem) {
1512 isc_throw(BadValue, "missing 'id'"
1513 " argument for the '" << command_name << "' command");
1514
1515 // Make sure it is an integer.
1516 } else if (id_elem->getType() != Element::integer) {
1517 isc_throw(BadValue, "'name' argument specified for the '"
1518 << command_name << "' command is not an integer");
1519 }
1520 SubnetID id(id_elem->intValue());
1521
1522 // Let's check if we have such a shared network
1523 auto network = networks->getByName(name);
1524
1525 if (!network) {
1526 std::stringstream tmp;
1527 tmp << "no " << protocol_version << " shared network with name '" << name << "' found";
1528 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1529 }
1530
1531 // Now check if there is such a subnet.
1532 auto subnet = network->getSubnet(id);
1533 if (!subnet) {
1534 std::stringstream tmp;
1535 tmp << "The " << protocol_version << " subnet with id " << id
1536 << " is not part of the shared network with name '" << name << "' found";
1537 return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
1538 }
1539
1540 // Ok, let's delete it.
1541 network->del(id);
1542
1543 // Add text stating that IPv4 or IPv6 subnet has been added.
1544 std::ostringstream response_text;
1545 response_text << protocol_version << " subnet " << subnet->toText() << " (id " <<
1546 id << ") is now removed from shared network '" << network->getName()
1547 << "'";
1548
1550 .arg(protocol_version).arg(subnet->toText()).arg(id).arg(network->getName());
1551
1552 // Create the response.
1554 response_text.str());
1555 return (response);
1556 }
1557
1558};
1559
1561 : impl_(new SubnetCmdsImpl()) {
1562}
1563
1566 ConstCfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1567 return (impl_->getSubnetList(cfg, "IPv4"));
1568}
1569
1572 ConstCfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1573 return (impl_->getSubnetList(cfg, "IPv6"));
1574}
1575
1578 ConstCfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1579 return (impl_->getSubnet<ConstSubnet4Ptr>(cfg, arguments, "subnet4-get",
1580 "subnet4", "IPv4"));
1581}
1582
1585 ConstCfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1586 return (impl_->getSubnet<ConstSubnet6Ptr>(cfg, arguments, "subnet6-get",
1587 "subnet6", "IPv6"));
1588}
1589
1591
1594 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1596 return (impl_->addSubnet<SimpleParser4, Subnet4ConfigParser>(cfg, arguments,
1597 "subnet4-add",
1598 "subnet4", "IPv4"));
1599}
1600
1603 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1605 return (impl_->addSubnet<SimpleParser6, Subnet6ConfigParser>(cfg, arguments,
1606 "subnet6-add",
1607 "subnet6", "IPv6"));
1608}
1609
1612 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1614 return (impl_->updateSubnet<SimpleParser4, Subnet4ConfigParser,
1615 SharedNetwork4Ptr, Subnet4>(cfg, arguments,
1616 "subnet4-update",
1617 "subnet4", "IPv4"));
1618}
1619
1622 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1624 return (impl_->updateSubnet<SimpleParser6, Subnet6ConfigParser,
1625 SharedNetwork6Ptr, Subnet6>(cfg, arguments,
1626 "subnet6-update",
1627 "subnet6", "IPv6"));
1628}
1629
1632 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1634 return (impl_->delSubnet<CfgSubnets4Ptr, SharedNetwork4Ptr>(cfg, arguments, "subnet4-del", "IPv4"));
1635}
1636
1639 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1641 return (impl_->delSubnet<CfgSubnets6Ptr, SharedNetwork6Ptr>(cfg, arguments, "subnet6-del", "IPv6"));
1642}
1643
1646 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1648 return (impl_->updateSubnet<SimpleParser4, Subnet4ConfigParser,
1649 SharedNetwork4Ptr, Subnet4>(cfg, arguments,
1650 "subnet4-delta-add",
1651 "subnet4", "IPv4",
1653}
1654
1657 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1659 return (impl_->updateSubnet<SimpleParser6, Subnet6ConfigParser,
1660 SharedNetwork6Ptr, Subnet6>(cfg, arguments,
1661 "subnet6-delta-add",
1662 "subnet6", "IPv6",
1664}
1665
1668 CfgSubnets4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1670 return (impl_->updateSubnet<SimpleParser4, Subnet4ConfigParser,
1671 SharedNetwork4Ptr, Subnet4>(cfg, arguments,
1672 "subnet4-delta-del",
1673 "subnet4", "IPv4",
1675}
1676
1679 CfgSubnets6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1681 return (impl_->updateSubnet<SimpleParser6, Subnet6ConfigParser,
1682 SharedNetwork6Ptr, Subnet6>(cfg, arguments,
1683 "subnet6-delta-del",
1684 "subnet6", "IPv6",
1686}
1687
1688// =============================================================================
1689// === SHARED NETWORKS =========================================================
1690// =============================================================================
1691
1694 CfgSharedNetworks4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1695 return (impl_->getNetworkList(cfg, "IPv4"));
1696}
1697
1700 CfgSharedNetworks6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1701 return (impl_->getNetworkList(cfg, "IPv6"));
1702}
1703
1706 CfgSharedNetworks4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1707 return (impl_->getNetwork<SharedNetwork4Ptr>(cfg, arguments, "network4-get", "IPv4"));
1708}
1709
1712 CfgSharedNetworks6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1713 return (impl_->getNetwork<SharedNetwork6Ptr>(cfg, arguments, "network6-get", "IPv6"));
1714}
1715
1717
1720 CfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1721 CfgSharedNetworks4Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1723 return (impl_->addNetwork<SimpleParser4, SharedNetwork4Parser>(networks, subnets, arguments,
1724 "network4-add", "IPv4"));
1725}
1726
1729 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1730 CfgSharedNetworks6Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1732 return (impl_->addNetwork<SimpleParser6, SharedNetwork6Parser>(networks, subnets, arguments,
1733 "network6-add", "IPv6"));
1734}
1735
1738 CfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1739 CfgSharedNetworks4Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1741 return (impl_->delNetwork(cfg, subnets, arguments, "network4-del", "IPv4"));
1742}
1743
1746 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1747 CfgSharedNetworks6Ptr cfg = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1749 return (impl_->delNetwork(cfg, subnets, arguments, "network6-del", "IPv6"));
1750}
1751
1754 CfgSharedNetworks4Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1755 CfgSubnets4Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4();
1757 return (impl_->addNetworkSubnet(networks, subnets, arguments, "network4-subnet-add",
1758 "IPv4"));
1759}
1760
1763 CfgSharedNetworks6Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1764 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
1766 return (impl_->addNetworkSubnet(networks, subnets, arguments, "network6-subnet-add",
1767 "IPv6"));
1768}
1769
1772 CfgSharedNetworks4Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks4();
1774 return (impl_->delNetworkSubnet(networks, arguments, "network4-subnet-del", "IPv4"));
1775}
1776
1779 CfgSharedNetworks6Ptr networks = CfgMgr::instance().getCurrentCfg()->getCfgSharedNetworks6();
1781 return (impl_->delNetworkSubnet(networks, arguments, "network6-subnet-del", "IPv6"));
1782}
1783
1784} // end of namespace isc::subnet_cmds
1785} // 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