Kea 2.2.0
adaptor_config.cc
Go to the documentation of this file.
1// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10
11using namespace std;
12using namespace isc::data;
13using namespace isc::dhcp;
14
15namespace {
16const string DHCP4_SPACE = "dhcp4";
17const string DHCP6_SPACE = "dhcp6";
18}
19
20namespace isc {
21namespace yang {
22
24}
25
27}
28
29bool
31 bool have_ids = true;
32
33 if (!subnets || subnets->empty()) {
34 // There are no subnets defined, so technically there are no ids.
35 // However, the flag is used to determine whether the code later
36 // needs to call assignIDs. Since there is no need to assign
37 // anything, the code returns true here.
38 return (true);
39 }
40
41 // If there are subnets defined, let's go over them one by one and
42 // collect subnet-ids used in them.
43 for (ConstElementPtr subnet : subnets->listValue()) {
44 if (!collectID(subnet, set)) {
45 have_ids = false;
46 }
47 }
48 return (have_ids);
49}
50
51bool
53 SubnetIDSet& set,
54 const string& subsel) {
55 if (!networks || networks->empty()) {
56 // There are no shared networks defined, so technically there are no
57 // ids. However, the flag is used to determine whether the code later
58 // needs to call assignIDs. Since there is no need to assign anything,
59 // the code returns true here.
60 return (true);
61 }
62
63 // This determines if EVERY subnet has subnet-id defined.
64 bool have_ids = true;
65 for (size_t i = 0; i < networks->size(); ++i) {
66 ElementPtr network = networks->getNonConst(i);
67 ConstElementPtr subnets = network->get(subsel);
68 if (subnets) {
69 if (!subnets->empty()) {
70 // If there are subnets, collect their subnet-ids. If any
71 // of them doesn't have a subnet-id, return false.
72 if (!subnetsCollectID(subnets, set)) {
73 have_ids = false;
74 }
75 } else {
76 // There's empty subnets list, so just remove it.
77 network->remove(subsel);
78 }
79 }
80 }
81 return (have_ids);
82}
83
84void
86 SubnetID& next) {
87 if (!subnets || subnets->empty()) {
88 // nothing to do here.
89 return;
90 }
91
92 for (size_t i = 0; i < subnets->size(); ++i) {
93 ElementPtr subnet = subnets->getNonConst(i);
94 assignID(subnet, set, next);
95 }
96}
97
98void
100 SubnetIDSet& set, SubnetID& next,
101 const string& subsel) {
102 if (!networks || networks->empty()) {
103 // nothing to do here.
104 return;
105 }
106
107 for (ConstElementPtr network : networks->listValue()) {
108 ConstElementPtr subnets = network->get(subsel);
109 if (!subnets || subnets->empty()) {
110 continue;
111 }
112
113 for (size_t i = 0; i < subnets->size(); ++i) {
114 ElementPtr subnet = subnets->getNonConst(i);
115 assignID(subnet, set, next);
116 }
117 }
118}
119
120void
122 if (!pools || pools->empty()) {
123 // nothing to do here.
124 return;
125 }
126
127 // Canonize (clean up name, remove extra spaces, add one space where
128 // needed) every pool on the list.
129 for (size_t i = 0; i < pools->size(); ++i) {
130 ElementPtr pool = pools->getNonConst(i);
132 }
133}
134
135void
137 if (!subnets || subnets->empty()) {
138 // nothing to do here.
139 return;
140 }
141
142 for (ConstElementPtr subnet : subnets->listValue()) {
143 sanitizePools(subnet->get("pools"));
144 }
145}
146
147void
149 const string& subsel) {
150 if (!networks || networks->empty()) {
151 // nothing to do here.
152 return;
153 }
154
155 for (ConstElementPtr network : networks->listValue()) {
156 sanitizePoolsInSubnets(network->get(subsel));
157 }
158}
159
160void
162 const string& space,
163 OptionCodes& codes) {
164 if (!defs || defs->empty()) {
165 // nothing to do here.
166 return;
167 }
168
169 // Do sanity checks on every option definition and fill any missing
170 // fields with default values.
171 for (size_t i = 0; i < defs->size(); ++i) {
172 ElementPtr def = defs->getNonConst(i);
173 checkCode(def);
174 checkType(def);
175 setSpace(def, space);
176 collect(def, codes);
177 }
178}
179
180void
182 const string& space,
183 const OptionCodes& codes) {
184 if (!options || options->empty()) {
185 // nothing to do here.
186 return;
187 }
188
189 // Sanitize option-data. The only missing elements we may possibly
190 // need to fill are option space and option code.
191 for (size_t i = 0; i < options->size(); ++i) {
192 ElementPtr option = options->getNonConst(i);
193 setSpace(option, space);
194 setCode(option, codes);
195 }
196}
197
198void
200 const string& space,
201 OptionCodes& codes) {
202 if (!classes || classes->empty()) {
203 // nothing to do here.
204 return;
205 }
206
207 // For every client class defined...
208 for (size_t i = 0; i < classes->size(); ++i) {
209 ElementPtr cclass = classes->getNonConst(i);
210
211 if (space == DHCP4_SPACE) {
212 ConstElementPtr options = cclass->get("option-def");
213 if (options) {
214 if (!options->empty()) {
215 // If present, sanitize it.
216 sanitizeOptionDefList(options, space, codes);
217 } else {
218 // If empty, remove it.
219 cclass->remove("option-def");
220 }
221 }
222 }
223
224 // also sanitize option data.
225 ConstElementPtr options = cclass->get("option-data");
226 if (options) {
227 if (!options->empty()) {
228 // If present, sanitize it.
229 sanitizeOptionDataList(options, space, codes);
230 } else {
231 // If empty, remove it.
232 cclass->remove("option-data");
233 }
234 }
235 }
236}
237
238void
240 const OptionCodes& codes) {
241 if (!pools || pools->empty()) {
242 // nothing to do here.
243 return;
244 }
245
246 for (size_t i = 0; i < pools->size(); ++i) {
247 ElementPtr pool = pools->getNonConst(i);
248 ConstElementPtr options = pool->get("option-data");
249 if (options) {
250 if (!options->empty()) {
251 sanitizeOptionDataList(options, space, codes);
252 } else {
253 pool->remove("option-data");
254 }
255 }
256 }
257}
258
259void
261 const OptionCodes& codes) {
262 if (!hosts || hosts->empty()) {
263 // nothing to do here.
264 return;
265 }
266
267 for (size_t i = 0; i < hosts->size(); ++i) {
268 ElementPtr host = hosts->getNonConst(i);
269 ConstElementPtr options = host->get("option-data");
270 if (options) {
271 if (!options->empty()) {
272 sanitizeOptionDataList(options, space, codes);
273 } else {
274 host->remove("option-data");
275 }
276 }
277 }
278}
279
280void
282 const string& space,
283 const OptionCodes& codes) {
284 if (!subnets || subnets->empty()) {
285 // nothing to do here.
286 return;
287 }
288
289 for (size_t i = 0; i < subnets->size(); ++i) {
290 ElementPtr subnet = subnets->getNonConst(i);
291
292 // Let's try to sanitize option-data first.
293 ConstElementPtr options = subnet->get("option-data");
294 if (options) {
295 if (!options->empty()) {
296 sanitizeOptionDataList(options, space, codes);
297 } else {
298 subnet->remove("option-data");
299 }
300 }
301
302 // Then try to sanitize pools.
303 ConstElementPtr pools = subnet->get("pools");
304 if (pools) {
305 if (!pools->empty()) {
306 sanitizeOptionPools(pools, space, codes);
307 } else {
308 subnet->remove("pools");
309 }
310 }
311
312 // If this is v6, also sanitize pd-pools.
313 if (space == DHCP6_SPACE) {
314 ConstElementPtr pools = subnet->get("pd-pools");
315 if (pools) {
316 if (!pools->empty()) {
317 sanitizeOptionPools(pools, space, codes);
318 } else {
319 subnet->remove("pd-pools");
320 }
321 }
322 }
323
324 // Finally, sanitize host reservations.
325 ConstElementPtr hosts = subnet->get("reservations");
326 if (hosts) {
327 if (!hosts->empty()) {
328 sanitizeOptionHosts(hosts, space, codes);
329 } else {
330 subnet->remove("reservations");
331 }
332 }
333 }
334}
335
336void
338 const string& space,
339 const OptionCodes& codes) {
340 if (!networks || networks->empty()) {
341 // nothing to do here.
342 return;
343 }
344
345 // For every shared network...
346 for (size_t i = 0; i < networks->size(); ++i) {
347 ElementPtr network = networks->getNonConst(i);
348
349 // try to sanitize shared network options first.
350 ConstElementPtr options = network->get("option-data");
351 if (options) {
352 if (!options->empty()) {
353 sanitizeOptionDataList(options, space, codes);
354 } else {
355 network->remove("option-data");
356 }
357 }
358 string subnet = "subnet";
359 if (space == DHCP4_SPACE) {
360 subnet += "4";
361 } else {
362 subnet += "6";
363 }
364
365 // Now try to sanitize subnets.
366 ConstElementPtr subnets = network->get(subnet);
367 if (subnets) {
368 if (!subnets->empty()) {
369 sanitizeOptionSubnets(subnets, space, codes);
370 } else {
371 network->remove(subnet);
372 }
373 }
374 }
375}
376
377void
379 if (!pools || pools->empty()) {
380 // nothing to do here.
381 return;
382 }
383
384 for (size_t i = 0; i < pools->size(); ++i) {
385 ElementPtr pool = pools->getNonConst(i);
386 ConstElementPtr requires = pool->get("require-client-classes");
387 if (requires && requires->empty()) {
388 pool->remove("require-client-classes");
389 }
390 }
391}
392
393void
395 if (!subnets || subnets->empty()) {
396 // nothing to do here.
397 return;
398 }
399
400 for (size_t i = 0; i < subnets->size(); ++i) {
401 ElementPtr subnet = subnets->getNonConst(i);
402 sanitizeRequireClassesPools(subnet->get("pools"));
403 sanitizeRequireClassesPools(subnet->get("pd-pools"));
404 ConstElementPtr requires = subnet->get("require-client-classes");
405 if (requires && requires->empty()) {
406 subnet->remove("require-client-classes");
407 }
408 }
409}
410
411void
413 const string& subsel) {
414 if (!networks || networks->empty()) {
415 // nothing to do here.
416 return;
417 }
418
419 for (size_t i = 0; i < networks->size(); ++i) {
420 ElementPtr network = networks->getNonConst(i);
421 sanitizeRequireClassesSubnets(network->get(subsel));
422 ConstElementPtr requires = network->get("require-client-classes");
423 if (requires && requires->empty()) {
424 network->remove("require-client-classes");
425 }
426 }
427}
428
429void
431
432 if (!hosts || hosts->empty()) {
433 // nothing to do here.
434 return;
435 }
436
437 for (size_t i = 0; i < hosts->size(); ++i) {
438 ElementPtr host = hosts->getNonConst(i);
439 quoteIdentifier(host);
440 }
441}
442
443void
445
446 if (!subnets || subnets->empty()) {
447 // nothing to do here.
448 return;
449 }
450
451 for (ConstElementPtr subnet : subnets->listValue()) {
452 sanitizeHostList(subnet->get("reservations"));
453 }
454}
455
456void
458 const string& space) {
459 if (!networks || networks->empty()) {
460 // nothing to do here.
461 return;
462 }
463
464 for (ConstElementPtr network : networks->listValue()) {
465 if (space == DHCP4_SPACE) {
466 sanitizeHostSubnets(network->get("subnet4"));
467 } else {
468 sanitizeHostSubnets(network->get("subnet6"));
469 }
470 }
471}
472
473void
475 if (!subnets || subnets->empty()) {
476 // nothing to do here.
477 return;
478 }
479
480 for (size_t i = 0; i < subnets->size(); ++i) {
481 ElementPtr subnet = subnets->getNonConst(i);
482 updateRelay(subnet);
483 }
484}
485
486void
488 const string& subsel) {
489 if (!networks || networks->empty()) {
490 // nothing to do here.
491 return;
492 }
493
494 for (size_t i = 0; i < networks->size(); ++i) {
495 ElementPtr network = networks->getNonConst(i);
496 updateRelay(network);
497 sanitizeRelaySubnets(network->get(subsel));
498 }
499}
500
501void
503 ConstElementPtr database = dhcp->get("hosts-database");
504 if (!database) {
505 // nothing to do here.
506 return;
507 }
508
509 ElementPtr mutable_dhcp = boost::const_pointer_cast<Element>(dhcp);
510 mutable_dhcp->remove("hosts-database");
511 ElementPtr list = Element::createList();
512 list->add(boost::const_pointer_cast<Element>(database));
513 mutable_dhcp->set("hosts-databases", list);
514}
515
516void
518 ConstElementPtr options = dhcp->get("relay-supplied-options");
519 if (!options || !options->empty()) {
520 // nothing to do here.
521 return;
522 }
523 ElementPtr mutable_dhcp = boost::const_pointer_cast<Element>(dhcp);
524 mutable_dhcp->remove("relay-supplied-options");
525}
526
527void
528AdaptorConfig::preProcess(ElementPtr dhcp, const string& subsel,
529 const string& space) {
530 if (!dhcp) {
531 isc_throw(BadValue, "preProcess: null DHCP config");
532 }
533 bool have_ids = true;
534 SubnetIDSet set;
535 ConstElementPtr subnets = dhcp->get(subsel);
536 if (subnets) {
537 if (!subnets->empty()) {
538 if (!subnetsCollectID(subnets, set)) {
539 have_ids = false;
540 }
541 } else {
542 dhcp->remove(subsel);
543 }
544 }
545 ConstElementPtr networks = dhcp->get("shared-networks");
546 if (networks) {
547 if (!networks->empty()) {
548 if (!sharedNetworksCollectID(networks, set, subsel)) {
549 have_ids = false;
550 }
551 } else {
552 dhcp->remove("shared-networks");
553 }
554 }
555
556 if (!have_ids) {
557 SubnetID next(1);
558 subnetsAssignID(subnets, set, next);
559 sharedNetworksAssignID(networks, set, next, subsel);
560 }
561
562 OptionCodes codes;
563 initCodes(codes, space);;
564 ConstElementPtr defs = dhcp->get("option-def");
565 if (defs) {
566 if (!defs->empty()) {
567 sanitizeOptionDefList(defs, space, codes);
568 } else {
569 dhcp->remove("option-def");
570 }
571 }
572 ConstElementPtr options = dhcp->get("option-data");
573 if (options) {
574 if (!options->empty()) {
575 sanitizeOptionDataList(options, space, codes);
576 } else {
577 dhcp->remove("option-data");
578 }
579 }
580 ConstElementPtr classes = dhcp->get("client-classes");
581 if (classes) {
582 if (!classes->empty()) {
583 sanitizeOptionClasses(classes, space, codes);
584 } else {
585 dhcp->remove("client-classes");
586 }
587 }
588 ConstElementPtr hosts = dhcp->get("reservations");
589 if (hosts) {
590 if (!hosts->empty()) {
591 sanitizeHostList(hosts);
592 sanitizeOptionHosts(hosts, space, codes);
593 } else {
594 dhcp->remove("reservations");
595 }
596 }
597 sanitizeOptionSubnets(subnets, space, codes);
598 sanitizeOptionSharedNetworks(networks, space, codes);
599
600 sanitizePoolsInSubnets(subnets);
601 sanitizePoolsInSharedNetworks(networks, subsel);
602
603 sanitizeHostSubnets(subnets);
604 SanitizeHostsInSharedNetworks(networks, space);
605
606 sanitizeRelaySubnets(subnets);
607 sanitizeRelayInSharedNetworks(networks, subsel);
608
610 requireClassesSharedNetworks(networks, subsel);
611
612 sanitizeDatabase(dhcp);
613
614 if (space == DHCP6_SPACE) {
616 }
617}
618
619void
621 if (!config) {
622 isc_throw(BadValue, "preProcess4: null config");
623 }
624 if (config->getType() != Element::map) {
625 isc_throw(BadValue, "preProcess4: not map: " << config->str());
626 }
627 if (config->contains("Logging")) {
628 isc_throw(BadValue, "preProcess4: got Logging object");
629 }
630 ConstElementPtr dhcp = config->get("Dhcp4");
631 if (!dhcp) {
632 return;
633 }
634 ElementPtr mutable_dhcp = boost::const_pointer_cast<Element>(dhcp);
635 preProcess(mutable_dhcp, "subnet4", DHCP4_SPACE);
636}
637
638void
640 if (!config) {
641 isc_throw(BadValue, "preProcess6: null config");
642 }
643 if (config->getType() != Element::map) {
644 isc_throw(BadValue, "preProcess6: not map: " << config->str());
645 }
646 if (config->contains("Logging")) {
647 isc_throw(BadValue, "preProcess6: got Logging object");
648 }
649 ConstElementPtr dhcp = config->get("Dhcp6");
650 if (!dhcp) {
651 return;
652 }
653 ElementPtr mutable_dhcp = boost::const_pointer_cast<Element>(dhcp);
654 preProcess(mutable_dhcp, "subnet6", DHCP6_SPACE);
655}
656
657} // end of namespace isc::yang
658} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static void sanitizeRequireClassesPools(isc::data::ConstElementPtr pools)
Process require client classes in a pool list.
static void sanitizeOptionSharedNetworks(isc::data::ConstElementPtr networks, const std::string &space, const OptionCodes &codes)
Set missing option codes to a shared network list.
static void subnetsAssignID(isc::data::ConstElementPtr subnets, SubnetIDSet &set, isc::dhcp::SubnetID &next)
Assigns subnet-id to every subnet in a subnet list.
static void sanitizeRelaySubnets(isc::data::ConstElementPtr subnets)
Sanitizes relay information in subnets in a subnet list.
static void sanitizeHostSubnets(isc::data::ConstElementPtr subnets)
Process host reservations in a subnet list.
static void sanitizeOptionPools(isc::data::ConstElementPtr pools, const std::string &space, const OptionCodes &codes)
Set missing option codes to a pool list.
static void sanitizeDatabase(isc::data::ConstElementPtr dhcp)
Update (hosts) database.
static void preProcess(isc::data::ElementPtr dhcp, const std::string &subsel, const std::string &space)
Pre process a configuration.
static void sharedNetworksAssignID(isc::data::ConstElementPtr networks, SubnetIDSet &set, isc::dhcp::SubnetID &next, const std::string &subsel)
Assigns subnet-id to every subnet in a shared network list.
static void sanitizePoolsInSubnets(isc::data::ConstElementPtr subnets)
Sanitizes all pools in a subnets list.
static void requireClassesSharedNetworks(isc::data::ConstElementPtr networks, const std::string &subsel)
Process require client classes in a shared network list.
static void preProcess4(isc::data::ConstElementPtr config)
Pre process a DHCPv4 configuration.
static bool subnetsCollectID(isc::data::ConstElementPtr subnets, SubnetIDSet &set)
Collects subnet-ids on all subnets.
static void sanitizeOptionHosts(isc::data::ConstElementPtr hosts, const std::string &space, const OptionCodes &codes)
Set missing option codes to a host reservation list.
static void sanitizeHostList(isc::data::ConstElementPtr hosts)
Process host reservation list.
static void SanitizeHostsInSharedNetworks(isc::data::ConstElementPtr networks, const std::string &space)
Process host reservations in a shared network list.
static void sanitizeOptionDefList(isc::data::ConstElementPtr defs, const std::string &space, OptionCodes &codes)
Collect option definitions from an option definition list.
virtual ~AdaptorConfig()
Destructor.
static void sanitizeRequireClassesSubnets(isc::data::ConstElementPtr subnets)
Process require client classes in a subnet list.
static void sanitizeOptionSubnets(isc::data::ConstElementPtr subnets, const std::string &space, const OptionCodes &codes)
Set missing option codes to a subnet list.
static void sanitizePools(isc::data::ConstElementPtr pools)
Sanitizes all pools in a pools list.
static void sanitizePoolsInSharedNetworks(isc::data::ConstElementPtr networks, const std::string &subsel)
Sanitizes all pools in all subnets in a shared network list.
static void sanitizeOptionClasses(isc::data::ConstElementPtr classes, const std::string &space, OptionCodes &codes)
Collect option definitions from a client class list and set missing option codes.
static bool sharedNetworksCollectID(isc::data::ConstElementPtr networks, SubnetIDSet &set, const std::string &subsel)
Collects subnet-ids in all subnets in all shared network list.
static void sanitizeRelaySuppliedOptions(isc::data::ConstElementPtr dhcp)
Update relay supplied options.
static void preProcess6(isc::data::ConstElementPtr config)
Pre process a DHCPv6 configuration.
static void sanitizeOptionDataList(isc::data::ConstElementPtr options, const std::string &space, const OptionCodes &codes)
Set missing option codes to an option data list.
static void sanitizeRelayInSharedNetworks(isc::data::ConstElementPtr networks, const std::string &subsel)
Sanitizes relay information in a shared network list.
static void quoteIdentifier(isc::data::ElementPtr host)
Quote when needed a host identifier.
Definition: adaptor_host.cc:33
static void setCode(isc::data::ElementPtr option, const OptionCodes &codes)
Set code from name and definitions.
static void initCodes(OptionCodes &codes, const std::string &space)
Initialize code map.
static void setSpace(isc::data::ElementPtr option, const std::string &space)
Set space.
static void checkType(isc::data::ConstElementPtr option)
Checks if type is specified in option definition.
static void collect(isc::data::ConstElementPtr option, OptionCodes &codes)
Collect definition.
static void checkCode(isc::data::ConstElementPtr option)
Check if code is specified in option defintion.
static void canonizePool(isc::data::ElementPtr pool)
Canonize pool.
Definition: adaptor_pool.cc:25
static bool collectID(isc::data::ConstElementPtr subnet, SubnetIDSet &set)
Collect a subnet ID.
static void updateRelay(isc::data::ElementPtr subnet)
Update relay.
static void assignID(isc::data::ElementPtr subnet, SubnetIDSet &set, isc::dhcp::SubnetID &next)
Assign subnet ID.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24
std::set< isc::dhcp::SubnetID > SubnetIDSet
Set of SubnetIDs.
std::map< std::string, uint16_t > OptionCodes
Map for DHCP option definitions handling code and an index built from space and name.
Defines the logger used by the top-level component of kea-lfc.