Kea  1.9.9-git
translator_pd_pool.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 <config.h>
8 
9 #include <yang/adaptor.h>
11 #include <yang/yang_models.h>
12 #include <boost/lexical_cast.hpp>
13 #include <sstream>
14 
15 using namespace std;
16 using namespace isc::data;
17 #ifndef HAVE_PRE_0_7_6_SYSREPO
18 using namespace sysrepo;
19 #endif
20 
21 namespace isc {
22 namespace yang {
23 
24 TranslatorPdPool::TranslatorPdPool(S_Session session, const string& model)
25  : TranslatorBasic(session, model),
26  TranslatorOptionData(session, model),
27  TranslatorOptionDataList(session, model) {
28 }
29 
31 }
32 
34 TranslatorPdPool::getPdPool(const string& xpath) {
35  try {
36  if (model_ == IETF_DHCPV6_SERVER) {
37  return (getPdPoolIetf6(xpath));
38  } else if (model_ == KEA_DHCP6_SERVER) {
39  return (getPdPoolKea(xpath));
40  }
41  } catch (const sysrepo_exception& ex) {
43  "sysrepo error getting pd-pool at '" << xpath
44  << "': " << ex.what());
45  }
47  "getPdPool not implemented for the model: " << model_);
48 }
49 
51 TranslatorPdPool::getPdPoolIetf6(const string& xpath) {
52  ElementPtr result = Element::createMap();
53  ConstElementPtr pref = getItem(xpath + "/prefix");
54  if (!pref) {
55  isc_throw(BadValue, "getPdPoolIetf6: prefix is required");
56  }
57  const string& prefix = pref->stringValue();
58  size_t slash = prefix.find("/");
59  if (slash == string::npos) {
61  "getPdPoolIetf6: no '/' in prefix '" << prefix << "'");
62  }
63  const string& address = prefix.substr(0, slash);
64  if (address.empty()) {
66  "getPdPoolIetf6: malformed prefix '" << prefix << "'");
67  }
68  result->set("prefix", Element::create(address));
69  // Silly: the prefix length is specified twice...
70  ConstElementPtr preflen = getItem(xpath + "/prefix-length");
71  if (!preflen) {
72  isc_throw(BadValue, "getPdPoolIetf6: prefix length is required");
73  }
74  result->set("prefix-len", preflen);
75  ConstElementPtr valid_lifetime = getItem(xpath + "/valid-lifetime");
76  if (valid_lifetime) {
77  result->set("valid-lifetime", valid_lifetime);
78  }
79  ConstElementPtr preferred_lifetime =
80  getItem(xpath + "/preferred-lifetime");
81  if (preferred_lifetime) {
82  result->set("preferred-lifetime", preferred_lifetime);
83  }
84  ConstElementPtr renew_time = getItem(xpath + "/renew-time");
85  if (renew_time) {
86  result->set("renew-timer", renew_time);
87  }
88  ConstElementPtr rebind_time = getItem(xpath + "/rebind-time");
89  if (rebind_time) {
90  result->set("rebind-timer", rebind_time);
91  }
92  // Skip rapid-commit.
93  ConstElementPtr guard = getItem(xpath + "/client-class");
94  if (guard) {
95  result->set("client-class", guard);
96  }
97  // no require-client-classes nor user-context.
98  // Skip max-pd-space-utilization.
99  // @todo option-data.
100  return (result);
101 }
102 
104 TranslatorPdPool::getPdPoolKea(const string& xpath) {
105  ElementPtr result = Element::createMap();
106  ConstElementPtr pref = getItem(xpath + "/prefix");
107  if (!pref) {
108  isc_throw(BadValue, "getPdPoolKea: no prefix defined at " << xpath);
109  }
110  const string& prefix = pref->stringValue();
111  size_t slash = prefix.find("/");
112  if (slash == string::npos) {
114  "getPdPoolKea: no '/' in prefix '" << prefix << "'");
115  }
116  const string& address = prefix.substr(0, slash);
117  const string& length = prefix.substr(slash + 1, string::npos);
118  if (address.empty() || length.empty()) {
120  "getPdPoolKea: malformed prefix '" << prefix << "'");
121  }
122  result->set("prefix", Element::create(address));
123  try {
124  unsigned len = boost::lexical_cast<unsigned>(length);
125  result->set("prefix-len", Element::create(static_cast<int>(len)));
126  } catch (const boost::bad_lexical_cast&) {
128  "getPdPoolKea: bad prefix length in '" << prefix << "'");
129  }
130 
131  ConstElementPtr xpref = getItem(xpath + "/excluded-prefix");
132  if (xpref) {
133  const string& xprefix = xpref->stringValue();
134  size_t xslash = xprefix.find("/");
135  if (xslash == string::npos) {
137  "getPdPoolKea: no '/' in excluded prefix '"
138  << xprefix << "'");
139  }
140  const string& xaddress = xprefix.substr(0, xslash);
141  const string& xlength = xprefix.substr(xslash + 1, string::npos);
142  if (xaddress.empty() || xlength.empty()) {
144  "getPdPoolKea: malformed excluded prefix '"
145  << xprefix << "'");
146  }
147  result->set("excluded-prefix", Element::create(xaddress));
148  try {
149  unsigned xlen = boost::lexical_cast<unsigned>(xlength);
150  result->set("excluded-prefix-len",
151  Element::create(static_cast<int>(xlen)));
152  } catch (const boost::bad_lexical_cast&) {
154  "getPdPoolKea: bad excluded prefix length in '"
155  << xprefix << "'");
156  }
157  }
158 
159  ConstElementPtr delegated = getItem(xpath + "/delegated-len");
160  if (delegated) {
161  result->set("delegated-len", delegated);
162  }
163  ConstElementPtr options = getOptionDataList(xpath);
164  if (options && (options->size() > 0)) {
165  result->set("option-data", options);
166  }
167  ConstElementPtr guard = getItem(xpath + "/client-class");
168  if (guard) {
169  result->set("client-class", guard);
170  }
171  ConstElementPtr required = getItems(xpath + "/require-client-classes");
172  if (required && (required->size() > 0)) {
173  result->set("require-client-classes", required);
174  }
175  ConstElementPtr context = getItem(xpath + "/user-context");
176  if (context) {
177  result->set("user-context", Element::fromJSON(context->stringValue()));
178  }
179  return (result);
180 }
181 
182 void
183 TranslatorPdPool::setPdPool(const string& xpath, ConstElementPtr elem) {
184  try {
185  if (model_ == IETF_DHCPV6_SERVER) {
186  setPdPoolIetf6(xpath, elem);
187  } else if (model_ == KEA_DHCP6_SERVER) {
188  setPdPoolKea(xpath, elem);
189  } else {
191  "setPdPool not implemented for the model: " << model_);
192  }
193  } catch (const sysrepo_exception& ex) {
195  "sysrepo error setting pd-pool '" << elem->str()
196  << "' at '" << xpath << "': " << ex.what());
197  }
198 }
199 
200 void
202  ConstElementPtr base = elem->get("prefix");
203  ConstElementPtr length = elem->get("prefix-len");
204  if (!base || !length) {
206  "setPdPoolIetf6 requires prefix and prefix length: "
207  << elem->str());
208  }
209  ostringstream prefix;
210  prefix << base->stringValue() << "/" << length->intValue();
211  setItem(xpath + "/prefix", Element::create(prefix.str()), SR_STRING_T);
212  setItem(xpath + "/prefix-length", length, SR_UINT8_T);
213  ConstElementPtr valid_lifetime = elem->get("valid-lifetime");
214  if (valid_lifetime) {
215  setItem(xpath + "/valid-lifetime", valid_lifetime, SR_UINT32_T);
216  }
217  ConstElementPtr preferred_lifetime = elem->get("preferred-lifetime");
218  if (preferred_lifetime) {
219  setItem(xpath + "/preferred-lifetime",
220  preferred_lifetime, SR_UINT32_T);
221  }
222  ConstElementPtr renew_timer = elem->get("renew-timer");
223  if (renew_timer) {
224  setItem(xpath + "/renew-time", renew_timer, SR_UINT32_T);
225  }
226  ConstElementPtr rebind_timer = elem->get("rebind-timer");
227  if (rebind_timer) {
228  setItem(xpath + "/rebind-time", rebind_timer, SR_UINT32_T);
229  }
230  // Skip rapid-commit.
231  ConstElementPtr guard = elem->get("client-class");
232  if (guard) {
233  setItem(xpath + "/client-class", guard, SR_STRING_T);
234  }
235  // Set max pd space utilization to disabled.
236  setItem(xpath + "/max-pd-space-utilization",
237  Element::create(string("disabled")),
238  SR_ENUM_T);
239  // @todo option-data.
240 }
241 
242 void
244  // Skip prefix as it is the key.
245  bool created = false;
246  ConstElementPtr delegated = elem->get("delegated-len");
247  if (delegated) {
248  setItem(xpath + "/delegated-len", delegated, SR_UINT8_T);
249  }
250  ConstElementPtr xprefix = elem->get("excluded-prefix");
251  ConstElementPtr xlen = elem->get("excluded-prefix-len");
252  if (xprefix && xlen) {
253  ostringstream xpref;
254  xpref << xprefix->stringValue() << "/" << xlen->intValue();
255  setItem(xpath + "/excluded-prefix", Element::create(xpref.str()),
256  SR_STRING_T);
257  created = true;
258  }
259  ConstElementPtr options = elem->get("option-data");
260  if (options && (options->size() > 0)) {
261  setOptionDataList(xpath, options);
262  created = true;
263  }
264  ConstElementPtr guard = elem->get("client-class");
265  if (guard) {
266  setItem(xpath + "/client-class", guard, SR_STRING_T);
267  created = true;
268  }
269  ConstElementPtr required = elem->get("require-client-classes");
270  if (required && (required->size() > 0)) {
271  for (ConstElementPtr rclass : required->listValue()) {
272  setItem(xpath + "/require-client-classes", rclass, SR_STRING_T);
273  created = true;
274  }
275  }
276  ConstElementPtr context = Adaptor::getContext(elem);
277  if (context) {
278  setItem(xpath + "/user-context", Element::create(context->str()),
279  SR_STRING_T);
280  created = true;
281  }
282  // There is no mandatory fields outside the keys so force creation.
283  if (!created) {
284  ConstElementPtr list = Element::createList();
285  setItem(xpath, list, SR_LIST_T);
286  }
287 }
288 
289 TranslatorPdPools::TranslatorPdPools(S_Session session, const string& model)
290  : TranslatorBasic(session, model),
291  TranslatorOptionData(session, model),
292  TranslatorOptionDataList(session, model),
293  TranslatorPdPool(session, model) {
294 }
295 
297 }
298 
300 TranslatorPdPools::getPdPools(const string& xpath) {
301  try {
302  if ((model_ == IETF_DHCPV6_SERVER) ||
303  (model_ == KEA_DHCP6_SERVER)) {
304  return (getPdPoolsCommon(xpath));
305  }
306  } catch (const sysrepo_exception& ex) {
308  "sysrepo error getting pd-pools at '" << xpath
309  << "': " << ex.what());
310  }
312  "getPdPools not implemented for the model: " << model_);
313 }
314 
317  ElementPtr result = Element::createList();
318  S_Iter_Value iter = getIter(xpath + "/pd-pool");
319  if (!iter) {
320  // Can't happen.
321  isc_throw(Unexpected, "getPdPools: can't get iterator: " << xpath);
322  }
323  for (;;) {
324  const string& pool = getNext(iter);
325  if (pool.empty()) {
326  break;
327  }
328  result->add(getPdPool(pool));
329  }
330  return (result);
331 }
332 
333 void
334 TranslatorPdPools::setPdPools(const string& xpath, ConstElementPtr elem) {
335  try {
336  if (model_ == IETF_DHCPV6_SERVER) {
337  setPdPoolsId(xpath, elem);
338  } else if (model_ == KEA_DHCP6_SERVER) {
339  setPdPoolsPrefix(xpath, elem);
340  } else {
342  "setPdPools not implemented for the model: " << model_);
343  }
344  } catch (const sysrepo_exception& ex) {
346  "sysrepo error setting pools '" << elem->str()
347  << "' at '" << xpath << "': " << ex.what());
348  }
349 }
350 
351 void
353  for (size_t i = 0; i < elem->size(); ++i) {
354  ConstElementPtr pool = elem->get(i);
355  ostringstream prefix;
356  prefix << xpath << "/pd-pool[pool-id='" << i << "']";
357  setPdPool(prefix.str(), pool);
358  }
359 }
360 
361 void
363  ConstElementPtr elem) {
364  for (size_t i = 0; i < elem->size(); ++i) {
365  ConstElementPtr pool = elem->get(i);
366  if (!pool->contains("prefix") || !pool->contains("prefix-len")) {
367  isc_throw(BadValue, "pd-pool requires prefix and prefix length: "
368  << pool->str());
369  }
370  ostringstream prefix;
371  prefix << xpath << "/pd-pool[prefix='"
372  << pool->get("prefix")->stringValue() << "/"
373  << pool->get("prefix-len")->intValue() << "']";
374  setPdPool(prefix.str(), pool);
375  }
376 }
377 
378 }; // end of namespace isc::yang
379 }; // end of namespace isc
isc::data::ElementPtr getItems(const std::string &xpath)
Get and translate a list of basic values from YANG to JSON.
Definition: translator.cc:126
A generic exception that is thrown when a function is not implemented.
isc::data::ElementPtr getPdPoolsCommon(const std::string &xpath)
getPdPools common part.
Between YANG and JSON translator class for basic values.
Definition: translator.h:27
void setPdPool(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set pd-pool from JSON to YANG.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
STL namespace.
TranslatorPdPools(sysrepo::S_Session session, const std::string &model)
Constructor.
virtual ~TranslatorPdPool()
Destructor.
virtual ~TranslatorPdPools()
Destructor.
isc::data::ElementPtr getPdPools(const std::string &xpath)
Get and translate pd-pools from YANG to JSON.
sysrepo::S_Iter_Value getIter(const std::string &xpath)
List iterator methods keeping the session private.
Definition: translator.cc:316
#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...
void setItem(const std::string &xpath, isc::data::ConstElementPtr elem, sr_type_t type)
Translate and set basic value from JSON to YANG.
Definition: translator.cc:288
isc::data::ElementPtr getPdPoolIetf6(const std::string &xpath)
getPdPool for ietf-dhcpv6-server.
A translator class for converting an option data list between YANG and JSON.
A generic exception that is thrown when an unexpected error condition occurs.
std::string model_
The model.
Definition: translator.h:132
isc::data::ElementPtr getPdPool(const std::string &xpath)
Get and translate a pd-pool from YANG to JSON.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
std::string getNext(sysrepo::S_Iter_Value iter)
Get xpath of the next YANG list item.
Definition: translator.cc:321
void setPdPoolsId(const std::string &xpath, isc::data::ConstElementPtr elem)
setPdPools using pool-id.
void setPdPools(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set pd-pools from JSON to YANG.
static isc::data::ConstElementPtr getContext(isc::data::ConstElementPtr parent)
Get user context.
Definition: adaptor.cc:27
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Defines the logger used by the top-level component of kea-dhcp-ddns.
isc::data::ConstElementPtr getOptionDataList(const std::string &xpath)
Get and translate option data list from YANG to JSON.
void setPdPoolIetf6(const std::string &xpath, isc::data::ConstElementPtr elem)
setPdPool for ietf-dhcpv6-server.
isc::data::ElementPtr getItem(const std::string &xpath)
Get and translate basic value from YANG to JSON.
Definition: translator.cc:111
Prefix delegation pool translation between YANG and JSON.
isc::data::ElementPtr getPdPoolKea(const std::string &xpath)
getPdPool for kea-dhcp6-server.
Option data translation between YANG and JSON.
void setOptionDataList(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set option data list from JSON to YANG.
void setPdPoolsPrefix(const std::string &xpath, isc::data::ConstElementPtr elem)
setPdPools using prefix.
void setPdPoolKea(const std::string &xpath, isc::data::ConstElementPtr elem)
setPdPool for kea-dhcp6-server.