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