Kea 2.7.6
translator_pool.cc
Go to the documentation of this file.
1// Copyright (C) 2018-2024 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
10#include <asiolink/io_address.h>
12#include <yang/yang_models.h>
13
14#include <boost/lexical_cast.hpp>
15
16#include <sstream>
17
18using namespace std;
19using namespace isc::data;
20using namespace isc::asiolink;
21using namespace libyang;
22using namespace sysrepo;
23
24namespace isc {
25namespace yang {
26
27TranslatorPool::TranslatorPool(Session session, const string& model)
28 : Translator(session, model),
29 TranslatorOptionData(session, model),
30 TranslatorOptionDataList(session, model) {
31}
32
34TranslatorPool::getPool(DataNode const& data_node) {
35 try {
36 if (model_ == IETF_DHCPV6_SERVER) {
37 return (getPoolIetf6(data_node));
38 } else if ((model_ == KEA_DHCP4_SERVER) ||
39 (model_ == KEA_DHCP6_SERVER)) {
40 return (getPoolKea(data_node));
41 }
42 } catch (Error const& ex) {
44 "getting pool:"
45 << ex.what());
46 }
48 "getPool not implemented for the model: " << model_);
49}
50
53 try {
54 return getPool(findXPath(xpath));
55 } catch (NetconfError const&) {
56 return ElementPtr();
57 }
58}
59
61TranslatorPool::getPoolIetf6(DataNode const& data_node) {
63
64 getMandatoryDivergingLeaf(result, data_node, "pool", "pool-prefix");
65
66 checkAndGetLeaf(result, data_node, "client-class");
67 checkAndGetLeaf(result, data_node, "preferred-lifetime");
68 checkAndGetLeaf(result, data_node, "valid-lifetime");
69
70 checkAndGetDivergingLeaf(result, data_node, "rebind-timer", "rebind-time");
71 checkAndGetDivergingLeaf(result, data_node, "renew-timer", "renew-time");
72
73 // Skip max-addr-count.
74 // Skip pool-id which exists but is not used.
75 // Skip rapid-commit.
76 // Skip start-address - end-address as prefix form is mandatory?
77 // @todo: option-data
78 // No require-client-classes.
79 // No user-context.
80
81 return (result->empty() ? ElementPtr() : result);
82}
83
85TranslatorPool::getPoolKea(DataNode const& data_node) {
87 ConstElementPtr prefix = getItem(data_node, "prefix");
88 if (prefix) {
89 result->set("pool", prefix);
90 } else {
91 ConstElementPtr start_addr = getItem(data_node, "start-address");
92 ConstElementPtr end_addr = getItem(data_node, "end-address");
93 if (!start_addr || !end_addr) {
94 isc_throw(MissingNode, "getPoolKea requires either prefix or "
95 "both start and end addresses");
96 }
97 ostringstream range;
98 range << start_addr->stringValue() << " - "
99 << end_addr->stringValue();
100 result->set("pool", Element::create(range.str()));
101 }
102 ConstElementPtr options = getOptionDataList(data_node);
103 if (options) {
104 result->set("option-data", options);
105 }
106
107 checkAndGetLeaf(result, data_node, "client-class");
108 checkAndGetLeaf(result, data_node, "require-client-classes");
109
110 checkAndGetLeaf(result, data_node, "pool-id");
111
112 checkAndGetAndJsonifyLeaf(result, data_node, "user-context");
113
114 return (result->empty() ? ElementPtr() : result);
115}
116
117void
118TranslatorPool::setPool(string const& xpath, ConstElementPtr elem) {
119 try {
120 if (model_ == IETF_DHCPV6_SERVER) {
121 setPoolIetf6(xpath, elem);
122 } else if ((model_ == KEA_DHCP4_SERVER) ||
123 (model_ == KEA_DHCP6_SERVER)) {
124 setPoolKea(xpath, elem);
125 } else {
127 "setPool not implemented for the model: " << model_);
128 }
129 } catch (Error const& ex) {
131 "setting pool '" << elem->str()
132 << "' : " << ex.what());
133 }
134}
135
136void
138 ConstElementPtr pool = elem->get("pool");
139 if (!pool) {
140 isc_throw(BadValue, "setPoolIetf6 requires pool: " << elem->str());
141 }
142 string prefix = pool->stringValue();
143 if (prefix.find("/") == string::npos) {
145 "setPoolIetf only supports pools in prefix (vs range) "
146 "format and was called with '" << prefix << "'");
147 }
148 setItem(xpath + "/pool-prefix", pool, LeafBaseType::String);
149 string addr = prefix.substr(0, prefix.find_first_of(" /"));
150 uint8_t plen = boost::lexical_cast<unsigned>
151 (prefix.substr(prefix.find_last_of(" /") + 1, string::npos));
152 const IOAddress& base(addr);
153 setItem(xpath + "/start-address",
154 Element::create(firstAddrInPrefix(base, plen).toText()),
155 LeafBaseType::String);
156 setItem(xpath + "/end-address",
157 Element::create(lastAddrInPrefix(base, plen).toText()),
158 LeafBaseType::String);
159
160 checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
161 checkAndSetLeaf(elem, xpath, "preferred-lifetime", LeafBaseType::Uint32);
162 checkAndSetLeaf(elem, xpath, "valid-lifetime", LeafBaseType::Uint32);
163
164 checkAndSetDivergingLeaf(elem, xpath, "rebind-timer", "rebind-time", LeafBaseType::Uint32);
165 checkAndSetDivergingLeaf(elem, xpath, "renew-timer", "renew-time", LeafBaseType::Uint32);
166
167 // Set max address count to disabled.
168 setItem(xpath + "/max-address-count",
169 Element::create("disabled"),
170 LeafBaseType::Enum);
171
172 // Skip max-addr-count.
173 // Skip rapid-commit.
174 // @todo: option-data
175}
176
177void
178TranslatorPool::setPoolKea(string const& xpath, ConstElementPtr elem) {
179 // Set the list element. This is important in case we have no other elements except the keys.
180 setItem(xpath, ElementPtr(), LeafBaseType::Unknown);
181
182 // Skip keys "start-address" and "end-address" since they were set with the
183 // list element in the call above with the LeafBaseType::Unknown parameter.
184
185 ConstElementPtr pool = elem->get("pool");
186 if (!pool) {
187 isc_throw(BadValue, "setPoolKea requires pool: " << elem->str());
188 }
189
190 // Keys are set by setting the list itself.
191 setItem(xpath, ElementPtr(), LeafBaseType::Unknown);
192
193 checkAndSetLeaf(elem, xpath, "client-class", LeafBaseType::String);
194
195 checkAndSetLeafList(elem, xpath, "require-client-classes", LeafBaseType::String);
196
197 checkAndSetLeaf(elem, xpath, "pool-id", LeafBaseType::Dec64);
198
199 checkAndSetUserContext(elem, xpath);
200
201 string prefix = pool->stringValue();
202 string start_addr;
203 string end_addr;
204 getAddresses(prefix, start_addr, end_addr);
205 if (prefix.find("/") != string::npos) {
206 setItem(xpath + "/prefix", pool, LeafBaseType::String);
207 }
208 ConstElementPtr options = elem->get("option-data");
209 if (options && !options->empty()) {
210 setOptionDataList(xpath, options);
211 }
212}
213
214void
215TranslatorPool::getAddresses(const string& prefix,
216 string& start_address, string& end_address) {
217 size_t slash = prefix.find("/");
218 if (slash != string::npos) {
219 string addr = prefix.substr(0, prefix.find_first_of(" /"));
220 uint8_t plen = boost::lexical_cast<unsigned>
221 (prefix.substr(prefix.find_last_of(" /") + 1, string::npos));
222 start_address = firstAddrInPrefix(IOAddress(addr), plen).toText();
223 end_address = lastAddrInPrefix(IOAddress(addr), plen).toText();
224 return;
225 }
226 size_t dash = prefix.find("-");
227 if (dash == string::npos) {
229 "getAddresses called with invalid prefix: " << prefix);
230 }
231 start_address = prefix.substr(0, prefix.find_first_of(" -"));
232 end_address = prefix.substr(prefix.find_last_of(" -") + 1, string::npos);
233}
234
235TranslatorPools::TranslatorPools(Session session, const string& model)
236 : Translator(session, model),
237 TranslatorOptionData(session, model),
238 TranslatorOptionDataList(session, model),
239 TranslatorPool(session, model) {
240}
241
243TranslatorPools::getPools(DataNode const& data_node) {
244 try {
245 if (model_ == IETF_DHCPV6_SERVER) {
246 return (getPoolsIetf(data_node));
247 } else if ((model_ == KEA_DHCP4_SERVER) ||
248 (model_ == KEA_DHCP6_SERVER)) {
249 return (getPoolsKea(data_node));
250 }
251 } catch (Error const& ex) {
253 "getting pools:"
254 << ex.what());
255 }
257 "getPools not implemented for the model: " << model_);
258}
259
262 try {
263 return getPools(findXPath(xpath));
264 } catch (NetconfError const&) {
265 return ElementPtr();
266 }
267}
268
270TranslatorPools::getPoolsIetf(DataNode const& data_node) {
271 return getList<TranslatorPool>(data_node, "address-pool", *this,
273}
274
276TranslatorPools::getPoolsKea(DataNode const& data_node) {
277 return getList<TranslatorPool>(data_node, "pool", *this,
279}
280
281void
282TranslatorPools::setPools(string const& xpath, ConstElementPtr elem) {
283 try {
284 if (model_ == IETF_DHCPV6_SERVER) {
285 setPoolsById(xpath, elem);
286 } else if ((model_ == KEA_DHCP4_SERVER) ||
287 (model_ == KEA_DHCP6_SERVER)) {
288 setPoolsByAddresses(xpath, elem);
289 } else {
291 "setPools not implemented for the model: " << model_);
292 }
293 } catch (Error const& ex) {
295 "setting pools '" << elem->str()
296 << "' : " << ex.what());
297 }
298}
299
300void
302 for (size_t i = 0; i < elem->size(); ++i) {
303 ElementPtr pool = elem->getNonConst(i);
304 ostringstream prefix;
305 prefix << xpath << "/address-pool[pool-id='" << i << "']";
306 setPool(prefix.str(), pool);
307 }
308}
309
310void
312 ConstElementPtr elem) {
313 for (size_t i = 0; i < elem->size(); ++i) {
314 ElementPtr pool = elem->getNonConst(i);
315 if (!pool->contains("pool")) {
316 isc_throw(BadValue, "setPoolsByAddresses: missing required pool: "
317 << pool->str());
318 }
319 string pref = pool->get("pool")->stringValue();
320 string start_addr;
321 string end_addr;
322 getAddresses(pref, start_addr, end_addr);
323 ostringstream prefix;
324 prefix << xpath << "/pool[start-address='" << start_addr
325 << "'][end-address='" << end_addr << "']";
326 setPool(prefix.str(), pool);
327 }
328}
329
330} // namespace yang
331} // 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 ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
A translator class for converting an option data list between YANG and JSON.
void setOptionDataList(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set option data list from JSON to YANG.
isc::data::ConstElementPtr getOptionDataList(libyang::DataNode const &data_node)
Translate option data list from YANG to JSON.
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 getPoolIetf6(libyang::DataNode const &data_node)
getPool for ietf-dhcpv6-server.
isc::data::ElementPtr getPool(libyang::DataNode const &data_node)
Translate a pool from YANG to JSON.
isc::data::ElementPtr getPoolKea(libyang::DataNode const &data_node)
getPool for kea-dhcp[46]-server.
TranslatorPool(sysrepo::Session session, const std::string &model)
Constructor.
isc::data::ElementPtr getPoolFromAbsoluteXpath(std::string const &xpath)
Translate a pool from YANG to JSON.
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.
void setPoolsByAddresses(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using address pair.
void setPoolsById(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using pool-id.
isc::data::ElementPtr getPoolsKea(libyang::DataNode const &data_node)
getPools for kea-dhcp[46]-server.
isc::data::ElementPtr getPoolsFromAbsoluteXpath(std::string const &xpath)
Translate pools from YANG to JSON.
TranslatorPools(sysrepo::Session session, const std::string &model)
Constructor.
void setPools(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pools from JSON to YANG.
isc::data::ElementPtr getPoolsIetf(libyang::DataNode const &data_node)
getPools for ietf-dhcpv6-server.
isc::data::ElementPtr getPools(libyang::DataNode const &data_node)
Translate pools from YANG to JSON.
Between YANG and JSON translator class for basic values.
Definition translator.h:23
void getMandatoryDivergingLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name, std::string const &yang_name) const
Retrieves a child YANG data node identified by one name from the given parent YANG container node and...
isc::data::ElementPtr getList(libyang::DataNode const &data_node, std::string const &xpath, T &t, isc::data::ElementPtr(T::*f)(libyang::DataNode const &)) const
Retrieve a list as ElementPtr from sysrepo from a certain xpath.
Definition translator.h:274
void checkAndSetLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
Definition translator.cc:63
isc::data::ElementPtr getItem(libyang::DataNode const &data_node, std::string const &xpath) const
Translate a basic value from YANG to JSON for a given xpath that is relative to the given source node...
libyang::DataNode findXPath(std::string const &xpath) const
Retrieves a YANG data node by xpath.
void checkAndGetLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node and sto...
Definition translator.cc:32
void checkAndSetUserContext(isc::data::ConstElementPtr const &from, std::string const &xpath)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
Definition translator.cc:99
void checkAndGetDivergingLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name, std::string const &yang_name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node and sto...
Definition translator.cc:42
void setItem(const std::string &xpath, isc::data::ConstElementPtr const elem, libyang::LeafBaseType const type)
Translate and set basic value from JSON to YANG.
std::string model_
The model.
Definition translator.h:427
void checkAndSetDivergingLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, std::string const &yang_name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
Definition translator.cc:74
void checkAndGetAndJsonifyLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, const std::string &name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node,...
Definition translator.cc:53
void checkAndSetLeafList(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath as a leaf-list.
Definition translator.cc:86
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
Defines the logger used by the top-level component of kea-lfc.
Missing node error.
Generic NETCONF error.