Kea 1.5.0
translator_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
11#include <yang/adaptor.h>
13#include <yang/yang_models.h>
14#include <boost/lexical_cast.hpp>
15#include <sstream>
16
17using namespace std;
18using namespace isc::data;
19using namespace isc::asiolink;
20using namespace isc::dhcp;
21#ifndef HAVE_PRE_0_7_6_SYSREPO
22using namespace sysrepo;
23#endif
24
25namespace isc {
26namespace yang {
27
28TranslatorPool::TranslatorPool(S_Session session, const string& model)
29 : TranslatorBasic(session, model),
30 TranslatorOptionData(session, model),
31 TranslatorOptionDataList(session, model) {
32}
33
35}
36
38TranslatorPool::getPool(const string& xpath) {
39 try {
40 if (model_ == IETF_DHCPV6_SERVER) {
41 return (getPoolIetf6(xpath));
42 } else if ((model_ == KEA_DHCP4_SERVER) ||
43 (model_ == KEA_DHCP6_SERVER)) {
44 return (getPoolKea(xpath));
45 }
46 } catch (const sysrepo_exception& ex) {
48 "sysrepo error getting pool at '" << xpath
49 << "': " << ex.what());
50 }
52 "getPool not implemented for the model: " << model_);
53}
54
56TranslatorPool::getPoolIetf6(const string& xpath) {
58 // Skip pool-id which exists but is not used.
59 ConstElementPtr pool = getItem(xpath + "/pool-prefix");
60 if (!pool) {
61 isc_throw(BadValue, "getPoolIetf6 requires pool prefix at " << xpath);
62 }
63 result->set("pool", pool);
64 // Ignore start-address - end-address as prefix form is mandatory?
65 ConstElementPtr guard = getItem(xpath + "/client-class");
66 if (guard) {
67 result->set("client-class", guard);
68 }
69 ConstElementPtr valid_lifetime = getItem(xpath + "/valid-lifetime");
70 if (valid_lifetime) {
71 result->set("valid-lifetime", valid_lifetime);
72 }
73 ConstElementPtr preferred_lifetime =
74 getItem(xpath + "/preferred-lifetime");
75 if (preferred_lifetime) {
76 result->set("preferred-lifetime", preferred_lifetime);
77 }
78 ConstElementPtr renew_time = getItem(xpath + "/renew-time");
79 if (renew_time) {
80 result->set("renew-timer", renew_time);
81 }
82 ConstElementPtr rebind_time = getItem(xpath + "/rebind-time");
83 if (rebind_time) {
84 result->set("rebind-timer", rebind_time);
85 }
86 // Skip max-addr-count
87 // @todo: option-data
89 // Skip rapid-commit.
90 return (result);
91}
92
94TranslatorPool::getPoolKea(const string& xpath) {
96 ConstElementPtr prefix = getItem(xpath + "/prefix");
97 if (prefix) {
98 result->set("pool", prefix);
99 } else {
100 ConstElementPtr start_addr = getItem(xpath + "/start-address");
101 ConstElementPtr end_addr = getItem(xpath + "/end-address");
102 if (!start_addr || !end_addr) {
103 isc_throw(BadValue, "getPoolKea requires either prefix or "
104 "both start and end addresses at " << xpath);
105 }
106 ostringstream range;
107 range << start_addr->stringValue() << " - "
108 << end_addr->stringValue();
109 result->set("pool", Element::create(range.str()));
110 }
111 ConstElementPtr options = getOptionDataList(xpath);
112 if (options && (options->size() > 0)) {
113 result->set("option-data", options);
114 }
115 ConstElementPtr guard = getItem(xpath + "/client-class");
116 if (guard) {
117 result->set("client-class", guard);
118 }
119 ConstElementPtr required = getItems(xpath + "/require-client-classes");
120 if (required && (required->size() > 0)) {
121 result->set("require-client-classes", required);
122 }
123 ConstElementPtr context = getItem(xpath + "/user-context");
124 if (context) {
125 result->set("user-context", Element::fromJSON(context->stringValue()));
126 }
127 return (result);
128}
129
130void
131TranslatorPool::setPool(const string& xpath, ConstElementPtr elem) {
132 try {
133 if (model_ == IETF_DHCPV6_SERVER) {
134 setPoolIetf6(xpath, elem);
135 } else if ((model_ == KEA_DHCP4_SERVER) ||
136 (model_ == KEA_DHCP6_SERVER)) {
137 setPoolKea(xpath, elem);
138 } else {
140 "setPool not implemented for the model: " << model_);
141 }
142 } catch (const sysrepo_exception& ex) {
144 "sysrepo error setting pool '" << elem->str()
145 << "' at '" << xpath << "': " << ex.what());
146 }
147}
148
149void
151 ConstElementPtr pool = elem->get("pool");
152 if (!pool) {
153 isc_throw(BadValue, "setPoolIetf6 requires pool: " << elem->str());
154 }
155 string prefix = pool->stringValue();
156 if (prefix.find("/") == string::npos) {
158 "setPoolIetf only supports pools in prefix (vs range) "
159 "format and was called with '" << prefix << "'");
160 }
161 setItem(xpath + "/pool-prefix", pool, SR_STRING_T);
162 string addr = prefix.substr(0, prefix.find_first_of(" /"));
163 uint8_t plen = boost::lexical_cast<unsigned>
164 (prefix.substr(prefix.find_last_of(" /") + 1, string::npos));
165 const IOAddress& base(addr);
166 setItem(xpath + "/start-address",
167 Element::create(firstAddrInPrefix(base, plen).toText()),
168 SR_STRING_T);
169 setItem(xpath + "/end-address",
170 Element::create(lastAddrInPrefix(base, plen).toText()),
171 SR_STRING_T);
172 ConstElementPtr valid_lifetime = elem->get("valid-lifetime");
173 if (valid_lifetime) {
174 setItem(xpath + "/valid-lifetime", valid_lifetime, SR_UINT32_T);
175 }
176 ConstElementPtr preferred_lifetime = elem->get("preferred-lifetime");
177 if (preferred_lifetime) {
178 setItem(xpath + "/preferred-lifetime",
179 preferred_lifetime, SR_UINT32_T);
180 }
181 ConstElementPtr renew_timer = elem->get("renew-timer");
182 if (renew_timer) {
183 setItem(xpath + "/renew-time", renew_timer, SR_UINT32_T);
184 }
185 ConstElementPtr rebind_timer = elem->get("rebind-timer");
186 if (rebind_timer) {
187 setItem(xpath + "/rebind-time", rebind_timer, SR_UINT32_T);
188 }
189 // skip rapid-commit
190 ConstElementPtr guard = elem->get("client-class");
191 if (guard) {
192 setItem(xpath + "/client-class", guard, SR_STRING_T);
193 }
194 // skip max-addr-count
195 // @todo option-data
196 // Set max address count to disabled.
197 setItem(xpath + "/max-address-count",
198 Element::create(string("disabled")),
199 SR_ENUM_T);
200}
201
202void
203TranslatorPool::setPoolKea(const string& xpath, ConstElementPtr elem) {
204 ConstElementPtr pool = elem->get("pool");
205 if (!pool) {
206 isc_throw(BadValue, "setPoolKea requires pool: " << elem->str());
207 }
208 bool created = false;
209 string prefix = pool->stringValue();
210 string start_addr;
211 string end_addr;
212 getAddresses(prefix, start_addr, end_addr);
213 if (prefix.find("/") != string::npos) {
214 setItem(xpath + "/prefix", pool, SR_STRING_T);
215 created = true;
216 }
217 // Skip start-address and end-address as are the keys.
218 ConstElementPtr options = elem->get("option-data");
219 if (options && (options->size() > 0)) {
220 setOptionDataList(xpath, options);
221 created = true;
222 }
223 ConstElementPtr guard = elem->get("client-class");
224 if (guard) {
225 setItem(xpath + "/client-class", guard, SR_STRING_T);
226 created = true;
227 }
228 ConstElementPtr required = elem->get("require-client-classes");
229 if (required && (required->size() > 0)) {
230 for (ConstElementPtr rclass : required->listValue()) {
231 setItem(xpath + "/require-client-classes", rclass, SR_STRING_T);
232 created = true;
233 }
234 }
235 ConstElementPtr context = Adaptor::getContext(elem);
236 if (context) {
237 setItem(xpath + "/user-context", Element::create(context->str()),
238 SR_STRING_T);
239 created = true;
240 }
241 // There is no mandatory fields outside the keys so force creation.
242 if (!created) {
244 setItem(xpath, list, SR_LIST_T);
245 }
246}
247
248void
249TranslatorPool::getAddresses(const string& prefix,
250 string& start_address, string& end_address) {
251 size_t slash = prefix.find("/");
252 if (slash != string::npos) {
253 string addr = prefix.substr(0, prefix.find_first_of(" /"));
254 uint8_t plen = boost::lexical_cast<unsigned>
255 (prefix.substr(prefix.find_last_of(" /") + 1, string::npos));
256 start_address = firstAddrInPrefix(IOAddress(addr), plen).toText();
257 end_address = lastAddrInPrefix(IOAddress(addr), plen).toText();
258 return;
259 }
260 size_t dash = prefix.find("-");
261 if (dash == string::npos) {
263 "getAddresses called with invalid prefix: " << prefix);
264 }
265 start_address = prefix.substr(0, prefix.find_first_of(" -"));
266 end_address = prefix.substr(prefix.find_last_of(" -") + 1, string::npos);
267}
268
269TranslatorPools::TranslatorPools(S_Session session, const string& model)
270 : TranslatorBasic(session, model),
271 TranslatorOptionData(session, model),
272 TranslatorOptionDataList(session, model),
273 TranslatorPool(session, model) {
274}
275
277}
278
280TranslatorPools::getPools(const string& xpath) {
281 try {
282 if (model_ == IETF_DHCPV6_SERVER) {
283 return (getPoolsIetf(xpath));
284 } else if ((model_ == KEA_DHCP4_SERVER) ||
285 (model_ == KEA_DHCP6_SERVER)) {
286 return (getPoolsKea(xpath));
287 }
288 } catch (const sysrepo_exception& ex) {
290 "sysrepo error getting pools at '" << xpath
291 << "': " << ex.what());
292 }
294 "getPools not implemented for the model: " << model_);
295}
296
298TranslatorPools::getPoolsIetf(const string& xpath) {
300 S_Iter_Value iter = getIter(xpath + "/address-pool");
301 if (!iter) {
302 // Can't happen.
303 isc_throw(Unexpected, "getPoolsIetf can't get iterator: " << xpath);
304 }
305 for (;;) {
306 const string& pool = getNext(iter);
307 if (pool.empty()) {
308 break;
309 }
310 result->add(getPool(pool));
311 }
312 return (result);
313}
314
316TranslatorPools::getPoolsKea(const string& xpath) {
318 S_Iter_Value iter = getIter(xpath + "/pool");
319 if (!iter) {
320 // Can't happen.
321 isc_throw(Unexpected, "getPoolsKea can't get iterator: " << xpath);
322 }
323 for (;;) {
324 const string& pool = getNext(iter);
325 if (pool.empty()) {
326 break;
327 }
328 result->add(getPool(pool));
329 }
330 return (result);
331}
332
333void
334TranslatorPools::setPools(const string& xpath, ConstElementPtr elem) {
335 try {
336 if (model_ == IETF_DHCPV6_SERVER) {
337 setPoolsById(xpath, elem);
338 } else if ((model_ == KEA_DHCP4_SERVER) ||
339 (model_ == KEA_DHCP6_SERVER)) {
340 setPoolsByAddresses(xpath, elem);
341 } else {
343 "setPools not implemented for the model: " << model_);
344 }
345 } catch (const sysrepo_exception& ex) {
347 "sysrepo error setting pools '" << elem->str()
348 << "' at '" << xpath << "': " << ex.what());
349 }
350}
351
352void
354 for (size_t i = 0; i < elem->size(); ++i) {
355 ConstElementPtr pool = elem->get(i);
356 ostringstream prefix;
357 prefix << xpath << "/address-pool[pool-id='" << i << "']";
358 setPool(prefix.str(), pool);
359 }
360}
361
362void
364 ConstElementPtr elem) {
365 for (size_t i = 0; i < elem->size(); ++i) {
366 ConstElementPtr pool = elem->get(i);
367 if (!pool->contains("pool")) {
368 isc_throw(BadValue, "setPoolsByAddresses: missing required pool: "
369 << pool->str());
370 }
371 string pref = pool->get("pool")->stringValue();
372 string start_addr;
373 string end_addr;
374 getAddresses(pref, start_addr, end_addr);
375 ostringstream prefix;
376 prefix << xpath << "/pool[start-address='" << start_addr
377 << "'][end-address='" << end_addr << "']";
378 setPool(prefix.str(), pool);
379 }
380}
381
382}; // end of namespace isc::yang
383}; // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when a function is not implemented.
A generic exception that is thrown when an unexpected error condition occurs.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:223
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition: data.cc:750
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:268
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:263
static isc::data::ConstElementPtr getContext(isc::data::ConstElementPtr parent)
Get user context.
Definition: adaptor.cc:25
Between YANG and JSON translator class for basic values.
Definition: translator.h:27
std::string getNext(sysrepo::S_Iter_Value iter)
Get xpath of the next YANG list item.
Definition: translator.cc:283
isc::data::ElementPtr getItem(const std::string &xpath)
Get and translate basic value from YANG to JSON.
Definition: translator.cc:104
sysrepo::S_Iter_Value getIter(const std::string &xpath)
List iterator methods keeping the session private.
Definition: translator.cc:278
std::string model_
The model.
Definition: translator.h:132
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:250
isc::data::ElementPtr getItems(const std::string &xpath)
Get and translate a list of basic values from YANG to JSON.
Definition: translator.cc:119
A translator class for converting an option data list between YANG and JSON.
isc::data::ConstElementPtr getOptionDataList(const std::string &xpath)
Get and translate option data list from YANG to JSON.
void setOptionDataList(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set option data list from JSON to YANG.
Option data translation between YANG and JSON.
A translator class for converting a pool between YANG and JSON.
void setPool(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pool from JSON to YANG.
void setPoolKea(const std::string &xpath, isc::data::ConstElementPtr elem)
setPool for kea-dhcp[46]-server.
isc::data::ElementPtr getPool(const std::string &xpath)
Get and translate a pool from YANG to JSON.
virtual ~TranslatorPool()
Destructor.
TranslatorPool(sysrepo::S_Session session, const std::string &model)
Constructor.
isc::data::ElementPtr getPoolKea(const std::string &xpath)
getPool for kea-dhcp[46]-server.
isc::data::ElementPtr getPoolIetf6(const std::string &xpath)
getPool for ietf-dhcpv6-server.
static void getAddresses(const std::string &prefix, std::string &start_address, std::string &end_address)
Get start and end addresses from prefix.
void setPoolIetf6(const std::string &xpath, isc::data::ConstElementPtr elem)
setPool for ietf-dhcpv6-server.
isc::data::ElementPtr getPools(const std::string &xpath)
Get and translate pools from YANG to JSON.
void setPoolsByAddresses(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using address pair.
virtual ~TranslatorPools()
Destructor.
void setPoolsById(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using pool-id.
TranslatorPools(sysrepo::S_Session session, const std::string &model)
Constructor.
isc::data::ElementPtr getPoolsKea(const std::string &xpath)
getPools for kea-dhcp[46]-server.
void setPools(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pools from JSON to YANG.
isc::data::ElementPtr getPoolsIetf(const std::string &xpath)
getPools for ietf-dhcpv6-server.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
boost::shared_ptr< Element > ElementPtr
Definition: data.h:22
isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress &prefix, uint8_t len)
This code is based on similar code from the Dibbler project.
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress &prefix, uint8_t len)
returns a last address in a given prefix
Defines the logger used by the top-level component of kea-dhcp-ddns.