Kea 3.3.3
binding_variables.cc
Go to the documentation of this file.
1// Copyright (C) 2025-2026 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 <cc/data.h>
10#include <eval/eval_context.h>
13
14#include <iostream>
15
16using namespace isc::dhcp;
17using namespace isc::data;
18
19namespace isc {
20namespace lease_cmds {
21
22BindingVariable::BindingVariable(const std::string& name,
23 const std::string& expression_str,
24 const Source& source,
25 uint32_t family)
26 : name_(name), expression_str_(expression_str), source_(source),
27 family_(family) {
28 if (name_.empty()) {
29 isc_throw(BadValue, "BindingVariable - name cannot be empty");
30 }
31
34 if (expression_str_.empty()) {
35 isc_throw(BadValue, "BindingVariable - '" << name_
36 << "' expression_str cannot be empty");
37 }
38
39 if (family_ != AF_INET && family_ != AF_INET6) {
40 isc_throw(BadValue, "BindingVariable - '" << name_
41 << "', invalid family: " << family_);
42 }
43
44 try {
45 EvalContext eval_ctx(family_ == AF_INET ? Option::V4 : Option::V6);
46 eval_ctx.parseString(expression_str_, EvalContext::PARSER_STRING);
47 expression_.reset(new Expression(eval_ctx.expression_));
48 } catch (const std::exception& ex) {
49 isc_throw(BadValue, "BindingVariable - '" << name_ << "', error parsing expression: '"
50 << expression_str_ << "' : " << ex.what());
51 }
52}
53
56{
57 { "name", Element::string },
58 { "expression", Element::string },
59 { "source", Element::string }
60};
61
64 // Note checkKeywords() will throw DhcpConfigError if there is a problem.
66
67 // Parse members.
68 std::string name = SimpleParser::getString(config, "name");;
69 std::string expression = SimpleParser::getString(config, "expression");;
70 std::string source_str = SimpleParser::getString(config, "source");;
71
72 try {
73 Source source;
74 if (source_str == "query") {
75 source = QUERY;
76 } else if (source_str == "response") {
77 source = RESPONSE;
78 } else {
79 isc_throw(BadValue, "invalid source '" << source_str
80 << "', must be either 'query' or 'response'");
81 }
82
83 // Attempt to create the variable.
84 return (BindingVariablePtr(new BindingVariable(name, expression, source, family)));
85 } catch (const std::exception& ex) {
86 isc_throw(DhcpConfigError, "invalid config: " << ex.what());
87 }
88}
89
90std::string
92 try {
93 return (evaluateString(*expression_, *packet));
94 } catch (const std::exception& ex) {
95 isc_throw(BadValue, "BindingVariable - " << name_ << ", error evaluating expression: ["
96 << expression_str_ << "] : " << ex.what());
97 }
98}
99
103 map->set("name", Element::create(name_));
104 map->set("expression", Element::create(expression_str_));
105 map->set("source", Element::create((source_ == QUERY ? "query" : "response")));
106 return (map);
107}
108
110 : variables_(), mutex_(new std::mutex) {
111}
112
113bool
115 util::MultiThreadingLock lock(*mutex_);
116 auto retpair = variables_.push_back(variable);
117 return(retpair.second);
118}
119
120void
122 util::MultiThreadingLock lock(*mutex_);
123 // Discard contents.
124 // We use modification time to remember the last time we flushed.
125 variables_.clear();
127}
128
129size_t
131 util::MultiThreadingLock lock(*mutex_);
132 return (variables_.size());
133}
134
135boost::posix_time::ptime
140
143 util::MultiThreadingLock lock(*mutex_);
144
146 const auto& index = variables_.get<VariableSequenceTag>();
147 for (auto const& variable : index) {
151 var_list->push_back(variable);
152 }
153
154 return (var_list);
155}
156
158BindingVariableCache::getByName(const std::string& name) {
159 util::MultiThreadingLock lock(*mutex_);
160
161 const auto& index = variables_.get<VariableNameTag>();
162 auto var_iter = index.find(name);
163 return (var_iter == index.end() ? BindingVariablePtr() : *var_iter);
164}
165
168 util::MultiThreadingLock lock(*mutex_);
169
171 const auto& index = variables_.get<VariableSourceTag>();
172 auto lower_limit = index.lower_bound(source);
173 auto upper_limit = index.upper_bound(source);
174 for (auto var_iter = lower_limit; var_iter != upper_limit; ++var_iter) {
175 var_list->push_back(*var_iter);
176 }
177
178 return (var_list);
179}
180
182 : family_(family) {
183 if (family_ != AF_INET && family_ != AF_INET6) {
184 isc_throw (BadValue, "BindingVariableMgr - invalid family: " << family_);
185 }
186
187 cache_.reset(new BindingVariableCache());
188}
189
190void
192 // Always wipe the cache.
193 cache_->clear();
194
195 ConstElementPtr elem = config->get("binding-variables");
196 if (!elem) {
197 // Nothing to do.
198 return;
199 }
200
201 // binding-variables should be a list.
202 if (elem->getType() != Element::list) {
203 isc_throw(DhcpConfigError, "'binding-variables' must be a list");
204 }
205
206 // iterate over the list adding variables to the cache
207 for (auto const& var_elem : elem->listValue()) {
208 try {
209 BindingVariablePtr variable = BindingVariable::parse(var_elem, family_);
210 cache_->add(variable);
211 } catch (const std::exception& ex) {
212 isc_throw(DhcpConfigError, "cannot add BindingVariable to cache: " << ex.what());
213 }
214 }
215}
216
217bool
219 if (!query || !response || !lease) {
220 isc_throw(BadValue, "evaluateVariables - missing query, response, and/or lease");
221 }
222
223 if (!cache_->size()) {
227 return(false);
228 }
229
230 auto const variables = cache_->getAll();
232 for (auto const& variable : *variables) {
233 try {
234 auto value = evaluateString(*(variable->getExpression()),
235 (variable->getSource() == BindingVariable::QUERY ?
236 *query : *response));
237 values->set(variable->getName(), Element::create(value));
238 } catch (const std::exception& ex) {
239 isc_throw(Unexpected, "expression blew up: " << ex.what());
240 }
241 }
242
243 return (lease->updateUserContextISC("binding-variables", values));
244}
245
246} // end of namespace lease_cmds
247} // end of namespace isc
static ElementPtr create(const Position &pos=ZERO_POSITION())
Create a NullElement.
Definition data.cc:300
@ list
Definition data.h:159
@ string
Definition data.h:157
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:355
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
boost::posix_time::ptime getModificationTime() const
Returns timestamp.
void updateModificationTime()
Sets timestamp to the current time.
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
To be removed. Please use ConfigError instead.
Evaluation context, an interface to the expression evaluation.
bool parseString(const std::string &str, ParserType type=PARSER_BOOL)
Run the parser on the string specified.
@ PARSER_STRING
expression is expected to evaluate to string
isc::dhcp::Expression expression_
Parsed expression (output tokens are stored here).
BindingVariableCache stores binding variables.
BindingVariableListPtr getBySource(const BindingVariable::Source &source)
Fetches all of the binding variables in the order they were added to the cache that use a specific so...
size_t size()
Returns number of entries in the cache.
void clear()
Delete all the entries in the cache.
BindingVariablePtr getByName(const std::string &name)
Fetches a binding variable by name.
BindingVariableListPtr getAll()
Fetches all of the binding variables in the order they were added to the cache.
boost::posix_time::ptime getLastFlushTime()
Returns the last time the cache was flushed (or the time it was created if it has never been flushed)...
bool add(BindingVariablePtr variable)
Adds (or replaces) the variable in the cache.
bool evaluateVariables(dhcp::PktPtr query, dhcp::PktPtr response, dhcp::LeasePtr lease)
Evaluates the binding variables for a given lease and packet pair.
BindingVariableMgr(uint32_t family)
Constructor.
void configure(data::ConstElementPtr config)
Configures the manager based on the given configuration.
static const data::SimpleKeywords CONFIG_KEYWORDS
List of valid configurable parameters for a BindingVariable.
std::string evaluate(dhcp::PktPtr packet) const
Evaluate the variable against the given packet.
virtual data::ElementPtr toElement() const
Creates an Element tree for the variable's configurable members.
Source
Specifies the packet that the expression should be evaluated against.
BindingVariable(const std::string &name, const std::string &expression_str, const Source &source, uint32_t family)
Constructor.
static BindingVariablePtr parse(data::ConstElementPtr config, uint16_t family)
Parses configuration elements into a BindingVarable instance.
if(!(yy_init))
Definition d2_lexer.cc:1515
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
std::map< std::string, isc::data::Element::types > SimpleKeywords
This specifies all accepted keywords with their types.
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:1006
std::string evaluateString(const Expression &expr, Pkt &pkt)
Evaluate a RPN expression for a v4 or v6 packet and return a string value.
Definition evaluate.cc:45
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition lease.h:27
std::vector< TokenPtr > Expression
This is a structure that holds an expression converted to RPN.
Definition token.h:31
boost::shared_ptr< BindingVariable > BindingVariablePtr
Defines a shared pointer to a BindingVariable.
std::list< BindingVariablePtr > BindingVariableList
Defines a list of BindingVariablePtr instances.
boost::shared_ptr< BindingVariableList > BindingVariableListPtr
Defines a pointer to a list of BindingVariablePtrs.
Defines the logger used by the top-level component of kea-lfc.
RAII lock object to protect the code in the same scope with a mutex.