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