mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 13:07:50 +00:00
[master] Merge branch 'trac4271' (vendor options support in classification)
# Conflicts: # src/lib/eval/lexer.cc # src/lib/eval/lexer.ll # src/lib/eval/location.hh # src/lib/eval/parser.cc # src/lib/eval/parser.h # src/lib/eval/parser.yy # src/lib/eval/position.hh # src/lib/eval/stack.hh # src/lib/eval/tests/context_unittest.cc # src/lib/eval/tests/token_unittest.cc # src/lib/eval/token.cc # src/lib/eval/token.h
This commit is contained in:
commit
ef676368f9
@ -202,7 +202,7 @@
|
||||
-->
|
||||
<row>
|
||||
<entry>Option existence</entry>
|
||||
<entry>option[123].exist</entry>
|
||||
<entry>option[123].exists</entry>
|
||||
<entry>'true'</entry>
|
||||
<entry>If the option with given code is present in the
|
||||
packet "true" else "false"</entry>
|
||||
@ -315,6 +315,88 @@
|
||||
<entry>The value of the transaction id in the DHCPv6
|
||||
packet.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Vendor option existence (any vendor)</entry>
|
||||
<entry>vendor[*].exists</entry>
|
||||
<entry>true</entry>
|
||||
<entry>Returns whether a vendor option from any vendor
|
||||
is present ('true') or absent ('false').</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Vendor option existence (specific vendor)</entry>
|
||||
<entry>vendor[4491].exists</entry>
|
||||
<entry>true</entry>
|
||||
<entry>Returns whether a vendor option from specified
|
||||
vendor (determined by its enterprise-id)
|
||||
is present ('true') or absent ('false').</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Enterprise-id from vendor option</entry>
|
||||
<entry>vendor.enterprise</entry>
|
||||
<entry>0x0000118b</entry>
|
||||
<entry>If the vendor option is present, it returns the
|
||||
value of the enterprise-id field padded to 4
|
||||
bytes. Returns '' otherwise.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Vendor sub-option existence</entry>
|
||||
<entry>vendor[4491].option[1].exists</entry>
|
||||
<entry>true</entry>
|
||||
<entry>Returns 'true' if there is vendor option with
|
||||
specified enterprise-id and given sub-option is present.
|
||||
Returns 'false' otherwise.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Vendor sub-option content</entry>
|
||||
<entry>vendor[4491].option[1].hex</entry>
|
||||
<entry>docsis3.0</entry>
|
||||
<entry>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.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Vendor class option existence (any vendor)</entry>
|
||||
<entry>vendor-class[*].exists</entry>
|
||||
<entry>true</entry>
|
||||
<entry>Returns whether a vendor class option from any vendor
|
||||
is present ('true') or absent ('false').</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Vendor class option existence (specific vendor)</entry>
|
||||
<entry>vendor-class[4491].exists</entry>
|
||||
<entry>true</entry>
|
||||
<entry>Returns whether a vendor class option from specified
|
||||
vendor (determined by its enterprise-id)
|
||||
is present ('true') or absent ('false').</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Enterprise-id from vendor class option</entry>
|
||||
<entry>vendor-class.enterprise</entry>
|
||||
<entry>0x0000118b</entry>
|
||||
<entry>If the vendor option is present, it returns the
|
||||
value of the enterprise-id field padded to 4
|
||||
bytes. Returns '' otherwise.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>First data chunk from vendor class option</entry>
|
||||
<entry>vendor-class[4491].data</entry>
|
||||
<entry>docsis3.0</entry>
|
||||
<entry>Returns content of the first data chunk from
|
||||
the vendor class option with specified enterprise-id.
|
||||
Returns '' if missing.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Specific data chunk from vendor class option</entry>
|
||||
<entry>vendor-class[4491].data[3]</entry>
|
||||
<entry>docsis3.0</entry>
|
||||
<entry>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.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@ -341,7 +423,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
"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.
|
||||
</para>
|
||||
|
||||
@ -387,6 +469,33 @@
|
||||
"0x00000001" or simply 1 as in "pkt6.msgtype == 1".
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>Vendor Class Identifier (option 60 in DHCPv4) can be
|
||||
accessed using option[60] expression.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>
|
||||
<table frame="all" id="classification-expressions-list">
|
||||
<title>List of Classification Expressions</title>
|
||||
@ -407,7 +516,8 @@
|
||||
<row><entry>And</entry> <entry>('foo' == 'bar') and ('bar' == 'foo')</entry><entry>Logical and</entry></row>
|
||||
<row><entry>Or</entry> <entry>('foo' == 'bar') or ('bar' == 'foo')</entry><entry>Logical or</entry></row>
|
||||
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
|
||||
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the concatenation of the strings</entry></row>
|
||||
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the
|
||||
concatenation of the strings</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
@ -3583,9 +3583,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc -->
|
||||
<listitem>
|
||||
<simpara>Host reservation (static addresses) is not supported yet.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>Full featured client classification is not supported yet.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
BOOTP (<ulink url="http://tools.ietf.org/html/rfc951">RFC 951</ulink>)
|
||||
@ -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.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>Address duplication report (DECLINE) is not supported yet.</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
|
@ -3828,8 +3828,7 @@ should include options from the isc option space:
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
Duplication report (DECLINE) and client reconfiguration (RECONFIGURE) are
|
||||
not yet supported.
|
||||
Client reconfiguration (RECONFIGURE) is not yet supported.
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -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
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
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<int>(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<int>(number);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
error(loc, "Invalid integer value in " + number);
|
||||
}
|
||||
if (n < 0 || n >= std::numeric_limits<uint8_t>::max()) {
|
||||
error(loc, "Invalid value in "
|
||||
+ number + ". Allowed range: 0..255");
|
||||
}
|
||||
|
||||
return (static_cast<uint8_t>(n));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EvalContext::convertUint32(const std::string& number,
|
||||
const isc::eval::location& loc)
|
||||
{
|
||||
uint64_t n = 0;
|
||||
try {
|
||||
n = boost::lexical_cast<uint64_t>(number);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
error(loc, "Invalid value in " + number);
|
||||
}
|
||||
if (n >= std::numeric_limits<uint32_t>::max()) {
|
||||
error(loc, "Invalid value in "
|
||||
+ number + ". Allowed range: 0..4294967295");
|
||||
}
|
||||
|
||||
return (static_cast<uint32_t>(n));
|
||||
}
|
||||
|
||||
void
|
||||
EvalContext::fatal (const std::string& what)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
||||
|
||||
|
@ -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));
|
||||
<<EOF>> return isc::eval::EvalParser::make_END(loc);
|
||||
%%
|
||||
|
@ -1,4 +1,3 @@
|
||||
// Generated 201608161508
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Locations for Bison parsers in C++
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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<int>(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 <typename Base>
|
||||
EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const uint32_t v, const location_type& l)
|
||||
: Base (t)
|
||||
, value (v)
|
||||
, location (l)
|
||||
{}
|
||||
|
||||
template <typename Base>
|
||||
EvalParser::basic_symbol<Base>::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<token_type> (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
|
||||
|
||||
|
||||
|
||||
|
@ -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 <std::string> STRING "constant string"
|
||||
@ -83,6 +88,7 @@ using namespace isc::eval;
|
||||
%token <std::string> IP_ADDRESS "ip address"
|
||||
|
||||
%type <uint16_t> option_code
|
||||
%type <uint32_t> enterprise_id
|
||||
%type <TokenOption::RepresentationType> option_repr_type
|
||||
%type <TokenRelay6Field::FieldType> relay6_field
|
||||
%type <uint8_t> 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"));
|
||||
|
@ -1,4 +1,3 @@
|
||||
// Generated 201608161508
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Positions for Bison parsers in C++
|
||||
|
@ -1,4 +1,3 @@
|
||||
// Generated 201608161508
|
||||
// A Bison parser, made by GNU Bison 3.0.4.
|
||||
|
||||
// Stack handling for Bison parsers in C++
|
||||
|
@ -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<TokenVendor> vendor =
|
||||
boost::dynamic_pointer_cast<TokenVendor>(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<TokenVendor> vendor =
|
||||
boost::dynamic_pointer_cast<TokenVendor>(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<TokenVendorClass> vendor =
|
||||
boost::dynamic_pointer_cast<TokenVendorClass>(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'",
|
||||
"<string>:1.8-9: Nest level has invalid value in -1. "
|
||||
"Allowed range: 0..31");
|
||||
"<string>: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) {
|
||||
"<string>: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);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <dhcp/dhcp4.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/option_string.h>
|
||||
#include <dhcp/option_vendor.h>
|
||||
#include <dhcp/option_vendor_class.h>
|
||||
#include <log/logger_manager.h>
|
||||
#include <log/logger_name.h>
|
||||
#include <log/logger_support.h>
|
||||
@ -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());
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include <dhcp/pkt4.h>
|
||||
#include <dhcp/pkt6.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <dhcp/dhcp4.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/option_vendor.h>
|
||||
#include <dhcp/option_vendor_class.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
@ -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<OptionVendor>(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<uint8_t>(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<OptionVendorClass>(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<uint8_t>(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_);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -5,12 +5,14 @@
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <testutils/log_utils.h>
|
||||
#include <iostream>
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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<string> 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_;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user