]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[150-add-sub-option-classification] Checkpoint: code done, todo regen and tests
authorFrancis Dupont <fdupont@isc.org>
Fri, 14 Jun 2019 18:40:17 +0000 (20:40 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Wed, 14 Aug 2019 08:13:02 +0000 (10:13 +0200)
src/lib/eval/eval_messages.cc
src/lib/eval/eval_messages.h
src/lib/eval/eval_messages.mes
src/lib/eval/parser.yy
src/lib/eval/token.cc
src/lib/eval/token.h

index 3f7803b3f5912f0d87d43ba72f75ccec602a2e53..a10d1e90f278781dcbf38d783ff2cb2d07efe493 100644 (file)
@@ -1,4 +1,4 @@
-// File created from ../../../src/lib/eval/eval_messages.mes on Fri Feb 08 2019 20:17
+// File created from ../../../src/lib/eval/eval_messages.mes on Fri Jun 14 2019 20:35
 
 #include <cstddef>
 #include <log/message_types.h>
@@ -27,6 +27,8 @@ extern const isc::log::MessageID EVAL_DEBUG_STRING = "EVAL_DEBUG_STRING";
 extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING = "EVAL_DEBUG_SUBSTRING";
 extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING_EMPTY = "EVAL_DEBUG_SUBSTRING_EMPTY";
 extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING_RANGE = "EVAL_DEBUG_SUBSTRING_RANGE";
+extern const isc::log::MessageID EVAL_DEBUG_SUB_OPTION = "EVAL_DEBUG_SUB_OPTION";
+extern const isc::log::MessageID EVAL_DEBUG_SUB_OPTION_NO_OPTION = "EVAL_DEBUG_SUB_OPTION_NO_OPTION";
 extern const isc::log::MessageID EVAL_DEBUG_TOHEXSTRING = "EVAL_DEBUG_TOHEXSTRING";
 extern const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_DATA = "EVAL_DEBUG_VENDOR_CLASS_DATA";
 extern const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND = "EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND";
@@ -66,6 +68,8 @@ const char* values[] = {
     "EVAL_DEBUG_SUBSTRING", "Popping length %1, start %2, string %3 pushing result %4",
     "EVAL_DEBUG_SUBSTRING_EMPTY", "Popping length %1, start %2, string %3 pushing result %4",
     "EVAL_DEBUG_SUBSTRING_RANGE", "Popping length %1, start %2, string %3 pushing result %4",
+    "EVAL_DEBUG_SUB_OPTION", "Pushing option %1 sub-option %2 with value %3",
+    "EVAL_DEBUG_SUB_OPTION_NO_OPTION", "Requested option %1 sub-option %2, but the parent option is not present, pushing result %3",
     "EVAL_DEBUG_TOHEXSTRING", "Popping binary value %1 and separator %2, pushing result %3",
     "EVAL_DEBUG_VENDOR_CLASS_DATA", "Data %1 (out of %2 received) in vendor class found, pushing result '%3'",
     "EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND", "Requested data index %1, but option with enterprise-id %2 has only %3 data tuple(s), pushing result '%4'",
index 99af4eabf3c1d455b9a0e34edc1ad6d85a366207..bae6c37c8e41b6f8252c0b8301a5639bf5678243 100644 (file)
@@ -1,4 +1,4 @@
-// File created from ../../../src/lib/eval/eval_messages.mes on Fri Feb 08 2019 20:17
+// File created from ../../../src/lib/eval/eval_messages.mes on Fri Jun 14 2019 20:35
 
 #ifndef EVAL_MESSAGES_H
 #define EVAL_MESSAGES_H
@@ -28,6 +28,8 @@ extern const isc::log::MessageID EVAL_DEBUG_STRING;
 extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING;
 extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING_EMPTY;
 extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING_RANGE;
+extern const isc::log::MessageID EVAL_DEBUG_SUB_OPTION;
+extern const isc::log::MessageID EVAL_DEBUG_SUB_OPTION_NO_OPTION;
 extern const isc::log::MessageID EVAL_DEBUG_TOHEXSTRING;
 extern const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_DATA;
 extern const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND;
index 0f37eaef6461648ac3a2ae53dfca58eca7af5f36..6a9698ad67fdbf6d742b3a4ebdab71fb0c34ae8f 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -144,6 +144,22 @@ string and an empty result will be pushed onto the stack.  The start,
 length and string are still popped from the stack and the result is
 still pushed.  The strings are displayed in hex.
 
+# For use with TokenSubOption
+
+% EVAL_DEBUG_SUB_OPTION Pushing option %1 sub-option %2 with value %3
+This debug message indicates that the given string representing the
+value of the requested sub-option of the requested parent option is
+being pushed onto the value stack. The string may be the text or
+binary value of the string based on the representation type requested
+(.text or .hex) or "true" or "false" if the requested type is .exists.
+The codes are the parent option and the sub-option codes as requested
+in the classification statement.
+
+% EVAL_DEBUG_SUB_OPTION_NO_OPTION Requested option %1 sub-option %2, but the parent option is not present, pushing result %3
+This debug message indicates that the parent option was not found.
+The codes are the parent option and the sub-option codes as requested
+in the classification statement.
+
 # For use with TokenToHexString
 
 % EVAL_DEBUG_TOHEXSTRING Popping binary value %1 and separator %2, pushing result %3
index f35fa23a77a65f56b020a7bac53e3662412e22e3..4f8626c1f8877d9e2436061b33ce3ecb027c64b6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+/* Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
 
    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -152,6 +152,11 @@ bool_expr : "(" bool_expr ")"
                     TokenPtr opt(new TokenOption($3, TokenOption::EXISTS));
                     ctx.expression.push_back(opt);
                 }
+          | OPTION "[" option_code "]" "." OPTION "[" option_code "]" "." EXISTS
+                {
+                    TokenPtr opt(new TokenSubOption($3, $8, TokenOption::EXISTS));
+                    ctx.expression.push_back(opt);
+                }
           | RELAY4 "[" option_code "]" "." EXISTS
                 {
                    switch (ctx.getUniverse()) {
@@ -251,6 +256,11 @@ string_expr : STRING
                       TokenPtr opt(new TokenOption($3, $6));
                       ctx.expression.push_back(opt);
                   }
+            | OPTION "[" option_code "]" "." OPTION "[" option_code "]" "." option_repr_type
+                  {
+                      TokenPtr opt(new TokenSubOption($3, $8, $11));
+                      ctx.expression.push_back(opt);
+                  }
             | RELAY4 "[" option_code "]" "." option_repr_type
                   {
                      switch (ctx.getUniverse()) {
index 1147fdfa3badf1bfcb8f9b11815026e6c0f2a475..f96dabe6692665708a7418ef076a309d9db72988 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -985,3 +985,62 @@ TokenInteger::TokenInteger(const uint32_t value)
     :TokenString(EvalContext::fromUint32(value)), int_value_(value) {
 
 }
+
+OptionPtr
+TokenSubOption::getSubOption(const OptionPtr& parent) {
+    return (parent->getOption(sub_option_code_));
+}
+
+void
+TokenSubOption::evaluate(Pkt& pkt, ValueStack& values) {
+    OptionPtr parent = getOption(pkt);
+    std::string txt;
+    if (!parent) {
+        // There's no parent option, give up.
+        txt = pushFailure(values);
+        LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUB_OPTION_NO_OPTION)
+            .arg(option_code_)
+            .arg(sub_option_code_)
+            .arg(txt);
+        return;
+    }
+
+    OptionPtr sub = getSubOption(parent);
+    if (!sub) {
+        // Failed to find the sub-option
+        txt = pushFailure(values);
+        LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUB_OPTION)
+            .arg(option_code_)
+            .arg(sub_option_code_)
+            .arg(txt);
+        return;
+    }
+
+    if (representation_type_ == TEXTUAL) {
+        txt = sub->toString();
+    } else if (representation_type_ == HEXADECIMAL) {
+        std::vector<uint8_t> binary = sub->toBinary();
+        txt.resize(binary.size());
+        if (!binary.empty()) {
+            memmove(&txt[0], &binary[0], binary.size());
+        }
+    } else {
+        txt = "true";
+    }
+    values.push(txt);
+
+    // Log what we pushed, both exists and textual are simple text
+    // and can be output directly.  We also include the code numbers
+    // of the requested parent option and sub-option.
+    if (representation_type_ == HEXADECIMAL) {
+        LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUB_OPTION)
+            .arg(option_code_)
+            .arg(sub_option_code_)
+            .arg(toHex(txt));
+    } else {
+        LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUB_OPTION)
+            .arg(option_code_)
+            .arg(sub_option_code_)
+            .arg('\'' + txt + '\'');
+    }
+}
index d3559fd21b85b75f8879188deafc3840d16fd50f..8275f98da1a12c7a440f969bfa605c33e7c7a302 100644 (file)
@@ -1057,6 +1057,68 @@ protected:
     uint16_t index_;
 };
 
+/// @brief Token that represents sub-options in DHCPv4 and DHCPv6.
+///
+/// It covers any options which encapsulate sub-options, for instance
+/// dhcp-agent-options (72, DHCPv4) or rsoo (66, DHCPv6).
+/// This class is derived from TokenOption and leverages its ability
+/// to operate on sub-options. It also adds additional capabilities.
+///
+/// It can represent the following expressions:
+/// option[149].exists - check if option 149 exists
+/// option[149].option[1].exists - check if suboption 1 exists in the option 149
+/// option[149].option[1].hex - return content of suboption 1 for option 149
+class TokenSubOption : public TokenOption {
+public:
+
+    /// @note Does not define its own representation type:
+    /// simply use the @c TokenOption::RepresentationType
+
+    /// @brief Constructor that takes an option and sub-option codes as parameter
+    ///
+    /// Note: There is no constructor that takes names.
+    ///
+    /// @param option_code code of the parent option.
+    /// @param sub_option_code code of the sub-option to be represented.
+    /// @param rep_type Token representation type.
+    TokenSubOption(const uint16_t option_code,
+                   const uint16_t sub_option_code,
+                   const RepresentationType& rep_type)
+        : TokenOption(option_code, rep_type), sub_option_code_(sub_option_code) {}
+
+    /// @brief This is a method for evaluating a packet.
+    ///
+    /// This token represents a value of the sub-option, so this method
+    /// attempts to extract the parent option from the packet and when
+    /// it succeeds to extract the sub-option from the option and
+    /// its value on the stack.
+    /// If the parent option or the sub-option is not there, an empty
+    /// string ("") is put on the stack.
+    ///
+    /// @param pkt specified parent option will be extracted from this packet
+    /// @param values value of the sub-option will be pushed here (or "")
+    virtual void evaluate(Pkt& pkt, ValueStack& values);
+
+    /// @brief Returns sub-option-code
+    ///
+    /// This method is used in testing to determine if the parser had
+    /// instantiated TokenSubOption with correct parameters.
+    ///
+    /// @return option-code of the sub-option this token expects to extract.
+    uint16_t getSubCode() const {
+        return (sub_option_code_);
+    }
+
+protected:
+    /// @brief Attempts to retrieve a sub-option.
+    ///
+    /// @param parent the sub-option will be retrieved from here
+    /// @return sub-option instance (or NULL if not found)
+    virtual OptionPtr getSubOption(const OptionPtr& parent);
+
+    uint16_t sub_option_code_; ///< Code of the sub-option to be extracted
+};
+
 }; // end of isc::dhcp namespace
 }; // end of isc namespace