mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[#3502] Checkpoint: added branch
This commit is contained in:
@@ -8,6 +8,7 @@ namespace isc {
|
|||||||
namespace dhcp {
|
namespace dhcp {
|
||||||
|
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_AND = "EVAL_DEBUG_AND";
|
extern const isc::log::MessageID EVAL_DEBUG_AND = "EVAL_DEBUG_AND";
|
||||||
|
extern const isc::log::MessageID EVAL_DEBUG_BRANCH = "EVAL_DEBUG_BRANCH";
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_CONCAT = "EVAL_DEBUG_CONCAT";
|
extern const isc::log::MessageID EVAL_DEBUG_CONCAT = "EVAL_DEBUG_CONCAT";
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_EQUAL = "EVAL_DEBUG_EQUAL";
|
extern const isc::log::MessageID EVAL_DEBUG_EQUAL = "EVAL_DEBUG_EQUAL";
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_HEXSTRING = "EVAL_DEBUG_HEXSTRING";
|
extern const isc::log::MessageID EVAL_DEBUG_HEXSTRING = "EVAL_DEBUG_HEXSTRING";
|
||||||
@@ -64,6 +65,7 @@ namespace {
|
|||||||
|
|
||||||
const char* values[] = {
|
const char* values[] = {
|
||||||
"EVAL_DEBUG_AND", "%1: Popping %2 and %3 pushing %4",
|
"EVAL_DEBUG_AND", "%1: Popping %2 and %3 pushing %4",
|
||||||
|
"EVAL_DEBUG_BRANCH", "Branching to %1",
|
||||||
"EVAL_DEBUG_CONCAT", "%1: Popping %2 and %3 pushing %4",
|
"EVAL_DEBUG_CONCAT", "%1: Popping %2 and %3 pushing %4",
|
||||||
"EVAL_DEBUG_EQUAL", "%1: Popping %2 and %3 pushing result %4",
|
"EVAL_DEBUG_EQUAL", "%1: Popping %2 and %3 pushing result %4",
|
||||||
"EVAL_DEBUG_HEXSTRING", "%1: Pushing hex string %2",
|
"EVAL_DEBUG_HEXSTRING", "%1: Pushing hex string %2",
|
||||||
|
@@ -9,6 +9,7 @@ namespace isc {
|
|||||||
namespace dhcp {
|
namespace dhcp {
|
||||||
|
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_AND;
|
extern const isc::log::MessageID EVAL_DEBUG_AND;
|
||||||
|
extern const isc::log::MessageID EVAL_DEBUG_BRANCH;
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_CONCAT;
|
extern const isc::log::MessageID EVAL_DEBUG_CONCAT;
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_EQUAL;
|
extern const isc::log::MessageID EVAL_DEBUG_EQUAL;
|
||||||
extern const isc::log::MessageID EVAL_DEBUG_HEXSTRING;
|
extern const isc::log::MessageID EVAL_DEBUG_HEXSTRING;
|
||||||
|
@@ -14,6 +14,12 @@ This debug message indicates that two values are popped from
|
|||||||
the value stack. Then are then combined via logical and and
|
the value stack. Then are then combined via logical and and
|
||||||
the result is pushed onto the value stack.
|
the result is pushed onto the value stack.
|
||||||
|
|
||||||
|
# For use with TokenBranch
|
||||||
|
% EVAL_DEBUG_BRANCH Branching to %1
|
||||||
|
Logged at debug log level 55.
|
||||||
|
This debug message indicates that an unconditional branch is performed
|
||||||
|
to the displayed target.
|
||||||
|
|
||||||
# For use with TokenConcat
|
# For use with TokenConcat
|
||||||
|
|
||||||
% EVAL_DEBUG_CONCAT %1: Popping %2 and %3 pushing %4
|
% EVAL_DEBUG_CONCAT %1: Popping %2 and %3 pushing %4
|
||||||
|
@@ -11,9 +11,8 @@
|
|||||||
namespace isc {
|
namespace isc {
|
||||||
namespace dhcp {
|
namespace dhcp {
|
||||||
|
|
||||||
bool
|
void
|
||||||
evaluateBool(const Expression& expr, Pkt& pkt) {
|
evaluateRaw(const Expression& expr, Pkt& pkt, ValueStack& values) {
|
||||||
ValueStack values;
|
|
||||||
for (auto it = expr.cbegin(); it != expr.cend(); ) {
|
for (auto it = expr.cbegin(); it != expr.cend(); ) {
|
||||||
unsigned label = (*it++)->evaluate(pkt, values);
|
unsigned label = (*it++)->evaluate(pkt, values);
|
||||||
if (label == 0) {
|
if (label == 0) {
|
||||||
@@ -29,6 +28,12 @@ evaluateBool(const Expression& expr, Pkt& pkt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
evaluateBool(const Expression& expr, Pkt& pkt) {
|
||||||
|
ValueStack values;
|
||||||
|
evaluateRaw(expr, pkt, values);
|
||||||
if (values.size() != 1) {
|
if (values.size() != 1) {
|
||||||
isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly "
|
isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly "
|
||||||
"1 value at the end of evaluation, got " << values.size());
|
"1 value at the end of evaluation, got " << values.size());
|
||||||
@@ -39,21 +44,7 @@ evaluateBool(const Expression& expr, Pkt& pkt) {
|
|||||||
std::string
|
std::string
|
||||||
evaluateString(const Expression& expr, Pkt& pkt) {
|
evaluateString(const Expression& expr, Pkt& pkt) {
|
||||||
ValueStack values;
|
ValueStack values;
|
||||||
for (auto it = expr.cbegin(); it != expr.cend(); ) {
|
evaluateRaw(expr, pkt, values);
|
||||||
unsigned label = (*it++)->evaluate(pkt, values);
|
|
||||||
if (label == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Scan for the given label.
|
|
||||||
for (;;) {
|
|
||||||
if (it == expr.cend()) {
|
|
||||||
isc_throw(EvalBadLabel, "can't reach label " << label);
|
|
||||||
}
|
|
||||||
if ((*it++)->getLabel() == label) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (values.size() != 1) {
|
if (values.size() != 1) {
|
||||||
isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly "
|
isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly "
|
||||||
"1 value at the end of evaluation, got " << values.size());
|
"1 value at the end of evaluation, got " << values.size());
|
||||||
|
@@ -13,6 +13,16 @@
|
|||||||
namespace isc {
|
namespace isc {
|
||||||
namespace dhcp {
|
namespace dhcp {
|
||||||
|
|
||||||
|
/// @brief Evaluate a RPN expression for a v4 or v6 packet
|
||||||
|
///
|
||||||
|
/// For tests and as the common part of the two next routines.
|
||||||
|
///
|
||||||
|
/// @param expr the RPN expression, i.e., a vector of parsed tokens
|
||||||
|
/// @param pkt The v4 or v6 packet
|
||||||
|
/// @param values The stack of values
|
||||||
|
/// @throw EvalBadLabel if there is a foreard branch to a not found target.
|
||||||
|
void evaluateRaw(const Expression& expr, Pkt& pkt, ValueStack& values);
|
||||||
|
|
||||||
/// @brief Evaluate a RPN expression for a v4 or v6 packet and return
|
/// @brief Evaluate a RPN expression for a v4 or v6 packet and return
|
||||||
/// a true or false decision
|
/// a true or false decision
|
||||||
///
|
///
|
||||||
@@ -23,9 +33,21 @@ namespace dhcp {
|
|||||||
/// stack at the end of the evaluation
|
/// stack at the end of the evaluation
|
||||||
/// @throw EvalTypeError if the value at the top of the stack at the
|
/// @throw EvalTypeError if the value at the top of the stack at the
|
||||||
/// end of the evaluation is not "false" or "true"
|
/// end of the evaluation is not "false" or "true"
|
||||||
|
/// @throw EvalBadLabel if there is a foreard branch to a not found target.
|
||||||
bool evaluateBool(const Expression& expr, Pkt& pkt);
|
bool evaluateBool(const Expression& expr, Pkt& pkt);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Evaluate a RPN expression for a v4 or v6 packet and return
|
||||||
|
/// a string value
|
||||||
|
///
|
||||||
|
/// @param expr the RPN expression, i.e., a vector of parsed tokens
|
||||||
|
/// @param pkt The v4 or v6 packet
|
||||||
|
/// @return the string value
|
||||||
|
/// @throw EvalStackError if there is not exactly one element on the value
|
||||||
|
/// stack at the end of the evaluation
|
||||||
|
/// @throw EvalTypeError if the value at the top of the stack at the
|
||||||
|
/// end of the evaluation is not "false" or "true"
|
||||||
|
/// @throw EvalBadLabel if there is a foreard branch to a not found target.
|
||||||
std::string evaluateString(const Expression& expr, Pkt& pkt);
|
std::string evaluateString(const Expression& expr, Pkt& pkt);
|
||||||
|
|
||||||
}; // end of isc::dhcp namespace
|
}; // end of isc::dhcp namespace
|
||||||
|
@@ -512,4 +512,71 @@ TEST_F(ExpressionsTest, evaluateString) {
|
|||||||
testExpressionString(Option::V4, "hexstring(0xf01234,'..')", "f0..12..34");
|
testExpressionString(Option::V4, "hexstring(0xf01234,'..')", "f0..12..34");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests the not found label.
|
||||||
|
TEST_F(ExpressionsTest, notFoundLabel) {
|
||||||
|
TokenPtr branch;
|
||||||
|
ASSERT_NO_THROW(branch.reset(new TokenBranch(123)));
|
||||||
|
e_.push_back(branch);
|
||||||
|
ValueStack values;
|
||||||
|
ASSERT_THROW(evaluateRaw(e_, *pkt4_, values), EvalBadLabel);
|
||||||
|
|
||||||
|
// Add a different label and a string.
|
||||||
|
TokenPtr label;
|
||||||
|
ASSERT_NO_THROW(label.reset(new TokenLabel(111)));
|
||||||
|
e_.push_back(label);
|
||||||
|
TokenPtr foo;
|
||||||
|
ASSERT_NO_THROW(foo.reset(new TokenString("foo")));
|
||||||
|
e_.push_back(foo);
|
||||||
|
ASSERT_THROW(evaluateRaw(e_, *pkt4_, values), EvalBadLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests the backward label.
|
||||||
|
TEST_F(ExpressionsTest, backwardLabel) {
|
||||||
|
// Add the label before the branch.
|
||||||
|
TokenPtr label;
|
||||||
|
ASSERT_NO_THROW(label.reset(new TokenLabel(123)));
|
||||||
|
e_.push_back(label);
|
||||||
|
|
||||||
|
TokenPtr branch;
|
||||||
|
ASSERT_NO_THROW(branch.reset(new TokenBranch(123)));
|
||||||
|
e_.push_back(branch);
|
||||||
|
ValueStack values;
|
||||||
|
ASSERT_THROW(evaluateRaw(e_, *pkt4_, values), EvalBadLabel);
|
||||||
|
|
||||||
|
// Add a different label and a string.
|
||||||
|
TokenPtr label2;
|
||||||
|
ASSERT_NO_THROW(label2.reset(new TokenLabel(111)));
|
||||||
|
e_.push_back(label2);
|
||||||
|
TokenPtr foo;
|
||||||
|
ASSERT_NO_THROW(foo.reset(new TokenString("foo")));
|
||||||
|
e_.push_back(foo);
|
||||||
|
ASSERT_THROW(evaluateRaw(e_, *pkt4_, values), EvalBadLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests the found label.
|
||||||
|
TEST_F(ExpressionsTest, label) {
|
||||||
|
TokenPtr branch;
|
||||||
|
ASSERT_NO_THROW(branch.reset(new TokenBranch(123)));
|
||||||
|
e_.push_back(branch);
|
||||||
|
TokenPtr label;
|
||||||
|
ASSERT_NO_THROW(label.reset(new TokenLabel(123)));
|
||||||
|
e_.push_back(label);
|
||||||
|
TokenPtr foo;
|
||||||
|
ASSERT_NO_THROW(foo.reset(new TokenString("foo")));
|
||||||
|
e_.push_back(foo);
|
||||||
|
string result;
|
||||||
|
ASSERT_NO_THROW(result = evaluateString(e_, *pkt6_));
|
||||||
|
EXPECT_EQ("foo", result);
|
||||||
|
|
||||||
|
// The branch is to the first occurence (of course the parser
|
||||||
|
// produces only one).
|
||||||
|
e_.push_back(label);
|
||||||
|
TokenPtr bar;
|
||||||
|
ASSERT_NO_THROW(bar.reset(new TokenString("bar")));
|
||||||
|
e_.push_back(bar);
|
||||||
|
ValueStack values;
|
||||||
|
ASSERT_NO_THROW(evaluateRaw(e_, *pkt4_, values));
|
||||||
|
EXPECT_EQ(2, values.size());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -3902,4 +3902,18 @@ TEST_F(TokenTest, label) {
|
|||||||
ASSERT_TRUE(values_.empty());
|
ASSERT_TRUE(values_.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify TokenBranch.
|
||||||
|
TEST_F(TokenTest, branch) {
|
||||||
|
// 0 is not a valid branch.
|
||||||
|
ASSERT_THROW(t_.reset(new TokenBranch(0)), EvalParseError);
|
||||||
|
|
||||||
|
// Evaluation does and uses nothing.
|
||||||
|
ASSERT_NO_THROW(t_.reset(new TokenBranch(123)));
|
||||||
|
EXPECT_EQ(0, t_->getLabel());
|
||||||
|
unsigned next(0);
|
||||||
|
ASSERT_NO_THROW(next = t_->evaluate(*pkt4_, values_));
|
||||||
|
EXPECT_EQ(123, next);
|
||||||
|
ASSERT_TRUE(values_.empty());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1516,3 +1516,16 @@ unsigned
|
|||||||
TokenLabel::evaluate(Pkt&, ValueStack&) {
|
TokenLabel::evaluate(Pkt&, ValueStack&) {
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TokenBranch::TokenBranch(const unsigned target) : target_(target) {
|
||||||
|
if (target == 0) {
|
||||||
|
isc_throw(EvalParseError, "target must be not zero");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
TokenBranch::evaluate(Pkt&, ValueStack&) {
|
||||||
|
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_BRANCH)
|
||||||
|
.arg(target_);
|
||||||
|
return (target_);
|
||||||
|
}
|
||||||
|
@@ -1408,7 +1408,34 @@ protected:
|
|||||||
unsigned label_;
|
unsigned label_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Token unconditional branch.
|
||||||
|
///
|
||||||
|
/// Unconditionally branch to a forward target.
|
||||||
|
class TokenBranch : public Token {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor
|
||||||
|
///
|
||||||
|
/// @param target the label to branch to
|
||||||
|
/// @throw EvalParseError when target is 0
|
||||||
|
TokenBranch(const unsigned target);
|
||||||
|
|
||||||
|
/// @brief Returns branchtarget
|
||||||
|
///
|
||||||
|
/// @return the label of the branch target
|
||||||
|
unsigned getTarget() const {
|
||||||
|
return (target_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Only return the target
|
||||||
|
///
|
||||||
|
/// @param pkt (unused)
|
||||||
|
/// @param values - stack of values (unused)
|
||||||
|
virtual unsigned evaluate(Pkt& pkt, ValueStack& values);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned target_;
|
||||||
|
};
|
||||||
|
|
||||||
} // end of isc::dhcp namespace
|
} // end of isc::dhcp namespace
|
||||||
} // end of isc namespace
|
} // end of isc namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user