Kea 2.2.0
translator_pool.cc
Go to the documentation of this file.
1// Copyright (C) 2018-2021 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 sysrepo;
21
22namespace isc {
23namespace yang {
24
25TranslatorPool::TranslatorPool(S_Session session, const string& model)
26 : TranslatorBasic(session, model),
27 TranslatorOptionData(session, model),
28 TranslatorOptionDataList(session, model) {
29}
30
32}
33
35TranslatorPool::getPool(const string& xpath) {
36 try {
37 if (model_ == IETF_DHCPV6_SERVER) {
38 return (getPoolIetf6(xpath));
39 } else if ((model_ == KEA_DHCP4_SERVER) ||
40 (model_ == KEA_DHCP6_SERVER)) {
41 return (getPoolKea(xpath));
42 }
43 } catch (const sysrepo_exception& ex) {
45 "sysrepo error getting pool at '" << xpath
46 << "': " << ex.what());
47 }
49 "getPool not implemented for the model: " << model_);
50}
51
53TranslatorPool::getPoolIetf6(const string& xpath) {
54 ElementPtr result = Element::createMap();
55 // Skip pool-id which exists but is not used.
56 ConstElementPtr pool = getItem(xpath + "/pool-prefix");
57 if (!pool) {
58 isc_throw(BadValue, "getPoolIetf6 requires pool prefix at " << xpath);
59 }
60 result->set("pool", pool);
61 // Ignore start-address - end-address as prefix form is mandatory?
62 ConstElementPtr guard = getItem(xpath + "/client-class");
63 if (guard) {
64 result->set("client-class", guard);
65 }
66 ConstElementPtr valid_lifetime = getItem(xpath + "/valid-lifetime");
67 if (valid_lifetime) {
68 result->set("valid-lifetime", valid_lifetime);
69 }
70 ConstElementPtr preferred_lifetime =
71 getItem(xpath + "/preferred-lifetime");
72 if (preferred_lifetime) {
73 result->set("preferred-lifetime", preferred_lifetime);
74 }
75 ConstElementPtr renew_time = getItem(xpath + "/renew-time");
76 if (renew_time) {
77 result->set("renew-timer", renew_time);
78 }
79 ConstElementPtr rebind_time = getItem(xpath + "/rebind-time");
80 if (rebind_time) {
81 result->set("rebind-timer", rebind_time);
82 }
83 // Skip max-addr-count
84 // @todo: option-data
86 // Skip rapid-commit.
87 if (result->empty()) {
88 return ElementPtr();
89 }
90 return (result);
91}
92
94TranslatorPool::getPoolKea(const string& xpath) {
95 ElementPtr result = Element::createMap();
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) {
243 ConstElementPtr list = Element::createList();
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) {
299 return getList<TranslatorPool>(xpath + "/address-pool", *this,
301}
302
304TranslatorPools::getPoolsKea(const string& xpath) {
305 return getList<TranslatorPool>(xpath + "/pool", *this,
307}
308
309void
310TranslatorPools::setPools(const string& xpath, ConstElementPtr elem) {
311 try {
312 if (model_ == IETF_DHCPV6_SERVER) {
313 setPoolsById(xpath, elem);
314 } else if ((model_ == KEA_DHCP4_SERVER) ||
315 (model_ == KEA_DHCP6_SERVER)) {
316 setPoolsByAddresses(xpath, elem);
317 } else {
319 "setPools not implemented for the model: " << model_);
320 }
321 } catch (const sysrepo_exception& ex) {
323 "sysrepo error setting pools '" << elem->str()
324 << "' at '" << xpath << "': " << ex.what());
325 }
326}
327
328void
330 for (size_t i = 0; i < elem->size(); ++i) {
331 ConstElementPtr pool = elem->get(i);
332 ostringstream prefix;
333 prefix << xpath << "/address-pool[pool-id='" << i << "']";
334 setPool(prefix.str(), pool);
335 }
336}
337
338void
340 ConstElementPtr elem) {
341 for (size_t i = 0; i < elem->size(); ++i) {
342 ConstElementPtr pool = elem->get(i);
343 if (!pool->contains("pool")) {
344 isc_throw(BadValue, "setPoolsByAddresses: missing required pool: "
345 << pool->str());
346 }
347 string pref = pool->get("pool")->stringValue();
348 string start_addr;
349 string end_addr;
350 getAddresses(pref, start_addr, end_addr);
351 ostringstream prefix;
352 prefix << xpath << "/pool[start-address='" << start_addr
353 << "'][end-address='" << end_addr << "']";
354 setPool(prefix.str(), pool);
355 }
356}
357
358} // namespace yang
359} // 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.
static isc::data::ConstElementPtr getContext(isc::data::ConstElementPtr parent)
Get user context.
Definition: adaptor.cc:27
Between YANG and JSON translator class for basic values.
Definition: translator.h:19
isc::data::ElementPtr getItem(const std::string &xpath)
Get and translate basic value from YANG to JSON.
Definition: translator.cc:105
std::string model_
The model.
Definition: translator.h:171
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:260
isc::data::ElementPtr getItems(const std::string &xpath)
Get and translate a list of basic values from YANG to JSON.
Definition: translator.cc:124
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:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
Defines the logger used by the top-level component of kea-lfc.