diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml
index f37a62bf3d..a33f005d43 100644
--- a/doc/guide/classify.xml
+++ b/doc/guide/classify.xml
@@ -202,7 +202,7 @@
-->
Option existence
- option[123].exist
+ option[123].exists
'true'
If the option with given code is present in the
packet "true" else "false"
@@ -315,6 +315,88 @@
The value of the transaction id in the DHCPv6
packet.
+
+
+ Vendor option existence (any vendor)
+ vendor[*].exists
+ true
+ Returns whether a vendor option from any vendor
+ is present ('true') or absent ('false').
+
+
+ Vendor option existence (specific vendor)
+ vendor[4491].exists
+ true
+ Returns whether a vendor option from specified
+ vendor (determined by its enterprise-id)
+ is present ('true') or absent ('false').
+
+
+ Enterprise-id from vendor option
+ vendor.enterprise
+ 0x0000118b
+ If the vendor option is present, it returns the
+ value of the enterprise-id field padded to 4
+ bytes. Returns '' otherwise.
+
+
+ Vendor sub-option existence
+ vendor[4491].option[1].exists
+ true
+ Returns 'true' if there is vendor option with
+ specified enterprise-id and given sub-option is present.
+ Returns 'false' otherwise.
+
+
+ Vendor sub-option content
+ vendor[4491].option[1].hex
+ docsis3.0
+ Returns content of the specified sub-option of
+ a vendor option with specified enterprise id. Returns
+ '' if no such option or sub-option is present.
+
+
+
+
+ Vendor class option existence (any vendor)
+ vendor-class[*].exists
+ true
+ Returns whether a vendor class option from any vendor
+ is present ('true') or absent ('false').
+
+
+ Vendor class option existence (specific vendor)
+ vendor-class[4491].exists
+ true
+ Returns whether a vendor class option from specified
+ vendor (determined by its enterprise-id)
+ is present ('true') or absent ('false').
+
+
+ Enterprise-id from vendor class option
+ vendor-class.enterprise
+ 0x0000118b
+ If the vendor option is present, it returns the
+ value of the enterprise-id field padded to 4
+ bytes. Returns '' otherwise.
+
+
+ First data chunk from vendor class option
+ vendor-class[4491].data
+ docsis3.0
+ Returns content of the first data chunk from
+ the vendor class option with specified enterprise-id.
+ Returns '' if missing.
+
+
+ Specific data chunk from vendor class option
+ vendor-class[4491].data[3]
+ docsis3.0
+ Returns content of the specified data chunk of
+ a vendor class option with specified enterprise id. Returns
+ '' if no such option or data chunk is present.
+
+
@@ -341,7 +423,7 @@
- "option[code].exist" checks if an option with the code "code" is present
+ "option[code].exists" checks if an option with the code "code" is present
in the incoming packet. It can be used with empty options.
@@ -387,6 +469,33 @@
"0x00000001" or simply 1 as in "pkt6.msgtype == 1".
+
+ Vendor option means Vendor-Identifying Vendor-specific Information
+ option (code 125, see Section 4 of RFC3925) in DHCPv4 and
+ Vendor-specific Information Option (code 17, defined in Section 22.17 of
+ RFC3315) in DHCPv6. Vendor class option means Vendor-Identifying Vendor
+ Class Option (code 124, see Section 3 of RFC3925) in DHCPv4 and Vendor
+ Class Option (code 16, see Section 22.16 of RFC3315). Vendor options may
+ have sub-options that are referenced by their codes. Vendor class
+ options do not have sub-options, but rather data chunks, which are
+ referenced by index value. Index 0 means the first data chunk, Index 1
+ is for the second data chunk (if present), etc.
+
+
+ In the vendor and vendor-class constructs Asterisk (*) or 0 can be
+ used to specify a wildcard enterprise-id value, i.e. it will match any
+ enterprise-id value.
+
+ Vendor Class Identifier (option 60 in DHCPv4) can be
+ accessed using option[60] expression.
+
+ RFC3925 and RFC3315 allow for multiple instances of vendor options
+ to appear in a single message. The client classification code currently
+ examines the first instance if more than one appear. For vendor.enterprise
+ and vendor-class.enterprise expressions, the value from the first instance
+ is returned. Please submit a feature request on Kea website if you need
+ support for multiple instances.
+
List of Classification Expressions
@@ -407,7 +516,8 @@
And ('foo' == 'bar') and ('bar' == 'foo')Logical and
Or ('foo' == 'bar') or ('bar' == 'foo')Logical or
Substringsubstring('foobar',0,3)Return the requested substring
-Concatconcat('foo','bar')Return the concatenation of the strings
+Concatconcat('foo','bar')Return the
+concatenation of the strings
diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml
index 352f50f667..7b09356207 100644
--- a/doc/guide/dhcp4-srv.xml
+++ b/doc/guide/dhcp4-srv.xml
@@ -3583,9 +3583,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc -->
Host reservation (static addresses) is not supported yet.
-
- Full featured client classification is not supported yet.
-
BOOTP (RFC 951)
@@ -3609,9 +3606,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc -->
allocating server should verify that address is not used by
sending ICMP echo request.
-
- Address duplication report (DECLINE) is not supported yet.
-
diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml
index 5b1d5c5858..4eac70db24 100644
--- a/doc/guide/dhcp6-srv.xml
+++ b/doc/guide/dhcp6-srv.xml
@@ -3828,8 +3828,7 @@ should include options from the isc option space:
- Duplication report (DECLINE) and client reconfiguration (RECONFIGURE) are
- not yet supported.
+ Client reconfiguration (RECONFIGURE) is not yet supported.
diff --git a/src/lib/eval/Makefile.am b/src/lib/eval/Makefile.am
index 2c8dd8ccd7..95cbba0c40 100644
--- a/src/lib/eval/Makefile.am
+++ b/src/lib/eval/Makefile.am
@@ -85,6 +85,11 @@ parser: lexer.cc location.hh position.hh stack.hh parser.cc parser.h
@echo "Flex/bison files regenerated"
# --- Flex/Bison stuff below --------------------------------------------------
+# When debugging grammar issues, it's useful to add -v to bison parameters.
+# bison will generate parser.output file that explains the whole grammar.
+# It can be used to manually follow what's going on in the parser.
+# This is especially useful if yydebug_ is set to 1 as that variable
+# will cause parser to print out its internal state.
location.hh position.hh stack.hh parser.cc parser.h: parser.yy
$(YACC) --defines=parser.h -o parser.cc parser.yy
diff --git a/src/lib/eval/eval_context.cc b/src/lib/eval/eval_context.cc
index ca27893092..4ede1dbc42 100644
--- a/src/lib/eval/eval_context.cc
+++ b/src/lib/eval/eval_context.cc
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
EvalContext::EvalContext(const Option::Universe& option_universe)
: trace_scanning_(false), trace_parsing_(false),
@@ -97,14 +98,9 @@ uint8_t
EvalContext::convertNestLevelNumber(const std::string& nest_level,
const isc::eval::location& loc)
{
- int n = 0;
- try {
- n = boost::lexical_cast(nest_level);
- } catch (const boost::bad_lexical_cast &) {
- error(loc, "Nest level has invalid value in " + nest_level);
- }
+ uint8_t n = convertUint8(nest_level, loc);
if (option_universe_ == Option::V6) {
- if (n < 0 || n >= HOP_COUNT_LIMIT) {
+ if (n >= HOP_COUNT_LIMIT) {
error(loc, "Nest level has invalid value in "
+ nest_level + ". Allowed range: 0..31");
}
@@ -112,9 +108,44 @@ EvalContext::convertNestLevelNumber(const std::string& nest_level,
error(loc, "Nest level invalid for DHCPv4 packets");
}
+ return (n);
+}
+
+uint8_t
+EvalContext::convertUint8(const std::string& number,
+ const isc::eval::location& loc)
+{
+ int n = 0;
+ try {
+ n = boost::lexical_cast(number);
+ } catch (const boost::bad_lexical_cast &) {
+ error(loc, "Invalid integer value in " + number);
+ }
+ if (n < 0 || n >= std::numeric_limits::max()) {
+ error(loc, "Invalid value in "
+ + number + ". Allowed range: 0..255");
+ }
+
return (static_cast(n));
}
+uint32_t
+EvalContext::convertUint32(const std::string& number,
+ const isc::eval::location& loc)
+{
+ uint64_t n = 0;
+ try {
+ n = boost::lexical_cast(number);
+ } catch (const boost::bad_lexical_cast &) {
+ error(loc, "Invalid value in " + number);
+ }
+ if (n >= std::numeric_limits::max()) {
+ error(loc, "Invalid value in "
+ + number + ". Allowed range: 0..4294967295");
+ }
+
+ return (static_cast(n));
+}
void
EvalContext::fatal (const std::string& what)
diff --git a/src/lib/eval/eval_context.h b/src/lib/eval/eval_context.h
index 939f9ec35e..4984554ec4 100644
--- a/src/lib/eval/eval_context.h
+++ b/src/lib/eval/eval_context.h
@@ -96,16 +96,34 @@ public:
///
/// @param option_name the option name
/// @param loc the location of the token
- /// @result the option code
+ /// @return the option code
/// @throw calls the syntax error function if the name cannot be resolved
uint16_t convertOptionName(const std::string& option_name,
const isc::eval::location& loc);
+ /// @brief Attempts to convert string to unsigned 32bit integer
+ ///
+ /// @param number string to be converted
+ /// @param loc the location of the token
+ /// @return the integer value
+ /// @throw EvalParseError if conversion fails or the value is out of range.
+ uint32_t convertUint32(const std::string& number,
+ const isc::eval::location& loc);
+
+ /// @brief Attempts to convert string to unsigned 8bit integer
+ ///
+ /// @param number string to be converted
+ /// @param loc the location of the token
+ /// @return the integer value
+ /// @throw EvalParseError if conversion fails or the value is out of range.
+ uint8_t convertUint8(const std::string& number,
+ const isc::eval::location& loc);
+
/// @brief Nest level conversion
///
/// @param nest_level a string representing the integer nesting level
/// @param loc the location of the token
- /// @result the nesting level
+ /// @return the nesting level
/// @throw calls the syntax error function if the value is not in
/// the range 0..31
uint8_t convertNestLevelNumber(const std::string& nest_level,
diff --git a/src/lib/eval/eval_messages.mes b/src/lib/eval/eval_messages.mes
index 14173f6ebf..6e7ba6a8ca 100644
--- a/src/lib/eval/eval_messages.mes
+++ b/src/lib/eval/eval_messages.mes
@@ -113,6 +113,51 @@ 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.
+% EVAL_DEBUG_VENDOR_CLASS_DATA Data %1 (out of %2 received) in vendor class found, pushing result '%3'
+This debug message indicates that vendor class option was found and passed
+enterprise-id checks and has sufficient number of data chunks. The total number
+of chunks and value pushed are reported as debugging aid.
+
+% 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'
+This debug message indicates that vendor class option was found and passed
+enterprise-id checks, but does not have sufficient number of data chunks.
+Note that the index starts at 0, so there has to be at least (index + 1)
+data chunks.
+
+% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result 0x%2
+This debug message indicates that the expression has been evaluated and vendor
+class option was found and its enterprise-id is being reported.
+
+% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result '%3'
+This debug message indicates that the expression has been evaluated
+and vendor class option was found, but has different enterprise-id than specified
+in the expression.
+
+% EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id %1 found, pushing result '%2'
+This debug message indicates that the expression has been evaluated and vendor
+class option was found.
+
+% EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code %1 missing, pushing result '%2'
+This debug message indicates that the expression has been evaluated
+and vendor class option was not found.
+
+% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result 0x%2
+This debug message indicates that the expression has been evaluated and vendor
+option was found and its enterprise-id is being reported.
+
+% EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result '%3'
+This debug message indicates that the expression has been evaluated
+and vendor option was found, but has different enterprise-id than specified
+in the expression.
+
+% EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id %1 found, pushing result '%2'
+This debug message indicates that the expression has been evaluated and vendor
+option was found.
+
+% EVAL_DEBUG_VENDOR_NO_OPTION Option with code %1 missing, pushing result '%2'
+This debug message indicates that the expression has been evaluated
+and vendor option was not found.
+
% EVAL_RESULT Expression %1 evaluated to %2
This debug message indicates that the expression has been evaluated
to said value. This message is mostly useful during debugging of the
diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc
index 6ba140daf2..69757ba1b3 100644
--- a/src/lib/eval/lexer.cc
+++ b/src/lib/eval/lexer.cc
@@ -284,7 +284,7 @@ struct yy_buffer_state
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
- yy_size_t yy_n_chars;
+ int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
@@ -368,7 +368,7 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
-static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
yy_size_t yyleng;
/* Points to current character in buffer. */
@@ -483,8 +483,8 @@ static void yy_fatal_error (yyconst char msg[] );
(yy_c_buf_p) = yy_cp;
/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
-#define YY_NUM_RULES 46
-#define YY_END_OF_BUFFER 47
+#define YY_NUM_RULES 51
+#define YY_END_OF_BUFFER 52
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@@ -492,58 +492,64 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static yyconst flex_int16_t yy_acclist[248] =
+static yyconst flex_int16_t yy_acclist[280] =
{ 0,
- 47, 45, 46, 1, 45, 46, 2, 46, 45, 46,
- 40, 45, 46, 41, 45, 46, 44, 45, 46, 45,
- 46, 39, 45, 46, 5, 45, 46, 5, 45, 46,
- 45, 46, 45, 46, 45, 46,16390, 45, 46,16390,
- 42, 45, 46, 43, 45, 46, 45, 46,16390, 45,
- 46,16390, 45, 46,16390, 45, 46,16390, 45, 46,
- 16390, 45, 46,16390, 45, 46,16390, 45, 46,16390,
- 45, 46,16390, 45, 46,16390, 45, 46,16390, 45,
- 46,16390, 45, 46,16390, 45, 46,16390, 45, 46,
- 16390, 45, 46,16390, 1, 2, 3, 5, 5, 7,
+ 52, 50, 51, 1, 50, 51, 2, 51, 50, 51,
+ 44, 50, 51, 45, 50, 51, 49, 50, 51, 48,
+ 50, 51, 50, 51, 43, 50, 51, 5, 50, 51,
+ 5, 50, 51, 50, 51, 50, 51, 50, 51,16390,
+ 50, 51,16390, 46, 50, 51, 47, 50, 51, 50,
+ 51,16390, 50, 51,16390, 50, 51,16390, 50, 51,
+ 16390, 50, 51,16390, 50, 51,16390, 50, 51,16390,
+ 50, 51,16390, 50, 51,16390, 50, 51,16390, 50,
+ 51,16390, 50, 51,16390, 50, 51,16390, 50, 51,
+ 16390, 50, 51,16390, 50, 51,16390, 50, 51,16390,
- 8,16390,16390, 8198,16390,16390,16390,16390,16390,16390,
+ 1, 2, 3, 5, 5, 7, 8,16390,16390, 8198,
16390,16390,16390,16390,16390,16390,16390,16390,16390,16390,
- 16390, 38,16390,16390,16390,16390,16390,16390,16390,16390,
- 16390,16390, 4, 7, 34,16390, 37,16390,16390,16390,
- 20,16390,16390,16390, 15,16390,16390,16390,16390, 21,
- 16390,16390, 23,16390,16390, 36,16390,16390,16390, 17,
- 16390,16390,16390, 19,16390,16390,16390,16390,16390,16390,
- 16390,16390,16390, 24,16390,16390,16390,16390,16390,16390,
- 16390, 22,16390, 30,16390,16390,16390,16390, 14,16390,
- 16390,16390,16390,16390,16390,16390, 25,16390, 18,16390,
+ 16390,16390,16390,16390,16390,16390,16390,16390,16390, 42,
+ 16390,16390,16390,16390,16390,16390,16390,16390,16390,16390,
+ 16390, 4, 7, 38,16390, 41,16390,16390,16390,16390,
+ 20,16390,16390,16390,16390, 15,16390,16390,16390,16390,
+ 21,16390,16390, 23,16390,16390, 40,16390,16390,16390,
+ 17,16390,16390,16390, 19,16390,16390,16390,16390,16390,
+ 16390,16390,16390, 35,16390,16390,16390,16390, 24,16390,
+ 16390,16390,16390,16390,16390,16390, 22,16390, 30,16390,
- 16390,16390,16390,16390,16390,16390,16390,16390,16390, 26,
- 16390, 35,16390, 16,16390, 27,16390,16390,16390, 9,
- 16390,16390, 10,16390, 11,16390, 29,16390,16390,16390,
- 28,16390, 7,16390, 31,16390,16390,16390, 32,16390,
- 13,16390, 12,16390,16390, 33,16390
+ 16390,16390,16390, 14,16390,16390,16390,16390,16390,16390,
+ 16390,16390,16390, 25,16390, 18,16390,16390,16390,16390,
+ 16390,16390,16390,16390,16390,16390,16390, 26,16390, 39,
+ 16390,16390, 16,16390, 27,16390,16390,16390, 9,16390,
+ 16390, 10,16390, 11,16390, 29,16390,16390,16390, 33,
+ 16390, 28,16390, 7,16390,16390, 31,16390,16390,16390,
+ 32,16390,16390, 13,16390, 12,16390,16390,16390,16390,
+ 37,16390,16390, 36,16390,16390,16390, 34,16390
} ;
-static yyconst flex_int16_t yy_accept[174] =
+static yyconst flex_int16_t yy_accept[199] =
{ 0,
1, 1, 1, 2, 4, 7, 9, 11, 14, 17,
- 20, 22, 25, 28, 31, 33, 35, 38, 41, 44,
+ 20, 23, 25, 28, 31, 34, 36, 38, 41, 44,
47, 50, 53, 56, 59, 62, 65, 68, 71, 74,
- 77, 80, 83, 86, 89, 92, 95, 96, 97, 97,
- 98, 99, 99, 100, 100, 100, 100, 100, 101, 102,
- 102, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 124, 125, 126, 127, 128, 129, 130, 131,
- 132, 133, 133, 134, 135, 137, 139, 140, 141, 143,
- 144, 145, 147, 148, 149, 150, 152, 153, 155, 156,
+ 77, 80, 83, 86, 89, 92, 95, 98, 101, 102,
+ 103, 103, 104, 105, 105, 106, 106, 106, 106, 106,
+ 107, 108, 108, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 142, 143, 144,
+ 146, 148, 149, 150, 151, 153, 154, 155, 156, 158,
+
+ 159, 160, 161, 163, 164, 166, 167, 169, 170, 171,
+ 173, 174, 175, 177, 178, 179, 180, 181, 182, 182,
+ 183, 184, 186, 187, 188, 189, 191, 192, 193, 194,
+ 195, 196, 197, 199, 201, 202, 203, 204, 206, 207,
+ 208, 209, 209, 210, 211, 212, 213, 214, 216, 218,
+ 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
+ 228, 230, 232, 233, 235, 237, 238, 239, 241, 242,
+ 244, 246, 248, 249, 250, 252, 254, 255, 256, 257,
+ 259, 260, 261, 263, 263, 264, 266, 268, 269, 270,
+ 271, 273, 274, 276, 277, 278, 280, 280
- 158, 159, 160, 162, 163, 164, 166, 167, 168, 169,
- 170, 170, 171, 172, 173, 174, 176, 177, 178, 179,
- 180, 181, 182, 184, 186, 187, 188, 189, 191, 192,
- 193, 193, 194, 195, 196, 197, 199, 201, 202, 203,
- 204, 205, 206, 207, 208, 209, 210, 210, 212, 214,
- 216, 218, 219, 220, 222, 223, 225, 227, 229, 230,
- 231, 233, 234, 235, 237, 238, 239, 241, 243, 245,
- 246, 248, 248
} ;
static yyconst YY_CHAR yy_ec[256] =
@@ -552,16 +558,16 @@ static yyconst YY_CHAR yy_ec[256] =
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 1, 1, 1, 1, 4, 5,
- 6, 1, 1, 7, 8, 9, 1, 10, 11, 11,
- 11, 12, 11, 13, 11, 11, 11, 14, 1, 1,
- 15, 1, 1, 1, 16, 16, 16, 16, 16, 16,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 18, 17, 17,
- 19, 1, 20, 1, 21, 1, 22, 23, 24, 25,
+ 6, 7, 1, 8, 9, 10, 1, 11, 12, 12,
+ 12, 13, 12, 14, 12, 12, 12, 15, 1, 1,
+ 16, 1, 1, 1, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 19, 18, 18,
+ 20, 1, 21, 1, 22, 1, 23, 24, 25, 26,
- 26, 27, 28, 29, 30, 17, 31, 32, 33, 34,
- 35, 36, 17, 37, 38, 39, 40, 17, 17, 41,
- 42, 17, 1, 1, 1, 1, 1, 1, 1, 1,
+ 27, 28, 29, 30, 31, 18, 32, 33, 34, 35,
+ 36, 37, 18, 38, 39, 40, 41, 42, 18, 43,
+ 44, 18, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -578,158 +584,172 @@ static yyconst YY_CHAR yy_ec[256] =
1, 1, 1, 1, 1
} ;
-static yyconst YY_CHAR yy_meta[43] =
+static yyconst YY_CHAR yy_meta[45] =
{ 0,
- 1, 1, 2, 1, 1, 1, 1, 1, 3, 4,
- 4, 4, 4, 5, 1, 4, 1, 1, 1, 1,
- 1, 4, 4, 4, 4, 4, 4, 1, 1, 1,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 3,
+ 4, 4, 4, 4, 5, 1, 4, 1, 1, 1,
+ 1, 1, 4, 4, 4, 4, 4, 4, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1
+ 1, 1, 1, 1
} ;
-static yyconst flex_uint16_t yy_base[178] =
+static yyconst flex_uint16_t yy_base[203] =
{ 0,
- 0, 0, 281, 282, 278, 276, 274, 282, 282, 282,
- 33, 282, 38, 35, 263, 261, 78, 111, 282, 282,
- 23, 36, 237, 233, 243, 43, 245, 42, 36, 236,
- 41, 100, 244, 102, 33, 239, 266, 264, 262, 282,
- 133, 137, 110, 251, 250, 0, 249, 0, 282, 138,
- 150, 0, 0, 282, 230, 236, 238, 225, 219, 227,
- 234, 214, 228, 211, 230, 217, 216, 225, 220, 208,
- 207, 0, 219, 205, 211, 220, 217, 217, 198, 216,
- 215, 150, 0, 0, 0, 0, 211, 211, 0, 196,
- 208, 0, 198, 195, 206, 0, 198, 0, 189, 0,
+ 0, 0, 310, 311, 307, 305, 303, 311, 311, 311,
+ 311, 34, 311, 39, 36, 291, 289, 81, 115, 311,
+ 311, 24, 37, 37, 26, 273, 45, 275, 43, 48,
+ 266, 43, 59, 274, 106, 50, 273, 268, 296, 294,
+ 292, 311, 122, 137, 112, 280, 279, 0, 278, 0,
+ 311, 143, 150, 0, 0, 311, 259, 265, 267, 254,
+ 248, 247, 246, 254, 261, 240, 255, 237, 257, 244,
+ 243, 252, 247, 235, 234, 0, 246, 232, 238, 247,
+ 244, 244, 224, 243, 230, 241, 146, 0, 0, 0,
+ 0, 237, 237, 238, 0, 233, 220, 232, 0, 222,
- 197, 189, 71, 203, 199, 0, 185, 183, 187, 195,
- 144, 194, 196, 178, 191, 0, 189, 188, 191, 170,
- 176, 188, 0, 0, 167, 183, 168, 0, 168, 180,
- 155, 167, 164, 164, 164, 0, 0, 175, 163, 164,
- 172, 117, 159, 158, 164, 156, 161, 0, 0, 0,
- 0, 167, 165, 0, 155, 0, 0, 0, 139, 72,
- 0, 165, 56, 0, 50, 51, 0, 0, 0, 45,
- 0, 282, 178, 180, 182, 63, 185
+ 219, 230, 0, 222, 0, 213, 0, 221, 213, 148,
+ 227, 223, 0, 209, 207, 211, 219, 218, 154, 217,
+ 219, 0, 203, 200, 213, 0, 211, 210, 213, 191,
+ 198, 210, 0, 0, 188, 205, 190, 0, 190, 192,
+ 201, 162, 188, 185, 187, 184, 184, 0, 0, 195,
+ 173, 172, 180, 156, 167, 165, 171, 163, 162, 166,
+ 0, 0, 161, 0, 0, 172, 170, 0, 170, 0,
+ 0, 0, 164, 168, 184, 0, 170, 161, 153, 0,
+ 152, 154, 0, 183, 149, 0, 0, 158, 130, 127,
+ 0, 78, 0, 58, 50, 0, 311, 208, 210, 212,
+
+ 71, 215
} ;
-static yyconst flex_int16_t yy_def[178] =
+static yyconst flex_int16_t yy_def[203] =
{ 0,
- 172, 1, 172, 172, 172, 172, 173, 172, 172, 172,
- 172, 172, 172, 13, 174, 172, 172, 17, 172, 172,
- 17, 17, 17, 17, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 172, 172, 173, 172,
- 172, 172, 13, 174, 175, 176, 174, 177, 172, 172,
- 18, 17, 18, 172, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 172, 176, 177, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 197, 1, 197, 197, 197, 197, 198, 197, 197, 197,
+ 197, 197, 197, 197, 14, 199, 197, 197, 18, 197,
+ 197, 18, 18, 18, 18, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 197, 197,
+ 198, 197, 197, 197, 14, 199, 200, 201, 199, 202,
+ 197, 197, 19, 18, 19, 197, 19, 19, 19, 19,
+ 18, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 197, 201, 202, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 172, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 172, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 172, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 172, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 0, 172, 172, 172, 172, 172
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 197, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 197, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 197,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 197, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 0, 197, 197, 197,
+
+ 197, 197
} ;
-static yyconst flex_uint16_t yy_nxt[325] =
+static yyconst flex_uint16_t yy_nxt[356] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 14, 14, 15, 16, 17, 18, 18, 19, 20,
- 4, 21, 17, 22, 23, 24, 17, 25, 26, 27,
- 18, 28, 29, 30, 31, 32, 33, 34, 35, 18,
- 18, 36, 41, 41, 41, 41, 42, 43, 43, 43,
- 43, 44, 172, 45, 55, 46, 56, 68, 79, 45,
- 45, 45, 45, 45, 45, 57, 83, 66, 62, 80,
- 58, 67, 171, 69, 63, 172, 71, 72, 46, 50,
- 50, 64, 123, 124, 170, 51, 169, 52, 52, 52,
- 52, 44, 168, 52, 53, 53, 167, 54, 51, 52,
+ 14, 15, 15, 15, 16, 17, 18, 19, 19, 20,
+ 21, 4, 22, 18, 23, 24, 25, 18, 26, 27,
+ 28, 19, 29, 30, 31, 32, 33, 34, 35, 36,
+ 19, 37, 19, 38, 43, 43, 43, 43, 44, 45,
+ 45, 45, 45, 46, 197, 47, 57, 48, 58, 61,
+ 63, 47, 47, 47, 47, 47, 47, 59, 64, 70,
+ 72, 66, 60, 71, 88, 62, 83, 67, 197, 75,
+ 76, 48, 52, 52, 68, 77, 73, 84, 196, 53,
+ 78, 54, 54, 54, 54, 46, 195, 54, 55, 55,
- 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 172, 73, 53, 172, 156, 157,
- 74, 76, 53, 53, 53, 53, 53, 53, 77, 50,
- 50, 78, 41, 41, 41, 41, 82, 82, 82, 82,
- 172, 172, 172, 131, 131, 131, 131, 54, 111, 82,
- 82, 82, 82, 147, 131, 131, 131, 131, 166, 172,
- 162, 162, 162, 162, 162, 162, 162, 162, 39, 165,
- 39, 39, 39, 47, 47, 45, 45, 84, 84, 84,
- 164, 163, 161, 160, 159, 158, 155, 154, 153, 152,
+ 194, 56, 53, 54, 54, 54, 54, 54, 54, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 197,
+ 197, 55, 43, 43, 43, 43, 80, 55, 55, 55,
+ 55, 55, 55, 81, 52, 52, 82, 87, 87, 87,
+ 87, 197, 197, 193, 197, 119, 87, 87, 87, 87,
+ 133, 134, 192, 56, 142, 142, 142, 142, 170, 171,
+ 197, 160, 142, 142, 142, 142, 177, 177, 177, 177,
+ 177, 177, 177, 177, 197, 197, 191, 190, 188, 187,
+ 186, 185, 184, 183, 182, 181, 180, 179, 178, 176,
- 151, 150, 149, 148, 146, 145, 144, 143, 142, 141,
- 140, 139, 138, 137, 136, 135, 134, 133, 132, 130,
- 129, 128, 127, 126, 125, 122, 121, 120, 119, 118,
- 117, 116, 115, 114, 113, 112, 110, 109, 108, 107,
- 106, 105, 104, 103, 102, 101, 100, 99, 98, 97,
- 96, 95, 94, 93, 92, 91, 90, 89, 88, 87,
- 86, 85, 48, 44, 48, 40, 38, 37, 81, 75,
- 70, 65, 61, 60, 59, 49, 48, 40, 38, 37,
- 172, 3, 172, 172, 172, 172, 172, 172, 172, 172,
- 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 175, 174, 173, 197, 172, 169, 168, 189, 41, 167,
+ 41, 41, 41, 49, 49, 47, 47, 89, 89, 89,
+ 166, 165, 164, 163, 162, 161, 159, 158, 157, 156,
+ 155, 154, 153, 152, 151, 150, 149, 148, 147, 146,
+ 145, 144, 143, 141, 140, 139, 138, 137, 136, 135,
+ 132, 131, 130, 129, 128, 127, 126, 125, 124, 123,
+ 122, 121, 120, 118, 117, 116, 115, 114, 113, 112,
+ 111, 110, 109, 108, 107, 106, 105, 104, 103, 102,
+ 101, 100, 99, 98, 97, 96, 95, 94, 93, 92,
+ 91, 90, 50, 46, 50, 42, 40, 39, 86, 85,
- 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
- 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
- 172, 172, 172, 172
+ 79, 74, 69, 65, 51, 50, 42, 40, 39, 197,
+ 3, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197
} ;
-static yyconst flex_int16_t yy_chk[325] =
+static yyconst flex_int16_t yy_chk[356] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 11, 11, 11, 11, 13, 13, 13, 13,
- 13, 13, 14, 13, 21, 13, 21, 29, 35, 13,
- 13, 13, 13, 13, 13, 22, 176, 28, 26, 35,
- 22, 28, 170, 29, 26, 14, 31, 31, 13, 17,
- 17, 26, 103, 103, 166, 17, 165, 17, 17, 17,
- 17, 17, 163, 17, 17, 17, 160, 17, 17, 17,
+ 1, 1, 1, 1, 12, 12, 12, 12, 14, 14,
+ 14, 14, 14, 14, 15, 14, 22, 14, 22, 24,
+ 25, 14, 14, 14, 14, 14, 14, 23, 25, 29,
+ 30, 27, 23, 29, 201, 24, 36, 27, 15, 32,
+ 32, 14, 18, 18, 27, 33, 30, 36, 195, 18,
+ 33, 18, 18, 18, 18, 18, 194, 18, 18, 18,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 18, 18, 18, 18, 18, 32, 18, 43, 142, 142,
- 32, 34, 18, 18, 18, 18, 18, 18, 34, 50,
- 50, 34, 41, 41, 41, 41, 42, 42, 42, 42,
- 43, 51, 51, 111, 111, 111, 111, 50, 82, 82,
- 82, 82, 82, 131, 131, 131, 131, 131, 159, 51,
- 147, 147, 147, 147, 162, 162, 162, 162, 173, 155,
- 173, 173, 173, 174, 174, 175, 175, 177, 177, 177,
- 153, 152, 146, 145, 144, 143, 141, 140, 139, 138,
+ 192, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 19, 19, 19, 19, 19,
+ 45, 19, 43, 43, 43, 43, 35, 19, 19, 19,
+ 19, 19, 19, 35, 52, 52, 35, 44, 44, 44,
+ 44, 53, 53, 190, 45, 87, 87, 87, 87, 87,
+ 110, 110, 189, 52, 119, 119, 119, 119, 154, 154,
+ 53, 142, 142, 142, 142, 142, 160, 160, 160, 160,
+ 177, 177, 177, 177, 184, 184, 188, 185, 182, 181,
+ 179, 178, 175, 174, 173, 169, 167, 166, 163, 159,
- 135, 134, 133, 132, 130, 129, 127, 126, 125, 122,
- 121, 120, 119, 118, 117, 115, 114, 113, 112, 110,
- 109, 108, 107, 105, 104, 102, 101, 99, 97, 95,
- 94, 93, 91, 90, 88, 87, 81, 80, 79, 78,
- 77, 76, 75, 74, 73, 71, 70, 69, 68, 67,
- 66, 65, 64, 63, 62, 61, 60, 59, 58, 57,
- 56, 55, 47, 45, 44, 39, 38, 37, 36, 33,
- 30, 27, 25, 24, 23, 16, 15, 7, 6, 5,
- 3, 172, 172, 172, 172, 172, 172, 172, 172, 172,
- 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
+ 158, 157, 156, 184, 155, 153, 152, 184, 198, 151,
+ 198, 198, 198, 199, 199, 200, 200, 202, 202, 202,
+ 150, 147, 146, 145, 144, 143, 141, 140, 139, 137,
+ 136, 135, 132, 131, 130, 129, 128, 127, 125, 124,
+ 123, 121, 120, 118, 117, 116, 115, 114, 112, 111,
+ 109, 108, 106, 104, 102, 101, 100, 98, 97, 96,
+ 94, 93, 92, 86, 85, 84, 83, 82, 81, 80,
+ 79, 78, 77, 75, 74, 73, 72, 71, 70, 69,
+ 68, 67, 66, 65, 64, 63, 62, 61, 60, 59,
+ 58, 57, 49, 47, 46, 41, 40, 39, 38, 37,
- 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
- 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
- 172, 172, 172, 172
+ 34, 31, 28, 26, 17, 16, 7, 6, 5, 3,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197
} ;
/* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[47] =
+static yyconst flex_int32_t yy_rule_can_match_eol[52] =
{ 0,
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, };
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
extern int yy_flex_debug;
int yy_flex_debug = 1;
-static yyconst flex_int16_t yy_rule_linenum[46] =
+static yyconst flex_int16_t yy_rule_linenum[51] =
{ 0,
82, 86, 92, 102, 108, 122, 129, 143, 144, 145,
146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
- 176, 177, 178, 179, 181
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185
} ;
static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
@@ -808,7 +828,7 @@ static isc::eval::location loc;
// by moving it ahead by yyleng bytes. yyleng specifies the length of the
// currently matched token.
#define YY_USER_ACTION loc.columns(yyleng);
-#line 812 "lexer.cc"
+#line 832 "lexer.cc"
#define INITIAL 0
@@ -1105,7 +1125,7 @@ YY_DECL
loc.step();
-#line 1109 "lexer.cc"
+#line 1129 "lexer.cc"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@@ -1133,14 +1153,14 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 173 )
+ if ( yy_current_state >= 198 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
*(yy_state_ptr)++ = yy_current_state;
++yy_cp;
}
- while ( yy_current_state != 172 );
+ while ( yy_current_state != 197 );
yy_find_action:
/* %% [10.0] code to find the action number goes here */
@@ -1203,13 +1223,13 @@ do_action: /* This label is used only to access EOF actions. */
{
if ( yy_act == 0 )
fprintf( stderr, "--scanner backing up\n" );
- else if ( yy_act < 46 )
+ else if ( yy_act < 51 )
fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
(long)yy_rule_linenum[yy_act], yytext );
- else if ( yy_act == 46 )
+ else if ( yy_act == 51 )
fprintf( stderr, "--accepting default rule (\"%s\")\n",
yytext );
- else if ( yy_act == 47 )
+ else if ( yy_act == 52 )
fprintf( stderr, "--(end of buffer or a NUL)\n" );
else
fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@ -1431,78 +1451,103 @@ return isc::eval::EvalParser::make_TRANSID(loc);
case 33:
YY_RULE_SETUP
#line 168 "lexer.ll"
-return isc::eval::EvalParser::make_SUBSTRING(loc);
+return isc::eval::EvalParser::make_VENDOR(loc);
YY_BREAK
case 34:
YY_RULE_SETUP
#line 169 "lexer.ll"
-return isc::eval::EvalParser::make_ALL(loc);
+return isc::eval::EvalParser::make_VENDOR_CLASS(loc);
YY_BREAK
case 35:
YY_RULE_SETUP
#line 170 "lexer.ll"
-return isc::eval::EvalParser::make_CONCAT(loc);
+return isc::eval::EvalParser::make_DATA(loc);
YY_BREAK
case 36:
YY_RULE_SETUP
#line 171 "lexer.ll"
-return isc::eval::EvalParser::make_NOT(loc);
+return isc::eval::EvalParser::make_ENTERPRISE(loc);
YY_BREAK
case 37:
YY_RULE_SETUP
#line 172 "lexer.ll"
-return isc::eval::EvalParser::make_AND(loc);
+return isc::eval::EvalParser::make_SUBSTRING(loc);
YY_BREAK
case 38:
YY_RULE_SETUP
#line 173 "lexer.ll"
-return isc::eval::EvalParser::make_OR(loc);
+return isc::eval::EvalParser::make_ALL(loc);
YY_BREAK
case 39:
YY_RULE_SETUP
#line 174 "lexer.ll"
-return isc::eval::EvalParser::make_DOT(loc);
+return isc::eval::EvalParser::make_CONCAT(loc);
YY_BREAK
case 40:
YY_RULE_SETUP
#line 175 "lexer.ll"
-return isc::eval::EvalParser::make_LPAREN(loc);
+return isc::eval::EvalParser::make_NOT(loc);
YY_BREAK
case 41:
YY_RULE_SETUP
#line 176 "lexer.ll"
-return isc::eval::EvalParser::make_RPAREN(loc);
+return isc::eval::EvalParser::make_AND(loc);
YY_BREAK
case 42:
YY_RULE_SETUP
#line 177 "lexer.ll"
-return isc::eval::EvalParser::make_LBRACKET(loc);
+return isc::eval::EvalParser::make_OR(loc);
YY_BREAK
case 43:
YY_RULE_SETUP
#line 178 "lexer.ll"
-return isc::eval::EvalParser::make_RBRACKET(loc);
+return isc::eval::EvalParser::make_DOT(loc);
YY_BREAK
case 44:
YY_RULE_SETUP
#line 179 "lexer.ll"
-return isc::eval::EvalParser::make_COMA(loc);
+return isc::eval::EvalParser::make_LPAREN(loc);
YY_BREAK
case 45:
YY_RULE_SETUP
-#line 181 "lexer.ll"
-driver.error (loc, "Invalid character: " + std::string(yytext));
- YY_BREAK
-case YY_STATE_EOF(INITIAL):
-#line 182 "lexer.ll"
-return isc::eval::EvalParser::make_END(loc);
+#line 180 "lexer.ll"
+return isc::eval::EvalParser::make_RPAREN(loc);
YY_BREAK
case 46:
YY_RULE_SETUP
+#line 181 "lexer.ll"
+return isc::eval::EvalParser::make_LBRACKET(loc);
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 182 "lexer.ll"
+return isc::eval::EvalParser::make_RBRACKET(loc);
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
#line 183 "lexer.ll"
+return isc::eval::EvalParser::make_COMA(loc);
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 184 "lexer.ll"
+return isc::eval::EvalParser::make_ANY(loc);
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 185 "lexer.ll"
+driver.error (loc, "Invalid character: " + std::string(yytext));
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+#line 186 "lexer.ll"
+return isc::eval::EvalParser::make_END(loc);
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 187 "lexer.ll"
ECHO;
YY_BREAK
-#line 1506 "lexer.cc"
+#line 1551 "lexer.cc"
case YY_END_OF_BUFFER:
{
@@ -1744,9 +1789,9 @@ static int yy_get_next_buffer (void)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
- if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
- yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
@@ -1787,7 +1832,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 173 )
+ if ( yy_current_state >= 198 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1815,11 +1860,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 173 )
+ if ( yy_current_state >= 198 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 172);
+ yy_is_jam = (yy_current_state == 197);
if ( ! yy_is_jam )
*(yy_state_ptr)++ = yy_current_state;
@@ -2212,7 +2257,7 @@ static void yyensure_buffer_stack (void)
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
*/
- num_to_alloc = 1; // After all that talk, this was set to 1 anyways...
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
@@ -2585,7 +2630,7 @@ void yyfree (void * ptr )
/* %ok-for-header */
-#line 183 "lexer.ll"
+#line 187 "lexer.ll"
diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll
index f7e489b339..fdefcecd63 100644
--- a/src/lib/eval/lexer.ll
+++ b/src/lib/eval/lexer.ll
@@ -140,44 +140,48 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
return isc::eval::EvalParser::make_IP_ADDRESS(yytext, loc);
}
-"==" return isc::eval::EvalParser::make_EQUAL(loc);
-"option" return isc::eval::EvalParser::make_OPTION(loc);
-"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
-"relay6" return isc::eval::EvalParser::make_RELAY6(loc);
-"peeraddr" return isc::eval::EvalParser::make_PEERADDR(loc);
-"linkaddr" return isc::eval::EvalParser::make_LINKADDR(loc);
-"text" return isc::eval::EvalParser::make_TEXT(loc);
-"hex" return isc::eval::EvalParser::make_HEX(loc);
-"exists" return isc::eval::EvalParser::make_EXISTS(loc);
-"pkt" return isc::eval::EvalParser::make_PKT(loc);
-"iface" return isc::eval::EvalParser::make_IFACE(loc);
-"src" return isc::eval::EvalParser::make_SRC(loc);
-"dst" return isc::eval::EvalParser::make_DST(loc);
-"len" return isc::eval::EvalParser::make_LEN(loc);
-"pkt4" return isc::eval::EvalParser::make_PKT4(loc);
-"mac" return isc::eval::EvalParser::make_CHADDR(loc);
-"hlen" return isc::eval::EvalParser::make_HLEN(loc);
-"htype" return isc::eval::EvalParser::make_HTYPE(loc);
-"ciaddr" return isc::eval::EvalParser::make_CIADDR(loc);
-"giaddr" return isc::eval::EvalParser::make_GIADDR(loc);
-"yiaddr" return isc::eval::EvalParser::make_YIADDR(loc);
-"siaddr" return isc::eval::EvalParser::make_SIADDR(loc);
-"pkt6" return isc::eval::EvalParser::make_PKT6(loc);
-"msgtype" return isc::eval::EvalParser::make_MSGTYPE(loc);
-"transid" return isc::eval::EvalParser::make_TRANSID(loc);
-"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
-"all" return isc::eval::EvalParser::make_ALL(loc);
-"concat" return isc::eval::EvalParser::make_CONCAT(loc);
-"not" return isc::eval::EvalParser::make_NOT(loc);
-"and" return isc::eval::EvalParser::make_AND(loc);
-"or" return isc::eval::EvalParser::make_OR(loc);
-"." return isc::eval::EvalParser::make_DOT(loc);
-"(" return isc::eval::EvalParser::make_LPAREN(loc);
-")" return isc::eval::EvalParser::make_RPAREN(loc);
-"[" return isc::eval::EvalParser::make_LBRACKET(loc);
-"]" return isc::eval::EvalParser::make_RBRACKET(loc);
-"," return isc::eval::EvalParser::make_COMA(loc);
-
+"==" return isc::eval::EvalParser::make_EQUAL(loc);
+"option" return isc::eval::EvalParser::make_OPTION(loc);
+"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
+"relay6" return isc::eval::EvalParser::make_RELAY6(loc);
+"peeraddr" return isc::eval::EvalParser::make_PEERADDR(loc);
+"linkaddr" return isc::eval::EvalParser::make_LINKADDR(loc);
+"text" return isc::eval::EvalParser::make_TEXT(loc);
+"hex" return isc::eval::EvalParser::make_HEX(loc);
+"exists" return isc::eval::EvalParser::make_EXISTS(loc);
+"pkt" return isc::eval::EvalParser::make_PKT(loc);
+"iface" return isc::eval::EvalParser::make_IFACE(loc);
+"src" return isc::eval::EvalParser::make_SRC(loc);
+"dst" return isc::eval::EvalParser::make_DST(loc);
+"len" return isc::eval::EvalParser::make_LEN(loc);
+"pkt4" return isc::eval::EvalParser::make_PKT4(loc);
+"mac" return isc::eval::EvalParser::make_CHADDR(loc);
+"hlen" return isc::eval::EvalParser::make_HLEN(loc);
+"htype" return isc::eval::EvalParser::make_HTYPE(loc);
+"ciaddr" return isc::eval::EvalParser::make_CIADDR(loc);
+"giaddr" return isc::eval::EvalParser::make_GIADDR(loc);
+"yiaddr" return isc::eval::EvalParser::make_YIADDR(loc);
+"siaddr" return isc::eval::EvalParser::make_SIADDR(loc);
+"pkt6" return isc::eval::EvalParser::make_PKT6(loc);
+"msgtype" return isc::eval::EvalParser::make_MSGTYPE(loc);
+"transid" return isc::eval::EvalParser::make_TRANSID(loc);
+"vendor" return isc::eval::EvalParser::make_VENDOR(loc);
+"vendor-class" return isc::eval::EvalParser::make_VENDOR_CLASS(loc);
+"data" return isc::eval::EvalParser::make_DATA(loc);
+"enterprise" return isc::eval::EvalParser::make_ENTERPRISE(loc);
+"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
+"all" return isc::eval::EvalParser::make_ALL(loc);
+"concat" return isc::eval::EvalParser::make_CONCAT(loc);
+"not" return isc::eval::EvalParser::make_NOT(loc);
+"and" return isc::eval::EvalParser::make_AND(loc);
+"or" return isc::eval::EvalParser::make_OR(loc);
+"." return isc::eval::EvalParser::make_DOT(loc);
+"(" return isc::eval::EvalParser::make_LPAREN(loc);
+")" return isc::eval::EvalParser::make_RPAREN(loc);
+"[" return isc::eval::EvalParser::make_LBRACKET(loc);
+"]" return isc::eval::EvalParser::make_RBRACKET(loc);
+"," return isc::eval::EvalParser::make_COMA(loc);
+"*" return isc::eval::EvalParser::make_ANY(loc);
. driver.error (loc, "Invalid character: " + std::string(yytext));
<> return isc::eval::EvalParser::make_END(loc);
%%
diff --git a/src/lib/eval/location.hh b/src/lib/eval/location.hh
index 3a91a8f6cd..effaa15add 100644
--- a/src/lib/eval/location.hh
+++ b/src/lib/eval/location.hh
@@ -1,4 +1,3 @@
-// Generated 201608161508
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++
diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc
index fdcbab31c9..8504c3d485 100644
--- a/src/lib/eval/parser.cc
+++ b/src/lib/eval/parser.cc
@@ -251,39 +251,43 @@ namespace isc { namespace eval {
{
switch (that.type_get ())
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
value.move< TokenOption::RepresentationType > (that.value);
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
value.move< TokenPkt4::FieldType > (that.value);
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
value.move< TokenPkt6::FieldType > (that.value);
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
value.move< TokenPkt::MetadataType > (that.value);
break;
- case 55: // relay6_field
+ case 61: // relay6_field
value.move< TokenRelay6Field::FieldType > (that.value);
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
value.move< std::string > (that.value);
break;
- case 49: // option_code
+ case 54: // option_code
value.move< uint16_t > (that.value);
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ value.move< uint32_t > (that.value);
+ break;
+
+ case 56: // nest_level
value.move< uint8_t > (that.value);
break;
@@ -302,39 +306,43 @@ namespace isc { namespace eval {
state = that.state;
switch (that.type_get ())
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
value.copy< TokenOption::RepresentationType > (that.value);
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
value.copy< TokenPkt4::FieldType > (that.value);
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
value.copy< TokenPkt6::FieldType > (that.value);
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
value.copy< TokenPkt::MetadataType > (that.value);
break;
- case 55: // relay6_field
+ case 61: // relay6_field
value.copy< TokenRelay6Field::FieldType > (that.value);
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
value.copy< std::string > (that.value);
break;
- case 49: // option_code
+ case 54: // option_code
value.copy< uint16_t > (that.value);
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ value.copy< uint32_t > (that.value);
+ break;
+
+ case 56: // nest_level
value.copy< uint8_t > (that.value);
break;
@@ -374,88 +382,95 @@ namespace isc { namespace eval {
<< yysym.location << ": ";
switch (yytype)
{
- case 40: // "constant string"
+ case 45: // "constant string"
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 382 "parser.cc" // lalr1.cc:636
+#line 390 "parser.cc" // lalr1.cc:636
break;
- case 41: // "integer"
+ case 46: // "integer"
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 389 "parser.cc" // lalr1.cc:636
+#line 397 "parser.cc" // lalr1.cc:636
break;
- case 42: // "constant hexstring"
+ case 47: // "constant hexstring"
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 396 "parser.cc" // lalr1.cc:636
+#line 404 "parser.cc" // lalr1.cc:636
break;
- case 43: // "option name"
+ case 48: // "option name"
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 403 "parser.cc" // lalr1.cc:636
+#line 411 "parser.cc" // lalr1.cc:636
break;
- case 44: // "ip address"
+ case 49: // "ip address"
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 410 "parser.cc" // lalr1.cc:636
+#line 418 "parser.cc" // lalr1.cc:636
break;
- case 49: // option_code
+ case 54: // option_code
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< uint16_t > (); }
-#line 417 "parser.cc" // lalr1.cc:636
+#line 425 "parser.cc" // lalr1.cc:636
break;
- case 50: // option_repr_type
+ case 55: // option_repr_type
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); }
-#line 424 "parser.cc" // lalr1.cc:636
+#line 432 "parser.cc" // lalr1.cc:636
break;
- case 51: // nest_level
+ case 56: // nest_level
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< uint8_t > (); }
-#line 431 "parser.cc" // lalr1.cc:636
+#line 439 "parser.cc" // lalr1.cc:636
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenPkt::MetadataType > (); }
-#line 438 "parser.cc" // lalr1.cc:636
+#line 446 "parser.cc" // lalr1.cc:636
break;
- case 53: // pkt4_field
+ case 58: // enterprise_id
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
+ { yyoutput << yysym.value.template as< uint32_t > (); }
+#line 453 "parser.cc" // lalr1.cc:636
+ break;
+
+ case 59: // pkt4_field
+
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenPkt4::FieldType > (); }
-#line 445 "parser.cc" // lalr1.cc:636
+#line 460 "parser.cc" // lalr1.cc:636
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenPkt6::FieldType > (); }
-#line 452 "parser.cc" // lalr1.cc:636
+#line 467 "parser.cc" // lalr1.cc:636
break;
- case 55: // relay6_field
+ case 61: // relay6_field
-#line 97 "parser.yy" // lalr1.cc:636
+#line 103 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenRelay6Field::FieldType > (); }
-#line 459 "parser.cc" // lalr1.cc:636
+#line 474 "parser.cc" // lalr1.cc:636
break;
@@ -655,39 +670,43 @@ namespace isc { namespace eval {
when using variants. */
switch (yyr1_[yyn])
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
yylhs.value.build< TokenOption::RepresentationType > ();
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
yylhs.value.build< TokenPkt4::FieldType > ();
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
yylhs.value.build< TokenPkt6::FieldType > ();
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
yylhs.value.build< TokenPkt::MetadataType > ();
break;
- case 55: // relay6_field
+ case 61: // relay6_field
yylhs.value.build< TokenRelay6Field::FieldType > ();
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
yylhs.value.build< std::string > ();
break;
- case 49: // option_code
+ case 54: // option_code
yylhs.value.build< uint16_t > ();
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ yylhs.value.build< uint32_t > ();
+ break;
+
+ case 56: // nest_level
yylhs.value.build< uint8_t > ();
break;
@@ -709,52 +728,52 @@ namespace isc { namespace eval {
switch (yyn)
{
case 4:
-#line 111 "parser.yy" // lalr1.cc:859
+#line 117 "parser.yy" // lalr1.cc:859
{
TokenPtr neg(new TokenNot());
ctx.expression.push_back(neg);
}
-#line 718 "parser.cc" // lalr1.cc:859
+#line 737 "parser.cc" // lalr1.cc:859
break;
case 5:
-#line 116 "parser.yy" // lalr1.cc:859
+#line 122 "parser.yy" // lalr1.cc:859
{
TokenPtr neg(new TokenAnd());
ctx.expression.push_back(neg);
}
-#line 727 "parser.cc" // lalr1.cc:859
+#line 746 "parser.cc" // lalr1.cc:859
break;
case 6:
-#line 121 "parser.yy" // lalr1.cc:859
+#line 127 "parser.yy" // lalr1.cc:859
{
TokenPtr neg(new TokenOr());
ctx.expression.push_back(neg);
}
-#line 736 "parser.cc" // lalr1.cc:859
+#line 755 "parser.cc" // lalr1.cc:859
break;
case 7:
-#line 126 "parser.yy" // lalr1.cc:859
+#line 132 "parser.yy" // lalr1.cc:859
{
TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq);
}
-#line 745 "parser.cc" // lalr1.cc:859
+#line 764 "parser.cc" // lalr1.cc:859
break;
case 8:
-#line 131 "parser.yy" // lalr1.cc:859
+#line 137 "parser.yy" // lalr1.cc:859
{
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS));
ctx.expression.push_back(opt);
}
-#line 754 "parser.cc" // lalr1.cc:859
+#line 773 "parser.cc" // lalr1.cc:859
break;
case 9:
-#line 136 "parser.yy" // lalr1.cc:859
+#line 142 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V4:
@@ -774,11 +793,11 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
}
}
-#line 778 "parser.cc" // lalr1.cc:859
+#line 797 "parser.cc" // lalr1.cc:859
break;
case 10:
-#line 156 "parser.yy" // lalr1.cc:859
+#line 162 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V6:
@@ -792,47 +811,87 @@ namespace isc { namespace eval {
error(yystack_[10].location, "relay6 can only be used in DHCPv6.");
}
}
-#line 796 "parser.cc" // lalr1.cc:859
+#line 815 "parser.cc" // lalr1.cc:859
break;
case 11:
-#line 172 "parser.yy" // lalr1.cc:859
+#line 176 "parser.yy" // lalr1.cc:859
+ {
+ // Expression: vendor-class[1234].exists
+ //
+ // This token will find option 124 (DHCPv4) or 16 (DHCPv6),
+ // and will check if enterprise-id equals specified value.
+ TokenPtr exist(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS));
+ ctx.expression.push_back(exist);
+ }
+#line 828 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 12:
+#line 185 "parser.yy" // lalr1.cc:859
+ {
+ // Expression: vendor[1234].exists
+ //
+ // This token will find option 125 (DHCPv4) or 17 (DHCPv6),
+ // and will check if enterprise-id equals specified value.
+ TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS));
+ ctx.expression.push_back(exist);
+ }
+#line 841 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 13:
+#line 194 "parser.yy" // lalr1.cc:859
+ {
+ // Expression vendor[1234].option[123].exists
+ //
+ // This token will check if specified vendor option
+ // exists, has specified enterprise-id and if has
+ // specified suboption.
+ TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), TokenOption::EXISTS, yystack_[3].value.as< uint16_t > ()));
+ ctx.expression.push_back(exist);
+ }
+#line 855 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 14:
+#line 206 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
-#line 805 "parser.cc" // lalr1.cc:859
+#line 864 "parser.cc" // lalr1.cc:859
break;
- case 12:
-#line 177 "parser.yy" // lalr1.cc:859
+ case 15:
+#line 211 "parser.yy" // lalr1.cc:859
{
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(hex);
}
-#line 814 "parser.cc" // lalr1.cc:859
+#line 873 "parser.cc" // lalr1.cc:859
break;
- case 13:
-#line 182 "parser.yy" // lalr1.cc:859
+ case 16:
+#line 216 "parser.yy" // lalr1.cc:859
{
TokenPtr ip(new TokenIpAddress(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(ip);
}
-#line 823 "parser.cc" // lalr1.cc:859
+#line 882 "parser.cc" // lalr1.cc:859
break;
- case 14:
-#line 187 "parser.yy" // lalr1.cc:859
+ case 17:
+#line 221 "parser.yy" // lalr1.cc:859
{
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ()));
ctx.expression.push_back(opt);
}
-#line 832 "parser.cc" // lalr1.cc:859
+#line 891 "parser.cc" // lalr1.cc:859
break;
- case 15:
-#line 192 "parser.yy" // lalr1.cc:859
+ case 18:
+#line 226 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V4:
@@ -852,11 +911,11 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
}
}
-#line 856 "parser.cc" // lalr1.cc:859
+#line 915 "parser.cc" // lalr1.cc:859
break;
- case 16:
-#line 213 "parser.yy" // lalr1.cc:859
+ case 19:
+#line 247 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V6:
@@ -870,20 +929,20 @@ namespace isc { namespace eval {
error(yystack_[10].location, "relay6 can only be used in DHCPv6.");
}
}
-#line 874 "parser.cc" // lalr1.cc:859
+#line 933 "parser.cc" // lalr1.cc:859
break;
- case 17:
-#line 228 "parser.yy" // lalr1.cc:859
+ case 20:
+#line 262 "parser.yy" // lalr1.cc:859
{
TokenPtr pkt_metadata(new TokenPkt(yystack_[0].value.as< TokenPkt::MetadataType > ()));
ctx.expression.push_back(pkt_metadata);
}
-#line 883 "parser.cc" // lalr1.cc:859
+#line 942 "parser.cc" // lalr1.cc:859
break;
- case 18:
-#line 233 "parser.yy" // lalr1.cc:859
+ case 21:
+#line 267 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V4:
@@ -897,11 +956,11 @@ namespace isc { namespace eval {
error(yystack_[2].location, "pkt4 can only be used in DHCPv4.");
}
}
-#line 901 "parser.cc" // lalr1.cc:859
+#line 960 "parser.cc" // lalr1.cc:859
break;
- case 19:
-#line 247 "parser.yy" // lalr1.cc:859
+ case 22:
+#line 281 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V6:
@@ -915,11 +974,11 @@ namespace isc { namespace eval {
error(yystack_[2].location, "pkt6 can only be used in DHCPv6.");
}
}
-#line 919 "parser.cc" // lalr1.cc:859
+#line 978 "parser.cc" // lalr1.cc:859
break;
- case 20:
-#line 261 "parser.yy" // lalr1.cc:859
+ case 23:
+#line 295 "parser.yy" // lalr1.cc:859
{
switch (ctx.getUniverse()) {
case Option::V6:
@@ -933,216 +992,306 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay6 can only be used in DHCPv6.");
}
}
-#line 937 "parser.cc" // lalr1.cc:859
+#line 996 "parser.cc" // lalr1.cc:859
break;
- case 21:
-#line 276 "parser.yy" // lalr1.cc:859
+ case 24:
+#line 310 "parser.yy" // lalr1.cc:859
{
TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub);
}
-#line 946 "parser.cc" // lalr1.cc:859
+#line 1005 "parser.cc" // lalr1.cc:859
break;
- case 22:
-#line 281 "parser.yy" // lalr1.cc:859
+ case 25:
+#line 315 "parser.yy" // lalr1.cc:859
{
TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc);
}
-#line 955 "parser.cc" // lalr1.cc:859
- break;
-
- case 23:
-#line 288 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
- }
-#line 963 "parser.cc" // lalr1.cc:859
- break;
-
- case 24:
-#line 292 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location);
- }
-#line 971 "parser.cc" // lalr1.cc:859
- break;
-
- case 25:
-#line 298 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
- }
-#line 979 "parser.cc" // lalr1.cc:859
+#line 1014 "parser.cc" // lalr1.cc:859
break;
case 26:
-#line 302 "parser.yy" // lalr1.cc:859
+#line 320 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
- }
-#line 987 "parser.cc" // lalr1.cc:859
- break;
-
- case 27:
-#line 308 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location);
- }
-#line 995 "parser.cc" // lalr1.cc:859
- break;
-
- case 28:
-#line 317 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::IFACE;
- }
-#line 1003 "parser.cc" // lalr1.cc:859
- break;
-
- case 29:
-#line 321 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::SRC;
- }
-#line 1011 "parser.cc" // lalr1.cc:859
- break;
-
- case 30:
-#line 325 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::DST;
- }
-#line 1019 "parser.cc" // lalr1.cc:859
- break;
-
- case 31:
-#line 329 "parser.yy" // lalr1.cc:859
- {
- yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::LEN;
- }
+ // expression: vendor.enterprise
+ //
+ // This token will return enterprise-id number of
+ // received vendor option.
+ TokenPtr vendor(new TokenVendor(ctx.getUniverse(), 0, TokenVendor::ENTERPRISE_ID));
+ ctx.expression.push_back(vendor);
+ }
#line 1027 "parser.cc" // lalr1.cc:859
break;
- case 32:
-#line 335 "parser.yy" // lalr1.cc:859
+ case 27:
+#line 329 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CHADDR;
+ // expression: vendor-class.enterprise
+ //
+ // This token will return enterprise-id number of
+ // received vendor class option.
+ TokenPtr vendor(new TokenVendorClass(ctx.getUniverse(), 0,
+ TokenVendor::ENTERPRISE_ID));
+ ctx.expression.push_back(vendor);
}
-#line 1035 "parser.cc" // lalr1.cc:859
+#line 1041 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 28:
+#line 339 "parser.yy" // lalr1.cc:859
+ {
+ // This token will search for vendor option with
+ // specified enterprise-id. If found, will search
+ // for specified suboption and finally will return
+ // its content.
+ TokenPtr opt(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), yystack_[0].value.as< TokenOption::RepresentationType > (), yystack_[3].value.as< uint16_t > ()));
+ ctx.expression.push_back(opt);
+ }
+#line 1054 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 29:
+#line 348 "parser.yy" // lalr1.cc:859
+ {
+ // expression: vendor-class[1234].data
+ //
+ // Vendor class option does not have suboptions,
+ // but chunks of data (typically 1, but the option
+ // structure allows multiple of them). If chunk
+ // offset is not specified, we assume the first (0th)
+ // is requested.
+ TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (),
+ TokenVendor::DATA, 0));
+ ctx.expression.push_back(vendor_class);
+ }
+#line 1071 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 30:
+#line 361 "parser.yy" // lalr1.cc:859
+ {
+ // expression: vendor-class[1234].data[5]
+ //
+ // Vendor class option does not have suboptions,
+ // but chunks of data (typically 1, but the option
+ // structure allows multiple of them). This syntax
+ // specifies which data chunk (tuple) we want.
+ uint8_t index = ctx.convertUint8(yystack_[1].value.as< std::string > (), yystack_[1].location);
+ TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[6].value.as< uint32_t > (),
+ TokenVendor::DATA, index));
+ ctx.expression.push_back(vendor_class);
+ }
+#line 1088 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 31:
+#line 376 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
+ }
+#line 1096 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 32:
+#line 380 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location);
+ }
+#line 1104 "parser.cc" // lalr1.cc:859
break;
case 33:
-#line 339 "parser.yy" // lalr1.cc:859
+#line 386 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HLEN;
- }
-#line 1043 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
+ }
+#line 1112 "parser.cc" // lalr1.cc:859
break;
case 34:
-#line 343 "parser.yy" // lalr1.cc:859
+#line 390 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HTYPE;
- }
-#line 1051 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
+ }
+#line 1120 "parser.cc" // lalr1.cc:859
break;
case 35:
-#line 347 "parser.yy" // lalr1.cc:859
+#line 396 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CIADDR;
- }
-#line 1059 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location);
+ }
+#line 1128 "parser.cc" // lalr1.cc:859
break;
case 36:
-#line 351 "parser.yy" // lalr1.cc:859
+#line 405 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::GIADDR;
- }
-#line 1067 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::IFACE;
+ }
+#line 1136 "parser.cc" // lalr1.cc:859
break;
case 37:
-#line 355 "parser.yy" // lalr1.cc:859
+#line 409 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::YIADDR;
- }
-#line 1075 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::SRC;
+ }
+#line 1144 "parser.cc" // lalr1.cc:859
break;
case 38:
-#line 359 "parser.yy" // lalr1.cc:859
+#line 413 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::SIADDR;
- }
-#line 1083 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::DST;
+ }
+#line 1152 "parser.cc" // lalr1.cc:859
break;
case 39:
-#line 365 "parser.yy" // lalr1.cc:859
+#line 417 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::MSGTYPE;
- }
-#line 1091 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenPkt::MetadataType > () = TokenPkt::LEN;
+ }
+#line 1160 "parser.cc" // lalr1.cc:859
break;
case 40:
-#line 369 "parser.yy" // lalr1.cc:859
+#line 423 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::TRANSID;
- }
-#line 1099 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< uint32_t > () = ctx.convertUint32(yystack_[0].value.as< std::string > (), yystack_[0].location);
+ }
+#line 1168 "parser.cc" // lalr1.cc:859
break;
case 41:
-#line 375 "parser.yy" // lalr1.cc:859
+#line 427 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::PEERADDR;
+ yylhs.value.as< uint32_t > () = 0;
}
-#line 1107 "parser.cc" // lalr1.cc:859
+#line 1176 "parser.cc" // lalr1.cc:859
break;
case 42:
-#line 379 "parser.yy" // lalr1.cc:859
+#line 433 "parser.yy" // lalr1.cc:859
{
- yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::LINKADDR;
- }
-#line 1115 "parser.cc" // lalr1.cc:859
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CHADDR;
+ }
+#line 1184 "parser.cc" // lalr1.cc:859
break;
case 43:
-#line 385 "parser.yy" // lalr1.cc:859
+#line 437 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HLEN;
+ }
+#line 1192 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 44:
+#line 441 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HTYPE;
+ }
+#line 1200 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 45:
+#line 445 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CIADDR;
+ }
+#line 1208 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 46:
+#line 449 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::GIADDR;
+ }
+#line 1216 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 47:
+#line 453 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::YIADDR;
+ }
+#line 1224 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 48:
+#line 457 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::SIADDR;
+ }
+#line 1232 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 49:
+#line 463 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::MSGTYPE;
+ }
+#line 1240 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 50:
+#line 467 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::TRANSID;
+ }
+#line 1248 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 51:
+#line 473 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::PEERADDR;
+ }
+#line 1256 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 52:
+#line 477 "parser.yy" // lalr1.cc:859
+ {
+ yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::LINKADDR;
+ }
+#line 1264 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 53:
+#line 483 "parser.yy" // lalr1.cc:859
+ {
+ TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
+ ctx.expression.push_back(str);
+ }
+#line 1273 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 54:
+#line 490 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
-#line 1124 "parser.cc" // lalr1.cc:859
+#line 1282 "parser.cc" // lalr1.cc:859
break;
- case 44:
-#line 392 "parser.yy" // lalr1.cc:859
- {
- TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
- ctx.expression.push_back(str);
- }
-#line 1133 "parser.cc" // lalr1.cc:859
- break;
-
- case 45:
-#line 397 "parser.yy" // lalr1.cc:859
+ case 55:
+#line 495 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString("all"));
ctx.expression.push_back(str);
}
-#line 1142 "parser.cc" // lalr1.cc:859
+#line 1291 "parser.cc" // lalr1.cc:859
break;
-#line 1146 "parser.cc" // lalr1.cc:859
+#line 1295 "parser.cc" // lalr1.cc:859
default:
break;
}
@@ -1397,127 +1546,151 @@ namespace isc { namespace eval {
}
- const signed char EvalParser::yypact_ninf_ = -70;
+ const signed char EvalParser::yypact_ninf_ = -89;
const signed char EvalParser::yytable_ninf_ = -1;
- const signed char
+ const short int
EvalParser::yypact_[] =
{
- 15, 15, 15, -13, 7, 14, -9, 25, 34, 53,
- 67, -70, -70, -70, 58, 37, 75, 32, -70, -12,
- -12, 45, 42, -17, -18, 51, 51, -70, 15, 15,
- 51, -70, -70, -70, 73, 74, -70, 77, -70, -70,
- -70, -70, -70, -70, -70, -70, -70, -70, -70, -70,
- -70, -70, -70, -70, 61, 80, 82, 59, 62, -70,
- 92, -70, 83, 85, 86, -12, -12, 45, 64, 51,
- 50, 60, 10, 88, 89, 91, -70, 69, 104, -70,
- -70, -70, -70, -70, -70, 95, -70, -70, -70, 94,
- 96, 97, -7, -70, -12, 55, 55, 40, -70, -70,
- 107, 99, 101, -70, 100, -12, 63, 102, -70, -70,
- 103, 55
+ 4, 4, 4, 11, 18, 46, 69, 70, 93, 94,
+ 85, -6, 36, -89, -89, -89, 105, 32, 100, 77,
+ -89, 58, 58, 71, 67, 48, 62, 62, 26, -11,
+ 72, -11, 76, -89, 4, 4, 62, -89, -89, -89,
+ 106, 107, -89, 108, -89, -89, -89, -89, -89, -89,
+ -89, -89, -89, -89, -89, -89, -89, 110, 111, 112,
+ 98, 99, 92, 95, -89, -89, -89, -89, -89, 113,
+ -89, 114, -89, -89, 125, -89, 116, 117, 118, 58,
+ 58, 71, -11, -11, 89, 62, 120, 121, 1, 29,
+ 14, 123, 124, 126, 127, 128, -89, 109, 136, -15,
+ -3, -89, -89, -89, -89, -89, -89, 131, -89, -89,
+ -89, 130, 132, 133, 134, 135, -29, -89, -89, 138,
+ 139, -89, 58, 25, 25, 21, 104, 145, -89, -89,
+ 151, 115, 58, 141, 143, 144, -89, 147, 148, 149,
+ 58, 58, -89, 150, 51, 152, 153, 75, -89, -89,
+ 154, 155, -89, -89, 25, 25
};
const unsigned char
EvalParser::yydefact_[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 11, 12, 13, 0, 2, 0, 0, 4, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- 0, 3, 23, 24, 0, 0, 27, 0, 28, 29,
- 30, 31, 17, 32, 33, 34, 35, 36, 37, 38,
- 18, 39, 40, 19, 0, 0, 0, 0, 0, 5,
- 6, 7, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 43, 0, 0, 25,
- 26, 8, 14, 9, 15, 0, 41, 42, 20, 0,
- 0, 0, 0, 22, 0, 0, 0, 0, 45, 44,
- 0, 0, 0, 21, 0, 0, 0, 0, 10, 16,
- 0, 0
+ 0, 0, 0, 14, 15, 16, 0, 2, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 3, 31, 32,
+ 0, 0, 35, 0, 36, 37, 38, 39, 20, 42,
+ 43, 44, 45, 46, 47, 48, 21, 0, 0, 0,
+ 0, 0, 0, 0, 49, 50, 22, 41, 40, 0,
+ 27, 0, 26, 5, 6, 7, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 53, 0, 0, 0,
+ 0, 33, 34, 8, 17, 9, 18, 0, 51, 52,
+ 23, 0, 0, 0, 0, 0, 0, 25, 11, 29,
+ 0, 12, 0, 0, 0, 0, 0, 0, 55, 54,
+ 0, 0, 0, 0, 0, 0, 24, 0, 0, 0,
+ 0, 0, 30, 0, 0, 0, 0, 0, 10, 19,
+ 0, 0, 13, 28, 0, 0
};
const signed char
EvalParser::yypgoto_[] =
{
- -70, -70, 4, -22, -20, -69, 54, -70, -70, -70,
- -70, -70, -70
+ -89, -89, 20, -24, -22, -88, 78, -89, -20, -89,
+ -89, -89, -89, -89
};
- const signed char
+ const short int
EvalParser::yydefgoto_[] =
{
- -1, 14, 15, 16, 34, 82, 37, 42, 50, 53,
- 88, 77, 100
+ -1, 16, 17, 18, 40, 104, 43, 48, 69, 56,
+ 66, 110, 97, 130
};
const unsigned char
EvalParser::yytable_[] =
{
- 35, 19, 84, 57, 58, 17, 18, 22, 61, 43,
- 44, 45, 46, 47, 48, 49, 51, 52, 1, 85,
- 2, 20, 86, 87, 3, 4, 5, 84, 21, 32,
- 98, 33, 59, 60, 99, 6, 31, 109, 28, 29,
- 7, 23, 109, 28, 29, 73, 74, 78, 8, 102,
- 24, 9, 86, 87, 10, 11, 25, 12, 27, 13,
- 54, 55, 56, 38, 39, 40, 41, 79, 80, 81,
- 26, 6, 79, 80, 101, 65, 7, 79, 80, 83,
- 79, 80, 108, 30, 8, 107, 36, 9, 62, 63,
- 10, 11, 64, 12, 66, 13, 67, 68, 28, 70,
- 69, 71, 72, 89, 90, 76, 91, 92, 93, 94,
- 95, 103, 96, 97, 104, 105, 106, 110, 0, 111,
- 0, 75
+ 41, 106, 62, 63, 118, 128, 120, 1, 29, 2,
+ 30, 71, 75, 3, 4, 5, 121, 129, 101, 102,
+ 103, 19, 20, 107, 6, 21, 108, 109, 119, 7,
+ 134, 67, 22, 108, 109, 68, 106, 8, 34, 35,
+ 9, 10, 101, 102, 11, 12, 101, 102, 105, 13,
+ 31, 14, 32, 15, 73, 74, 149, 91, 92, 153,
+ 23, 98, 94, 95, 64, 65, 149, 153, 101, 102,
+ 148, 57, 58, 59, 49, 50, 51, 52, 53, 54,
+ 55, 37, 6, 34, 35, 24, 25, 7, 44, 45,
+ 46, 47, 101, 102, 152, 8, 26, 27, 9, 10,
+ 133, 28, 60, 61, 38, 33, 39, 13, 36, 14,
+ 138, 15, 82, 83, 30, 32, 70, 42, 145, 146,
+ 72, 76, 77, 78, 79, 80, 81, 84, 86, 87,
+ 85, 34, 88, 89, 90, 96, 99, 100, 111, 112,
+ 117, 113, 114, 115, 116, 122, 123, 119, 124, 125,
+ 126, 127, 131, 132, 135, 136, 139, 140, 141, 93,
+ 0, 137, 142, 143, 0, 144, 147, 150, 151, 0,
+ 154, 155
};
- const signed char
+ const short int
EvalParser::yycheck_[] =
{
- 20, 14, 71, 25, 26, 1, 2, 16, 30, 26,
- 27, 28, 29, 30, 31, 32, 34, 35, 3, 9,
- 5, 14, 12, 13, 9, 10, 11, 96, 14, 41,
- 37, 43, 28, 29, 41, 20, 4, 106, 6, 7,
- 25, 16, 111, 6, 7, 65, 66, 69, 33, 9,
- 16, 36, 12, 13, 39, 40, 3, 42, 0, 44,
- 9, 10, 11, 21, 22, 23, 24, 17, 18, 19,
- 3, 20, 17, 18, 94, 14, 25, 17, 18, 19,
- 17, 18, 19, 8, 33, 105, 41, 36, 15, 15,
- 39, 40, 15, 42, 14, 44, 14, 38, 6, 16,
- 38, 16, 16, 15, 15, 41, 15, 38, 4, 14,
- 16, 4, 16, 16, 15, 14, 16, 15, -1, 16,
- -1, 67
+ 22, 89, 26, 27, 19, 34, 9, 3, 14, 5,
+ 16, 31, 36, 9, 10, 11, 19, 46, 17, 18,
+ 19, 1, 2, 9, 20, 14, 12, 13, 43, 25,
+ 9, 42, 14, 12, 13, 46, 124, 33, 6, 7,
+ 36, 37, 17, 18, 40, 41, 17, 18, 19, 45,
+ 14, 47, 16, 49, 34, 35, 144, 79, 80, 147,
+ 14, 85, 82, 83, 38, 39, 154, 155, 17, 18,
+ 19, 9, 10, 11, 26, 27, 28, 29, 30, 31,
+ 32, 4, 20, 6, 7, 16, 16, 25, 21, 22,
+ 23, 24, 17, 18, 19, 33, 3, 3, 36, 37,
+ 122, 16, 40, 41, 46, 0, 48, 45, 8, 47,
+ 132, 49, 14, 14, 16, 16, 44, 46, 140, 141,
+ 44, 15, 15, 15, 14, 14, 14, 35, 15, 15,
+ 35, 6, 16, 16, 16, 46, 16, 16, 15, 15,
+ 4, 15, 15, 15, 35, 14, 16, 43, 16, 16,
+ 16, 16, 14, 14, 9, 4, 15, 14, 14, 81,
+ -1, 46, 15, 15, -1, 16, 16, 15, 15, -1,
+ 16, 16
};
const unsigned char
EvalParser::yystos_[] =
{
0, 3, 5, 9, 10, 11, 20, 25, 33, 36,
- 39, 40, 42, 44, 46, 47, 48, 47, 47, 14,
- 14, 14, 16, 16, 16, 3, 3, 0, 6, 7,
- 8, 4, 41, 43, 49, 49, 41, 51, 21, 22,
- 23, 24, 52, 26, 27, 28, 29, 30, 31, 32,
- 53, 34, 35, 54, 9, 10, 11, 48, 48, 47,
- 47, 48, 15, 15, 15, 14, 14, 14, 38, 38,
- 16, 16, 16, 49, 49, 51, 41, 56, 48, 17,
- 18, 19, 50, 19, 50, 9, 12, 13, 55, 15,
- 15, 15, 38, 4, 14, 16, 16, 16, 37, 41,
- 57, 49, 9, 4, 15, 14, 16, 49, 19, 50,
- 15, 16
+ 37, 40, 41, 45, 47, 49, 51, 52, 53, 52,
+ 52, 14, 14, 14, 16, 16, 3, 3, 16, 14,
+ 16, 14, 16, 0, 6, 7, 8, 4, 46, 48,
+ 54, 54, 46, 56, 21, 22, 23, 24, 57, 26,
+ 27, 28, 29, 30, 31, 32, 59, 9, 10, 11,
+ 40, 41, 53, 53, 38, 39, 60, 42, 46, 58,
+ 44, 58, 44, 52, 52, 53, 15, 15, 15, 14,
+ 14, 14, 14, 14, 35, 35, 15, 15, 16, 16,
+ 16, 54, 54, 56, 58, 58, 46, 62, 53, 16,
+ 16, 17, 18, 19, 55, 19, 55, 9, 12, 13,
+ 61, 15, 15, 15, 15, 15, 35, 4, 19, 43,
+ 9, 19, 14, 16, 16, 16, 16, 16, 34, 46,
+ 63, 14, 14, 54, 9, 9, 4, 46, 54, 15,
+ 14, 14, 15, 15, 16, 54, 54, 16, 19, 55,
+ 15, 15, 19, 55, 16, 16
};
const unsigned char
EvalParser::yyr1_[] =
{
- 0, 45, 46, 47, 47, 47, 47, 47, 47, 47,
- 47, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 49, 49, 50, 50, 51, 52, 52,
- 52, 52, 53, 53, 53, 53, 53, 53, 53, 54,
- 54, 55, 55, 56, 57, 57
+ 0, 50, 51, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 54, 54, 55, 55, 56, 57, 57, 57, 57,
+ 58, 58, 59, 59, 59, 59, 59, 59, 59, 60,
+ 60, 61, 61, 62, 63, 63
};
const unsigned char
EvalParser::yyr2_[] =
{
0, 2, 1, 3, 2, 3, 3, 3, 6, 6,
- 11, 1, 1, 1, 6, 6, 11, 3, 3, 3,
- 6, 8, 6, 1, 1, 1, 1, 1, 1, 1,
+ 11, 6, 6, 11, 1, 1, 1, 6, 6, 11,
+ 3, 3, 3, 6, 8, 6, 3, 3, 11, 6,
+ 9, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1
};
@@ -1534,24 +1707,26 @@ namespace isc { namespace eval {
"\"peeraddr\"", "\"linkaddr\"", "\"[\"", "\"]\"", "\".\"", "\"text\"",
"\"hex\"", "\"exists\"", "\"pkt\"", "\"iface\"", "\"src\"", "\"dst\"",
"\"len\"", "\"pkt4\"", "\"mac\"", "\"hlen\"", "\"htype\"", "\"ciaddr\"",
- "\"giaddr\"", "\"yiaddr\"", "\"siaddr\"", "\"pkt6\"", "\"msgtype\"",
- "\"transid\"", "\"substring\"", "\"all\"", "\",\"", "\"concat\"",
+ "\"giaddr\"", "\"yiaddr\"", "\"siaddr\"", "\"substring\"", "\"all\"",
+ "\",\"", "\"concat\"", "\"pkt6\"", "\"msgtype\"", "\"transid\"",
+ "\"vendor-class\"", "\"vendor\"", "\"*\"", "\"data\"", "\"enterprise\"",
"\"constant string\"", "\"integer\"", "\"constant hexstring\"",
"\"option name\"", "\"ip address\"", "$accept", "expression",
"bool_expr", "string_expr", "option_code", "option_repr_type",
- "nest_level", "pkt_metadata", "pkt4_field", "pkt6_field", "relay6_field",
- "start_expr", "length_expr", YY_NULLPTR
+ "nest_level", "pkt_metadata", "enterprise_id", "pkt4_field",
+ "pkt6_field", "relay6_field", "start_expr", "length_expr", YY_NULLPTR
};
#if YYDEBUG
const unsigned short int
EvalParser::yyrline_[] =
{
- 0, 106, 106, 109, 110, 115, 120, 125, 130, 135,
- 155, 171, 176, 181, 186, 191, 212, 227, 232, 246,
- 260, 275, 280, 287, 291, 297, 301, 307, 316, 320,
- 324, 328, 334, 338, 342, 346, 350, 354, 358, 364,
- 368, 374, 378, 384, 391, 396
+ 0, 112, 112, 115, 116, 121, 126, 131, 136, 141,
+ 161, 175, 184, 193, 205, 210, 215, 220, 225, 246,
+ 261, 266, 280, 294, 309, 314, 319, 328, 338, 347,
+ 360, 375, 379, 385, 389, 395, 404, 408, 412, 416,
+ 422, 426, 432, 436, 440, 444, 448, 452, 456, 462,
+ 466, 472, 476, 482, 489, 494
};
// Print the state stack on the debug stream.
@@ -1586,8 +1761,8 @@ namespace isc { namespace eval {
#line 13 "parser.yy" // lalr1.cc:1167
} } // isc::eval
-#line 1590 "parser.cc" // lalr1.cc:1167
-#line 403 "parser.yy" // lalr1.cc:1168
+#line 1765 "parser.cc" // lalr1.cc:1167
+#line 501 "parser.yy" // lalr1.cc:1168
void
isc::eval::EvalParser::error(const location_type& loc,
diff --git a/src/lib/eval/parser.h b/src/lib/eval/parser.h
index fe72128758..f61db8fff2 100644
--- a/src/lib/eval/parser.h
+++ b/src/lib/eval/parser.h
@@ -320,8 +320,11 @@ namespace isc { namespace eval {
// option_code
char dummy7[sizeof(uint16_t)];
+ // enterprise_id
+ char dummy8[sizeof(uint32_t)];
+
// nest_level
- char dummy8[sizeof(uint8_t)];
+ char dummy9[sizeof(uint8_t)];
};
/// Symbol semantic values.
@@ -375,18 +378,23 @@ namespace isc { namespace eval {
TOKEN_GIADDR = 285,
TOKEN_YIADDR = 286,
TOKEN_SIADDR = 287,
- TOKEN_PKT6 = 288,
- TOKEN_MSGTYPE = 289,
- TOKEN_TRANSID = 290,
- TOKEN_SUBSTRING = 291,
- TOKEN_ALL = 292,
- TOKEN_COMA = 293,
- TOKEN_CONCAT = 294,
- TOKEN_STRING = 295,
- TOKEN_INTEGER = 296,
- TOKEN_HEXSTRING = 297,
- TOKEN_OPTION_NAME = 298,
- TOKEN_IP_ADDRESS = 299
+ TOKEN_SUBSTRING = 288,
+ TOKEN_ALL = 289,
+ TOKEN_COMA = 290,
+ TOKEN_CONCAT = 291,
+ TOKEN_PKT6 = 292,
+ TOKEN_MSGTYPE = 293,
+ TOKEN_TRANSID = 294,
+ TOKEN_VENDOR_CLASS = 295,
+ TOKEN_VENDOR = 296,
+ TOKEN_ANY = 297,
+ TOKEN_DATA = 298,
+ TOKEN_ENTERPRISE = 299,
+ TOKEN_STRING = 300,
+ TOKEN_INTEGER = 301,
+ TOKEN_HEXSTRING = 302,
+ TOKEN_OPTION_NAME = 303,
+ TOKEN_IP_ADDRESS = 304
};
};
@@ -438,6 +446,8 @@ namespace isc { namespace eval {
basic_symbol (typename Base::kind_type t, const uint16_t v, const location_type& l);
+ basic_symbol (typename Base::kind_type t, const uint32_t v, const location_type& l);
+
basic_symbol (typename Base::kind_type t, const uint8_t v, const location_type& l);
@@ -631,18 +641,6 @@ namespace isc { namespace eval {
symbol_type
make_SIADDR (const location_type& l);
- static inline
- symbol_type
- make_PKT6 (const location_type& l);
-
- static inline
- symbol_type
- make_MSGTYPE (const location_type& l);
-
- static inline
- symbol_type
- make_TRANSID (const location_type& l);
-
static inline
symbol_type
make_SUBSTRING (const location_type& l);
@@ -659,6 +657,38 @@ namespace isc { namespace eval {
symbol_type
make_CONCAT (const location_type& l);
+ static inline
+ symbol_type
+ make_PKT6 (const location_type& l);
+
+ static inline
+ symbol_type
+ make_MSGTYPE (const location_type& l);
+
+ static inline
+ symbol_type
+ make_TRANSID (const location_type& l);
+
+ static inline
+ symbol_type
+ make_VENDOR_CLASS (const location_type& l);
+
+ static inline
+ symbol_type
+ make_VENDOR (const location_type& l);
+
+ static inline
+ symbol_type
+ make_ANY (const location_type& l);
+
+ static inline
+ symbol_type
+ make_DATA (const location_type& l);
+
+ static inline
+ symbol_type
+ make_ENTERPRISE (const location_type& l);
+
static inline
symbol_type
make_STRING (const std::string& v, const location_type& l);
@@ -746,7 +776,7 @@ namespace isc { namespace eval {
// Tables.
// YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
// STATE-NUM.
- static const signed char yypact_[];
+ static const short int yypact_[];
// YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
// Performed when YYTABLE does not specify something else to do. Zero
@@ -757,14 +787,14 @@ namespace isc { namespace eval {
static const signed char yypgoto_[];
// YYDEFGOTO[NTERM-NUM].
- static const signed char yydefgoto_[];
+ static const short int yydefgoto_[];
// YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
// positive, shift that token. If negative, reduce the rule whose
// number is the opposite. If YYTABLE_NINF, syntax error.
static const unsigned char yytable_[];
- static const signed char yycheck_[];
+ static const short int yycheck_[];
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing
// symbol of state STATE-NUM.
@@ -884,12 +914,12 @@ namespace isc { namespace eval {
enum
{
yyeof_ = 0,
- yylast_ = 121, ///< Last index in yytable_.
- yynnts_ = 13, ///< Number of nonterminal symbols.
- yyfinal_ = 27, ///< Termination state number.
+ yylast_ = 171, ///< Last index in yytable_.
+ yynnts_ = 14, ///< Number of nonterminal symbols.
+ yyfinal_ = 33, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
- yyntokens_ = 45 ///< Number of tokens.
+ yyntokens_ = 50 ///< Number of tokens.
};
@@ -935,9 +965,10 @@ namespace isc { namespace eval {
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49
};
- const unsigned int user_token_number_max_ = 299;
+ const unsigned int user_token_number_max_ = 304;
const token_number_type undef_token_ = 2;
if (static_cast(t) <= yyeof_)
@@ -970,39 +1001,43 @@ namespace isc { namespace eval {
{
switch (other.type_get ())
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
value.copy< TokenOption::RepresentationType > (other.value);
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
value.copy< TokenPkt4::FieldType > (other.value);
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
value.copy< TokenPkt6::FieldType > (other.value);
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
value.copy< TokenPkt::MetadataType > (other.value);
break;
- case 55: // relay6_field
+ case 61: // relay6_field
value.copy< TokenRelay6Field::FieldType > (other.value);
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
value.copy< std::string > (other.value);
break;
- case 49: // option_code
+ case 54: // option_code
value.copy< uint16_t > (other.value);
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ value.copy< uint32_t > (other.value);
+ break;
+
+ case 56: // nest_level
value.copy< uint8_t > (other.value);
break;
@@ -1023,39 +1058,43 @@ namespace isc { namespace eval {
(void) v;
switch (this->type_get ())
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
value.copy< TokenOption::RepresentationType > (v);
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
value.copy< TokenPkt4::FieldType > (v);
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
value.copy< TokenPkt6::FieldType > (v);
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
value.copy< TokenPkt::MetadataType > (v);
break;
- case 55: // relay6_field
+ case 61: // relay6_field
value.copy< TokenRelay6Field::FieldType > (v);
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
value.copy< std::string > (v);
break;
- case 49: // option_code
+ case 54: // option_code
value.copy< uint16_t > (v);
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ value.copy< uint32_t > (v);
+ break;
+
+ case 56: // nest_level
value.copy< uint8_t > (v);
break;
@@ -1123,6 +1162,13 @@ namespace isc { namespace eval {
, location (l)
{}
+ template
+ EvalParser::basic_symbol::basic_symbol (typename Base::kind_type t, const uint32_t v, const location_type& l)
+ : Base (t)
+ , value (v)
+ , location (l)
+ {}
+
template
EvalParser::basic_symbol::basic_symbol (typename Base::kind_type t, const uint8_t v, const location_type& l)
: Base (t)
@@ -1156,39 +1202,43 @@ namespace isc { namespace eval {
// Type destructor.
switch (yytype)
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
value.template destroy< TokenOption::RepresentationType > ();
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
value.template destroy< TokenPkt4::FieldType > ();
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
value.template destroy< TokenPkt6::FieldType > ();
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
value.template destroy< TokenPkt::MetadataType > ();
break;
- case 55: // relay6_field
+ case 61: // relay6_field
value.template destroy< TokenRelay6Field::FieldType > ();
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
value.template destroy< std::string > ();
break;
- case 49: // option_code
+ case 54: // option_code
value.template destroy< uint16_t > ();
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ value.template destroy< uint32_t > ();
+ break;
+
+ case 56: // nest_level
value.template destroy< uint8_t > ();
break;
@@ -1215,39 +1265,43 @@ namespace isc { namespace eval {
super_type::move(s);
switch (this->type_get ())
{
- case 50: // option_repr_type
+ case 55: // option_repr_type
value.move< TokenOption::RepresentationType > (s.value);
break;
- case 53: // pkt4_field
+ case 59: // pkt4_field
value.move< TokenPkt4::FieldType > (s.value);
break;
- case 54: // pkt6_field
+ case 60: // pkt6_field
value.move< TokenPkt6::FieldType > (s.value);
break;
- case 52: // pkt_metadata
+ case 57: // pkt_metadata
value.move< TokenPkt::MetadataType > (s.value);
break;
- case 55: // relay6_field
+ case 61: // relay6_field
value.move< TokenRelay6Field::FieldType > (s.value);
break;
- case 40: // "constant string"
- case 41: // "integer"
- case 42: // "constant hexstring"
- case 43: // "option name"
- case 44: // "ip address"
+ case 45: // "constant string"
+ case 46: // "integer"
+ case 47: // "constant hexstring"
+ case 48: // "option name"
+ case 49: // "ip address"
value.move< std::string > (s.value);
break;
- case 49: // option_code
+ case 54: // option_code
value.move< uint16_t > (s.value);
break;
- case 51: // nest_level
+ case 58: // enterprise_id
+ value.move< uint32_t > (s.value);
+ break;
+
+ case 56: // nest_level
value.move< uint8_t > (s.value);
break;
@@ -1310,7 +1364,7 @@ namespace isc { namespace eval {
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
- 295, 296, 297, 298, 299
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304
};
return static_cast (yytoken_number_[type]);
}
@@ -1501,24 +1555,6 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_SIADDR, l);
}
- EvalParser::symbol_type
- EvalParser::make_PKT6 (const location_type& l)
- {
- return symbol_type (token::TOKEN_PKT6, l);
- }
-
- EvalParser::symbol_type
- EvalParser::make_MSGTYPE (const location_type& l)
- {
- return symbol_type (token::TOKEN_MSGTYPE, l);
- }
-
- EvalParser::symbol_type
- EvalParser::make_TRANSID (const location_type& l)
- {
- return symbol_type (token::TOKEN_TRANSID, l);
- }
-
EvalParser::symbol_type
EvalParser::make_SUBSTRING (const location_type& l)
{
@@ -1543,6 +1579,54 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_CONCAT, l);
}
+ EvalParser::symbol_type
+ EvalParser::make_PKT6 (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_PKT6, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_MSGTYPE (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_MSGTYPE, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_TRANSID (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_TRANSID, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_VENDOR_CLASS (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_VENDOR_CLASS, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_VENDOR (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_VENDOR, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_ANY (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_ANY, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_DATA (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_DATA, l);
+ }
+
+ EvalParser::symbol_type
+ EvalParser::make_ENTERPRISE (const location_type& l)
+ {
+ return symbol_type (token::TOKEN_ENTERPRISE, l);
+ }
+
EvalParser::symbol_type
EvalParser::make_STRING (const std::string& v, const location_type& l)
{
@@ -1576,7 +1660,7 @@ namespace isc { namespace eval {
#line 13 "parser.yy" // lalr1.cc:377
} } // isc::eval
-#line 1580 "parser.h" // lalr1.cc:377
+#line 1664 "parser.h" // lalr1.cc:377
diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy
index 92bdbbc865..62a6bd270c 100644
--- a/src/lib/eval/parser.yy
+++ b/src/lib/eval/parser.yy
@@ -67,13 +67,18 @@ using namespace isc::eval;
GIADDR "giaddr"
YIADDR "yiaddr"
SIADDR "siaddr"
- PKT6 "pkt6"
- MSGTYPE "msgtype"
- TRANSID "transid"
SUBSTRING "substring"
ALL "all"
COMA ","
CONCAT "concat"
+ PKT6 "pkt6"
+ MSGTYPE "msgtype"
+ TRANSID "transid"
+ VENDOR_CLASS "vendor-class"
+ VENDOR "vendor"
+ ANY "*"
+ DATA "data"
+ ENTERPRISE "enterprise"
;
%token STRING "constant string"
@@ -83,6 +88,7 @@ using namespace isc::eval;
%token IP_ADDRESS "ip address"
%type option_code
+%type enterprise_id
%type option_repr_type
%type relay6_field
%type nest_level
@@ -166,6 +172,34 @@ bool_expr : "(" bool_expr ")"
error(@1, "relay6 can only be used in DHCPv6.");
}
}
+ | VENDOR_CLASS "[" enterprise_id "]" "." EXISTS
+ {
+ // Expression: vendor-class[1234].exists
+ //
+ // This token will find option 124 (DHCPv4) or 16 (DHCPv6),
+ // and will check if enterprise-id equals specified value.
+ TokenPtr exist(new TokenVendorClass(ctx.getUniverse(), $3, TokenOption::EXISTS));
+ ctx.expression.push_back(exist);
+ }
+ | VENDOR "[" enterprise_id "]" "." EXISTS
+ {
+ // Expression: vendor[1234].exists
+ //
+ // This token will find option 125 (DHCPv4) or 17 (DHCPv6),
+ // and will check if enterprise-id equals specified value.
+ TokenPtr exist(new TokenVendor(ctx.getUniverse(), $3, TokenOption::EXISTS));
+ ctx.expression.push_back(exist);
+ }
+ | VENDOR "[" enterprise_id "]" "." OPTION "[" option_code "]" "." EXISTS
+ {
+ // Expression vendor[1234].option[123].exists
+ //
+ // This token will check if specified vendor option
+ // exists, has specified enterprise-id and if has
+ // specified suboption.
+ TokenPtr exist(new TokenVendor(ctx.getUniverse(), $3, TokenOption::EXISTS, $8));
+ ctx.expression.push_back(exist);
+ }
;
string_expr : STRING
@@ -282,6 +316,60 @@ string_expr : STRING
TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc);
}
+ | VENDOR "." ENTERPRISE
+ {
+ // expression: vendor.enterprise
+ //
+ // This token will return enterprise-id number of
+ // received vendor option.
+ TokenPtr vendor(new TokenVendor(ctx.getUniverse(), 0, TokenVendor::ENTERPRISE_ID));
+ ctx.expression.push_back(vendor);
+ }
+ | VENDOR_CLASS "." ENTERPRISE
+ {
+ // expression: vendor-class.enterprise
+ //
+ // This token will return enterprise-id number of
+ // received vendor class option.
+ TokenPtr vendor(new TokenVendorClass(ctx.getUniverse(), 0,
+ TokenVendor::ENTERPRISE_ID));
+ ctx.expression.push_back(vendor);
+ }
+ | VENDOR "[" enterprise_id "]" "." OPTION "[" option_code "]" "." option_repr_type
+ {
+ // This token will search for vendor option with
+ // specified enterprise-id. If found, will search
+ // for specified suboption and finally will return
+ // its content.
+ TokenPtr opt(new TokenVendor(ctx.getUniverse(), $3, $11, $8));
+ ctx.expression.push_back(opt);
+ }
+ | VENDOR_CLASS "[" enterprise_id "]" "." DATA
+ {
+ // expression: vendor-class[1234].data
+ //
+ // Vendor class option does not have suboptions,
+ // but chunks of data (typically 1, but the option
+ // structure allows multiple of them). If chunk
+ // offset is not specified, we assume the first (0th)
+ // is requested.
+ TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), $3,
+ TokenVendor::DATA, 0));
+ ctx.expression.push_back(vendor_class);
+ }
+ | VENDOR_CLASS "[" enterprise_id "]" "." DATA "[" INTEGER "]"
+ {
+ // expression: vendor-class[1234].data[5]
+ //
+ // Vendor class option does not have suboptions,
+ // but chunks of data (typically 1, but the option
+ // structure allows multiple of them). This syntax
+ // specifies which data chunk (tuple) we want.
+ uint8_t index = ctx.convertUint8($8, @8);
+ TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), $3,
+ TokenVendor::DATA, index));
+ ctx.expression.push_back(vendor_class);
+ }
;
option_code : INTEGER
@@ -331,6 +419,16 @@ pkt_metadata : IFACE
}
;
+enterprise_id : INTEGER
+ {
+ $$ = ctx.convertUint32($1, @1);
+ }
+ | "*"
+ {
+ $$ = 0;
+ }
+ ;
+
pkt4_field : CHADDR
{
$$ = TokenPkt4::CHADDR;
@@ -382,17 +480,17 @@ relay6_field : PEERADDR
;
start_expr : INTEGER
+ {
+ TokenPtr str(new TokenString($1));
+ ctx.expression.push_back(str);
+ }
+ ;
+
+length_expr : INTEGER
{
TokenPtr str(new TokenString($1));
ctx.expression.push_back(str);
}
- ;
-
-length_expr : INTEGER
- {
- TokenPtr str(new TokenString($1));
- ctx.expression.push_back(str);
- }
| ALL
{
TokenPtr str(new TokenString("all"));
diff --git a/src/lib/eval/position.hh b/src/lib/eval/position.hh
index 772a8edd92..b3eebe04f6 100644
--- a/src/lib/eval/position.hh
+++ b/src/lib/eval/position.hh
@@ -1,4 +1,3 @@
-// Generated 201608161508
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++
diff --git a/src/lib/eval/stack.hh b/src/lib/eval/stack.hh
index f9c21780ea..6bda37bbcf 100644
--- a/src/lib/eval/stack.hh
+++ b/src/lib/eval/stack.hh
@@ -1,4 +1,3 @@
-// Generated 201608161508
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++
diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc
index b278ed9a81..d8811d1ffe 100644
--- a/src/lib/eval/tests/context_unittest.cc
+++ b/src/lib/eval/tests/context_unittest.cc
@@ -417,8 +417,189 @@ public:
universe_ = universe;
}
- Option::Universe universe_;
+ /// @brief Checks if the given token is TokenVendor and has expected characteristics
+ /// @param token token to be checked
+ /// @param exp_vendor_id expected vendor-id (aka enterprise number)
+ /// @param exp_repr expected representation (either 'exists' or 'hex')
+ /// @param exp_option_code expected option code (ignored if 0)
+ void checkTokenVendor(const TokenPtr& token, uint32_t exp_vendor_id,
+ uint16_t exp_option_code,
+ TokenOption::RepresentationType exp_repr) {
+ ASSERT_TRUE(token);
+
+ boost::shared_ptr vendor =
+ boost::dynamic_pointer_cast(token);
+
+ ASSERT_TRUE(vendor);
+
+ EXPECT_EQ(exp_vendor_id, vendor->getVendorId());
+ EXPECT_EQ(exp_repr, vendor->getRepresentation());
+ EXPECT_EQ(exp_option_code, vendor->getCode());
+ }
+
+ /// @brief Tests if specified token vendor expression can be parsed
+ ///
+ /// This test assumes the first token will be token vendor. Any additional
+ /// tokens are ignored. Tests expressions:
+ /// vendor[1234].option[234].hex
+ /// vendor[1234].option[234].exists
+ ///
+ /// @param expr expression to be parsed
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id expected vendor-id (aka enterprise number)
+ /// @param option_code expected option code (ignored if 0)
+ /// @param expected_repr expected representation (either 'exists' or 'hex')
+ void testVendor(std::string expr, Option::Universe u, uint32_t vendor_id,
+ uint16_t option_code, TokenOption::RepresentationType expected_repr) {
+ EvalContext eval(u);
+
+ EXPECT_NO_THROW(parsed_ = eval.parseString(expr));
+ EXPECT_TRUE(parsed_);
+
+ // We need at least one token, we will evaluate the first one.
+ ASSERT_FALSE(eval.expression.empty());
+
+ checkTokenVendor(eval.expression.at(0), vendor_id, option_code, expected_repr);
+ }
+
+ /// @brief Checks if token is really a TokenVendor, that the vendor_id was
+ /// stored properly and that it has expected representation
+ ///
+ /// This test is able to handle expressions similar to:
+ /// vendor[4491].option[1].hex
+ /// vendor[4491].option[1].exists
+ /// vendor[4491].exists
+ /// vendor[*].exists
+ ///
+ /// @param expr expression to be parsed
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id expected vendor-id (aka enterprise number)
+ /// @param expected_repr expected representation (either 'exists' or 'hex')
+ void testVendor(std::string expr, Option::Universe u, uint32_t vendor_id,
+ TokenOption::RepresentationType expected_repr) {
+ testVendor(expr, u, vendor_id, 0, expected_repr);
+ }
+
+ /// @brief Tests if the expression parses into token vendor that returns enterprise-id
+ ///
+ /// This test is able to handle expressions similar to:
+ /// vendor.enterprise
+ ///
+ /// @param expr expression to be parsed
+ /// @param u universe (V4 or V6)
+ void testVendorEnterprise(std::string expr, Option::Universe u) {
+ EvalContext eval(u);
+
+ EXPECT_NO_THROW(parsed_ = eval.parseString(expr));
+ EXPECT_TRUE(parsed_);
+
+ ASSERT_FALSE(eval.expression.empty());
+
+ boost::shared_ptr vendor =
+ boost::dynamic_pointer_cast(eval.expression.at(0));
+
+ ASSERT_TRUE(vendor);
+ EXPECT_EQ(TokenVendor::ENTERPRISE_ID, vendor->getField());
+ }
+
+ /// @brief This test checks if vendor-class token is correct
+ ///
+ /// This test checks if EXISTS representation is set correctly.
+ /// It covers cases like:
+ /// - vendor-class[4491].exists
+ /// - vendor-class[*].exists
+ ///
+ /// @param expr expression to be parsed
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id expected vendor-id (aka enterprise number)
+ void testVendorClass(std::string expr, Option::Universe u, uint32_t vendor_id) {
+ EvalContext eval(u);
+
+ EXPECT_NO_THROW(parsed_ = eval.parseString(expr));
+ EXPECT_TRUE(parsed_);
+
+ ASSERT_EQ(1, eval.expression.size());
+ checkTokenVendorClass(eval.expression.at(0), vendor_id, 0, TokenOption::EXISTS,
+ TokenVendor::EXISTS);
+ }
+
+ /// @brief Tests if specified token vendor class expression can be parsed
+ ///
+ /// This test assumes the first token will be token vendor-class.
+ /// Any additional tokens are ignored. Tests expressions:
+ /// - vendor-class[4491].exists
+ /// - vendor-class[*].exists
+ /// - vendor-class[4491].data
+ /// - vendor-class[4491].data[3]
+ ///
+ /// @param expr expression to be parsed
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id expected vendor-id (aka enterprise number)
+ /// @param index expected data index
+ void testVendorClass(std::string expr, Option::Universe u, uint32_t vendor_id,
+ uint16_t index) {
+ EvalContext eval(u);
+
+ EXPECT_NO_THROW(parsed_ = eval.parseString(expr));
+ EXPECT_TRUE(parsed_);
+
+ // Make sure there's at least one token
+ ASSERT_FALSE(eval.expression.empty());
+
+ // The first token should be TokenVendorClass, let's take a closer look.
+ checkTokenVendorClass(eval.expression.at(0), vendor_id, index,
+ TokenOption::HEXADECIMAL, TokenVendor::DATA);
+
+ }
+
+ /// @brief Tests if the expression parses into vendor class token that
+ /// returns enterprise-id.
+ ///
+ /// This test is able to handle expressions similar to:
+ /// - vendor-class.enterprise
+ ///
+ /// @param expr expression to be parsed
+ /// @param u universe (V4 or V6)
+ void testVendorClassEnterprise(std::string expr, Option::Universe u) {
+ EvalContext eval(u);
+
+ EXPECT_NO_THROW(parsed_ = eval.parseString(expr));
+ EXPECT_TRUE(parsed_);
+
+ // Make sure there's at least one token
+ ASSERT_FALSE(eval.expression.empty());
+
+ // The first token should be TokenVendorClass, let's take a closer look.
+ checkTokenVendorClass(eval.expression.at(0), 0, 0, TokenOption::HEXADECIMAL,
+ TokenVendor::ENTERPRISE_ID);
+ }
+
+ /// @brief Checks if the given token is TokenVendorClass and has expected characteristics
+ ///
+ /// @param token token to be checked
+ /// @param vendor_id expected vendor-id (aka enterprise number)
+ /// @param index expected index (used for data field only)
+ /// @param repr expected representation (either 'exists' or 'hex')
+ /// @param field expected field (none, enterprise or data)
+ void checkTokenVendorClass(const TokenPtr& token, uint32_t vendor_id,
+ uint16_t index, TokenOption::RepresentationType repr,
+ TokenVendor::FieldType field) {
+ ASSERT_TRUE(token);
+
+ boost::shared_ptr vendor =
+ boost::dynamic_pointer_cast(token);
+
+ ASSERT_TRUE(vendor);
+
+ EXPECT_EQ(vendor_id, vendor->getVendorId());
+ EXPECT_EQ(index, vendor->getDataIndex());
+ EXPECT_EQ(repr, vendor->getRepresentation());
+ EXPECT_EQ(field, vendor->getField());
+ }
+
+ Option::Universe universe_; ///< Universe (V4 or V6)
bool parsed_; ///< Parsing status
+
};
// Test the error method without location
@@ -751,8 +932,7 @@ TEST_F(EvalContextTest, relay6OptionLimits) {
// next level must be a positive number
checkError("relay6[-1].option[123].text == 'foo'",
- ":1.8-9: Nest level has invalid value in -1. "
- "Allowed range: 0..31");
+ ":1.8-9: Invalid value in -1. Allowed range: 0..255");
}
// Verify that relay6[13].option is not usable in v4
@@ -1168,4 +1348,95 @@ TEST_F(EvalContextTest, typeErrors) {
":1.8-9: syntax error, unexpected or, expecting ==");
}
+
+TEST_F(EvalContextTest, vendor4SpecificVendorExists) {
+ testVendor("vendor[4491].exists", Option::V4, 4491, TokenOption::EXISTS);
+}
+
+TEST_F(EvalContextTest, vendor6SpecificVendorExists) {
+ testVendor("vendor[4491].exists", Option::V6, 4491, TokenOption::EXISTS);
+}
+
+TEST_F(EvalContextTest, vendor4AnyVendorExists) {
+ testVendor("vendor[*].exists", Option::V4, 0, TokenOption::EXISTS);
+}
+
+TEST_F(EvalContextTest, vendor6AnyVendorExists) {
+ testVendor("vendor[*].exists", Option::V6, 0, TokenOption::EXISTS);
+}
+
+TEST_F(EvalContextTest, vendor4enterprise) {
+ testVendorEnterprise("vendor.enterprise == 0x1234", Option::V4);
+}
+
+TEST_F(EvalContextTest, vendor6enterprise) {
+ testVendorEnterprise("vendor.enterprise == 0x1234", Option::V6);
+}
+
+TEST_F(EvalContextTest, vendor4SuboptionExists) {
+ testVendor("vendor[4491].option[1].exists", Option::V4, 4491, 1, TokenOption::EXISTS);
+}
+
+TEST_F(EvalContextTest, vendor6SuboptionExists) {
+ testVendor("vendor[4491].option[1].exists", Option::V6, 4491, 1, TokenOption::EXISTS);
+}
+
+TEST_F(EvalContextTest, vendor4SuboptionHex) {
+ testVendor("vendor[4491].option[1].hex == 0x1234", Option::V4, 4491, 1,
+ TokenOption::HEXADECIMAL);
+}
+
+TEST_F(EvalContextTest, vendor6SuboptionHex) {
+ testVendor("vendor[4491].option[1].hex == 0x1234", Option::V6, 4491, 1,
+ TokenOption::HEXADECIMAL);
+}
+
+TEST_F(EvalContextTest, vendorClass4SpecificVendorExists) {
+ testVendorClass("vendor-class[4491].exists", Option::V4, 4491);
+}
+
+TEST_F(EvalContextTest, vendorClass6SpecificVendorExists) {
+ testVendorClass("vendor-class[4491].exists", Option::V6, 4491);
+}
+
+TEST_F(EvalContextTest, vendorClass4AnyVendorExists) {
+ testVendorClass("vendor-class[*].exists", Option::V4, 0);
+}
+
+TEST_F(EvalContextTest, vendorClass6AnyVendorExists) {
+ testVendorClass("vendor-class[*].exists", Option::V6, 0);
+}
+
+TEST_F(EvalContextTest, vendorClass4enterprise) {
+ testVendorClassEnterprise("vendor-class.enterprise == 0x1234", Option::V4);
+}
+
+TEST_F(EvalContextTest, vendorClass6enterprise) {
+ testVendorClassEnterprise("vendor-class.enterprise == 0x1234", Option::V6);
+}
+
+TEST_F(EvalContextTest, vendorClass4SpecificVendorData) {
+ testVendorClass("vendor-class[4491].data == 0x1234", Option::V4, 4491, 0);
+}
+
+TEST_F(EvalContextTest, vendorClass6SpecificVendorData) {
+ testVendorClass("vendor-class[4491].data == 0x1234", Option::V6, 4491, 0);
+}
+
+TEST_F(EvalContextTest, vendorClass4AnyVendorData) {
+ testVendorClass("vendor-class[*].data == 0x1234", Option::V4, 0, 0);
+}
+
+TEST_F(EvalContextTest, vendorClass6AnyVendorData) {
+ testVendorClass("vendor-class[*].data == 0x1234", Option::V6, 0, 0);
+}
+
+TEST_F(EvalContextTest, vendorClass4DataIndex) {
+ testVendorClass("vendor-class[4491].data[3] == 0x1234", Option::V4, 4491, 3);
+}
+
+TEST_F(EvalContextTest, vendorClass6DataIndex) {
+ testVendorClass("vendor-class[4491].data[3] == 0x1234", Option::V6, 4491, 3);
+}
+
};
diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc
index ac759a0245..96b52137e1 100644
--- a/src/lib/eval/tests/token_unittest.cc
+++ b/src/lib/eval/tests/token_unittest.cc
@@ -12,6 +12,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -51,6 +53,10 @@ public:
pkt4_->addOption(option_str4_);
pkt6_->addOption(option_str6_);
+
+ // Change this to true if you need extra information about logging
+ // checks to be printed.
+ logCheckVerbose(false);
}
/// @brief Inserts RAI option with several suboptions
@@ -185,6 +191,19 @@ public:
t_.reset();
}
+ /// @brief Aux. function that stores integer values as 4 bytes string.
+ ///
+ /// @param value integer value to be stored
+ /// @return 4 bytes long string with encoded value.
+ string encode(uint32_t value) {
+ string tmp(4,0);
+ tmp[0] = value >> 24;
+ tmp[1] = value >> 16;
+ tmp[2] = value >> 8;
+ tmp[3] = value;
+ return (tmp);
+ }
+
TokenPtr t_; ///< Just a convenience pointer
ValueStack values_; ///< evaluated values will be stored here
@@ -195,6 +214,8 @@ public:
OptionPtr option_str4_; ///< A string option for DHCPv4
OptionPtr option_str6_; ///< A string option for DHCPv6
+ OptionVendorPtr vendor_; ///< Vendor option used during tests
+ OptionVendorClassPtr vendor_class_; ///< Vendor class option used during tests
/// @brief Verify that the substring eval works properly
///
@@ -236,8 +257,233 @@ public:
}
}
- /// @todo: Add more option types here
+ /// @brief Creates vendor-option with specified value and adds it to packet
+ ///
+ /// This method creates specified vendor option, removes any existing
+ /// vendor options and adds the new one to v4 or v6 packet.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id specifies enterprise-id value.
+ void setVendorOption(Option::Universe u, uint32_t vendor_id) {
+ vendor_.reset(new OptionVendor(u, vendor_id));
+ switch (u) {
+ case Option::V4:
+ pkt4_->delOption(DHO_VIVSO_SUBOPTIONS);
+ pkt4_->addOption(vendor_);
+ break;
+ case Option::V6:
+ pkt6_->delOption(D6O_VENDOR_OPTS);
+ pkt6_->addOption(vendor_);
+ break;
+ }
+ }
+ /// @brief Creates vendor-class option with specified values and adds it to packet
+ ///
+ /// This method creates specified vendor-class option, removes any existing
+ /// vendor class options and adds the new one to v4 or v6 packet.
+ /// It also creates data tuples with greek alphabet names.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id specifies enterprise-id value.
+ /// @param tuples_size number of data tuples to create.
+ void setVendorClassOption(Option::Universe u, uint32_t vendor_id,
+ size_t tuples_size = 0) {
+ // Create the option first.
+ vendor_class_.reset(new OptionVendorClass(u, vendor_id));
+
+ // Now let's add specified number of data tuples
+ OpaqueDataTuple::LengthFieldType len = (u == Option::V4?OpaqueDataTuple::LENGTH_1_BYTE:
+ OpaqueDataTuple::LENGTH_2_BYTES);
+ const char * content[] = { "alpha", "beta", "delta", "gamma", "epsilon",
+ "zeta", "eta", "theta", "iota", "kappa" };
+ ASSERT_TRUE(tuples_size < sizeof(content));
+ for (int i = 0; i < tuples_size; i++) {
+ OpaqueDataTuple tuple(len);
+ tuple.assign(string(content[i]));
+ if (u == Option::V4 && i == 0) {
+ // vendor-clas for v4 has a pecurilar quirk. The first tuple is being
+ // added, even if there's no data at all.
+ vendor_class_->setTuple(0, tuple);
+ } else {
+ vendor_class_->addTuple(tuple);
+ }
+ }
+
+ switch (u) {
+ case Option::V4:
+ pkt4_->delOption(DHO_VIVCO_SUBOPTIONS);
+ pkt4_->addOption(vendor_class_);
+ break;
+ case Option::V6:
+ pkt6_->delOption(D6O_VENDOR_CLASS);
+ pkt6_->addOption(vendor_class_);
+ break;
+ }
+ }
+
+ /// @brief Auxiliary function that evaluates tokens and checks result
+ ///
+ /// Depending on the universe, either pkt4_ or pkt6_ are supposed to have
+ /// all the necessary values and options set. The result is checked
+ /// on the values_ stack.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param expected_result text representation of the expected outcome
+ void evaluate(Option::Universe u, std::string expected_result) {
+ switch (u) {
+ case Option::V4:
+ EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+ break;
+ case Option::V6:
+ EXPECT_NO_THROW(t_->evaluate(*pkt6_, values_));
+ break;
+ default:
+ ADD_FAILURE() << "Invalid universe specified.";
+ }
+ ASSERT_EQ(1, values_.size());
+ EXPECT_EQ(expected_result, values_.top());
+ }
+
+ /// @brief Tests if vendor token behaves properly.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param token_vendor_id enterprise-id used in the token
+ /// @param option_vendor_id enterprise-id used in option (0 means don't
+ /// create the option)
+ /// @param expected_result text representation of the expected outcome
+ void testVendorExists(Option::Universe u, uint32_t token_vendor_id,
+ uint32_t option_vendor_id, std::string expected_result) {
+ // Let's clear any old values, so we can run multiple cases in each test
+ clearStack();
+
+ // Create the token
+ ASSERT_NO_THROW(t_.reset(new TokenVendor(u, token_vendor_id,
+ TokenOption::EXISTS)));
+
+ // If specified option is non-zero, create it.
+ if (option_vendor_id) {
+ setVendorOption(u, option_vendor_id);
+ }
+
+ evaluate(u, expected_result);
+ }
+
+ /// @brief Tests if vendor token properly returns enterprise-id.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param option_vendor_id enterprise-id used in option (0 means don't
+ /// create the option)
+ /// @param expected_result text representation of the expected outcome
+ void testVendorEnterprise(Option::Universe u, uint32_t option_vendor_id,
+ std::string expected_result) {
+ // Let's clear any old values, so we can run multiple cases in each test
+ clearStack();
+
+ ASSERT_NO_THROW(t_.reset(new TokenVendor(u, 0, TokenVendor::ENTERPRISE_ID)));
+ if (option_vendor_id) {
+ setVendorOption(u, option_vendor_id);
+ }
+
+ evaluate(u, expected_result);
+ }
+
+ /// @brief Tests if vendor class token properly returns enterprise-id.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param option_vendor_id enterprise-id used in option (0 means don't
+ /// create the option)
+ /// @param expected_result text representation of the expected outcome
+ void testVendorClassEnterprise(Option::Universe u, uint32_t option_vendor_id,
+ std::string expected_result) {
+ // Let's clear any old values, so we can run multiple cases in each test
+ clearStack();
+
+ ASSERT_NO_THROW(t_.reset(new TokenVendorClass(u, 0, TokenVendor::ENTERPRISE_ID)));
+ if (option_vendor_id) {
+ setVendorClassOption(u, option_vendor_id);
+ }
+
+ evaluate(u, expected_result);
+ }
+
+ /// @brief Tests if vendor class token can report existence properly.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param token_vendor_id enterprise-id used in the token
+ /// @param option_vendor_id enterprise-id used in option (0 means don't
+ /// create the option)
+ /// @param expected_result text representation of the expected outcome
+ void testVendorClassExists(Option::Universe u, uint32_t token_vendor_id,
+ uint32_t option_vendor_id, std::string expected_result) {
+ // Let's clear any old values, so we can run multiple cases in each test
+ clearStack();
+
+ ASSERT_NO_THROW(t_.reset(new TokenVendorClass(u, token_vendor_id,
+ TokenOption::EXISTS)));
+
+ if (option_vendor_id) {
+ setVendorClassOption(u, option_vendor_id);
+ }
+
+ evaluate(u, expected_result);
+ }
+
+ /// @brief Tests if vendor token can handle sub-options properly.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param token_vendor_id enterprise-id used in the token
+ /// @param token_option_code option code in the token
+ /// @param option_vendor_id enterprise-id used in option (0 means don't
+ /// create the option)
+ /// @param option_code sub-option code (0 means don't create suboption)
+ /// @param repr representation (TokenOption::EXISTS or HEXADECIMAL)
+ /// @param expected_result text representation of the expected outcome
+ void testVendorSuboption(Option::Universe u,
+ uint32_t token_vendor_id, uint16_t token_option_code,
+ uint32_t option_vendor_id, uint16_t option_code,
+ TokenOption::RepresentationType repr, std::string expected) {
+ // Let's clear any old values, so we can run multiple cases in each test
+ clearStack();
+
+ ASSERT_NO_THROW(t_.reset(new TokenVendor(u, token_vendor_id, repr,
+ token_option_code)));
+ if (option_vendor_id) {
+ setVendorOption(u, option_vendor_id);
+ if (option_code) {
+ ASSERT_TRUE(vendor_);
+ OptionPtr subopt(new OptionString(u, option_code, "alpha"));
+ vendor_->addOption(subopt);
+ }
+ }
+
+ evaluate(u, expected);
+ }
+
+ /// @brief Tests if vendor class token can handle data chunks properly.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param token_vendor_id enterprise-id used in the token
+ /// @param token_index data index used in the token
+ /// @param option_vendor_id enterprise-id used in option (0 means don't
+ /// create the option)
+ /// @param data_tuples number of data tuples in the option
+ /// @param expected_result text representation of the expected outcome
+ void testVendorClassData(Option::Universe u,
+ uint32_t token_vendor_id, uint16_t token_index,
+ uint32_t option_vendor_id, uint16_t data_tuples,
+ std::string expected) {
+ // Let's clear any old values, so we can run multiple cases in each test
+ clearStack();
+
+ ASSERT_NO_THROW(t_.reset(new TokenVendorClass(u, token_vendor_id,
+ TokenVendor::DATA, token_index)));
+ if (option_vendor_id) {
+ setVendorClassOption(u, option_vendor_id, data_tuples);
+ }
+
+ evaluate(u, expected);
+ }
};
// This tests the toBool() conversions
@@ -1817,4 +2063,662 @@ TEST_F(TokenTest, operatorOrTrue) {
EXPECT_TRUE(checkFile());
}
+// This test verifies if expression vendor[4491].exists works properly in DHCPv4.
+TEST_F(TokenTest, vendor4SpecificVendorExists) {
+ // Case 1: no option, should evaluate to false
+ testVendorExists(Option::V4, 4491, 0, "false");
+
+ // Case 2: option present, but uses different enterprise-id, should fail
+ testVendorExists(Option::V4, 4491, 1234, "false");
+
+ // Case 3: option present and has matchin enterprise-id, should succeed
+ testVendorExists(Option::V4, 4491, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 125 missing, "
+ "pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies if expression vendor[4491].exists works properly in DHCPv6.
+TEST_F(TokenTest, vendor6SpecificVendorExists) {
+ // Case 1: no option, should evaluate to false
+ testVendorExists(Option::V6, 4491, 0, "false");
+
+ // Case 2: option present, but uses different enterprise-id, should fail
+ testVendorExists(Option::V6, 4491, 1234, "false");
+
+ // Case 3: option present and has matchin enterprise-id, should suceed
+ testVendorExists(Option::V6, 4491, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 17 missing, "
+ "pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+/// Test if expression vendor[*].exists works properly for DHCPv4.
+TEST_F(TokenTest, vendor4AnyVendorExists) {
+ // Case 1: no option, should evaluate to false
+ testVendorExists(Option::V4, 0, 0, "false");
+
+ // Case 2: option present with vendor-id 1234, should succeed
+ testVendorExists(Option::V4, 0, 1234, "true");
+
+ // Case 3: option present with vendor-id 4491, should succeed
+ testVendorExists(Option::V4, 0, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 125 missing, "
+ "pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 1234 "
+ "found, pushing result 'true'");
+ addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test if expression vendor[*].exists works properly for DHCPv6.
+TEST_F(TokenTest, vendor6AnyVendorExists) {
+ // Case 1: no option, should evaluate to false
+ testVendorExists(Option::V6, 0, 0, "false");
+
+ // Case 2: option present with vendor-id 1234, should succeed
+ testVendorExists(Option::V6, 0, 1234, "true");
+
+ // Case 3: option present with vendor-id 4491, should succeed
+ testVendorExists(Option::V6, 0, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 17 missing, "
+ "pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 1234 "
+ "found, pushing result 'true'");
+ addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test if expression vendor[*].enterprise works properly for DHCPv4.
+TEST_F(TokenTest, vendor4enterprise) {
+ // Case 1: No option present, should return empty string
+ testVendorEnterprise(Option::V4, 0, "");
+
+ // Case 2: Option with vendor-id 1234, should return "1234"
+ testVendorEnterprise(Option::V4, 1234, encode(1234));
+
+ // Case 3: Option with vendor-id set to maximum value, should still
+ // be able to handle it
+ testVendorEnterprise(Option::V4, 4294967295, encode(4294967295));
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 125 missing, pushing"
+ " result ''");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 1234 as "
+ "result 0x000004D2");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 4294967295"
+ " as result 0xFFFFFFFF");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test if expression vendor[*].enterprise works properly for DHCPv6.
+TEST_F(TokenTest, vendor6enterprise) {
+ // Case 1: No option present, should return empty string
+ testVendorEnterprise(Option::V6, 0, "");
+
+ // Case 2: Option with vendor-id 1234, should return "1234"
+ testVendorEnterprise(Option::V6, 1234, encode(1234));
+
+ // Case 3: Option with vendor-id set to maximum value, should still
+ // be able to handle it
+ testVendorEnterprise(Option::V6, 4294967295, encode(4294967295));
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 17 missing, pushing"
+ " result ''");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 1234 as "
+ "result 0x000004D2");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 4294967295 "
+ "as result 0xFFFFFFFF");
+ EXPECT_TRUE(checkFile());
+}
+
+// This one tests "vendor[4491].option[1].exists" expression. There are so many
+// wonderful ways in which this could fail: the option could not be there,
+// it could have different enterprise-id, may not have suboption 1. Or may
+// have the suboption with valid type, but enterprise may be different.
+TEST_F(TokenTest, vendor4SuboptionExists) {
+ // Case 1: expression vendor[4491].option[1].exists, no option present
+ testVendorSuboption(Option::V4, 4491, 1, 0, 0, TokenOption::EXISTS, "false");
+
+ // Case 2: expression vendor[4491].option[1].exists, option with vendor-id = 1234,
+ // no suboptions, expected result "false"
+ testVendorSuboption(Option::V4, 4491, 1, 1234, 0, TokenOption::EXISTS, "false");
+
+ // Case 3: expression vendor[4491].option[1].exists, option with vendor-id = 1234,
+ // suboption 1, expected result "false"
+ testVendorSuboption(Option::V4, 4491, 1, 1234, 1, TokenOption::EXISTS, "false");
+
+ // Case 4: expression vendor[4491].option[1].exists, option with vendor-id = 4491,
+ // suboption 2, expected result "false"
+ testVendorSuboption(Option::V4, 4491, 1, 4491, 2, TokenOption::EXISTS, "false");
+
+ // Case 5: expression vendor[4491].option[1].exists, option with vendor-id = 4491,
+ // suboption 1, expected result "true"
+ testVendorSuboption(Option::V4, 4491, 1, 4491, 1, TokenOption::EXISTS, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 125 missing, pushing "
+ "result 'false'");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 'false'");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This is similar to the previous one, but tests vendor[4491].option[1].exists
+// for DHCPv6.
+TEST_F(TokenTest, vendor6SuboptionExists) {
+ // Case 1: expression vendor[4491].option[1].exists, no option present
+ testVendorSuboption(Option::V6, 4491, 1, 0, 0, TokenOption::EXISTS, "false");
+
+ // Case 2: expression vendor[4491].option[1].exists, option with vendor-id = 1234,
+ // no suboptions, expected result "false"
+ testVendorSuboption(Option::V6, 4491, 1, 1234, 0, TokenOption::EXISTS, "false");
+
+ // Case 3: expression vendor[4491].option[1].exists, option with vendor-id = 1234,
+ // suboption 1, expected result "false"
+ testVendorSuboption(Option::V6, 4491, 1, 1234, 1, TokenOption::EXISTS, "false");
+
+ // Case 4: expression vendor[4491].option[1].exists, option with vendor-id = 4491,
+ // suboption 2, expected result "false"
+ testVendorSuboption(Option::V6, 4491, 1, 4491, 2, TokenOption::EXISTS, "false");
+
+ // Case 5: expression vendor[4491].option[1].exists, option with vendor-id = 4491,
+ // suboption 1, expected result "true"
+ testVendorSuboption(Option::V6, 4491, 1, 4491, 1, TokenOption::EXISTS, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 17 missing, pushing "
+ "result 'false'");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 'false'");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies if vendor[4491].option[1].hex expression properly returns
+// value of said sub-option or empty string if desired option is not present.
+// This test is for DHCPv4.
+TEST_F(TokenTest, vendor4SuboptionHex) {
+ // Case 1: no option present, should return empty string
+ testVendorSuboption(Option::V4, 4491, 1, 0, 0, TokenOption::HEXADECIMAL, "");
+
+ // Case 2: option with vendor-id = 1234, no suboptions, expected result ""
+ testVendorSuboption(Option::V4, 4491, 1, 1234, 0, TokenOption::HEXADECIMAL, "");
+
+ // Case 3: option with vendor-id = 1234, suboption 1, expected result ""
+ testVendorSuboption(Option::V4, 4491, 1, 1234, 1, TokenOption::HEXADECIMAL, "");
+
+ // Case 4: option with vendor-id = 4491, suboption 2, expected result ""
+ testVendorSuboption(Option::V4, 4491, 1, 4491, 2, TokenOption::HEXADECIMAL, "");
+
+ // Case 5: option with vendor-id = 4491, suboption 1, expected result content
+ // of the option
+ testVendorSuboption(Option::V4, 4491, 1, 4491, 1, TokenOption::HEXADECIMAL, "alpha");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 125 missing, pushing "
+ "result ''");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 0x");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 0x616C706861");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies if vendor[4491].option[1].hex expression properly returns
+// value of said sub-option or empty string if desired option is not present.
+// This test is for DHCPv4.
+TEST_F(TokenTest, vendor6SuboptionHex) {
+ // Case 1: no option present, should return empty string
+ testVendorSuboption(Option::V6, 4491, 1, 0, 0, TokenOption::HEXADECIMAL, "");
+
+ // Case 2: option with vendor-id = 1234, no suboptions, expected result ""
+ testVendorSuboption(Option::V6, 4491, 1, 1234, 0, TokenOption::HEXADECIMAL, "");
+
+ // Case 3: option with vendor-id = 1234, suboption 1, expected result ""
+ testVendorSuboption(Option::V6, 4491, 1, 1234, 1, TokenOption::HEXADECIMAL, "");
+
+ // Case 4: option with vendor-id = 4491, suboption 2, expected result ""
+ testVendorSuboption(Option::V6, 4491, 1, 4491, 2, TokenOption::HEXADECIMAL, "");
+
+ // Case 5: option with vendor-id = 4491, suboption 1, expected result content
+ // of the option
+ testVendorSuboption(Option::V6, 4491, 1, 4491, 1, TokenOption::HEXADECIMAL, "alpha");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_NO_OPTION Option with code 17 missing, pushing "
+ "result ''");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, "
+ "option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 0x");
+ addString("EVAL_DEBUG_OPTION Pushing option 1 with value 0x616C706861");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies that "vendor-class[4491].exists" expression can be used
+// in DHCPv4.
+TEST_F(TokenTest, vendorClass4SpecificVendorExists) {
+ // Case 1: no option present, should fail
+ testVendorClassExists(Option::V4, 4491, 0, "false");
+
+ // Case 2: option exists, but has different vendor-id (1234), should fail
+ testVendorClassExists(Option::V4, 4491, 1234, "false");
+
+ // Case 3: option exists and has matching vendor-id, should succeed
+ testVendorClassExists(Option::V4, 4491, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 124 missing, "
+ "pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies that "vendor-class[4491].exists" expression can be used
+// in DHCPv6.
+TEST_F(TokenTest, vendorClass6SpecificVendorExists) {
+ // Case 1: no option present, should fail
+ testVendorClassExists(Option::V6, 4491, 0, "false");
+
+ // Case 2: option exists, but has different vendor-id (1234), should fail
+ testVendorClassExists(Option::V6, 4491, 1234, "false");
+
+ // Case 3: option exists and has matching vendor-id, should succeed
+ testVendorClassExists(Option::V6, 4491, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, pushing "
+ "result 'false'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies that "vendor-class[*].exists" can be used in DHCPv4
+// and it matches a vendor class option with any vendor-id.
+TEST_F(TokenTest, vendorClass4AnyVendorExists) {
+ // Case 1: no option present, should fail
+ testVendorClassExists(Option::V4, 0, 0, "false");
+
+ // Case 2: option exists, should succeed, regardless of the vendor-id
+ testVendorClassExists(Option::V4, 0, 1234, "true");
+
+ // Case 3: option exists, should succeed, regardless of the vendor-id
+ testVendorClassExists(Option::V4, 0, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 124 missing, "
+ "pushing result 'false'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id 1234 "
+ "found, pushing result 'true'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies that "vendor-class[*].exists" can be used in DHCPv6
+// and it matches a vendor class option with any vendor-id.
+TEST_F(TokenTest, vendorClass6AnyVendorExists) {
+ // Case 1: no option present, should fail
+ testVendorClassExists(Option::V6, 0, 0, "false");
+
+ // Case 2: option exists, should succeed, regardless of the vendor-id
+ testVendorClassExists(Option::V6, 0, 1234, "true");
+
+ // Case 3: option exists, should succeed, regardless of the vendor-id
+ testVendorClassExists(Option::V6, 0, 4491, "true");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, pushing "
+ "result 'false'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id 1234 "
+ "found, pushing result 'true'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id 4491 "
+ "found, pushing result 'true'");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test if expression "vendor-class.enterprise" works properly for DHCPv4.
+TEST_F(TokenTest, vendorClass4enterprise) {
+ // Case 1: No option present, should return empty string
+ testVendorClassEnterprise(Option::V4, 0, "");
+
+ // Case 2: Option with vendor-id 1234, should return "1234"
+ testVendorClassEnterprise(Option::V4, 1234, encode(1234));
+
+ // Case 3: Option with vendor-id set to maximum value, should still
+ // be able to handle it
+ testVendorClassEnterprise(Option::V4, 4294967295, encode(4294967295));
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 124 missing, pushing "
+ "result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id "
+ "1234 as result 0x000004D2");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id "
+ "4294967295 as result 0xFFFFFFFF");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test if expression "vendor-class.enterprise" works properly for DHCPv6.
+TEST_F(TokenTest, vendorClass6enterprise) {
+ // Case 1: No option present, should return empty string
+ testVendorClassEnterprise(Option::V6, 0, "");
+
+ // Case 2: Option with vendor-id 1234, should return "1234"
+ testVendorClassEnterprise(Option::V6, 1234, encode(1234));
+
+ // Case 3: Option with vendor-id set to maximum value, should still
+ // be able to handle it.
+ testVendorClassEnterprise(Option::V6, 4294967295, encode(4294967295));
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, pushing "
+ "result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id "
+ "1234 as result 0x000004D2");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id "
+ "4294967295 as result 0xFFFFFFFF");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test that expression "vendor-class[4491].data" is able to retrieve content
+// of the first tuple of the vendor-class option in DHCPv4.
+TEST_F(TokenTest, vendorClass4SpecificVendorData) {
+ // Case 1: Expression looks for vendor-id 4491, data[0], there is no
+ // vendor-class option at all, expected result is empty string.
+ testVendorClassData(Option::V4, 4491, 0, 0, 0, "");
+
+ // Case 2: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 1234 and no data, expected result is empty string.
+ testVendorClassData(Option::V4, 4491, 0, 1234, 0, "");
+
+ // Case 3: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 4491 and no data, expected result is empty string.
+ // Note that vendor option in v4 always have at least one data chunk, even though
+ // it may be empty. The OptionVendor code was told to not create any special
+ // tuples, but it creates one empty on its own. So the code finds that one
+ // tuple and extracts its content (an empty string).
+ testVendorClassData(Option::V4, 4491, 0, 4491, 0, "");
+
+ // Case 4: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 1234 and 1 data tuple, expected result is empty string
+ testVendorClassData(Option::V4, 4491, 0, 1234, 1, "");
+
+ // Case 5: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 4491 and 1 data tuple, expected result is
+ // content of that data ("alpha")
+ testVendorClassData(Option::V4, 4491, 0, 4491, 1, "alpha");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 124 missing, "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in vendor "
+ "class found, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in vendor "
+ "class found, pushing result 'alpha'");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test that expression "vendor-class[4491].data" is able to retrieve content
+// of the first tuple of the vendor-class option in DHCPv6.
+TEST_F(TokenTest, vendorClass6SpecificVendorData) {
+ // Case 1: Expression looks for vendor-id 4491, data[0], there is no
+ // vendor-class option at all, expected result is empty string.
+ testVendorClassData(Option::V6, 4491, 0, 0, 0, "");
+
+ // Case 2: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 1234 and no data, expected result is empty string.
+ testVendorClassData(Option::V6, 4491, 0, 1234, 0, "");
+
+ // Case 3: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 4491 and no data, expected result is empty string
+ testVendorClassData(Option::V6, 4491, 0, 4491, 0, "");
+
+ // Case 4: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 1234 and 1 data tuple, expected result is empty string
+ testVendorClassData(Option::V6, 4491, 0, 1234, 1, "");
+
+ // Case 5: Expression looks for vendor-id 4491, data[0], there is
+ // vendor-class with vendor-id 4491 and 1 data tuple, expected result is
+ // content of that data ("alpha")
+ testVendorClassData(Option::V6, 4491, 0, 4491, 1, "alpha");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 0, "
+ "but option with enterprise-id 4491 has only 0 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in vendor "
+ "class found, pushing result 'alpha'");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test that expression "vendor-class[*].data" is able to retrieve content
+// of the first tuple of the vendor-class option in DHCPv4.
+TEST_F(TokenTest, vendorClass4AnyVendorData) {
+ // Case 1: Expression looks for any vendor-id (0), data[0], there is no
+ // vendor-class option at all, expected result is empty string.
+ testVendorClassData(Option::V4, 0, 0, 0, 0, "");
+
+ // Case 2: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 1234 and no data (one empty tuple), expected
+ // result is empty string.
+ testVendorClassData(Option::V4, 0, 0, 1234, 0, "");
+
+ // Case 3: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 4491 and no data (one empty tuple), expected
+ // result is empty string.
+ testVendorClassData(Option::V4, 0, 0, 4491, 0, "");
+
+ // Case 4: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 1234 and 1 data tuple, expected result is
+ // content of that data ("alpha")
+ testVendorClassData(Option::V4, 0, 0, 1234, 1, "alpha");
+
+ // Case 5: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 4491 and 1 data tuple, expected result is
+ // content of that data ("alpha")
+ testVendorClassData(Option::V4, 0, 0, 4491, 1, "alpha");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 124 missing, "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in "
+ "vendor class found, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in "
+ "vendor class found, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in "
+ "vendor class found, pushing result 'alpha'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in "
+ "vendor class found, pushing result 'alpha'");
+ EXPECT_TRUE(checkFile());
+}
+
+// Test that expression "vendor-class[*].data" is able to retrieve content
+// of the first tuple of the vendor-class option in DHCPv6.
+TEST_F(TokenTest, vendorClass6AnyVendorData) {
+ // Case 1: Expression looks for any vendor-id (0), data[0], there is no
+ // vendor-class option at all, expected result is empty string.
+ testVendorClassData(Option::V6, 0, 0, 0, 0, "");
+
+ // Case 2: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 1234 and no data, expected result is empty string.
+ testVendorClassData(Option::V6, 0, 0, 1234, 0, "");
+
+ // Case 3: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 4491 and no data, expected result is empty string
+ testVendorClassData(Option::V6, 0, 0, 4491, 0, "");
+
+ // Case 4: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 1234 and 1 data tuple, expected result is
+ // content of that data ("alpha")
+ testVendorClassData(Option::V6, 0, 0, 1234, 1, "alpha");
+
+ // Case 5: Expression looks for any vendor-id (0), data[0], there is
+ // vendor-class with vendor-id 4491 and 1 data tuple, expected result is
+ // content of that data ("alpha")
+ testVendorClassData(Option::V6, 0, 0, 4491, 1, "alpha");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 0, "
+ "but option with enterprise-id 1234 has only 0 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 0, "
+ "but option with enterprise-id 4491 has only 0 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in vendor "
+ "class found, pushing result 'alpha'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 0 (out of 1 received) in vendor "
+ "class found, pushing result 'alpha'");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies if expression vendor-class[4491].data[3] is able to access
+// the tuple specified by index. This is a DHCPv4 test.
+TEST_F(TokenTest, vendorClass4DataIndex) {
+ // Case 1: Expression looks for vendor-id 4491, data[3], there is no
+ // vendor-class option at all, expected result is empty string.
+ testVendorClassData(Option::V4, 4491, 3, 0, 0, "");
+
+ // Case 2: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 1234 and no data, expected result is empty string.
+ testVendorClassData(Option::V4, 4491, 3, 1234, 0, "");
+
+ // Case 3: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 4491 and no data, expected result is empty string
+ testVendorClassData(Option::V4, 4491, 3, 4491, 0, "");
+
+ // Case 4: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 1234 and 1 data tuple, expected result is empty string.
+ testVendorClassData(Option::V4, 4491, 3, 1234, 1, "");
+
+ // Case 5: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 4491, but has only 3 data tuples, expected
+ // result is empty string.
+ testVendorClassData(Option::V4, 4491, 3, 4491, 3, "");
+
+ // Case 6: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 4491 and 5 data tuples, expected result is
+ // content of that tuple ("gamma")
+ testVendorClassData(Option::V4, 4491, 3, 4491, 5, "gamma");
+
+ // Case 6: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 1234 and 5 data tuples, expected result is
+ // empty string, because vendor-id does not match.
+ testVendorClassData(Option::V4, 4491, 3, 1234, 5, "");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 124 missing, "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 3, "
+ "but option with enterprise-id 4491 has only 1 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 3, "
+ "but option with enterprise-id 4491 has only 3 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 3 (out of 5 received) in vendor "
+ "class found, pushing result 'gamma'");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ EXPECT_TRUE(checkFile());
+}
+
+// This test verifies if expression vendor-class[4491].data[3] is able to access
+// the tuple specified by index. This is a DHCPv6 test.
+TEST_F(TokenTest, vendorClass6DataIndex) {
+ // Case 1: Expression looks for vendor-id 4491, data[3], there is no
+ // vendor-class option at all, expected result is empty string.
+ testVendorClassData(Option::V6, 4491, 3, 0, 0, "");
+
+ // Case 2: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 1234 and no data, expected result is empty string.
+ testVendorClassData(Option::V6, 4491, 3, 1234, 0, "");
+
+ // Case 3: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 4491 and no data, expected result is empty string
+ testVendorClassData(Option::V6, 4491, 3, 4491, 0, "");
+
+ // Case 4: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 1234 and 5 data tuples, expected result is empty string.
+ testVendorClassData(Option::V6, 4491, 3, 1234, 5, "");
+
+ // Case 5: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 4491, but has only 3 data tuples, expected
+ // result is empty string.
+ testVendorClassData(Option::V6, 4491, 3, 4491, 3, "");
+
+ // Case 6: Expression looks for vendor-id 4491, data[3], there is
+ // vendor-class with vendor-id 4491 and 5 data tuples, expected result is
+ // content of that tuple ("gamma")
+ testVendorClassData(Option::V6, 4491, 3, 4491, 5, "gamma");
+
+ // Check if the logged messages are correct.
+ addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 3, "
+ "but option with enterprise-id 4491 has only 0 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for "
+ "4491, option had 1234, pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 3, "
+ "but option with enterprise-id 4491 has only 3 data tuple(s), "
+ "pushing result ''");
+ addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 3 (out of 5 received) in vendor"
+ " class found, pushing result 'gamma'");
+ EXPECT_TRUE(checkFile());
+}
+
};
diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc
index 918e4e9ae7..7ef16a0348 100644
--- a/src/lib/eval/token.cc
+++ b/src/lib/eval/token.cc
@@ -12,6 +12,10 @@
#include
#include
#include
+#include
+#include
+#include
+#include
#include
#include
@@ -137,6 +141,16 @@ TokenOption::evaluate(Pkt& pkt, ValueStack& values) {
}
}
+std::string
+TokenOption::pushFailure(ValueStack& values) {
+ std::string txt;
+ if (representation_type_ == EXISTS) {
+ txt = "false";
+ }
+ values.push(txt);
+ return (txt);
+}
+
TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
const RepresentationType& rep_type)
:TokenOption(option_code, rep_type) {
@@ -641,3 +655,227 @@ TokenOr::evaluate(Pkt& /*pkt*/, ValueStack& values) {
.arg('\'' + op2 + '\'')
.arg('\'' + values.top() + '\'');
}
+
+TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, RepresentationType repr,
+ uint16_t option_code)
+ :TokenOption(option_code, repr), universe_(u), vendor_id_(vendor_id),
+ field_(option_code ? SUBOPTION : EXISTS)
+{
+}
+
+TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field)
+ :TokenOption(0, TokenOption::HEXADECIMAL), universe_(u), vendor_id_(vendor_id),
+ field_(field)
+{
+ if (field_ == EXISTS) {
+ representation_type_ = TokenOption::EXISTS;
+ }
+}
+
+uint32_t TokenVendor::getVendorId() const {
+ return (vendor_id_);
+}
+
+TokenVendor::FieldType TokenVendor::getField() const {
+ return (field_);
+}
+
+void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) {
+
+ // Get the option first.
+ uint16_t code = 0;
+ switch (universe_) {
+ case Option::V4:
+ code = DHO_VIVSO_SUBOPTIONS;
+ break;
+ case Option::V6:
+ code = D6O_VENDOR_OPTS;
+ break;
+ }
+
+ OptionPtr opt = pkt.getOption(code);
+ OptionVendorPtr vendor = boost::dynamic_pointer_cast(opt);
+ if (!vendor) {
+ // There's no vendor option, give up.
+ std::string txt = pushFailure(values);
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_NO_OPTION)
+ .arg(code)
+ .arg(txt);
+ return;
+ }
+
+ if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
+ // There is vendor option, but it has other vendor-id value
+ // than we're looking for. (0 means accept any vendor-id)
+ std::string txt = pushFailure(values);
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH)
+ .arg(vendor_id_)
+ .arg(vendor->getVendorId())
+ .arg(txt);
+ return;
+ }
+
+ switch (field_) {
+ case ENTERPRISE_ID:
+ {
+ // Extract enterprise-id
+ string txt(sizeof(uint32_t), 0);
+ uint32_t value = htonl(vendor->getVendorId());
+ memcpy(&txt[0], &value, sizeof(uint32_t));
+ values.push(txt);
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID)
+ .arg(vendor->getVendorId())
+ .arg(util::encode::encodeHex(std::vector(txt.begin(),
+ txt.end())));
+ return;
+ }
+ case SUBOPTION:
+ /// This is vendor[X].option[Y].exists, let's try to
+ /// extract the option
+ TokenOption::evaluate(pkt, values);
+ return;
+ case EXISTS:
+ // We already passed all the checks: the option is there and has specified
+ // enterprise-id.
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_EXISTS)
+ .arg(vendor->getVendorId())
+ .arg("true");
+ values.push("true");
+ return;
+ case DATA:
+ // This is for vendor-class option, we can skip it here.
+ isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
+ return;
+ }
+}
+
+OptionPtr TokenVendor::getOption(Pkt& pkt) {
+ uint16_t code = 0;
+ switch (universe_) {
+ case Option::V4:
+ code = DHO_VIVSO_SUBOPTIONS;
+ break;
+ case Option::V6:
+ code = D6O_VENDOR_OPTS;
+ break;
+ }
+
+ OptionPtr opt = pkt.getOption(code);
+ if (!opt) {
+ // If vendor option is not found, return NULL
+ return (opt);
+ }
+
+ // If vendor option is found, try to return its
+ // encapsulated option.
+ return (opt->getOption(option_code_));
+}
+
+TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id,
+ RepresentationType repr)
+ :TokenVendor(u, vendor_id, repr, 0), index_(0) {
+}
+
+TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id,
+ FieldType field, uint16_t index)
+ :TokenVendor(u, vendor_id, TokenOption::HEXADECIMAL, 0), index_(index)
+{
+ field_ = field;
+}
+
+uint16_t TokenVendorClass::getDataIndex() const {
+ return (index_);
+}
+
+void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) {
+
+ // Get the option first.
+ uint16_t code = 0;
+ switch (universe_) {
+ case Option::V4:
+ code = DHO_VIVCO_SUBOPTIONS;
+ break;
+ case Option::V6:
+ code = D6O_VENDOR_CLASS;
+ break;
+ }
+
+ OptionPtr opt = pkt.getOption(code);
+ OptionVendorClassPtr vendor = boost::dynamic_pointer_cast(opt);
+ if (!vendor) {
+ // There's no vendor class option, give up.
+ std::string txt = pushFailure(values);
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_NO_OPTION)
+ .arg(code)
+ .arg(txt);
+ return;
+ }
+
+ if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
+ // There is vendor option, but it has other vendor-id value
+ // than we're looking for. (0 means accept any vendor-id)
+ std::string txt = pushFailure(values);
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH)
+ .arg(vendor_id_)
+ .arg(vendor->getVendorId())
+ .arg(txt);
+ return;
+ }
+
+ switch (field_) {
+ case ENTERPRISE_ID:
+ {
+ // Extract enterprise-id
+ string txt(sizeof(uint32_t), 0);
+ uint32_t value = htonl(vendor->getVendorId());
+ memcpy(&txt[0], &value, sizeof(uint32_t));
+ values.push(txt);
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID)
+ .arg(vendor->getVendorId())
+ .arg(util::encode::encodeHex(std::vector(txt.begin(),
+ txt.end())));
+ return;
+ }
+ case SUBOPTION:
+ // Extract sub-options
+ isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
+ return;
+ case EXISTS:
+ // We already passed all the checks: the option is there and has specified
+ // enterprise-id.
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_EXISTS)
+ .arg(vendor->getVendorId())
+ .arg("true");
+ values.push("true");
+ return;
+ case DATA:
+ {
+ size_t max = vendor->getTuplesNum();
+ if (index_ + 1 > max) {
+ // The index specified is out of bounds, e.g. there are only
+ // 2 tuples and index specified is 5.
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND)
+ .arg(index_)
+ .arg(vendor->getVendorId())
+ .arg(max)
+ .arg("");
+ values.push("");
+ return;
+ }
+
+ OpaqueDataTuple tuple = vendor->getTuple(index_);
+ OpaqueDataTuple::Buffer buf = tuple.getData();
+ string txt(buf.begin(), buf.end());
+
+ LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA)
+ .arg(index_)
+ .arg(max)
+ .arg(txt);
+
+ values.push(txt);
+ return;
+ }
+ default:
+ isc_throw(EvalTypeError, "Invalid field specified." << field_);
+ }
+}
diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h
index ff2e78c2cd..aabca84397 100644
--- a/src/lib/eval/token.h
+++ b/src/lib/eval/token.h
@@ -256,6 +256,14 @@ protected:
/// @return option instance (or NULL if not found)
virtual OptionPtr getOption(Pkt& pkt);
+ /// @brief Auxiliary method that puts string representing a failure
+ ///
+ /// Depending on the representation type, this is either "" or "false".
+ ///
+ /// @param values a string representing failure will be pushed here.
+ /// @return value pushed
+ virtual std::string pushFailure(ValueStack& values);
+
uint16_t option_code_; ///< Code of the option to be extracted
RepresentationType representation_type_; ///< Representation type.
};
@@ -728,6 +736,191 @@ public:
void evaluate(Pkt& pkt, ValueStack& values);
};
+/// @brief Token that represents vendor options in DHCPv4 and DHCPv6.
+///
+/// It covers vendor independent vendor information option (125, DHCPv4)
+/// and vendor option (17, DHCPv6). Since both of those options may have
+/// suboptions, this class is derived from TokenOption and leverages its
+/// ability to operate on sub-options. It also adds additional capabilities.
+/// In particular, it allows retrieving enterprise-id.
+///
+/// It can represent the following expressions:
+/// vendor[4491].exists - if vendor option with enterprise-id = 4491 exists
+/// vendor[*].exists - if any vendor option exists
+/// vendor.enterprise - returns enterprise-id from vendor option
+/// vendor[4491].option[1].exists - check if suboption 1 exists for vendor 4491
+/// vendor[4491].option[1].hex - return content of suboption 1 for vendor 4491
+class TokenVendor : public TokenOption {
+public:
+
+ /// @brief Specifies a field of the vendor option
+ enum FieldType {
+ SUBOPTION, ///< If this token fetches a suboption, not a field.
+ ENTERPRISE_ID, ///< enterprise-id field (vendor-info, vendor-class)
+ EXISTS, ///< vendor[123].exists
+ DATA ///< data chunk, used in derived vendor-class only
+ };
+
+ /// @brief Constructor used for accessing a field
+ ///
+ /// @param u universe (either V4 or V6)
+ /// @param vendor_id specifies enterprise-id (0 means any)
+ /// @param field specifies which field should be returned
+ TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field);
+
+
+ /// @brief Constructor used for accessing an option
+ ///
+ /// This constructor is used for accessing suboptions. In general
+ /// option_code is mandatory, except when repr is EXISTS. For
+ /// option_code = 0 and repr = EXISTS, the token will return true
+ /// if the whole option exists, not suboptions.
+ ///
+ /// @param u universe (either V4 or V6)
+ /// @param vendor_id specifies enterprise-id (0 means any)
+ /// @param repr representation type (hex or exists)
+ /// @param option_code sub-option code
+ TokenVendor(Option::Universe u, uint32_t vendor_id, RepresentationType repr,
+ uint16_t option_code = 0);
+
+ /// @brief Returns enterprise-id
+ ///
+ /// Used in tests only.
+ ///
+ /// @return enterprise-id
+ uint32_t getVendorId() const;
+
+ /// @brief Returns field.
+ ///
+ /// Used in tests only.
+ ///
+ /// @return field type.
+ FieldType getField() const;
+
+ /// @brief This is a method for evaluating a packet.
+ ///
+ /// Depending on the value of vendor_id, field type, representation and
+ /// option code, it will attempt to return specified characteristic of the
+ /// vendor option
+ ///
+ /// If vendor-id is specified, check only option with that particular
+ /// enterprise-id. If vendor-id is 0, check any vendor option, regardless
+ /// of its enterprise-id value.
+ ///
+ /// If FieldType is NONE, get specified suboption represented by option_code
+ /// and represent it as specified by repr.
+ ///
+ /// If FieldType is ENTERPRISE_ID, return value of the enterprise-id field
+ /// or "" if there's no vendor option.
+ ///
+ /// @throw EvalTypeError for any other FieldType values.
+ ///
+ /// The parameters passed are:
+ ///
+ /// @param pkt - vendor options will be searched for here.
+ /// @param values - the evaluated value will be pushed here.
+ virtual void evaluate(Pkt& pkt, ValueStack& values);
+
+protected:
+ /// @brief Attempts to get a suboption.
+ ///
+ /// This method overrides behavior of TokenOption method. It attempts to retrieve
+ /// the sub-option of the vendor option. Using derived method allows usage of
+ /// TokenOption routines.
+ ///
+ /// @param pkt vendor option will be searched here.
+ /// @return suboption of the vendor option (if exists)
+ virtual OptionPtr getOption(Pkt& pkt);
+
+ /// @brief Universe (V4 or V6)
+ ///
+ /// We need to remember it, because depending on the universe, the code needs
+ /// to retrieve either option 125 (DHCPv4) or 17 (DHCPv6).
+ Option::Universe universe_;
+
+ /// @brief Enterprise-id value
+ ///
+ /// Yeah, I know it technically should be called enterprise-id, but that's
+ /// too long and everyone calls it vendor-id.
+ uint32_t vendor_id_;
+
+ /// @brief Specifies which field should be accessed.
+ FieldType field_;
+};
+
+/// @brief Token that represents vendor class options in DHCPv4 and DHCPv6.
+///
+/// It covers vendor independent vendor information option (124, DHCPv4)
+/// and vendor option (16, DHCPv6). Contrary to vendor options, vendor class
+/// options don't have suboptions, but have data chunks (tuples) instead.
+/// Therefore they're not referenced by option codes, but by indexes.
+/// The first data chunk is data[0], the second is data[1] etc.
+///
+/// This class is derived from OptionVendor to take advantage of the
+/// enterprise handling field and field type.
+///
+/// It can represent the following expressions:
+/// vendor-class[4491].exists
+/// vendor-class[*].exists
+/// vendor-class[*].enterprise
+/// vendor-class[4491].data - content of the opaque-data of the first tuple
+/// vendor-class[4491].data[3] - content of the opaque-data of the 4th tuple
+class TokenVendorClass : public TokenVendor {
+public:
+
+ /// @brief This constructor is used to access fields.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id value of enterprise-id field (0 means any)
+ /// @param repr representation type (EXISTS or HEX)
+ TokenVendorClass(Option::Universe u, uint32_t vendor_id, RepresentationType repr);
+
+ /// @brief This constructor is used to access data chunks.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param vendor_id value of enterprise-id field (0 means any)
+ /// @param field type of the field (usually DATA or ENTERPRISE)
+ /// @param index specifies which data chunk to retrieve
+ TokenVendorClass(Option::Universe u, uint32_t vendor_id, FieldType field,
+ uint16_t index = 0);
+
+ /// @brief Returns data index.
+ ///
+ /// Used in testing.
+ /// @return data index (specifies which data chunk to retrieve)
+ uint16_t getDataIndex() const;
+
+protected:
+
+ /// @brief This is a method for evaluating a packet.
+ ///
+ /// Depending on the value of vendor_id, field type, representation and
+ /// option code, it will attempt to return specified characteristic of the
+ /// vendor option
+ ///
+ /// If vendor-id is specified, check only option with that particular
+ /// enterprise-id. If vendor-id is 0, check any vendor option, regardless
+ /// of its enterprise-id value.
+ ///
+ /// If FieldType is ENTERPRISE_ID, return value of the enterprise-id field
+ /// or "" if there's no vendor option.
+ ///
+ /// If FieldType is DATA, get specified data chunk represented by index_.
+ ///
+ /// If FieldType is EXISTS, return true if vendor-id matches.
+ ///
+ /// @throw EvalTypeError for any other FieldType values.
+ ///
+ /// The parameters passed are:
+ ///
+ /// @param pkt - vendor options will be searched for here.
+ /// @param values - the evaluated value will be pushed here.
+ void evaluate(Pkt& pkt, ValueStack& values);
+
+ /// @brief Data chunk index.
+ uint16_t index_;
+};
+
}; // end of isc::dhcp namespace
}; // end of isc namespace
diff --git a/src/lib/testutils/log_utils.cc b/src/lib/testutils/log_utils.cc
index 2bfcc78843..669d91e01d 100644
--- a/src/lib/testutils/log_utils.cc
+++ b/src/lib/testutils/log_utils.cc
@@ -5,12 +5,14 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include
+#include
namespace isc {
namespace dhcp {
namespace test {
-LogContentTest::LogContentTest() {
+LogContentTest::LogContentTest()
+ :verbose_(false) {
// Get rid of any old files
remFile();
@@ -41,18 +43,31 @@ bool LogContentTest::checkFile() {
int i = 0;
bool found = true;
+ using namespace std;
+
while (getline(file, line) && (i != exp_strings_.size())) {
exp_line = exp_strings_[i];
+ if (verbose_) {
+ cout << "Read line :" << line << endl;
+ cout << "Looking for:" << exp_line << endl;
+ }
i++;
if (string::npos == line.find(exp_line)) {
+ if (verbose_) {
+ cout << "Verdict : not found" << endl;
+ }
found = false;
}
}
file.close();
- if ((i != exp_strings_.size()) || (found == false))
+ if ((i != exp_strings_.size()) || (found == false)) {
+ if (verbose_) {
+ cout << "Final verdict: false" << endl;
+ }
return (false);
+ }
return (true);
}
diff --git a/src/lib/testutils/log_utils.h b/src/lib/testutils/log_utils.h
index fbfd24cb33..c7f835b389 100644
--- a/src/lib/testutils/log_utils.h
+++ b/src/lib/testutils/log_utils.h
@@ -63,6 +63,15 @@ public:
/// @brief remove the test log file
void remFile();
+ /// @brief Enables or disables verbose mode.
+ ///
+ /// See @ref verbose_ for details.
+ ///
+ /// @param talk_a_lot (true - as the name says, false - shut up)
+ void logCheckVerbose(bool talk_a_lot) {
+ verbose_ = talk_a_lot;
+ }
+
/// @brief Add a string to the vector of expected strings
///
/// @param new_string the string to add to the end of the vector
@@ -71,6 +80,14 @@ public:
vector exp_strings_;
static const char* LOG_FILE;
+
+ /// @brief controls whether the checkFile() should print more details.
+ ///
+ /// If set to true, checkFile() will print each expected line, each
+ /// logged line and will print out a failure message if those two do
+ /// not match. Also, a final verdict is printed. Everything is printed
+ /// on stdout.
+ bool verbose_;
};