mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 05:27:55 +00:00
[#3502] Checkpoint: added branch
This commit is contained in:
parent
10555aac77
commit
be3136c164
@ -8,6 +8,7 @@ namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
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_EQUAL = "EVAL_DEBUG_EQUAL";
|
||||
extern const isc::log::MessageID EVAL_DEBUG_HEXSTRING = "EVAL_DEBUG_HEXSTRING";
|
||||
@ -64,6 +65,7 @@ namespace {
|
||||
|
||||
const char* values[] = {
|
||||
"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_EQUAL", "%1: Popping %2 and %3 pushing result %4",
|
||||
"EVAL_DEBUG_HEXSTRING", "%1: Pushing hex string %2",
|
||||
|
@ -9,6 +9,7 @@ namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
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_EQUAL;
|
||||
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 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
|
||||
|
||||
% EVAL_DEBUG_CONCAT %1: Popping %2 and %3 pushing %4
|
||||
|
@ -11,9 +11,8 @@
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
bool
|
||||
evaluateBool(const Expression& expr, Pkt& pkt) {
|
||||
ValueStack values;
|
||||
void
|
||||
evaluateRaw(const Expression& expr, Pkt& pkt, ValueStack& values) {
|
||||
for (auto it = expr.cbegin(); it != expr.cend(); ) {
|
||||
unsigned label = (*it++)->evaluate(pkt, values);
|
||||
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) {
|
||||
isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly "
|
||||
"1 value at the end of evaluation, got " << values.size());
|
||||
@ -39,21 +44,7 @@ evaluateBool(const Expression& expr, Pkt& pkt) {
|
||||
std::string
|
||||
evaluateString(const Expression& expr, Pkt& pkt) {
|
||||
ValueStack values;
|
||||
for (auto it = expr.cbegin(); it != expr.cend(); ) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
evaluateRaw(expr, pkt, values);
|
||||
if (values.size() != 1) {
|
||||
isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly "
|
||||
"1 value at the end of evaluation, got " << values.size());
|
||||
|
@ -13,6 +13,16 @@
|
||||
namespace isc {
|
||||
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
|
||||
/// a true or false decision
|
||||
///
|
||||
@ -23,9 +33,21 @@ namespace dhcp {
|
||||
/// 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.
|
||||
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);
|
||||
|
||||
}; // end of isc::dhcp namespace
|
||||
|
@ -512,4 +512,71 @@ TEST_F(ExpressionsTest, evaluateString) {
|
||||
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());
|
||||
}
|
||||
|
||||
// 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&) {
|
||||
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_;
|
||||
};
|
||||
|
||||
/// @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 namespace
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user