Kea  2.1.7-git
adaptor_config.cc
Go to the documentation of this file.
1 // Copyright (C) 2018-2020 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 <yang/adaptor_config.h>
10 
11 using namespace std;
12 using namespace isc::data;
13 using namespace isc::dhcp;
14 
15 namespace {
16 const string DHCP4_SPACE = "dhcp4";
17 const string DHCP6_SPACE = "dhcp6";
18 }
19 
20 namespace isc {
21 namespace yang {
22 
23 AdaptorConfig::AdaptorConfig() {
24 }
25 
26 AdaptorConfig::~AdaptorConfig() {
27 }
28 
29 bool
30 AdaptorConfig::subnetsCollectID(ConstElementPtr subnets, SubnetIDSet& set) {
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 
51 bool
52 AdaptorConfig::sharedNetworksCollectID(ConstElementPtr networks,
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 
84 void
85 AdaptorConfig::subnetsAssignID(ConstElementPtr subnets, SubnetIDSet& set,
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 
98 void
99 AdaptorConfig::sharedNetworksAssignID(ConstElementPtr networks,
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 
120 void
121 AdaptorConfig::sanitizePools(ConstElementPtr pools) {
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);
131  AdaptorPool::canonizePool(pool);
132  }
133 }
134 
135 void
136 AdaptorConfig::sanitizePoolsInSubnets(ConstElementPtr subnets) {
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 
147 void
148 AdaptorConfig::sanitizePoolsInSharedNetworks(ConstElementPtr networks,
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 
160 void
161 AdaptorConfig::sanitizeOptionDefList(ConstElementPtr defs,
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 
180 void
181 AdaptorConfig::sanitizeOptionDataList(ConstElementPtr options,
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 
198 void
199 AdaptorConfig::sanitizeOptionClasses(ConstElementPtr classes,
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 
238 void
239 AdaptorConfig::sanitizeOptionPools(ConstElementPtr pools, const string& space,
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 
259 void
260 AdaptorConfig::sanitizeOptionHosts(ConstElementPtr hosts, const string& space,
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 
280 void
281 AdaptorConfig::sanitizeOptionSubnets(ConstElementPtr subnets,
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 
336 void
337 AdaptorConfig::sanitizeOptionSharedNetworks(ConstElementPtr networks,
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 
377 void
378 AdaptorConfig::sanitizeRequireClassesPools(ConstElementPtr pools) {
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 
393 void
394 AdaptorConfig::sanitizeRequireClassesSubnets(ConstElementPtr subnets) {
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 
411 void
412 AdaptorConfig::requireClassesSharedNetworks(ConstElementPtr networks,
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 
429 void
430 AdaptorConfig::sanitizeHostList(ConstElementPtr hosts) {
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 
443 void
444 AdaptorConfig::sanitizeHostSubnets(ConstElementPtr subnets) {
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 
456 void
457 AdaptorConfig::SanitizeHostsInSharedNetworks(ConstElementPtr networks,
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 
473 void
474 AdaptorConfig::sanitizeRelaySubnets(ConstElementPtr subnets) {
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 
486 void
487 AdaptorConfig::sanitizeRelayInSharedNetworks(ConstElementPtr networks,
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 
501 void
502 AdaptorConfig::sanitizeDatabase(ConstElementPtr dhcp) {
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 
516 void
517 AdaptorConfig::sanitizeRelaySuppliedOptions(ConstElementPtr dhcp) {
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 
527 void
528 AdaptorConfig::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 
609  sanitizeRequireClassesSubnets(subnets);
610  requireClassesSharedNetworks(networks, subsel);
611 
612  sanitizeDatabase(dhcp);
613 
614  if (space == DHCP6_SPACE) {
615  sanitizeRelaySuppliedOptions(dhcp);
616  }
617 }
618 
619 void
620 AdaptorConfig::preProcess4(ConstElementPtr config) {
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 
638 void
639 AdaptorConfig::preProcess6(ConstElementPtr config) {
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
std::map< std::string, uint16_t > OptionCodes
Map for DHCP option definitions handling code and an index built from space and name.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
STL namespace.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
Defines the logger used by the top-level component of kea-lfc.
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:70
std::set< isc::dhcp::SubnetID > SubnetIDSet
Set of SubnetIDs.
virtual void remove(const int i)
Removes the element at the given position.
Definition: data.cc:150
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24