]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3502] Checkpoint: added branch
authorFrancis Dupont <fdupont@isc.org>
Wed, 7 Aug 2024 13:38:27 +0000 (15:38 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 21 Aug 2024 13:12:38 +0000 (15:12 +0200)
src/lib/eval/eval_messages.cc
src/lib/eval/eval_messages.h
src/lib/eval/eval_messages.mes
src/lib/eval/evaluate.cc
src/lib/eval/evaluate.h
src/lib/eval/tests/evaluate_unittest.cc
src/lib/eval/tests/token_unittest.cc
src/lib/eval/token.cc
src/lib/eval/token.h

index 5b9312b4b4bdc8ce1dd41e4d3c1d8fdfffaf1228..7e7ad0e721cd2ca83e76c253c9f610bdf9b6cb56 100644 (file)
@@ -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",
index def72149f812936c068f7d12a2208e78a4cffc95..f9b2ec5acfd16d5b66e05a89100eac1fd0ab02f8 100644 (file)
@@ -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;
index a9cb7f898eaeff7d86d6cf5307fce7452342492b..ad81a3d229335f8ba7f7f7d9975689631d7abae3 100644 (file)
@@ -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
index 6b77280d5f8f80a59e7fa99ff93fc861c90402ee..4b1cfdd6002bb47fabb814fb12ff769c180a0a22 100644 (file)
@@ -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());
index b2f6eb23e1ffb4723d5a4e19266eb63d2dffc5f0..ea2a0ed72e603f600df4425f9559386069bbce61 100644 (file)
 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
index 37c4f83d31c06552c0042844087f3ee7405b1583..ecf4db79e18c8a29ad075879640c5009299d22ad 100644 (file)
@@ -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());
+}
+
 };
index aa23b48affeae4d3914e28d1c42739d373f0cfef..3b71f6db89d108c729ee223d98337c9f2a9dcf50 100644 (file)
@@ -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());
+}
+
 }
index 2249652a5b89c452a2e7dcb63d16d85bd84edcce..f6d2b6cbd9acf2ea46bfb2609a254dce29831583 100644 (file)
@@ -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_);
+}
index e8e6fe1b5c61ab7439b54dfd77796a8155a0899d..c7ca87512f4c2d2a1d518de6aefdcdf90fe2db84 100644 (file)
@@ -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