Kea: translator_pool.cc Source File

| 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
9#include <asiolink/io_address.h>
10#include <asiolink/addr_utilities.h>
11#include <yang/adaptor.h>
12#include <yang/translator_pool.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
31TranslatorPool::~TranslatorPool() {
32}
33
34 ElementPtr
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) {
44 isc_throw(SysrepoError,
45 "sysrepo error getting pool at '" << xpath
46 << "': " << ex.what());
47 }
48 isc_throw(NotImplemented,
49 "getPool not implemented for the model: " << model_);
50}
51
52 ElementPtr
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
93 ElementPtr
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 {
139 isc_throw(NotImplemented,
140 "setPool not implemented for the model: " << model_);
141 }
142 } catch (const sysrepo_exception& ex) {
143 isc_throw(SysrepoError,
144 "sysrepo error setting pool '" << elem->str()
145 << "' at '" << xpath << "': " << ex.what());
146 }
147}
148
149void
150TranslatorPool::setPoolIetf6(const string& xpath, ConstElementPtr elem) {
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) {
157 isc_throw(BadValue,
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) {
262 isc_throw(BadValue,
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
276TranslatorPools::~TranslatorPools() {
277}
278
279 ElementPtr
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) {
289 isc_throw(SysrepoError,
290 "sysrepo error getting pools at '" << xpath
291 << "': " << ex.what());
292 }
293 isc_throw(NotImplemented,
294 "getPools not implemented for the model: " << model_);
295}
296
297 ElementPtr
298TranslatorPools::getPoolsIetf(const string& xpath) {
299 return getList<TranslatorPool>(xpath + "/address-pool", *this,
300 &TranslatorPool::getPool);
301}
302
303 ElementPtr
304TranslatorPools::getPoolsKea(const string& xpath) {
305 return getList<TranslatorPool>(xpath + "/pool", *this,
306 &TranslatorPool::getPool);
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 {
318 isc_throw(NotImplemented,
319 "setPools not implemented for the model: " << model_);
320 }
321 } catch (const sysrepo_exception& ex) {
322 isc_throw(SysrepoError,
323 "sysrepo error setting pools '" << elem->str()
324 << "' at '" << xpath << "': " << ex.what());
325 }
326}
327
328void
329TranslatorPools::setPoolsById(const string& xpath, ConstElementPtr elem) {
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
339TranslatorPools::setPoolsByAddresses(const string& xpath,
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
adaptor.h
addr_utilities.h
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::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc::NotImplemented
A generic exception that is thrown when a function is not implemented.
Definition: exceptions/exceptions.h:166
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic)
Definition: io_address.h:45
isc::asiolink::IOAddress::toText
std::string toText() const
Convert the address to a string.
Definition: io_address.cc:52
isc::yang::Adaptor::getContext
static isc::data::ConstElementPtr getContext(isc::data::ConstElementPtr parent)
Get user context.
Definition: adaptor.cc:27
isc::yang::SysrepoError
Sysrepo error.
Definition: sysrepo_error.h:16
isc::yang::TranslatorBasic
Between YANG and JSON translator class for basic values.
Definition: translator.h:19
isc::yang::TranslatorBasic::getItem
isc::data::ElementPtr getItem(const std::string &xpath)
Get and translate basic value from YANG to JSON.
Definition: translator.cc:105
isc::yang::TranslatorBasic::model_
std::string model_
The model.
Definition: translator.h:171
isc::yang::TranslatorBasic::setItem
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::yang::TranslatorBasic::getItems
isc::data::ElementPtr getItems(const std::string &xpath)
Get and translate a list of basic values from YANG to JSON.
Definition: translator.cc:124
isc::yang::TranslatorOptionDataList
A translator class for converting an option data list between YANG and JSON.
Definition: translator_option_data.h:123
isc::yang::TranslatorOptionDataList::getOptionDataList
isc::data::ConstElementPtr getOptionDataList(const std::string &xpath)
Get and translate option data list from YANG to JSON.
Definition: translator_option_data.cc:136
isc::yang::TranslatorOptionDataList::setOptionDataList
void setOptionDataList(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set option data list from JSON to YANG.
Definition: translator_option_data.cc:158
isc::yang::TranslatorOptionData
Option data translation between YANG and JSON.
Definition: translator_option_data.h:76
isc::yang::TranslatorPool
A translator class for converting a pool between YANG and JSON.
Definition: translator_pool.h:125
isc::yang::TranslatorPool::setPool
void setPool(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pool from JSON to YANG.
Definition: translator_pool.cc:131
isc::yang::TranslatorPool::setPoolKea
void setPoolKea(const std::string &xpath, isc::data::ConstElementPtr elem)
setPool for kea-dhcp[46]-server.
Definition: translator_pool.cc:203
isc::yang::TranslatorPool::getPool
isc::data::ElementPtr getPool(const std::string &xpath)
Get and translate a pool from YANG to JSON.
Definition: translator_pool.cc:35
isc::yang::TranslatorPool::~TranslatorPool
virtual ~TranslatorPool()
Destructor.
Definition: translator_pool.cc:31
isc::yang::TranslatorPool::TranslatorPool
TranslatorPool(sysrepo::S_Session session, const std::string &model)
Constructor.
Definition: translator_pool.cc:25
isc::yang::TranslatorPool::getPoolKea
isc::data::ElementPtr getPoolKea(const std::string &xpath)
getPool for kea-dhcp[46]-server.
Definition: translator_pool.cc:94
isc::yang::TranslatorPool::getPoolIetf6
isc::data::ElementPtr getPoolIetf6(const std::string &xpath)
getPool for ietf-dhcpv6-server.
Definition: translator_pool.cc:53
isc::yang::TranslatorPool::getAddresses
static void getAddresses(const std::string &prefix, std::string &start_address, std::string &end_address)
Get start and end addresses from prefix.
Definition: translator_pool.cc:249
isc::yang::TranslatorPool::setPoolIetf6
void setPoolIetf6(const std::string &xpath, isc::data::ConstElementPtr elem)
setPool for ietf-dhcpv6-server.
Definition: translator_pool.cc:150
isc::yang::TranslatorPools::getPools
isc::data::ElementPtr getPools(const std::string &xpath)
Get and translate pools from YANG to JSON.
Definition: translator_pool.cc:280
isc::yang::TranslatorPools::setPoolsByAddresses
void setPoolsByAddresses(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using address pair.
Definition: translator_pool.cc:339
isc::yang::TranslatorPools::~TranslatorPools
virtual ~TranslatorPools()
Destructor.
Definition: translator_pool.cc:276
isc::yang::TranslatorPools::setPoolsById
void setPoolsById(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using pool-id.
Definition: translator_pool.cc:329
isc::yang::TranslatorPools::TranslatorPools
TranslatorPools(sysrepo::S_Session session, const std::string &model)
Constructor.
Definition: translator_pool.cc:269
isc::yang::TranslatorPools::getPoolsKea
isc::data::ElementPtr getPoolsKea(const std::string &xpath)
getPools for kea-dhcp[46]-server.
Definition: translator_pool.cc:304
isc::yang::TranslatorPools::setPools
void setPools(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pools from JSON to YANG.
Definition: translator_pool.cc:310
isc::yang::TranslatorPools::getPoolsIetf
isc::data::ElementPtr getPoolsIetf(const std::string &xpath)
getPools for ietf-dhcpv6-server.
Definition: translator_pool.cc:298
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:210
io_address.h
isc::asiolink
Definition: addr_utilities.cc:170
isc::asiolink::firstAddrInPrefix
IOAddress firstAddrInPrefix(const IOAddress &prefix, uint8_t len)
This code is based on similar code from the Dibbler project.
Definition: addr_utilities.cc:172
isc::asiolink::lastAddrInPrefix
IOAddress lastAddrInPrefix(const IOAddress &prefix, uint8_t len)
returns a last address in a given prefix
Definition: addr_utilities.cc:182
isc::data
Definition: base_stamped_element.cc:12
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
translator_pool.h
yang_models.h