From ae2d315369b96f3337ea15974034b7dac1ef5128 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 9 Aug 2016 15:36:46 +0200 Subject: [PATCH 01/15] [4271] Vendor and Vendor-class tokens implemented. --- src/lib/eval/Makefile.am | 5 + src/lib/eval/eval_context.cc | 45 +- src/lib/eval/eval_context.h | 20 +- src/lib/eval/lexer.ll | 5 + src/lib/eval/parser.yy | 101 +++- src/lib/eval/tests/context_unittest.cc | 274 ++++++++++- src/lib/eval/tests/token_unittest.cc | 646 ++++++++++++++++++++++++- src/lib/eval/token.cc | 202 +++++++- src/lib/eval/token.h | 192 ++++++++ 9 files changed, 1475 insertions(+), 15 deletions(-) diff --git a/src/lib/eval/Makefile.am b/src/lib/eval/Makefile.am index 2c8dd8ccd7..95cbba0c40 100644 --- a/src/lib/eval/Makefile.am +++ b/src/lib/eval/Makefile.am @@ -85,6 +85,11 @@ parser: lexer.cc location.hh position.hh stack.hh parser.cc parser.h @echo "Flex/bison files regenerated" # --- Flex/Bison stuff below -------------------------------------------------- +# When debugging grammar issues, it's useful to add -v to bison parameters. +# bison will generate parser.output file that explains the whole grammar. +# It can be used to manually follow what's going on in the parser. +# This is especially useful if yydebug_ is set to 1 as that variable +# will cause parser to print out its internal state. location.hh position.hh stack.hh parser.cc parser.h: parser.yy $(YACC) --defines=parser.h -o parser.cc parser.yy diff --git a/src/lib/eval/eval_context.cc b/src/lib/eval/eval_context.cc index 059cb0fe63..b1f4dbf443 100644 --- a/src/lib/eval/eval_context.cc +++ b/src/lib/eval/eval_context.cc @@ -13,6 +13,7 @@ #include #include #include +#include EvalContext::EvalContext(const Option::Universe& option_universe) : trace_scanning_(false), trace_parsing_(false), @@ -97,14 +98,9 @@ uint8_t EvalContext::convertNestLevelNumber(const std::string& nest_level, const isc::eval::location& loc) { - int n = 0; - try { - n = boost::lexical_cast(nest_level); - } catch (const boost::bad_lexical_cast &) { - error(loc, "Nest level has invalid value in " + nest_level); - } + uint8_t n = convertUint8(nest_level, loc); if (option_universe_ == Option::V6) { - if (n < 0 || n >= HOP_COUNT_LIMIT) { + if (n >= HOP_COUNT_LIMIT) { error(loc, "Nest level has invalid value in " + nest_level + ". Allowed range: 0..31"); } @@ -112,9 +108,44 @@ EvalContext::convertNestLevelNumber(const std::string& nest_level, error(loc, "Nest level invalid for DHCPv4 packets"); } + return (n); +} + +uint8_t +EvalContext::convertUint8(const std::string& number, + const isc::eval::location& loc) +{ + int n = 0; + try { + n = boost::lexical_cast(number); + } catch (const boost::bad_lexical_cast &) { + error(loc, "Invalid integer value in " + number); + } + if (n < 0 || n >= std::numeric_limits::max()) { + error(loc, "Invalid value in " + + number + ". Allowed range: 0..255"); + } + return (static_cast(n)); } +uint32_t +EvalContext::convertUint32(const std::string& number, + const isc::eval::location& loc) +{ + uint64_t n = 0; + try { + n = boost::lexical_cast(number); + } catch (const boost::bad_lexical_cast &) { + error(loc, "Invalid value in " + number); + } + if (n >= std::numeric_limits::max()) { + error(loc, "Invalid value in " + + number + ". Allowed range: 0..4294967295"); + } + + return (static_cast(n)); +} void EvalContext::fatal (const std::string& what) diff --git a/src/lib/eval/eval_context.h b/src/lib/eval/eval_context.h index 939f9ec35e..e7049b723b 100644 --- a/src/lib/eval/eval_context.h +++ b/src/lib/eval/eval_context.h @@ -96,11 +96,29 @@ 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 unsinged 32bit integer + /// + /// @param number string to be converted + /// @param loc the location of the token + /// @return the option code + /// @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 unsinged 8bit integer + /// + /// @param number string to be converted + /// @param loc the location of the token + /// @return the option code + /// @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 diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index ef2c460396..8b83dc0510 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -169,10 +169,15 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]* "[" 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); "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); . driver.error (loc, "Invalid character: " + std::string(yytext)); <> return isc::eval::EvalParser::make_END(loc); diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 52e69c0668..f4fac66891 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -69,6 +69,11 @@ using namespace isc::eval; PKT6 "pkt6" MSGTYPE "msgtype" TRANSID "transid" + VENDOR_CLASS "vendor-class" + VENDOR "vendor" + ANY "*" + DATA "data" + ENTERPRISE "enterprise" ; %token STRING "constant string" @@ -78,6 +83,7 @@ using namespace isc::eval; %token IP_ADDRESS "ip address" %type option_code +%type enterprise_id %type option_repr_type %type relay6_field %type nest_level @@ -160,7 +166,35 @@ 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 { @@ -253,7 +287,59 @@ 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 +{ + // expression: vendor[1234].option[56].exists + // expression: vendor[1234].option[56].hex + // + // This token will search for vendor option with specified enterprise-id. + // If found, will search for specified suboption and finally will return + // if it exists ('exists') or its content ('hex') + 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 { @@ -275,6 +361,15 @@ option_repr_type : TEXT } ; +enterprise_id : INTEGER +{ + $$ = ctx.convertUint32($1, @1); +} +| "*" +{ + $$ = 0; +} + pkt4_field : CHADDR { $$ = TokenPkt4::CHADDR; @@ -330,7 +425,7 @@ relay6_field : PEERADDR { $$ = TokenRelay6Field::PEERADDR; } nest_level : INTEGER { - $$ = ctx.convertNestLevelNumber($1, @1); + $$ = ctx.convertNestLevelNumber($1, @1); } // Eventually we may add strings to handle different // ways of choosing from which relay we want to extract diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index 9d757d6690..cb5752fc0b 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -372,7 +372,188 @@ public: checkTokenPkt6(eval.expression.at(0), exp_type); } - Option::Universe universe_; + + /// @brief Checks if the given token is TokenVendor and has expected characteristics + /// @param token token to be checked + /// @param exp_vendor_id expected vendor-id (aka enterprise number) + /// @param exp_repr expected representation (either 'exists' or 'hex') + /// @param exp_option_code expected option code (ignored if 0) + void checkTokenVendor(const TokenPtr& token, uint32_t exp_vendor_id, + uint16_t exp_option_code, + TokenOption::RepresentationType exp_repr) { + ASSERT_TRUE(token); + + boost::shared_ptr vendor = + boost::dynamic_pointer_cast(token); + + ASSERT_TRUE(vendor); + + EXPECT_EQ(exp_vendor_id, vendor->getVendorId()); + EXPECT_EQ(exp_repr, vendor->getRepresentation()); + EXPECT_EQ(exp_option_code, vendor->getCode()); + } + + /// @brief Tests if specified token vendor expression can be parsed + /// + /// This test assumes the first token will be token vendor. Any additional + /// tokens are ignored. Tests experssions: + /// vendor[1234].option[234].hex + /// vendor[1234].option[234].exists + /// + /// @param expr expression to be parsed + /// @param u universe (V4 or V6) + /// @param vendor_id expected vendor-id (aka enterprise number) + /// @param option_code expected option code (ignored if 0) + /// @param expected_repr expected representation (either 'exists' or 'hex') + void testVendor(std::string expr, Option::Universe u, uint32_t vendor_id, + uint16_t option_code, TokenOption::RepresentationType expected_repr) { + EvalContext eval(u); + + EXPECT_NO_THROW(parsed_ = eval.parseString(expr)); + EXPECT_TRUE(parsed_); + + // We need at least one token, we will evaluate the first one. + ASSERT_FALSE(eval.expression.empty()); + + checkTokenVendor(eval.expression.at(0), vendor_id, option_code, expected_repr); + } + + /// @brief Checks if token is really a TokenVendor, that the vendor_id was + /// stored properly and that it has expected representation + /// + /// This test is able to handle expressions similar to: + /// vendor[4491].option[1].hex + /// vendor[4491].option[1].exists + /// vendor[4491].exists + /// vendor[*].exists + /// + /// @param expr expression to be parsed + /// @param u universe (V4 or V6) + /// @param vendor_id expected vendor-id (aka enterprise number) + /// @param expected_repr expected representation (either 'exists' or 'hex') + void testVendor(std::string expr, Option::Universe u, uint32_t vendor_id, + TokenOption::RepresentationType expected_repr) { + testVendor(expr, u, vendor_id, 0, expected_repr); + } + + /// @brief Tests if the expression parses into token vendor that returns enterprise-id + /// + /// This test is able to handle expressions similar to: + /// vendor.enterprise + /// + /// @param expr expression to be parsed + /// @param u universe (V4 or V6) + void testVendorEnterprise(std::string expr, Option::Universe u) { + EvalContext eval(u); + + EXPECT_NO_THROW(parsed_ = eval.parseString(expr)); + EXPECT_TRUE(parsed_); + + ASSERT_FALSE(eval.expression.empty()); + + boost::shared_ptr vendor = + boost::dynamic_pointer_cast(eval.expression.at(0)); + + ASSERT_TRUE(vendor); + EXPECT_EQ(TokenVendor::ENTERPRISE_ID, vendor->getField()); + } + + /// @brief This test checks if vendor-class token is correct + /// + /// This test checks if EXISTS representation is set correctly. + /// It covers cases like: + /// - vendor-class[4491].exist + /// - vendor-class[*].exist + /// + /// @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. Any additional + /// tokens are ignored. Tests experssions: + /// - vendor-class[4491].exists + /// - vendor-class[*].exists + /// - vendor-class[4491].data + /// - vendor-class[4491].data[3] + /// + /// @param expr expression to be parsed + /// @param u universe (V4 or V6) + /// @param vendor_id expected vendor-id (aka enterprise number) + /// @param index expected data index + void testVendorClass(std::string expr, Option::Universe u, uint32_t vendor_id, + uint16_t index) { + EvalContext eval(u); + + EXPECT_NO_THROW(parsed_ = eval.parseString(expr)); + EXPECT_TRUE(parsed_); + + // Make sure there's at least one token + ASSERT_FALSE(eval.expression.empty()); + + // The first token should be TokenVendorClass, let's take a closer look. + checkTokenVendorClass(eval.expression.at(0), vendor_id, index, + TokenOption::HEXADECIMAL, TokenVendor::DATA); + + } + + /// @brief Tests if the expression parses into vendor class token that + /// returns enterprise-id. + /// + /// This test is able to handle expressions similar to: + /// - vendor-class.enterprise + /// + /// @param expr expression to be parsed + /// @param u universe (V4 or V6) + void testVendorClassEnterprise(std::string expr, Option::Universe u) { + EvalContext eval(u); + + EXPECT_NO_THROW(parsed_ = eval.parseString(expr)); + EXPECT_TRUE(parsed_); + + // Make sure there's at least one token + ASSERT_FALSE(eval.expression.empty()); + + // The first token should be TokenVendorClass, let's take a closer look. + checkTokenVendorClass(eval.expression.at(0), 0, 0, TokenOption::HEXADECIMAL, + TokenVendor::ENTERPRISE_ID); + } + + /// @brief Checks if the given token is TokenVendorClass and has expected characteristics + /// + /// @param token token to be checked + /// @param vendor_id expected vendor-id (aka enterprise number) + /// @param index expected index (used for data field only) + /// @param repr expected representation (either 'exists' or 'hex') + /// @param field expected field (none, enterprise or data) + void checkTokenVendorClass(const TokenPtr& token, uint32_t vendor_id, + uint16_t index, TokenOption::RepresentationType repr, + TokenVendor::FieldType field) { + ASSERT_TRUE(token); + + boost::shared_ptr vendor = + boost::dynamic_pointer_cast(token); + + ASSERT_TRUE(vendor); + + EXPECT_EQ(vendor_id, vendor->getVendorId()); + EXPECT_EQ(index, vendor->getDataIndex()); + EXPECT_EQ(repr, vendor->getRepresentation()); + EXPECT_EQ(field, vendor->getField()); + } + + Option::Universe universe_; ///< Universe (V4 or V6) bool parsed_; ///< Parsing status }; @@ -1025,4 +1206,95 @@ TEST_F(EvalContextTest, typeErrors) { ":1.8-9: syntax error, unexpected or, expecting =="); } + +TEST_F(EvalContextTest, vendor4SpecificVendorExists) { + testVendor("vendor[4491].exists", Option::V4, 4491, TokenOption::EXISTS); +} + +TEST_F(EvalContextTest, vendor6SpecificVendorExists) { + testVendor("vendor[4491].exists", Option::V6, 4491, TokenOption::EXISTS); +} + +TEST_F(EvalContextTest, vendor4AnyVendorExists) { + testVendor("vendor[*].exists", Option::V4, 0, TokenOption::EXISTS); +} + +TEST_F(EvalContextTest, vendor6AnyVendorExists) { + testVendor("vendor[*].exists", Option::V6, 0, TokenOption::EXISTS); +} + +TEST_F(EvalContextTest, vendor4enterprise) { + testVendorEnterprise("vendor.enterprise == 0x1234", Option::V4); +} + +TEST_F(EvalContextTest, vendor6enterprise) { + testVendorEnterprise("vendor.enterprise == 0x1234", Option::V6); +} + +TEST_F(EvalContextTest, vendor4SuboptionExists) { + testVendor("vendor[4491].option[1].exists", Option::V4, 4491, 1, TokenOption::EXISTS); +} + +TEST_F(EvalContextTest, vendor6SuboptionExists) { + testVendor("vendor[4491].option[1].exists", Option::V6, 4491, 1, TokenOption::EXISTS); +} + +TEST_F(EvalContextTest, vendor4SuboptionHex) { + testVendor("vendor[4491].option[1].hex == 0x1234", Option::V4, 4491, 1, + TokenOption::HEXADECIMAL); +} + +TEST_F(EvalContextTest, vendor6SuboptionHex) { + testVendor("vendor[4491].option[1].hex == 0x1234", Option::V6, 4491, 1, + TokenOption::HEXADECIMAL); +} + +TEST_F(EvalContextTest, vendorClass4SpecificVendorExists) { + testVendorClass("vendor-class[4491].exists", Option::V4, 4491); +} + +TEST_F(EvalContextTest, vendorClass6SpecificVendorExists) { + testVendorClass("vendor-class[4491].exists", Option::V6, 4491); +} + +TEST_F(EvalContextTest, vendorClass4AnyVendorExists) { + testVendorClass("vendor-class[*].exists", Option::V4, 0); +} + +TEST_F(EvalContextTest, vendorClass6AnyVendorExists) { + testVendorClass("vendor-class[*].exists", Option::V6, 0); +} + +TEST_F(EvalContextTest, vendorClass4enterprise) { + testVendorClassEnterprise("vendor-class.enterprise == 0x1234", Option::V4); +} + +TEST_F(EvalContextTest, vendorClass6enterprise) { + testVendorClassEnterprise("vendor-class.enterprise == 0x1234", Option::V6); +} + +TEST_F(EvalContextTest, vendorClass4SpecificVendorData) { + testVendorClass("vendor-class[4491].data == 0x1234", Option::V4, 4491, 0); +} + +TEST_F(EvalContextTest, vendorClass6SpecificVendorData) { + testVendorClass("vendor-class[4491].data == 0x1234", Option::V6, 4491, 0); +} + +TEST_F(EvalContextTest, vendorClass4AnyVendorData) { + testVendorClass("vendor-class[*].data == 0x1234", Option::V4, 0, 0); +} + +TEST_F(EvalContextTest, vendorClass6AnyVendorData) { + testVendorClass("vendor-class[*].data == 0x1234", Option::V6, 0, 0); +} + +TEST_F(EvalContextTest, vendorClass4DataIndex) { + testVendorClass("vendor-class[4491].data[3] == 0x1234", Option::V4, 4491, 3); +} + +TEST_F(EvalContextTest, vendorClass6DataIndex) { + testVendorClass("vendor-class[4491].data[3] == 0x1234", Option::V6, 4491, 3); +} + }; diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index c4cbec6003..04d5d1f303 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -185,6 +187,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 +210,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 +253,232 @@ 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 class 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 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 @@ -1671,4 +1912,407 @@ TEST_F(TokenTest, pkt6Fields) { EXPECT_TRUE(checkFile()); } + +// This test verifies if expression vendor[4491].exist 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 suceed + testVendorExists(Option::V4, 4491, 4491, "true"); +} + +// This test verifies if expression vendor[4491].exist 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"); +} + +/// 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"); +} + +// 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"); +} + +// 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)); +} + +// 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)); +} + +// 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"); +} + +// 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"); +} + +// 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"); +} + +// 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"); +} + +// 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"); +} + +// 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"); +} + +// 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"); +} + +// 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"); +} + +// 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)); +} + +// 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)); +} + +// 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 + 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"); +} + +// 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"); +} + +// 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, 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, 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 empty string + 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"); +} + +// 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 empty string + 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"); +} + +// 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 2 data tuples, 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 2 data tuples, expected + // result is empty string. + testVendorClassData(Option::V4, 4491, 3, 1234, 1, ""); + + // 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"); +} + +// 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 2 data tuples, expected result is empty string. + testVendorClassData(Option::V6, 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 2 data tuples, expected + // result is empty string. + testVendorClassData(Option::V6, 4491, 3, 1234, 1, ""); + + // 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"); +} + }; diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index c9f5c969b7..f8df034e05 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -11,6 +11,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -63,7 +67,7 @@ TokenHexString::evaluate(Pkt& /*pkt*/, ValueStack& values) { // Log what we pushed LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_HEXSTRING) .arg("0x" + util::encode::encodeHex(std::vector(value_.begin(), - value_.end()))); + value_.end()))); } TokenIpAddress::TokenIpAddress(const string& addr) : value_("") { @@ -89,7 +93,7 @@ TokenIpAddress::evaluate(Pkt& /*pkt*/, ValueStack& values) { // Log what we pushed LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IPADDRESS) .arg("0x" + util::encode::encodeHex(std::vector(value_.begin(), - value_.end()))); + value_.end()))); } OptionPtr @@ -136,6 +140,15 @@ TokenOption::evaluate(Pkt& pkt, ValueStack& values) { } } +void +TokenOption::pushFailure(ValueStack& values) { + if (representation_type_ == EXISTS) { + values.push("false"); + } else { + values.push(""); + } +} + TokenRelay4Option::TokenRelay4Option(const uint16_t option_code, const RepresentationType& rep_type) :TokenOption(option_code, rep_type) { @@ -599,3 +612,188 @@ TokenPkt6::evaluate(Pkt& pkt, ValueStack& values) { .arg("0x" + util::encode::encodeHex(std::vector(value.begin(), value.end()))); } + +TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, RepresentationType repr, + uint16_t option_code) + :TokenOption(option_code, repr), universe_(u), vendor_id_(vendor_id), + field_(option_code ? SUBOPTION : EXISTS) +{ +} + +TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field) + :TokenOption(0, TokenOption::HEXADECIMAL), universe_(u), vendor_id_(vendor_id), + field_(field) +{ + if (field_ == EXISTS) { + representation_type_ = TokenOption::EXISTS; + } +} + +uint32_t TokenVendor::getVendorId() const { + return (vendor_id_); +} + +TokenVendor::FieldType TokenVendor::getField() const { + return (field_); +} + +void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) { + + // Get the option first. + uint16_t code = 0; + switch (universe_) { + case Option::V4: + code = DHO_VIVSO_SUBOPTIONS; + break; + case Option::V6: + code = D6O_VENDOR_OPTS; + break; + } + + OptionPtr opt = pkt.getOption(code); + OptionVendorPtr vendor = boost::dynamic_pointer_cast(opt); + if (!vendor) { + // There's no vendor option, give up. + pushFailure(values); + 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) + pushFailure(values); + 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); + 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. + values.push("true"); + return; + case DATA: + // This is for vendor-class option, we can skip it here. + isc_throw(EvalTypeError, "Field None is not valid for vendor-class"); + return; + } +} + +OptionPtr TokenVendor::getOption(Pkt& pkt) { + uint16_t code = 0; + switch (universe_) { + case Option::V4: + code = DHO_VIVSO_SUBOPTIONS; + break; + case Option::V6: + code = D6O_VENDOR_OPTS; + break; + } + + OptionPtr opt = pkt.getOption(code); + if (!opt) { + // If vendor option is not found, return NULL + return (opt); + } + + // If vendor option is found, try to return its + // encapsulated option. + return (opt->getOption(option_code_)); +} + +TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id, + RepresentationType repr) + :TokenVendor(u, vendor_id, repr, 0), index_(0) { +} + +TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id, + FieldType field, uint16_t index) + :TokenVendor(u, vendor_id, TokenOption::HEXADECIMAL, 0), index_(index) +{ + field_ = field; +} + +uint16_t TokenVendorClass::getDataIndex() const { + return (index_); +} + +void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { + + // Get the option first. + uint16_t code = 0; + switch (universe_) { + case Option::V4: + code = DHO_VIVCO_SUBOPTIONS; + break; + case Option::V6: + code = D6O_VENDOR_CLASS; + break; + } + + OptionPtr opt = pkt.getOption(code); + OptionVendorClassPtr vendor = boost::dynamic_pointer_cast(opt); + if (!vendor) { + // There's no vendor option, give up. + pushFailure(values); + 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) + pushFailure(values); + 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); + 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. + values.push("true"); + return; + case DATA: + { + size_t max = vendor->getTuplesNum(); + if (index_ + 1 > max) { + // The index specified if out of bound, e.g. there are only + // 2 tuples and index specified is 5. + values.push(""); + return; + } + + OpaqueDataTuple tuple = vendor->getTuple(index_); + OpaqueDataTuple::Buffer buf = tuple.getData(); + string txt(buf.begin(), buf.end()); + values.push(txt); + return; + } + default: + isc_throw(EvalTypeError, "Invalid field specified." << field_); + } +} diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index 4b7812e664..fcc123df57 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -256,6 +256,13 @@ 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. + virtual void pushFailure(ValueStack& values); + uint16_t option_code_; ///< Code of the option to be extracted RepresentationType representation_type_; ///< Representation type. }; @@ -681,6 +688,191 @@ private: FieldType type_; }; +/// @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].exist - if vendor option with enterprise-id = 4491 exists +/// vendor[*].exist - if any vendor option exists +/// vendor.enterprise - returns enterprise-id from vendor option +/// vendor[4491].option[1].exist - 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's 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].exist +/// vendor-class[*].exist +/// 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 of 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 From 312d0a56701726d72be44124b5c12a2ac4488d8f Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 9 Aug 2016 15:37:42 +0200 Subject: [PATCH 02/15] [4271] Lexer files regenerated. --- src/lib/eval/lexer.cc | 406 ++++++++++++---------- src/lib/eval/location.hh | 1 - src/lib/eval/parser.cc | 716 ++++++++++++++++++++++++--------------- src/lib/eval/parser.h | 204 +++++++---- src/lib/eval/position.hh | 1 - src/lib/eval/stack.hh | 1 - 6 files changed, 814 insertions(+), 515 deletions(-) diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc index 8cbd38952e..6b6a1e32f6 100644 --- a/src/lib/eval/lexer.cc +++ b/src/lib/eval/lexer.cc @@ -284,7 +284,7 @@ struct yy_buffer_state /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - yy_size_t yy_n_chars; + int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -368,7 +368,7 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; -static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ +static int yy_n_chars; /* number of characters read into yy_ch_buf */ yy_size_t yyleng; /* Points to current character in buffer. */ @@ -483,8 +483,8 @@ static void yy_fatal_error (yyconst char msg[] ); (yy_c_buf_p) = yy_cp; /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ -#define YY_NUM_RULES 41 -#define YY_END_OF_BUFFER 42 +#define YY_NUM_RULES 46 +#define YY_END_OF_BUFFER 47 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -492,55 +492,61 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_acclist[227] = +static yyconst flex_int16_t yy_acclist[262] = { 0, - 42, 40, 41, 1, 40, 41, 2, 41, 40, 41, - 32, 40, 41, 33, 40, 41, 36, 40, 41, 40, - 41, 31, 40, 41, 5, 40, 41, 5, 40, 41, - 40, 41, 40, 41, 40, 41,16390, 40, 41,16390, - 34, 40, 41, 35, 40, 41, 40, 41,16390, 40, - 41,16390, 40, 41,16390, 40, 41,16390, 40, 41, - 16390, 40, 41,16390, 40, 41,16390, 40, 41,16390, - 40, 41,16390, 40, 41,16390, 40, 41,16390, 40, - 41,16390, 40, 41,16390, 40, 41,16390, 1, 2, - 3, 5, 5, 7, 8,16390,16390, 8198,16390,16390, + 47, 45, 46, 1, 45, 46, 2, 46, 45, 46, + 32, 45, 46, 33, 45, 46, 37, 45, 46, 36, + 45, 46, 45, 46, 31, 45, 46, 5, 45, 46, + 5, 45, 46, 45, 46, 45, 46, 45, 46,16390, + 45, 46,16390, 34, 45, 46, 35, 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, 8,16390,16390, 8198,16390,16390,16390, 16390,16390,16390,16390,16390,16390,16390,16390,16390,16390, - 16390,16390, 30,16390,16390,16390,16390,16390,16390,16390, - 16390,16390, 4, 7, 26,16390, 29,16390,16390,16390, - 16390,16390, 15,16390,16390,16390,16390, 18,16390,16390, - 28,16390,16390,16390,16390,16390,16390,16390,16390,16390, - 16390,16390,16390,16390,16390, 19,16390,16390,16390,16390, - 16390,16390, 17,16390, 37,16390,16390,16390,16390, 14, + 16390,16390,16390, 30,16390,16390,16390,16390,16390,16390, + 16390,16390,16390,16390, 4, 7, 26,16390, 29,16390, + 16390,16390,16390,16390,16390,16390, 15,16390,16390,16390, + 16390, 18,16390,16390, 28,16390,16390,16390,16390,16390, + 16390,16390,16390,16390,16390,16390,16390,16390, 43,16390, + 16390,16390,16390, 19,16390,16390,16390,16390,16390,16390, + 17,16390, 38,16390,16390,16390,16390, 14,16390,16390, 16390,16390,16390,16390,16390,16390,16390, 20,16390,16390, - 16390,16390,16390,16390,16390,16390,16390,16390, 21,16390, - 27,16390, 16,16390, 22,16390,16390,16390, 9,16390, - 16390, 10,16390, 11,16390, 24,16390,16390,16390, 23, - 16390, 7,16390, 38,16390,16390,16390, 39,16390, 13, - 16390, 12,16390,16390, 25,16390 + 16390,16390,16390,16390,16390,16390,16390,16390,16390, 21, + 16390, 27,16390,16390, 16,16390, 22,16390,16390,16390, + 9,16390,16390, 10,16390, 11,16390, 24,16390,16390, + 16390, 41,16390, 23,16390, 7,16390,16390, 39,16390, + 16390,16390, 40,16390,16390, 13,16390, 12,16390,16390, + 16390,16390, 25,16390,16390, 44,16390,16390,16390, 42, + 16390 } ; -static yyconst flex_int16_t yy_accept[162] = +static yyconst flex_int16_t yy_accept[188] = { 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, 90, 91, 91, 92, 93, - 93, 94, 94, 94, 94, 94, 95, 96, 96, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 123, 124, 125, 127, - 129, 130, 131, 132, 133, 135, 136, 137, 138, 140, - 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 77, 80, 83, 86, 89, 92, 95, 98, 99, 100, + 100, 101, 102, 102, 103, 103, 103, 103, 103, 104, + 105, 105, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 135, 136, 137, 139, 141, 142, 143, 144, + 145, 146, 147, 149, 150, 151, 152, 154, 155, 157, - 152, 152, 153, 154, 155, 156, 158, 159, 160, 161, - 162, 163, 165, 167, 168, 169, 170, 172, 173, 174, - 174, 175, 176, 177, 178, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 189, 191, 193, 195, 197, - 198, 199, 201, 202, 204, 206, 208, 209, 210, 212, - 213, 214, 216, 217, 218, 220, 222, 224, 225, 227, - 227 + 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 167, 168, 169, 171, 172, 173, 174, 176, 177, 178, + 179, 180, 181, 183, 185, 186, 187, 188, 190, 191, + 192, 193, 193, 194, 195, 196, 197, 198, 200, 201, + 202, 203, 204, 205, 206, 207, 208, 209, 210, 210, + 212, 214, 215, 217, 219, 220, 221, 223, 224, 226, + 228, 230, 231, 232, 234, 236, 237, 238, 239, 241, + 242, 243, 245, 245, 246, 248, 250, 251, 252, 253, + 255, 256, 258, 259, 260, 262, 262 } ; static yyconst YY_CHAR yy_ec[256] = @@ -549,16 +555,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, 16, 27, 28, 29, 17, 30, 31, 32, 33, - 34, 35, 17, 36, 37, 38, 39, 17, 17, 40, - 41, 17, 1, 1, 1, 1, 1, 1, 1, 1, + 27, 17, 28, 29, 30, 18, 31, 32, 33, 34, + 35, 36, 18, 37, 38, 39, 40, 41, 18, 42, + 43, 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, @@ -575,151 +581,166 @@ static yyconst YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst YY_CHAR yy_meta[42] = +static yyconst YY_CHAR yy_meta[44] = { 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, 1, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1 + 1, 1, 1 } ; -static yyconst flex_uint16_t yy_base[166] = +static yyconst flex_uint16_t yy_base[192] = { 0, - 0, 0, 267, 268, 264, 262, 260, 268, 268, 268, - 32, 268, 37, 34, 249, 247, 76, 108, 268, 268, - 23, 35, 221, 231, 42, 230, 35, 224, 30, 41, - 231, 46, 55, 227, 253, 251, 249, 268, 115, 125, - 105, 238, 237, 0, 236, 0, 268, 137, 139, 0, - 0, 268, 218, 223, 225, 213, 216, 222, 203, 216, - 200, 207, 215, 211, 199, 198, 0, 209, 196, 202, - 210, 208, 190, 207, 206, 137, 0, 0, 0, 0, - 202, 202, 188, 199, 0, 190, 187, 191, 0, 182, - 0, 190, 182, 70, 195, 191, 178, 176, 180, 187, + 0, 0, 296, 297, 293, 291, 289, 297, 297, 297, + 297, 33, 297, 38, 35, 277, 275, 79, 112, 297, + 297, 24, 36, 267, 25, 259, 46, 258, 37, 252, + 32, 43, 259, 46, 52, 258, 254, 281, 279, 277, + 297, 119, 129, 53, 265, 264, 0, 263, 0, 297, + 142, 144, 0, 0, 297, 245, 250, 252, 240, 234, + 233, 241, 247, 227, 241, 224, 232, 240, 236, 224, + 223, 0, 234, 221, 227, 235, 233, 214, 232, 220, + 230, 138, 0, 0, 0, 0, 226, 226, 227, 222, + 210, 221, 0, 212, 209, 213, 0, 204, 0, 212, + + 204, 70, 217, 213, 200, 198, 202, 209, 208, 142, + 207, 209, 0, 194, 191, 203, 0, 201, 204, 183, + 190, 201, 0, 0, 180, 196, 182, 0, 182, 184, + 192, 147, 180, 177, 179, 176, 176, 0, 186, 165, + 164, 171, 153, 159, 157, 163, 155, 154, 157, 0, + 0, 153, 0, 0, 163, 161, 0, 161, 0, 0, + 0, 156, 159, 175, 0, 161, 153, 145, 0, 144, + 146, 0, 174, 141, 0, 0, 150, 132, 135, 0, + 111, 0, 90, 61, 0, 297, 199, 201, 203, 83, + 206 - 141, 186, 188, 171, 183, 0, 181, 184, 164, 170, - 181, 0, 0, 161, 176, 162, 0, 162, 173, 151, - 161, 158, 158, 158, 0, 168, 157, 158, 165, 131, - 153, 152, 158, 150, 155, 0, 0, 0, 0, 160, - 148, 0, 133, 0, 0, 0, 127, 130, 0, 159, - 93, 0, 59, 43, 0, 0, 0, 43, 0, 268, - 172, 174, 176, 54, 179 } ; -static yyconst flex_int16_t yy_def[166] = +static yyconst flex_int16_t yy_def[192] = { 0, - 160, 1, 160, 160, 160, 160, 161, 160, 160, 160, - 160, 160, 160, 13, 162, 160, 160, 17, 160, 160, - 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 160, 160, 161, 160, 160, 160, - 13, 162, 163, 164, 162, 165, 160, 160, 18, 17, - 18, 160, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 160, 164, 165, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 186, 1, 186, 186, 186, 186, 187, 186, 186, 186, + 186, 186, 186, 186, 14, 188, 186, 186, 18, 186, + 186, 18, 18, 18, 18, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 186, 186, 187, + 186, 186, 186, 14, 188, 189, 190, 188, 191, 186, + 186, 19, 18, 19, 186, 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, 186, 190, 191, 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, 186, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 186, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 186, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 186, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 186, 186, 186, 186, + 186 - 160, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 160, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 160, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 160, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, - 160, 160, 160, 160, 160 } ; -static yyconst flex_uint16_t yy_nxt[310] = +static yyconst flex_uint16_t yy_nxt[341] = { 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, 17, 23, 24, 25, 18, 18, - 26, 27, 28, 29, 30, 31, 32, 33, 18, 18, - 34, 39, 39, 39, 39, 40, 41, 41, 41, 41, - 42, 160, 43, 53, 44, 54, 63, 77, 43, 43, - 43, 43, 43, 55, 66, 67, 68, 59, 56, 159, - 69, 64, 60, 160, 71, 158, 44, 48, 48, 61, - 73, 112, 113, 49, 72, 50, 50, 50, 50, 42, - 74, 50, 51, 51, 157, 52, 49, 50, 50, 50, + 14, 15, 15, 15, 16, 17, 18, 19, 19, 20, + 21, 4, 22, 18, 23, 24, 25, 26, 27, 19, + 19, 28, 29, 30, 31, 32, 33, 34, 35, 19, + 36, 19, 37, 42, 42, 42, 42, 43, 44, 44, + 44, 44, 45, 186, 46, 56, 47, 57, 61, 68, + 46, 46, 46, 46, 46, 58, 62, 71, 72, 73, + 59, 186, 64, 74, 69, 76, 186, 65, 78, 47, + 51, 51, 123, 124, 66, 77, 83, 52, 79, 53, + 53, 53, 53, 45, 186, 53, 54, 54, 185, 55, - 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 160, 160, 51, 39, 39, 39, 39, 156, 51, - 51, 51, 51, 51, 76, 76, 76, 76, 48, 48, - 160, 160, 144, 145, 160, 101, 76, 76, 76, 76, - 120, 120, 120, 120, 155, 154, 52, 153, 160, 135, - 120, 120, 120, 120, 150, 150, 150, 150, 150, 150, - 150, 150, 37, 152, 37, 37, 37, 45, 45, 43, - 43, 78, 78, 78, 151, 149, 148, 147, 146, 143, - 142, 141, 140, 139, 138, 137, 136, 134, 133, 132, + 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 186, 184, 54, 42, + 42, 42, 42, 183, 54, 54, 54, 54, 54, 82, + 82, 82, 82, 51, 51, 186, 186, 110, 82, 82, + 82, 82, 132, 132, 132, 132, 149, 132, 132, 132, + 132, 182, 55, 181, 186, 159, 160, 166, 166, 166, + 166, 166, 166, 166, 166, 186, 186, 180, 179, 177, + 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, + 165, 164, 163, 162, 186, 161, 158, 157, 178, 40, - 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, - 121, 119, 118, 117, 116, 115, 114, 111, 110, 109, - 108, 107, 106, 105, 104, 103, 102, 100, 99, 98, - 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, - 87, 86, 85, 84, 83, 82, 81, 80, 79, 46, - 42, 46, 38, 36, 35, 75, 70, 65, 62, 58, - 57, 47, 46, 38, 36, 35, 160, 3, 160, 160, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 156, 40, 40, 40, 48, 48, 46, 46, 84, 84, + 84, 155, 154, 153, 152, 151, 150, 148, 147, 146, + 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, + 135, 134, 133, 131, 130, 129, 128, 127, 126, 125, + 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, + 112, 111, 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, 49, 45, 49, + 41, 39, 38, 81, 80, 75, 70, 67, 63, 60, + 50, 49, 41, 39, 38, 186, 3, 186, 186, 186, - 160, 160, 160, 160, 160, 160, 160, 160, 160 + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186 } ; -static yyconst flex_int16_t yy_chk[310] = +static yyconst flex_int16_t yy_chk[341] = { 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, 11, 11, 11, 11, 13, 13, 13, 13, 13, - 13, 14, 13, 21, 13, 21, 27, 164, 13, 13, - 13, 13, 13, 22, 29, 29, 30, 25, 22, 158, - 30, 27, 25, 14, 32, 154, 13, 17, 17, 25, - 33, 94, 94, 17, 32, 17, 17, 17, 17, 17, - 33, 17, 17, 17, 153, 17, 17, 17, 17, 17, + 1, 1, 1, 12, 12, 12, 12, 14, 14, 14, + 14, 14, 14, 15, 14, 22, 14, 22, 25, 29, + 14, 14, 14, 14, 14, 23, 25, 31, 31, 32, + 23, 44, 27, 32, 29, 34, 15, 27, 35, 14, + 18, 18, 102, 102, 27, 34, 190, 18, 35, 18, + 18, 18, 18, 18, 44, 18, 18, 18, 184, 18, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, - 18, 18, 41, 18, 39, 39, 39, 39, 151, 18, - 18, 18, 18, 18, 40, 40, 40, 40, 48, 48, - 49, 49, 130, 130, 41, 76, 76, 76, 76, 76, - 101, 101, 101, 101, 148, 147, 48, 143, 49, 120, - 120, 120, 120, 120, 135, 135, 135, 135, 150, 150, - 150, 150, 161, 141, 161, 161, 161, 162, 162, 163, - 163, 165, 165, 165, 140, 134, 133, 132, 131, 129, - 128, 127, 126, 124, 123, 122, 121, 119, 118, 116, + 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, 183, 19, 42, + 42, 42, 42, 181, 19, 19, 19, 19, 19, 43, + 43, 43, 43, 51, 51, 52, 52, 82, 82, 82, + 82, 82, 110, 110, 110, 110, 132, 132, 132, 132, + 132, 179, 51, 178, 52, 143, 143, 149, 149, 149, + 149, 166, 166, 166, 166, 173, 173, 177, 174, 171, + 170, 168, 167, 164, 163, 162, 158, 156, 155, 152, + 148, 147, 146, 145, 173, 144, 142, 141, 173, 187, - 115, 114, 111, 110, 109, 108, 107, 105, 104, 103, - 102, 100, 99, 98, 97, 96, 95, 93, 92, 90, - 88, 87, 86, 84, 83, 82, 81, 75, 74, 73, - 72, 71, 70, 69, 68, 66, 65, 64, 63, 62, - 61, 60, 59, 58, 57, 56, 55, 54, 53, 45, - 43, 42, 37, 36, 35, 34, 31, 28, 26, 24, - 23, 16, 15, 7, 6, 5, 3, 160, 160, 160, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 140, 187, 187, 187, 188, 188, 189, 189, 191, 191, + 191, 139, 137, 136, 135, 134, 133, 131, 130, 129, + 127, 126, 125, 122, 121, 120, 119, 118, 116, 115, + 114, 112, 111, 109, 108, 107, 106, 105, 104, 103, + 101, 100, 98, 96, 95, 94, 92, 91, 90, 89, + 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, 48, 46, 45, + 40, 39, 38, 37, 36, 33, 30, 28, 26, 24, + 17, 16, 7, 6, 5, 3, 186, 186, 186, 186, - 160, 160, 160, 160, 160, 160, 160, 160, 160 + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[42] = +static yyconst flex_int32_t yy_rule_can_match_eol[47] = { 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, }; extern int yy_flex_debug; int yy_flex_debug = 1; -static yyconst flex_int16_t yy_rule_linenum[41] = +static yyconst flex_int16_t yy_rule_linenum[46] = { 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, 173, 174, 175, 177 + 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, + 177, 178, 179, 180, 182 } ; static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; @@ -798,7 +819,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 802 "lexer.cc" +#line 823 "lexer.cc" #define INITIAL 0 @@ -1095,7 +1116,7 @@ YY_DECL loc.step(); -#line 1099 "lexer.cc" +#line 1120 "lexer.cc" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1123,14 +1144,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 >= 161 ) + if ( yy_current_state >= 187 ) 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 != 160 ); + while ( yy_current_state != 186 ); yy_find_action: /* %% [10.0] code to find the action number goes here */ @@ -1193,13 +1214,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 < 41 ) + else if ( yy_act < 46 ) fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", (long)yy_rule_linenum[yy_act], yytext ); - else if ( yy_act == 41 ) + else if ( yy_act == 46 ) fprintf( stderr, "--accepting default rule (\"%s\")\n", yytext ); - else if ( yy_act == 42 ) + else if ( yy_act == 47 ) fprintf( stderr, "--(end of buffer or a NUL)\n" ); else fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); @@ -1440,34 +1461,59 @@ return isc::eval::EvalParser::make_COMA(loc); YY_BREAK case 37: YY_RULE_SETUP -#line 173 "lexer.ll" -return isc::eval::EvalParser::make_PKT6(loc); +#line 172 "lexer.ll" +return isc::eval::EvalParser::make_ANY(loc); YY_BREAK case 38: YY_RULE_SETUP #line 174 "lexer.ll" -return isc::eval::EvalParser::make_MSGTYPE(loc); +return isc::eval::EvalParser::make_PKT6(loc); YY_BREAK case 39: YY_RULE_SETUP #line 175 "lexer.ll" -return isc::eval::EvalParser::make_TRANSID(loc); +return isc::eval::EvalParser::make_MSGTYPE(loc); YY_BREAK case 40: YY_RULE_SETUP -#line 177 "lexer.ll" -driver.error (loc, "Invalid character: " + std::string(yytext)); - YY_BREAK -case YY_STATE_EOF(INITIAL): -#line 178 "lexer.ll" -return isc::eval::EvalParser::make_END(loc); +#line 176 "lexer.ll" +return isc::eval::EvalParser::make_TRANSID(loc); YY_BREAK case 41: YY_RULE_SETUP +#line 177 "lexer.ll" +return isc::eval::EvalParser::make_VENDOR(loc); + YY_BREAK +case 42: +YY_RULE_SETUP +#line 178 "lexer.ll" +return isc::eval::EvalParser::make_VENDOR_CLASS(loc); + YY_BREAK +case 43: +YY_RULE_SETUP #line 179 "lexer.ll" +return isc::eval::EvalParser::make_DATA(loc); + YY_BREAK +case 44: +YY_RULE_SETUP +#line 180 "lexer.ll" +return isc::eval::EvalParser::make_ENTERPRISE(loc); + YY_BREAK +case 45: +YY_RULE_SETUP +#line 182 "lexer.ll" +driver.error (loc, "Invalid character: " + std::string(yytext)); + YY_BREAK +case YY_STATE_EOF(INITIAL): +#line 183 "lexer.ll" +return isc::eval::EvalParser::make_END(loc); + YY_BREAK +case 46: +YY_RULE_SETUP +#line 184 "lexer.ll" ECHO; YY_BREAK -#line 1471 "lexer.cc" +#line 1517 "lexer.cc" case YY_END_OF_BUFFER: { @@ -1709,9 +1755,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()" ); @@ -1752,7 +1798,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 >= 161 ) + if ( yy_current_state >= 187 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1780,11 +1826,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 >= 161 ) + if ( yy_current_state >= 187 ) 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 == 160); + yy_is_jam = (yy_current_state == 186); if ( ! yy_is_jam ) *(yy_state_ptr)++ = yy_current_state; @@ -2177,7 +2223,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*) ); @@ -2550,7 +2596,7 @@ void yyfree (void * ptr ) /* %ok-for-header */ -#line 179 "lexer.ll" +#line 184 "lexer.ll" diff --git a/src/lib/eval/location.hh b/src/lib/eval/location.hh index ee07b99710..effaa15add 100644 --- a/src/lib/eval/location.hh +++ b/src/lib/eval/location.hh @@ -1,4 +1,3 @@ -// Generated 201604271143 // A Bison parser, made by GNU Bison 3.0.4. // Locations for Bison parsers in C++ diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc index c14a54942f..971771895c 100644 --- a/src/lib/eval/parser.cc +++ b/src/lib/eval/parser.cc @@ -251,35 +251,39 @@ namespace isc { namespace eval { { switch (that.type_get ()) { - case 45: // option_repr_type + case 50: // option_repr_type value.move< TokenOption::RepresentationType > (that.value); break; - case 46: // pkt4_field + case 52: // pkt4_field value.move< TokenPkt4::FieldType > (that.value); break; - case 51: // pkt6_field + case 57: // pkt6_field value.move< TokenPkt6::FieldType > (that.value); break; - case 49: // relay6_field + case 55: // relay6_field value.move< TokenRelay6Field::FieldType > (that.value); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" value.move< std::string > (that.value); break; - case 44: // option_code + case 49: // option_code value.move< uint16_t > (that.value); break; - case 50: // nest_level + case 51: // enterprise_id + value.move< uint32_t > (that.value); + break; + + case 56: // nest_level value.move< uint8_t > (that.value); break; @@ -298,35 +302,39 @@ namespace isc { namespace eval { state = that.state; switch (that.type_get ()) { - case 45: // option_repr_type + case 50: // option_repr_type value.copy< TokenOption::RepresentationType > (that.value); break; - case 46: // pkt4_field + case 52: // pkt4_field value.copy< TokenPkt4::FieldType > (that.value); break; - case 51: // pkt6_field + case 57: // pkt6_field value.copy< TokenPkt6::FieldType > (that.value); break; - case 49: // relay6_field + case 55: // relay6_field value.copy< TokenRelay6Field::FieldType > (that.value); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" value.copy< std::string > (that.value); break; - case 44: // option_code + case 49: // option_code value.copy< uint16_t > (that.value); break; - case 50: // nest_level + case 51: // enterprise_id + value.copy< uint32_t > (that.value); + break; + + case 56: // nest_level value.copy< uint8_t > (that.value); break; @@ -366,81 +374,88 @@ namespace isc { namespace eval { << yysym.location << ": "; switch (yytype) { - case 35: // "constant string" + case 40: // "constant string" -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } -#line 374 "parser.cc" // lalr1.cc:636 +#line 382 "parser.cc" // lalr1.cc:636 break; - case 36: // "integer" + case 41: // "integer" -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } -#line 381 "parser.cc" // lalr1.cc:636 +#line 389 "parser.cc" // lalr1.cc:636 break; - case 37: // "constant hexstring" + case 42: // "constant hexstring" -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } -#line 388 "parser.cc" // lalr1.cc:636 +#line 396 "parser.cc" // lalr1.cc:636 break; - case 38: // "option name" + case 43: // "option name" -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } -#line 395 "parser.cc" // lalr1.cc:636 +#line 403 "parser.cc" // lalr1.cc:636 break; - case 39: // "ip address" + case 44: // "ip address" -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } -#line 402 "parser.cc" // lalr1.cc:636 +#line 410 "parser.cc" // lalr1.cc:636 break; - case 44: // option_code + case 49: // option_code -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< uint16_t > (); } -#line 409 "parser.cc" // lalr1.cc:636 +#line 417 "parser.cc" // lalr1.cc:636 break; - case 45: // option_repr_type + case 50: // option_repr_type -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); } -#line 416 "parser.cc" // lalr1.cc:636 +#line 424 "parser.cc" // lalr1.cc:636 break; - case 46: // pkt4_field + case 51: // enterprise_id -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 + { yyoutput << yysym.value.template as< uint32_t > (); } +#line 431 "parser.cc" // lalr1.cc:636 + break; + + case 52: // pkt4_field + +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenPkt4::FieldType > (); } -#line 423 "parser.cc" // lalr1.cc:636 +#line 438 "parser.cc" // lalr1.cc:636 break; - case 49: // relay6_field + case 55: // relay6_field -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenRelay6Field::FieldType > (); } -#line 430 "parser.cc" // lalr1.cc:636 +#line 445 "parser.cc" // lalr1.cc:636 break; - case 50: // nest_level + case 56: // nest_level -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< uint8_t > (); } -#line 437 "parser.cc" // lalr1.cc:636 +#line 452 "parser.cc" // lalr1.cc:636 break; - case 51: // pkt6_field + case 57: // pkt6_field -#line 91 "parser.yy" // lalr1.cc:636 +#line 97 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenPkt6::FieldType > (); } -#line 444 "parser.cc" // lalr1.cc:636 +#line 459 "parser.cc" // lalr1.cc:636 break; @@ -640,35 +655,39 @@ namespace isc { namespace eval { when using variants. */ switch (yyr1_[yyn]) { - case 45: // option_repr_type + case 50: // option_repr_type yylhs.value.build< TokenOption::RepresentationType > (); break; - case 46: // pkt4_field + case 52: // pkt4_field yylhs.value.build< TokenPkt4::FieldType > (); break; - case 51: // pkt6_field + case 57: // pkt6_field yylhs.value.build< TokenPkt6::FieldType > (); break; - case 49: // relay6_field + case 55: // relay6_field yylhs.value.build< TokenRelay6Field::FieldType > (); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" yylhs.value.build< std::string > (); break; - case 44: // option_code + case 49: // option_code yylhs.value.build< uint16_t > (); break; - case 50: // nest_level + case 51: // enterprise_id + yylhs.value.build< uint32_t > (); + break; + + case 56: // nest_level yylhs.value.build< uint8_t > (); break; @@ -690,52 +709,52 @@ namespace isc { namespace eval { switch (yyn) { case 4: -#line 105 "parser.yy" // lalr1.cc:859 +#line 111 "parser.yy" // lalr1.cc:859 { TokenPtr neg(new TokenNot()); ctx.expression.push_back(neg); } -#line 699 "parser.cc" // lalr1.cc:859 +#line 718 "parser.cc" // lalr1.cc:859 break; case 5: -#line 110 "parser.yy" // lalr1.cc:859 +#line 116 "parser.yy" // lalr1.cc:859 { TokenPtr neg(new TokenAnd()); ctx.expression.push_back(neg); } -#line 708 "parser.cc" // lalr1.cc:859 +#line 727 "parser.cc" // lalr1.cc:859 break; case 6: -#line 115 "parser.yy" // lalr1.cc:859 +#line 121 "parser.yy" // lalr1.cc:859 { TokenPtr neg(new TokenOr()); ctx.expression.push_back(neg); } -#line 717 "parser.cc" // lalr1.cc:859 +#line 736 "parser.cc" // lalr1.cc:859 break; case 7: -#line 120 "parser.yy" // lalr1.cc:859 +#line 126 "parser.yy" // lalr1.cc:859 { TokenPtr eq(new TokenEqual()); ctx.expression.push_back(eq); } -#line 726 "parser.cc" // lalr1.cc:859 +#line 745 "parser.cc" // lalr1.cc:859 break; case 8: -#line 125 "parser.yy" // lalr1.cc:859 +#line 131 "parser.yy" // lalr1.cc:859 { TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS)); ctx.expression.push_back(opt); } -#line 735 "parser.cc" // lalr1.cc:859 +#line 754 "parser.cc" // lalr1.cc:859 break; case 9: -#line 130 "parser.yy" // lalr1.cc:859 +#line 136 "parser.yy" // lalr1.cc:859 { switch (ctx.getUniverse()) { case Option::V4: @@ -755,11 +774,11 @@ namespace isc { namespace eval { error(yystack_[5].location, "relay4 can only be used in DHCPv4."); } } -#line 759 "parser.cc" // lalr1.cc:859 +#line 778 "parser.cc" // lalr1.cc:859 break; case 10: -#line 150 "parser.yy" // lalr1.cc:859 +#line 156 "parser.yy" // lalr1.cc:859 { switch (ctx.getUniverse()) { case Option::V6: @@ -773,47 +792,87 @@ namespace isc { namespace eval { error(yystack_[10].location, "relay6 can only be used in DHCPv6."); } } -#line 777 "parser.cc" // lalr1.cc:859 +#line 796 "parser.cc" // lalr1.cc:859 break; case 11: -#line 166 "parser.yy" // lalr1.cc:859 +#line 170 "parser.yy" // lalr1.cc:859 + { + // Expression: vendor-class[1234].exists + // + // This token will find option 124 (DHCPv4) or 16 (DHCPv6), and will check + // if enterprise-id equals specified value. + TokenPtr exist(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS)); + ctx.expression.push_back(exist); +} +#line 809 "parser.cc" // lalr1.cc:859 + break; + + case 12: +#line 179 "parser.yy" // lalr1.cc:859 + { + // Expression: vendor[1234].exists + // + // This token will find option 125 (DHCPv4) or 17 (DHCPv6), and will check + // if enterprise-id equals specified value. + TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS)); + ctx.expression.push_back(exist); + +} +#line 823 "parser.cc" // lalr1.cc:859 + break; + + case 13: +#line 189 "parser.yy" // lalr1.cc:859 + { + // Expression vendor[1234].option[123].exists + // + // This token will check if specified vendor option exists, has specified + // enterprise-id and if has specified suboption. + TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), TokenOption::EXISTS, yystack_[3].value.as< uint16_t > ())); + ctx.expression.push_back(exist); +} +#line 836 "parser.cc" // lalr1.cc:859 + break; + + case 14: +#line 200 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); } -#line 786 "parser.cc" // lalr1.cc:859 +#line 845 "parser.cc" // lalr1.cc:859 break; - case 12: -#line 171 "parser.yy" // lalr1.cc:859 + case 15: +#line 205 "parser.yy" // lalr1.cc:859 { TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(hex); } -#line 795 "parser.cc" // lalr1.cc:859 +#line 854 "parser.cc" // lalr1.cc:859 break; - case 13: -#line 176 "parser.yy" // lalr1.cc:859 + case 16: +#line 210 "parser.yy" // lalr1.cc:859 { TokenPtr ip(new TokenIpAddress(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(ip); } -#line 804 "parser.cc" // lalr1.cc:859 +#line 863 "parser.cc" // lalr1.cc:859 break; - case 14: -#line 181 "parser.yy" // lalr1.cc:859 + case 17: +#line 215 "parser.yy" // lalr1.cc:859 { TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); ctx.expression.push_back(opt); } -#line 813 "parser.cc" // lalr1.cc:859 +#line 872 "parser.cc" // lalr1.cc:859 break; - case 15: -#line 186 "parser.yy" // lalr1.cc:859 + case 18: +#line 220 "parser.yy" // lalr1.cc:859 { switch (ctx.getUniverse()) { case Option::V4: @@ -833,11 +892,11 @@ namespace isc { namespace eval { error(yystack_[5].location, "relay4 can only be used in DHCPv4."); } } -#line 837 "parser.cc" // lalr1.cc:859 +#line 896 "parser.cc" // lalr1.cc:859 break; - case 16: -#line 207 "parser.yy" // lalr1.cc:859 + case 19: +#line 241 "parser.yy" // lalr1.cc:859 { switch (ctx.getUniverse()) { case Option::V6: @@ -851,11 +910,11 @@ namespace isc { namespace eval { error(yystack_[10].location, "relay6 can only be used in DHCPv6."); } } -#line 855 "parser.cc" // lalr1.cc:859 +#line 914 "parser.cc" // lalr1.cc:859 break; - case 17: -#line 222 "parser.yy" // lalr1.cc:859 + case 20: +#line 256 "parser.yy" // lalr1.cc:859 { switch (ctx.getUniverse()) { case Option::V6: @@ -869,194 +928,281 @@ namespace isc { namespace eval { error(yystack_[5].location, "relay6 can only be used in DHCPv6."); } } -#line 873 "parser.cc" // lalr1.cc:859 +#line 932 "parser.cc" // lalr1.cc:859 break; - case 18: -#line 237 "parser.yy" // lalr1.cc:859 + case 21: +#line 271 "parser.yy" // lalr1.cc:859 { TokenPtr pkt4_field(new TokenPkt4(yystack_[0].value.as< TokenPkt4::FieldType > ())); ctx.expression.push_back(pkt4_field); } -#line 882 "parser.cc" // lalr1.cc:859 +#line 941 "parser.cc" // lalr1.cc:859 break; - case 19: -#line 242 "parser.yy" // lalr1.cc:859 + case 22: +#line 276 "parser.yy" // lalr1.cc:859 { TokenPtr pkt6_field(new TokenPkt6(yystack_[0].value.as< TokenPkt6::FieldType > ())); ctx.expression.push_back(pkt6_field); } -#line 891 "parser.cc" // lalr1.cc:859 +#line 950 "parser.cc" // lalr1.cc:859 break; - case 20: -#line 247 "parser.yy" // lalr1.cc:859 + case 23: +#line 281 "parser.yy" // lalr1.cc:859 { TokenPtr sub(new TokenSubstring()); ctx.expression.push_back(sub); } -#line 900 "parser.cc" // lalr1.cc:859 +#line 959 "parser.cc" // lalr1.cc:859 break; - case 21: -#line 252 "parser.yy" // lalr1.cc:859 + case 24: +#line 286 "parser.yy" // lalr1.cc:859 { TokenPtr conc(new TokenConcat()); ctx.expression.push_back(conc); } -#line 909 "parser.cc" // lalr1.cc:859 - break; - - case 22: -#line 259 "parser.yy" // lalr1.cc:859 - { - yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); - } -#line 917 "parser.cc" // lalr1.cc:859 - break; - - case 23: -#line 263 "parser.yy" // lalr1.cc:859 - { - yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); - } -#line 925 "parser.cc" // lalr1.cc:859 - break; - - case 24: -#line 269 "parser.yy" // lalr1.cc:859 - { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; - } -#line 933 "parser.cc" // lalr1.cc:859 +#line 968 "parser.cc" // lalr1.cc:859 break; case 25: -#line 273 "parser.yy" // lalr1.cc:859 +#line 291 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; - } -#line 941 "parser.cc" // lalr1.cc:859 + // expression: vendor.enterprise + // + // This token will return enterprise-id number of received vendor option. + TokenPtr vendor(new TokenVendor(ctx.getUniverse(), 0, TokenVendor::ENTERPRISE_ID)); + ctx.expression.push_back(vendor); +} +#line 980 "parser.cc" // lalr1.cc:859 break; case 26: -#line 279 "parser.yy" // lalr1.cc:859 +#line 299 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CHADDR; - } -#line 949 "parser.cc" // lalr1.cc:859 + // expression: vendor-class.enterprise + // + // This token will return enterprise-id number of received vendor class option. + TokenPtr vendor(new TokenVendorClass(ctx.getUniverse(), 0, + TokenVendor::ENTERPRISE_ID)); + ctx.expression.push_back(vendor); +} +#line 993 "parser.cc" // lalr1.cc:859 break; case 27: -#line 283 "parser.yy" // lalr1.cc:859 +#line 308 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HLEN; - } -#line 957 "parser.cc" // lalr1.cc:859 + // expression: vendor[1234].option[56].exists + // expression: vendor[1234].option[56].hex + // + // This token will search for vendor option with specified enterprise-id. + // If found, will search for specified suboption and finally will return + // if it exists ('exists') or its content ('hex') + TokenPtr opt(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), yystack_[0].value.as< TokenOption::RepresentationType > (), yystack_[3].value.as< uint16_t > ())); + ctx.expression.push_back(opt); +} +#line 1008 "parser.cc" // lalr1.cc:859 break; case 28: -#line 287 "parser.yy" // lalr1.cc:859 +#line 319 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HTYPE; - } -#line 965 "parser.cc" // lalr1.cc:859 + // expression: vendor-class[1234].data + // + // Vendor class option does not have suboptions, but chunks of data (typically 1, + // but the option structure allows multiple of them). If chunk offset is not + // specified, we assume the first (0th) is requested. + TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), + TokenVendor::DATA, 0)); + ctx.expression.push_back(vendor_class); +} +#line 1023 "parser.cc" // lalr1.cc:859 break; case 29: -#line 291 "parser.yy" // lalr1.cc:859 +#line 330 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CIADDR; - } -#line 973 "parser.cc" // lalr1.cc:859 + // expression: vendor-class[1234].data[5] + // + // Vendor class option does not have suboptions, but chunks of data (typically 1, + // but the option structure allows multiple of them). This syntax specifies + // which data chunk (tuple) we want. + uint8_t index = ctx.convertUint8(yystack_[1].value.as< std::string > (), yystack_[1].location); + TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[6].value.as< uint32_t > (), + TokenVendor::DATA, index)); + ctx.expression.push_back(vendor_class); +} +#line 1039 "parser.cc" // lalr1.cc:859 break; case 30: -#line 295 "parser.yy" // lalr1.cc:859 +#line 345 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::GIADDR; - } -#line 981 "parser.cc" // lalr1.cc:859 + yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); + } +#line 1047 "parser.cc" // lalr1.cc:859 break; case 31: -#line 299 "parser.yy" // lalr1.cc:859 +#line 349 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::YIADDR; - } -#line 989 "parser.cc" // lalr1.cc:859 + yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); + } +#line 1055 "parser.cc" // lalr1.cc:859 break; case 32: -#line 303 "parser.yy" // lalr1.cc:859 +#line 355 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::SIADDR; - } -#line 997 "parser.cc" // lalr1.cc:859 + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; + } +#line 1063 "parser.cc" // lalr1.cc:859 break; case 33: -#line 309 "parser.yy" // lalr1.cc:859 +#line 359 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; + } +#line 1071 "parser.cc" // lalr1.cc:859 + break; + + case 34: +#line 365 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< uint32_t > () = ctx.convertUint32(yystack_[0].value.as< std::string > (), yystack_[0].location); +} +#line 1079 "parser.cc" // lalr1.cc:859 + break; + + case 35: +#line 369 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< uint32_t > () = 0; +} +#line 1087 "parser.cc" // lalr1.cc:859 + break; + + case 36: +#line 374 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CHADDR; + } +#line 1095 "parser.cc" // lalr1.cc:859 + break; + + case 37: +#line 378 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HLEN; + } +#line 1103 "parser.cc" // lalr1.cc:859 + break; + + case 38: +#line 382 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HTYPE; + } +#line 1111 "parser.cc" // lalr1.cc:859 + break; + + case 39: +#line 386 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CIADDR; + } +#line 1119 "parser.cc" // lalr1.cc:859 + break; + + case 40: +#line 390 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::GIADDR; + } +#line 1127 "parser.cc" // lalr1.cc:859 + break; + + case 41: +#line 394 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::YIADDR; + } +#line 1135 "parser.cc" // lalr1.cc:859 + break; + + case 42: +#line 398 "parser.yy" // lalr1.cc:859 + { + yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::SIADDR; + } +#line 1143 "parser.cc" // lalr1.cc:859 + break; + + case 43: +#line 404 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); } -#line 1006 "parser.cc" // lalr1.cc:859 +#line 1152 "parser.cc" // lalr1.cc:859 break; - case 34: -#line 316 "parser.yy" // lalr1.cc:859 + case 44: +#line 411 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); } -#line 1015 "parser.cc" // lalr1.cc:859 +#line 1161 "parser.cc" // lalr1.cc:859 break; - case 35: -#line 321 "parser.yy" // lalr1.cc:859 + case 45: +#line 416 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString("all")); ctx.expression.push_back(str); } -#line 1024 "parser.cc" // lalr1.cc:859 +#line 1170 "parser.cc" // lalr1.cc:859 break; - case 36: -#line 327 "parser.yy" // lalr1.cc:859 + case 46: +#line 422 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::PEERADDR; } -#line 1030 "parser.cc" // lalr1.cc:859 +#line 1176 "parser.cc" // lalr1.cc:859 break; - case 37: -#line 328 "parser.yy" // lalr1.cc:859 + case 47: +#line 423 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::LINKADDR; } -#line 1036 "parser.cc" // lalr1.cc:859 +#line 1182 "parser.cc" // lalr1.cc:859 break; - case 38: -#line 332 "parser.yy" // lalr1.cc:859 + case 48: +#line 427 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location); + yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location); } -#line 1044 "parser.cc" // lalr1.cc:859 +#line 1190 "parser.cc" // lalr1.cc:859 break; - case 39: -#line 340 "parser.yy" // lalr1.cc:859 + case 49: +#line 435 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::MSGTYPE; } -#line 1050 "parser.cc" // lalr1.cc:859 +#line 1196 "parser.cc" // lalr1.cc:859 break; - case 40: -#line 341 "parser.yy" // lalr1.cc:859 + case 50: +#line 436 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::TRANSID; } -#line 1056 "parser.cc" // lalr1.cc:859 +#line 1202 "parser.cc" // lalr1.cc:859 break; -#line 1060 "parser.cc" // lalr1.cc:859 +#line 1206 "parser.cc" // lalr1.cc:859 default: break; } @@ -1311,122 +1457,146 @@ namespace isc { namespace eval { } - const signed char EvalParser::yypact_ninf_ = -62; + const signed char EvalParser::yypact_ninf_ = -82; const signed char EvalParser::yytable_ninf_ = -1; - const signed char + const short int EvalParser::yypact_[] = { - 14, 14, 14, 6, 17, 18, 21, 41, 44, 48, - -62, -62, -62, 72, 20, 66, 29, -62, 12, 12, - 16, 36, 45, 45, -24, -62, 14, 14, 45, -62, - -62, -62, 60, 63, -62, 73, -62, -62, -62, -62, - -62, -62, -62, -62, 67, 69, 75, 61, 62, -62, - -62, -62, -62, 84, -62, 77, 78, 79, 12, 12, - 16, 64, 45, -3, 52, -1, 81, 82, 83, -62, - 71, 95, -62, -62, -62, -62, -62, -62, 88, -62, - -62, -62, 87, 89, 90, -23, -62, 12, 49, 49, - 9, -62, -62, 100, 92, 94, -62, 93, 12, 68, - 96, -62, -62, 97, 49 + 65, 65, 65, -4, -1, 7, 29, 47, 66, 41, + 2, 24, -82, -82, -82, 84, 92, 83, 40, -82, + 45, 45, 67, 56, -3, -3, 69, -11, 75, -11, + 77, -82, 65, 65, -3, -82, -82, -82, 80, 91, + -82, 100, -82, -82, -82, -82, -82, -82, -82, -82, + 103, 104, 105, 73, 76, 90, 94, -82, -82, -82, + -82, -82, 106, -82, 107, -82, -82, 117, -82, 109, + 110, 111, 45, 45, 67, -11, -11, 87, -3, 113, + 114, 36, 43, 11, 116, 118, 119, 120, 121, -82, + 102, 133, -16, 0, -82, -82, -82, -82, -82, -82, + 124, -82, -82, -82, 123, 125, 126, 127, 128, -14, + -82, -82, 131, 132, -82, 45, 93, 93, 22, 112, + 138, -82, -82, 136, 108, 45, 137, 134, 139, -82, + 140, 141, 135, 45, 45, -82, 142, 46, 144, 145, + 54, -82, -82, 146, 147, -82, -82, 93, 93 }; const unsigned char EvalParser::yydefact_[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, 12, 13, 0, 2, 0, 0, 4, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, - 22, 23, 0, 0, 38, 0, 26, 27, 28, 29, - 30, 31, 32, 18, 0, 0, 0, 0, 0, 39, - 40, 19, 5, 6, 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, - 0, 0, 24, 25, 8, 14, 9, 15, 0, 36, - 37, 17, 0, 0, 0, 0, 21, 0, 0, 0, - 0, 35, 34, 0, 0, 0, 20, 0, 0, 0, - 0, 10, 16, 0, 0 + 0, 0, 14, 15, 16, 0, 2, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 3, 30, 31, 0, 0, + 48, 0, 36, 37, 38, 39, 40, 41, 42, 21, + 0, 0, 0, 0, 0, 0, 0, 49, 50, 22, + 35, 34, 0, 26, 0, 25, 5, 6, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, + 0, 0, 0, 0, 32, 33, 8, 17, 9, 18, + 0, 46, 47, 20, 0, 0, 0, 0, 0, 0, + 24, 11, 28, 0, 12, 0, 0, 0, 0, 0, + 0, 45, 44, 0, 0, 0, 0, 0, 0, 23, + 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, + 0, 10, 19, 0, 0, 13, 27, 0, 0 }; const signed char EvalParser::yypgoto_[] = { - -62, -62, 3, -21, -19, -61, -62, -62, -62, -62, - 50, -62 + -82, -82, 10, -20, -21, -81, -27, -82, -82, -82, + -82, 95, -82 }; const signed char EvalParser::yydefgoto_[] = { - -1, 13, 14, 15, 32, 75, 43, 70, 93, 81, - 35, 51 + -1, 15, 16, 17, 38, 97, 62, 49, 90, 123, + 103, 41, 59 }; const unsigned char EvalParser::yytable_[] = { - 33, 47, 48, 77, 16, 17, 91, 54, 78, 49, - 50, 79, 80, 92, 72, 73, 74, 1, 95, 2, - 18, 79, 80, 3, 4, 5, 26, 27, 77, 52, - 53, 19, 20, 29, 6, 26, 27, 21, 102, 66, - 67, 71, 7, 102, 22, 8, 9, 23, 30, 10, - 31, 11, 34, 12, 44, 45, 46, 36, 37, 38, - 39, 40, 41, 42, 24, 6, 72, 73, 94, 72, - 73, 76, 25, 7, 28, 55, 8, 9, 56, 100, - 10, 58, 11, 59, 12, 72, 73, 101, 57, 60, - 26, 61, 62, 63, 64, 65, 82, 83, 84, 86, - 69, 85, 87, 88, 96, 89, 90, 97, 98, 99, - 68, 103, 0, 104 + 39, 99, 64, 111, 55, 56, 50, 51, 52, 113, + 20, 18, 19, 21, 68, 121, 27, 6, 28, 114, + 100, 22, 112, 101, 102, 7, 60, 122, 8, 9, + 61, 127, 53, 54, 101, 102, 99, 12, 29, 13, + 30, 14, 66, 67, 35, 23, 32, 33, 87, 88, + 24, 84, 85, 94, 95, 96, 142, 26, 91, 146, + 94, 95, 98, 94, 95, 141, 142, 146, 1, 25, + 2, 94, 95, 145, 3, 4, 5, 42, 43, 44, + 45, 46, 47, 48, 31, 6, 36, 75, 37, 28, + 76, 34, 30, 7, 126, 69, 8, 9, 32, 33, + 10, 11, 57, 58, 131, 12, 70, 13, 40, 14, + 94, 95, 138, 139, 63, 71, 65, 72, 73, 74, + 77, 79, 80, 32, 78, 81, 82, 83, 89, 92, + 93, 104, 109, 105, 106, 107, 108, 110, 115, 116, + 129, 117, 118, 119, 120, 124, 125, 128, 133, 130, + 112, 137, 132, 134, 0, 135, 136, 0, 140, 143, + 144, 0, 147, 148, 0, 0, 0, 0, 0, 86 }; - const signed char + const short int EvalParser::yycheck_[] = { - 19, 22, 23, 64, 1, 2, 29, 28, 9, 33, - 34, 12, 13, 36, 17, 18, 19, 3, 9, 5, - 14, 12, 13, 9, 10, 11, 6, 7, 89, 26, - 27, 14, 14, 4, 20, 6, 7, 16, 99, 58, - 59, 62, 28, 104, 3, 31, 32, 3, 36, 35, - 38, 37, 36, 39, 9, 10, 11, 21, 22, 23, - 24, 25, 26, 27, 16, 20, 17, 18, 87, 17, - 18, 19, 0, 28, 8, 15, 31, 32, 15, 98, - 35, 14, 37, 14, 39, 17, 18, 19, 15, 14, - 6, 30, 30, 16, 16, 16, 15, 15, 15, 4, - 36, 30, 14, 16, 4, 16, 16, 15, 14, 16, - 60, 15, -1, 16 + 21, 82, 29, 19, 24, 25, 9, 10, 11, 9, + 14, 1, 2, 14, 34, 29, 14, 20, 16, 19, + 9, 14, 38, 12, 13, 28, 37, 41, 31, 32, + 41, 9, 35, 36, 12, 13, 117, 40, 14, 42, + 16, 44, 32, 33, 4, 16, 6, 7, 75, 76, + 3, 72, 73, 17, 18, 19, 137, 16, 78, 140, + 17, 18, 19, 17, 18, 19, 147, 148, 3, 3, + 5, 17, 18, 19, 9, 10, 11, 21, 22, 23, + 24, 25, 26, 27, 0, 20, 41, 14, 43, 16, + 14, 8, 16, 28, 115, 15, 31, 32, 6, 7, + 35, 36, 33, 34, 125, 40, 15, 42, 41, 44, + 17, 18, 133, 134, 39, 15, 39, 14, 14, 14, + 30, 15, 15, 6, 30, 16, 16, 16, 41, 16, + 16, 15, 30, 15, 15, 15, 15, 4, 14, 16, + 4, 16, 16, 16, 16, 14, 14, 9, 14, 41, + 38, 16, 15, 14, -1, 15, 15, -1, 16, 15, + 15, -1, 16, 16, -1, -1, -1, -1, -1, 74 }; const unsigned char EvalParser::yystos_[] = { 0, 3, 5, 9, 10, 11, 20, 28, 31, 32, - 35, 37, 39, 41, 42, 43, 42, 42, 14, 14, - 14, 16, 3, 3, 16, 0, 6, 7, 8, 4, - 36, 38, 44, 44, 36, 50, 21, 22, 23, 24, - 25, 26, 27, 46, 9, 10, 11, 43, 43, 33, - 34, 51, 42, 42, 43, 15, 15, 15, 14, 14, - 14, 30, 30, 16, 16, 16, 44, 44, 50, 36, - 47, 43, 17, 18, 19, 45, 19, 45, 9, 12, - 13, 49, 15, 15, 15, 30, 4, 14, 16, 16, - 16, 29, 36, 48, 44, 9, 4, 15, 14, 16, - 44, 19, 45, 15, 16 + 35, 36, 40, 42, 44, 46, 47, 48, 47, 47, + 14, 14, 14, 16, 3, 3, 16, 14, 16, 14, + 16, 0, 6, 7, 8, 4, 41, 43, 49, 49, + 41, 56, 21, 22, 23, 24, 25, 26, 27, 52, + 9, 10, 11, 35, 36, 48, 48, 33, 34, 57, + 37, 41, 51, 39, 51, 39, 47, 47, 48, 15, + 15, 15, 14, 14, 14, 14, 14, 30, 30, 15, + 15, 16, 16, 16, 49, 49, 56, 51, 51, 41, + 53, 48, 16, 16, 17, 18, 19, 50, 19, 50, + 9, 12, 13, 55, 15, 15, 15, 15, 15, 30, + 4, 19, 38, 9, 19, 14, 16, 16, 16, 16, + 16, 29, 41, 54, 14, 14, 49, 9, 9, 4, + 41, 49, 15, 14, 14, 15, 15, 16, 49, 49, + 16, 19, 50, 15, 15, 19, 50, 16, 16 }; const unsigned char EvalParser::yyr1_[] = { - 0, 40, 41, 42, 42, 42, 42, 42, 42, 42, - 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 44, 44, 45, 45, 46, 46, 46, 46, - 46, 46, 46, 47, 48, 48, 49, 49, 50, 51, - 51 + 0, 45, 46, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 49, 49, 50, 50, 51, 51, 52, 52, 52, 52, + 52, 52, 52, 53, 54, 54, 55, 55, 56, 57, + 57 }; const unsigned char EvalParser::yyr2_[] = { 0, 2, 1, 3, 2, 3, 3, 3, 6, 6, - 11, 1, 1, 1, 6, 6, 11, 6, 3, 3, - 8, 6, 1, 1, 1, 1, 1, 1, 1, 1, + 11, 6, 6, 11, 1, 1, 1, 6, 6, 11, + 6, 3, 3, 8, 6, 3, 3, 11, 6, 9, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -1444,22 +1614,24 @@ namespace isc { namespace eval { "\"hex\"", "\"exists\"", "\"pkt4\"", "\"mac\"", "\"hlen\"", "\"htype\"", "\"ciaddr\"", "\"giaddr\"", "\"yiaddr\"", "\"siaddr\"", "\"substring\"", "\"all\"", "\",\"", "\"concat\"", "\"pkt6\"", "\"msgtype\"", - "\"transid\"", "\"constant string\"", "\"integer\"", + "\"transid\"", "\"vendor-class\"", "\"vendor\"", "\"*\"", "\"data\"", + "\"enterprise\"", "\"constant string\"", "\"integer\"", "\"constant hexstring\"", "\"option name\"", "\"ip address\"", "$accept", "expression", "bool_expr", "string_expr", "option_code", - "option_repr_type", "pkt4_field", "start_expr", "length_expr", - "relay6_field", "nest_level", "pkt6_field", YY_NULLPTR + "option_repr_type", "enterprise_id", "pkt4_field", "start_expr", + "length_expr", "relay6_field", "nest_level", "pkt6_field", YY_NULLPTR }; #if YYDEBUG const unsigned short int EvalParser::yyrline_[] = { - 0, 100, 100, 103, 104, 109, 114, 119, 124, 129, - 149, 165, 170, 175, 180, 185, 206, 221, 236, 241, - 246, 251, 258, 262, 268, 272, 278, 282, 286, 290, - 294, 298, 302, 308, 315, 320, 327, 328, 331, 340, - 341 + 0, 106, 106, 109, 110, 115, 120, 125, 130, 135, + 155, 169, 178, 188, 199, 204, 209, 214, 219, 240, + 255, 270, 275, 280, 285, 290, 298, 307, 318, 329, + 344, 348, 354, 358, 364, 368, 373, 377, 381, 385, + 389, 393, 397, 403, 410, 415, 422, 423, 426, 435, + 436 }; // Print the state stack on the debug stream. @@ -1494,8 +1666,8 @@ namespace isc { namespace eval { #line 13 "parser.yy" // lalr1.cc:1167 } } // isc::eval -#line 1498 "parser.cc" // lalr1.cc:1167 -#line 344 "parser.yy" // lalr1.cc:1168 +#line 1670 "parser.cc" // lalr1.cc:1167 +#line 439 "parser.yy" // lalr1.cc:1168 void isc::eval::EvalParser::error(const location_type& loc, diff --git a/src/lib/eval/parser.h b/src/lib/eval/parser.h index 8e725ab898..a4883dcfbf 100644 --- a/src/lib/eval/parser.h +++ b/src/lib/eval/parser.h @@ -317,8 +317,11 @@ namespace isc { namespace eval { // option_code char dummy6[sizeof(uint16_t)]; + // enterprise_id + char dummy7[sizeof(uint32_t)]; + // nest_level - char dummy7[sizeof(uint8_t)]; + char dummy8[sizeof(uint8_t)]; }; /// Symbol semantic values. @@ -374,11 +377,16 @@ namespace isc { namespace eval { TOKEN_PKT6 = 287, TOKEN_MSGTYPE = 288, TOKEN_TRANSID = 289, - TOKEN_STRING = 290, - TOKEN_INTEGER = 291, - TOKEN_HEXSTRING = 292, - TOKEN_OPTION_NAME = 293, - TOKEN_IP_ADDRESS = 294 + TOKEN_VENDOR_CLASS = 290, + TOKEN_VENDOR = 291, + TOKEN_ANY = 292, + TOKEN_DATA = 293, + TOKEN_ENTERPRISE = 294, + TOKEN_STRING = 295, + TOKEN_INTEGER = 296, + TOKEN_HEXSTRING = 297, + TOKEN_OPTION_NAME = 298, + TOKEN_IP_ADDRESS = 299 }; }; @@ -428,6 +436,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); @@ -629,6 +639,26 @@ namespace isc { namespace eval { 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); @@ -716,7 +746,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 @@ -734,7 +764,7 @@ namespace isc { namespace eval { // 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. @@ -854,12 +884,12 @@ namespace isc { namespace eval { enum { yyeof_ = 0, - yylast_ = 113, ///< Last index in yytable_. - yynnts_ = 12, ///< Number of nonterminal symbols. - yyfinal_ = 25, ///< Termination state number. + yylast_ = 169, ///< Last index in yytable_. + yynnts_ = 13, ///< Number of nonterminal symbols. + yyfinal_ = 31, ///< Termination state number. yyterror_ = 1, yyerrcode_ = 256, - yyntokens_ = 40 ///< Number of tokens. + yyntokens_ = 45 ///< Number of tokens. }; @@ -905,9 +935,9 @@ 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 + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 }; - const unsigned int user_token_number_max_ = 294; + const unsigned int user_token_number_max_ = 299; const token_number_type undef_token_ = 2; if (static_cast(t) <= yyeof_) @@ -940,35 +970,39 @@ namespace isc { namespace eval { { switch (other.type_get ()) { - case 45: // option_repr_type + case 50: // option_repr_type value.copy< TokenOption::RepresentationType > (other.value); break; - case 46: // pkt4_field + case 52: // pkt4_field value.copy< TokenPkt4::FieldType > (other.value); break; - case 51: // pkt6_field + case 57: // pkt6_field value.copy< TokenPkt6::FieldType > (other.value); break; - case 49: // relay6_field + case 55: // relay6_field value.copy< TokenRelay6Field::FieldType > (other.value); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" value.copy< std::string > (other.value); break; - case 44: // option_code + case 49: // option_code value.copy< uint16_t > (other.value); break; - case 50: // nest_level + case 51: // enterprise_id + value.copy< uint32_t > (other.value); + break; + + case 56: // nest_level value.copy< uint8_t > (other.value); break; @@ -989,35 +1023,39 @@ namespace isc { namespace eval { (void) v; switch (this->type_get ()) { - case 45: // option_repr_type + case 50: // option_repr_type value.copy< TokenOption::RepresentationType > (v); break; - case 46: // pkt4_field + case 52: // pkt4_field value.copy< TokenPkt4::FieldType > (v); break; - case 51: // pkt6_field + case 57: // pkt6_field value.copy< TokenPkt6::FieldType > (v); break; - case 49: // relay6_field + case 55: // relay6_field value.copy< TokenRelay6Field::FieldType > (v); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" value.copy< std::string > (v); break; - case 44: // option_code + case 49: // option_code value.copy< uint16_t > (v); break; - case 50: // nest_level + case 51: // enterprise_id + value.copy< uint32_t > (v); + break; + + case 56: // nest_level value.copy< uint8_t > (v); break; @@ -1078,6 +1116,13 @@ namespace isc { namespace eval { , location (l) {} + template + EvalParser::basic_symbol::basic_symbol (typename Base::kind_type t, const uint32_t v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} + template EvalParser::basic_symbol::basic_symbol (typename Base::kind_type t, const uint8_t v, const location_type& l) : Base (t) @@ -1111,35 +1156,39 @@ namespace isc { namespace eval { // Type destructor. switch (yytype) { - case 45: // option_repr_type + case 50: // option_repr_type value.template destroy< TokenOption::RepresentationType > (); break; - case 46: // pkt4_field + case 52: // pkt4_field value.template destroy< TokenPkt4::FieldType > (); break; - case 51: // pkt6_field + case 57: // pkt6_field value.template destroy< TokenPkt6::FieldType > (); break; - case 49: // relay6_field + case 55: // relay6_field value.template destroy< TokenRelay6Field::FieldType > (); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" value.template destroy< std::string > (); break; - case 44: // option_code + case 49: // option_code value.template destroy< uint16_t > (); break; - case 50: // nest_level + case 51: // enterprise_id + value.template destroy< uint32_t > (); + break; + + case 56: // nest_level value.template destroy< uint8_t > (); break; @@ -1166,35 +1215,39 @@ namespace isc { namespace eval { super_type::move(s); switch (this->type_get ()) { - case 45: // option_repr_type + case 50: // option_repr_type value.move< TokenOption::RepresentationType > (s.value); break; - case 46: // pkt4_field + case 52: // pkt4_field value.move< TokenPkt4::FieldType > (s.value); break; - case 51: // pkt6_field + case 57: // pkt6_field value.move< TokenPkt6::FieldType > (s.value); break; - case 49: // relay6_field + case 55: // relay6_field value.move< TokenRelay6Field::FieldType > (s.value); break; - case 35: // "constant string" - case 36: // "integer" - case 37: // "constant hexstring" - case 38: // "option name" - case 39: // "ip address" + case 40: // "constant string" + case 41: // "integer" + case 42: // "constant hexstring" + case 43: // "option name" + case 44: // "ip address" value.move< std::string > (s.value); break; - case 44: // option_code + case 49: // option_code value.move< uint16_t > (s.value); break; - case 50: // nest_level + case 51: // enterprise_id + value.move< uint32_t > (s.value); + break; + + case 56: // nest_level value.move< uint8_t > (s.value); break; @@ -1256,7 +1309,8 @@ namespace isc { namespace eval { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 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 + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299 }; return static_cast (yytoken_number_[type]); } @@ -1459,6 +1513,36 @@ namespace isc { namespace eval { 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) { @@ -1492,7 +1576,7 @@ namespace isc { namespace eval { #line 13 "parser.yy" // lalr1.cc:377 } } // isc::eval -#line 1496 "parser.h" // lalr1.cc:377 +#line 1580 "parser.h" // lalr1.cc:377 diff --git a/src/lib/eval/position.hh b/src/lib/eval/position.hh index a7c81176bc..b3eebe04f6 100644 --- a/src/lib/eval/position.hh +++ b/src/lib/eval/position.hh @@ -1,4 +1,3 @@ -// Generated 201604271143 // A Bison parser, made by GNU Bison 3.0.4. // Positions for Bison parsers in C++ diff --git a/src/lib/eval/stack.hh b/src/lib/eval/stack.hh index c7fa5852ea..6bda37bbcf 100644 --- a/src/lib/eval/stack.hh +++ b/src/lib/eval/stack.hh @@ -1,4 +1,3 @@ -// Generated 201604271143 // A Bison parser, made by GNU Bison 3.0.4. // Stack handling for Bison parsers in C++ From f59eab97101aa3773925429422f80d545b6e1df8 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 9 Aug 2016 16:08:11 +0200 Subject: [PATCH 03/15] [4271] Debug logging added. --- src/lib/eval/eval_messages.mes | 47 +++++++++++++++++++++++++++++++ src/lib/eval/token.cc | 51 ++++++++++++++++++++++++++++------ src/lib/eval/token.h | 3 +- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/lib/eval/eval_messages.mes b/src/lib/eval/eval_messages.mes index 3ee2da1306..10e7af5f60 100644 --- a/src/lib/eval/eval_messages.mes +++ b/src/lib/eval/eval_messages.mes @@ -111,3 +111,50 @@ still pushed. The strings are displayed in hex. This debug message indicates that the expression has been evaluated to said value. This message is mostly useful during debugging of the client classification expressions. + +% EVAL_DEBUG_VENDOR_NO_OPTION Vendor option (code %1) missing, pushing result %2 +This debug message indicates that the expression has been evaluated +and vendor option was not found. This message is mostly useful during +debugging of the client classification expressions. + +% EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Vendor option was found, but does not have expected enterprise-id (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. This message is mostly useful during debugging of the +client classification expressions. + +% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Vendor option found, pushing enterprise-id %1 as result %2 +This debug message indicates that the expression has been evaluated and vendor +option was found and its enterprise-id is being reported. This message is mostly +useful during debugging of the client classification expressions. + +% EVAL_DEBUG_VENDOR_EXISTS Vendor option exists, pushing result %1 +This debug message indicates that the expression has been evaluated and vendor +option was found. This message is mostly useful during debugging of the client +classification expressions. + +% EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Vendor class option (code %1) missing, pushing result %2 +This debug message indicates that the expression has been evaluated +and vendor class option was not found. This message is mostly useful during +debugging of the client classification expressions. + +% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Vendor class option was found, but does not have expected enterprise-id (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. This message is mostly useful during debugging of the +client classification expressions. + +% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Vendor class option found, pushing enterprise-id %1 as result %2 +This debug message indicates that the expression has been evaluated and vendor +class option was found and its enterprise-id is being reported. This message is mostly +useful during debugging of the client classification expressions. + +% EVAL_DEBUG_VENDOR_CLASS_EXISTS Vendor class option exists, pushing result %1 +This debug message indicates that the expression has been evaluated and vendor +class option was found. This message is mostly useful during debugging of the +client classification expressions. + +% EVAL_DEBUG_VENDOR_CLASS_DATA Vendor class data %1 (out of %2 received) is pushed as %3 +This debug message indicates that vendor class option was found and passed +enterprise-id checks and has sufficient number of data chunks. Total numer +of chunks and value pushed are reported as debugging aid. diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index f8df034e05..a2b5cd8f60 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -140,13 +140,14 @@ TokenOption::evaluate(Pkt& pkt, ValueStack& values) { } } -void +std::string TokenOption::pushFailure(ValueStack& values) { + std::string txt; if (representation_type_ == EXISTS) { - values.push("false"); - } else { - values.push(""); + txt = "false"; } + values.push(txt); + return (txt); } TokenRelay4Option::TokenRelay4Option(const uint16_t option_code, @@ -654,14 +655,21 @@ void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) { OptionVendorPtr vendor = boost::dynamic_pointer_cast(opt); if (!vendor) { // There's no vendor option, give up. - pushFailure(values); + 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) - pushFailure(values); + 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; } @@ -673,6 +681,10 @@ void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) { 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_id_) + .arg(util::encode::encodeHex(std::vector(txt.begin(), + txt.end()))); return; } case SUBOPTION: @@ -683,6 +695,8 @@ void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) { 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("true"); values.push("true"); return; case DATA: @@ -746,15 +760,22 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { OptionPtr opt = pkt.getOption(code); OptionVendorClassPtr vendor = boost::dynamic_pointer_cast(opt); if (!vendor) { - // There's no vendor option, give up. - pushFailure(values); + // 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) - pushFailure(values); + 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; } @@ -766,6 +787,10 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { 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_id_) + .arg(util::encode::encodeHex(std::vector(txt.begin(), + txt.end()))); return; } case SUBOPTION: @@ -775,6 +800,8 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { 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("true"); values.push("true"); return; case DATA: @@ -790,6 +817,12 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { 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(util::encode::encodeHex(buf)); + values.push(txt); return; } diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index fcc123df57..28c444c617 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -261,7 +261,8 @@ protected: /// Depending on the representation type, this is either "" or "false". /// /// @param values a string representing failure will be pushed here. - virtual void pushFailure(ValueStack& values); + /// @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. From 30cdc3cbd8a981e34f0e30cfe3c29ff8e4371323 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 9 Aug 2016 16:36:04 +0200 Subject: [PATCH 04/15] [4271] Debug in LogContnetTest class implemented. --- src/lib/testutils/log_utils.cc | 19 +++++++++++++++++-- src/lib/testutils/log_utils.h | 8 ++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/lib/testutils/log_utils.cc b/src/lib/testutils/log_utils.cc index 2bfcc78843..669d91e01d 100644 --- a/src/lib/testutils/log_utils.cc +++ b/src/lib/testutils/log_utils.cc @@ -5,12 +5,14 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include +#include namespace isc { namespace dhcp { namespace test { -LogContentTest::LogContentTest() { +LogContentTest::LogContentTest() + :verbose_(false) { // Get rid of any old files remFile(); @@ -41,18 +43,31 @@ bool LogContentTest::checkFile() { int i = 0; bool found = true; + using namespace std; + while (getline(file, line) && (i != exp_strings_.size())) { exp_line = exp_strings_[i]; + if (verbose_) { + cout << "Read line :" << line << endl; + cout << "Looking for:" << exp_line << endl; + } i++; if (string::npos == line.find(exp_line)) { + if (verbose_) { + cout << "Verdict : not found" << endl; + } found = false; } } file.close(); - if ((i != exp_strings_.size()) || (found == false)) + if ((i != exp_strings_.size()) || (found == false)) { + if (verbose_) { + cout << "Final verdict: false" << endl; + } return (false); + } return (true); } diff --git a/src/lib/testutils/log_utils.h b/src/lib/testutils/log_utils.h index fbfd24cb33..340ef8a9b3 100644 --- a/src/lib/testutils/log_utils.h +++ b/src/lib/testutils/log_utils.h @@ -63,6 +63,12 @@ public: /// @brief remove the test log file void remFile(); + /// @brief Enables or disables verbose mode. + /// @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 +77,8 @@ public: vector exp_strings_; static const char* LOG_FILE; + + bool verbose_; }; From 77848fb77ee1e593cf0eabe844a6b8a4f095f39b Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 9 Aug 2016 16:36:48 +0200 Subject: [PATCH 05/15] [4271] Messages are now more terse. --- src/lib/eval/eval_messages.mes | 18 +++++++++--------- src/lib/eval/tests/token_unittest.cc | 11 +++++++++++ src/lib/eval/token.cc | 2 ++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/lib/eval/eval_messages.mes b/src/lib/eval/eval_messages.mes index 10e7af5f60..2db350f964 100644 --- a/src/lib/eval/eval_messages.mes +++ b/src/lib/eval/eval_messages.mes @@ -112,49 +112,49 @@ This debug message indicates that the expression has been evaluated to said value. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_NO_OPTION Vendor option (code %1) missing, pushing result %2 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Vendor option was found, but does not have expected enterprise-id (was looking for %1, option had %2), pushing result %3 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Vendor option found, pushing enterprise-id %1 as result %2 +% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result %2 This debug message indicates that the expression has been evaluated and vendor option was found and its enterprise-id is being reported. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_EXISTS Vendor option exists, pushing result %1 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Vendor class option (code %1) missing, pushing result %2 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Vendor class option was found, but does not have expected enterprise-id (was looking for %1, option had %2), pushing result %3 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Vendor class option found, pushing enterprise-id %1 as result %2 +% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result %2 This debug message indicates that the expression has been evaluated and vendor class option was found and its enterprise-id is being reported. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_EXISTS Vendor class option exists, pushing result %1 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_DATA Vendor class data %1 (out of %2 received) is pushed as %3 +% EVAL_DEBUG_VENDOR_CLASS_DATA Data %1 (out of %2 received) in vendor class found pushing as %3 This debug message indicates that vendor class option was found and passed enterprise-id checks and has sufficient number of data chunks. Total numer of chunks and value pushed are reported as debugging aid. diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index 04d5d1f303..b65c8d99b7 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -1923,6 +1923,17 @@ TEST_F(TokenTest, vendor4SpecificVendorExists) { // Case 3: option present and has matchin enterprise-id, should suceed testVendorExists(Option::V4, 4491, 4491, "true"); + + + 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"); + + logCheckVerbose(true); + EXPECT_TRUE(checkFile()); } // This test verifies if expression vendor[4491].exist works properly in DHCPv6. diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index a2b5cd8f60..3f479193a0 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -696,6 +696,7 @@ void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) { // 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; @@ -801,6 +802,7 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { // 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; From d7f927a1556f4ad5ed1d51dc7c43cf8028d62ee1 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Wed, 10 Aug 2016 16:38:03 +0200 Subject: [PATCH 06/15] [4271] Logging checks added for TokenVendor and TokenVendorClass --- src/lib/eval/eval_messages.mes | 24 ++- src/lib/eval/tests/token_unittest.cc | 262 +++++++++++++++++++++++++-- src/lib/eval/token.cc | 11 +- 3 files changed, 272 insertions(+), 25 deletions(-) diff --git a/src/lib/eval/eval_messages.mes b/src/lib/eval/eval_messages.mes index 2db350f964..6b7d1d1792 100644 --- a/src/lib/eval/eval_messages.mes +++ b/src/lib/eval/eval_messages.mes @@ -112,49 +112,55 @@ This debug message indicates that the expression has been evaluated to said value. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_NO_OPTION Option with code %1 missing, pushing result %2 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result %3 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result %2 +% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result '%2' This debug message indicates that the expression has been evaluated and vendor option was found and its enterprise-id is being reported. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id %1 found, pushing result %2 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code %1 missing, pushing result %2 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for %1, option had %2, pushing result %3 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result %2 +% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result '%2' This debug message indicates that the expression has been evaluated and vendor class option was found and its enterprise-id is being reported. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_EXISTS Option with enterprise-id %1 found, pushing result %2 +% 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. This message is mostly useful during debugging of the client classification expressions. -% EVAL_DEBUG_VENDOR_CLASS_DATA Data %1 (out of %2 received) in vendor class found pushing as %3 +% 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. Total numer 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. \ No newline at end of file diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index b65c8d99b7..712ec610c4 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -53,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 @@ -1924,15 +1928,13 @@ TEST_F(TokenTest, vendor4SpecificVendorExists) { // Case 3: option present and has matchin enterprise-id, should suceed 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"); + "pushing result 'false'"); addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH Was looking for 4491, " - "option had 1234, pushing result false"); + "option had 1234, pushing result 'false'"); addString("EVAL_DEBUG_VENDOR_EXISTS Option with enterprise-id 4491 " - "found, pushing result true"); - - logCheckVerbose(true); + "found, pushing result 'true'"); EXPECT_TRUE(checkFile()); } @@ -1946,6 +1948,15 @@ TEST_F(TokenTest, vendor6SpecificVendorExists) { // 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. @@ -1958,6 +1969,15 @@ TEST_F(TokenTest, vendor4AnyVendorExists) { // 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. @@ -1970,6 +1990,15 @@ TEST_F(TokenTest, vendor6AnyVendorExists) { // 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. @@ -1983,6 +2012,15 @@ TEST_F(TokenTest, vendor4enterprise) { // 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 '000004D2'"); + addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 4294967295" + " as result 'FFFFFFFF'"); + EXPECT_TRUE(checkFile()); } // Test if expression vendor[*].enterprise works properly for DHCPv6. @@ -1996,6 +2034,15 @@ TEST_F(TokenTest, vendor6enterprise) { // 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 '000004D2'"); + addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 4294967295 " + "as result 'FFFFFFFF'"); + EXPECT_TRUE(checkFile()); } // This one tests "vendor[4491].option[1].exists" expression. There are so many @@ -2021,6 +2068,17 @@ TEST_F(TokenTest, vendor4SuboptionExists) { // 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 @@ -2044,6 +2102,17 @@ TEST_F(TokenTest, vendor6SuboptionExists) { // 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 @@ -2065,6 +2134,17 @@ TEST_F(TokenTest, vendor4SuboptionHex) { // 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 @@ -2086,6 +2166,17 @@ TEST_F(TokenTest, vendor6SuboptionHex) { // 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 @@ -2099,6 +2190,15 @@ TEST_F(TokenTest, vendorClass4SpecificVendorExists) { // 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 @@ -2112,6 +2212,15 @@ TEST_F(TokenTest, vendorClass6SpecificVendorExists) { // 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 @@ -2125,6 +2234,15 @@ TEST_F(TokenTest, vendorClass4AnyVendorExists) { // 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 @@ -2138,6 +2256,15 @@ TEST_F(TokenTest, vendorClass6AnyVendorExists) { // 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. @@ -2151,6 +2278,15 @@ TEST_F(TokenTest, vendorClass4enterprise) { // 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 '000004D2'"); + addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id " + "4294967295 as result 'FFFFFFFF'"); + EXPECT_TRUE(checkFile()); } // Test if expression "vendor-class.enterprise" works properly for DHCPv6. @@ -2164,6 +2300,15 @@ TEST_F(TokenTest, vendorClass6enterprise) { // 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 '000004D2'"); + addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id " + "4294967295 as result 'FFFFFFFF'"); + EXPECT_TRUE(checkFile()); } // Test that expression "vendor-class[4491].data" is able to retrieve content @@ -2189,6 +2334,19 @@ TEST_F(TokenTest, vendorClass4SpecificVendorData) { // 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 @@ -2214,6 +2372,20 @@ TEST_F(TokenTest, vendorClass6SpecificVendorData) { // 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 @@ -2224,11 +2396,13 @@ TEST_F(TokenTest, vendorClass4AnyVendorData) { 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, expected result is empty string. + // 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, expected result is empty string + // 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 @@ -2239,6 +2413,19 @@ TEST_F(TokenTest, vendorClass4AnyVendorData) { // 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 @@ -2264,6 +2451,21 @@ TEST_F(TokenTest, vendorClass6AnyVendorData) { // 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 @@ -2288,12 +2490,29 @@ TEST_F(TokenTest, vendorClass4DataIndex) { // Case 5: Expression looks for vendor-id 4491, data[3], there is // vendor-class with vendor-id 4491, but has only 2 data tuples, expected // result is empty string. - testVendorClassData(Option::V4, 4491, 3, 1234, 1, ""); + 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"); + + // 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'"); + EXPECT_TRUE(checkFile()); } // This test verifies if expression vendor-class[4491].data[3] is able to access @@ -2312,18 +2531,35 @@ TEST_F(TokenTest, vendorClass6DataIndex) { 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 2 data tuples, expected result is empty string. - testVendorClassData(Option::V6, 4491, 3, 1234, 1, ""); + // 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 2 data tuples, expected + // vendor-class with vendor-id 4491, but has only 3 data tuples, expected // result is empty string. - testVendorClassData(Option::V6, 4491, 3, 1234, 1, ""); + testVendorClassData(Option::V6, 4491, 3, 4491, 3, ""); // Case 6: Expression looks for vendor-id 4491, data[3], there is // vendor-class with vendor-id 4491 and 5 data tuples, expected result is // content of that tuple ("gamma") testVendorClassData(Option::V6, 4491, 3, 4491, 5, "gamma"); + + // Check if the logged messages are correct. + addString("EVAL_DEBUG_VENDOR_CLASS_NO_OPTION Option with code 16 missing, " + "pushing result ''"); + addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for " + "4491, option had 1234, pushing result ''"); + addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 3, " + "but option with enterprise-id 4491 has only 0 data tuple(s), " + "pushing result ''"); + addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH Was looking for " + "4491, option had 1234, pushing result ''"); + addString("EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND Requested data index 3, " + "but option with enterprise-id 4491 has only 3 data tuple(s), " + "pushing result ''"); + addString("EVAL_DEBUG_VENDOR_CLASS_DATA Data 3 (out of 5 received) in vendor" + " class found, pushing result 'gamma'"); + EXPECT_TRUE(checkFile()); } }; diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index 3f479193a0..7963a52e34 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -682,7 +682,7 @@ void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) { memcpy(&txt[0], &value, sizeof(uint32_t)); values.push(txt); LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID) - .arg(vendor_id_) + .arg(vendor->getVendorId()) .arg(util::encode::encodeHex(std::vector(txt.begin(), txt.end()))); return; @@ -789,7 +789,7 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { 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_id_) + .arg(vendor->getVendorId()) .arg(util::encode::encodeHex(std::vector(txt.begin(), txt.end()))); return; @@ -812,6 +812,11 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { if (index_ + 1 > max) { // The index specified if out of bound, 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; } @@ -823,7 +828,7 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA) .arg(index_) .arg(max) - .arg(util::encode::encodeHex(buf)); + .arg(txt); values.push(txt); return; From 0fea47e1b93d2c5b5801c1826eba9032dfae7288 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Wed, 10 Aug 2016 18:58:51 +0200 Subject: [PATCH 07/15] [4271] User's Guide updated. --- doc/guide/classify.xml | 101 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index 322cb46797..3b8f45037e 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -291,6 +291,88 @@ The value of the transaction id in the DHCPv6 packet. + + + Vendor option existence (any vendor) + vendor[*].exist + true + Returns whether a vendor option from any vendor + is present ('true') or absent ('false'). + + + Vendor option existence (specific vendor) + vendor[4491].exists + true + Returns whether a vendor option from specified + vendor (determined by its enterprise-id) + is present ('true') or absent ('false'). + + + Enterprise-id from vendor option + vendor.enterprise + 0x0000118b + If the vendor option is present, it returns the + value of the enterprise-id field padded to 4 + bytes. Returns '' otherwise. + + + Vendor sub-option existence + vendor[4491].option[1].exists + true + Returns 'true' if there is vendor option with + specified enterprise-id and given sub-option is present. + Returns 'false' otherwise. + + + Vendor sub-option content + vendor[4491].option[1].hex + docsis3.0 + Returns content of the specified sub-option of + a vendor option with specified enterprise id. Returns + '' if no such option or sub-option is present. + + + + + Vendor class option existence (any vendor) + vendor-class[*].exist + true + Returns whether a vendor class option from any vendor + is present ('true') or absent ('false'). + + + Vendor class option existence (specific vendor) + vendor-class[4491].exists + true + Returns whether a vendor class option from specified + vendor (determined by its enterprise-id) + is present ('true') or absent ('false'). + + + Enterprise-id from vendor class option + vendor-class.enterprise + 0x0000118b + If the vendor option is present, it returns the + value of the enterprise-id field padded to 4 + bytes. Returns '' otherwise. + + + First data chunk from vendor class option + vendor-class[4491].data + true + Returns content of the first data chunk from + the vendor class option with specified enterprise-id. + Returns '' if missing. + + + Specific data chunk from vendor class option + vendor-class[4491].data[3] + docsis3.0 + Returns content of the specified data chunk of + a vendor class option with specified enterprise id. Returns + '' if no such option or data chunk is present. + + @@ -362,6 +444,22 @@ "0x00000001" or simply 1 as in "pkt6.msgtype == 1". + + Vendor option means Vendor-Identifying Vendor-specific Information + option (code 125, see Section 4 of RFC3925) in DHCPv4 and + Vendor-specific Information Option (code 17, defined in Section 22.17 of + RFC3315) in DHCPv6. Vendor class option means Vendor-Identifying Vendor + Class Option (code 124, see Section 3 of RFC3925) in DHCPv4 and Vendor + Class Option (code 16, see Section 22.16 of RFC3315). Vendor options may + have sub-options that are referenced by their codes. Vendor class + options do not have sub-options, but rather data chunks, which are + referenced by index value. Index 0 means the first data chunk, Index 1 + is for the second data chunk (if present), etc. + + + Asterisk (*) or 0 can be used to specify wildcard enterprise-id + value, i.e. it will match any enterprise-id value. + List of Classification Expressions @@ -382,7 +480,8 @@ And ('foo' == 'bar') and ('bar' == 'foo')Logical andOr ('foo' == 'bar') or ('bar' == 'foo')Logical orSubstringsubstring('foobar',0,3)Return the requested substring -Concatconcat('foo','bar')Return the concatenation of the strings +Concatconcat('foo','bar')Return the +concatenation of the strings
From caf8a886797e947fb68f80489df68564432a811f Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Wed, 10 Aug 2016 19:01:41 +0200 Subject: [PATCH 08/15] [4271] Limitations sections trimmed down --- doc/guide/dhcp4-srv.xml | 6 ------ doc/guide/dhcp6-srv.xml | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml index 352f50f667..7b09356207 100644 --- a/doc/guide/dhcp4-srv.xml +++ b/doc/guide/dhcp4-srv.xml @@ -3583,9 +3583,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc --> Host reservation (static addresses) is not supported yet. - - Full featured client classification is not supported yet. - BOOTP (RFC 951) @@ -3609,9 +3606,6 @@ src/lib/dhcpsrv/cfg_host_operations.cc --> allocating server should verify that address is not used by sending ICMP echo request. - - Address duplication report (DECLINE) is not supported yet. - diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml index 5b1d5c5858..4eac70db24 100644 --- a/doc/guide/dhcp6-srv.xml +++ b/doc/guide/dhcp6-srv.xml @@ -3828,8 +3828,7 @@ should include options from the isc option space: - Duplication report (DECLINE) and client reconfiguration (RECONFIGURE) are - not yet supported. + Client reconfiguration (RECONFIGURE) is not yet supported. From dbab626c4daa0199d345a0e6c6ab0bdbcd361f00 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Wed, 10 Aug 2016 19:06:56 +0200 Subject: [PATCH 09/15] [4271] Minor doc update. --- doc/guide/classify.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index 3b8f45037e..b501cc64ca 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -460,6 +460,9 @@ Asterisk (*) or 0 can be used to specify wildcard enterprise-id value, i.e. it will match any enterprise-id value. + Vendor Class Identifier (option 60 in DHCPv4) can be + accessed using option[60] expression. + List of Classification Expressions From d6fa702fef01cce17641f1f7f38bb6d80b0dedd7 Mon Sep 17 00:00:00 2001 From: Shawn Routhier Date: Wed, 17 Aug 2016 00:24:30 -0700 Subject: [PATCH 10/15] [4271] Mostly typo level clean up --- doc/guide/classify.xml | 10 +++++----- src/lib/eval/eval_context.h | 10 +++++----- src/lib/eval/eval_messages.mes | 2 +- src/lib/eval/tests/context_unittest.cc | 6 +++--- src/lib/eval/tests/token_unittest.cc | 18 ++++++++++-------- src/lib/eval/token.cc | 2 +- src/lib/eval/token.h | 14 +++++++------- 7 files changed, 32 insertions(+), 30 deletions(-) diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index b501cc64ca..1100b50f57 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -202,7 +202,7 @@ --> Option existence - option[123].exist + option[123].exists 'true' If the option with given code is present in the packet "true" else "false" @@ -294,7 +294,7 @@ Vendor option existence (any vendor) - vendor[*].exist + vendor[*].exists true Returns whether a vendor option from any vendor is present ('true') or absent ('false'). @@ -335,7 +335,7 @@ Vendor class option existence (any vendor) - vendor-class[*].exist + vendor-class[*].exists true Returns whether a vendor class option from any vendor is present ('true') or absent ('false'). @@ -359,7 +359,7 @@ First data chunk from vendor class option vendor-class[4491].data - true + docsis3.0 Returns content of the first data chunk from the vendor class option with specified enterprise-id. Returns '' if missing. @@ -399,7 +399,7 @@ - "option[code].exist" checks if an option with the code "code" is present + "option[code].exists" checks if an option with the code "code" is present in the incoming packet. It can be used with empty options. diff --git a/src/lib/eval/eval_context.h b/src/lib/eval/eval_context.h index e7049b723b..4984554ec4 100644 --- a/src/lib/eval/eval_context.h +++ b/src/lib/eval/eval_context.h @@ -101,20 +101,20 @@ public: uint16_t convertOptionName(const std::string& option_name, const isc::eval::location& loc); - /// @brief Attempts to convert string to unsinged 32bit integer + /// @brief Attempts to convert string to unsigned 32bit integer /// /// @param number string to be converted /// @param loc the location of the token - /// @return the option code + /// @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 unsinged 8bit integer + /// @brief Attempts to convert string to unsigned 8bit integer /// /// @param number string to be converted /// @param loc the location of the token - /// @return the option code + /// @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); @@ -123,7 +123,7 @@ public: /// /// @param nest_level a string representing the integer nesting level /// @param loc the location of the token - /// @result the nesting level + /// @return the nesting level /// @throw calls the syntax error function if the value is not in /// the range 0..31 uint8_t convertNestLevelNumber(const std::string& nest_level, diff --git a/src/lib/eval/eval_messages.mes b/src/lib/eval/eval_messages.mes index 6b7d1d1792..539ebac4b6 100644 --- a/src/lib/eval/eval_messages.mes +++ b/src/lib/eval/eval_messages.mes @@ -156,7 +156,7 @@ client classification expressions. % 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. Total numer +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' diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index cb5752fc0b..6e82e53c51 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -462,8 +462,8 @@ public: /// /// This test checks if EXISTS representation is set correctly. /// It covers cases like: - /// - vendor-class[4491].exist - /// - vendor-class[*].exist + /// - vendor-class[4491].exists + /// - vendor-class[*].exists /// /// @param expr expression to be parsed /// @param u universe (V4 or V6) @@ -481,7 +481,7 @@ public: /// @brief Tests if specified token vendor class expression can be parsed /// - /// This test assumes the first token will be token vendor. Any additional + /// This test assumes the first token will be token vendor-class. Any additional /// tokens are ignored. Tests experssions: /// - vendor-class[4491].exists /// - vendor-class[*].exists diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index 712ec610c4..23745989c6 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -429,7 +429,7 @@ public: evaluate(u, expected_result); } - /// @brief Tests if vendor class token can handle sub-options properly. + /// @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 @@ -1917,7 +1917,7 @@ TEST_F(TokenTest, pkt6Fields) { EXPECT_TRUE(checkFile()); } -// This test verifies if expression vendor[4491].exist works properly in DHCPv4. +// 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"); @@ -1925,7 +1925,7 @@ TEST_F(TokenTest, vendor4SpecificVendorExists) { // 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 suceed + // Case 3: option present and has matchin enterprise-id, should succeed testVendorExists(Option::V4, 4491, 4491, "true"); // Check if the logged messages are correct. @@ -1938,7 +1938,7 @@ TEST_F(TokenTest, vendor4SpecificVendorExists) { EXPECT_TRUE(checkFile()); } -// This test verifies if expression vendor[4491].exist works properly in DHCPv6. +// 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"); @@ -2406,7 +2406,8 @@ TEST_F(TokenTest, vendorClass4AnyVendorData) { 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 empty string + // 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 @@ -2444,7 +2445,8 @@ TEST_F(TokenTest, vendorClass6AnyVendorData) { 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 empty string + // 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 @@ -2484,11 +2486,11 @@ TEST_F(TokenTest, vendorClass4DataIndex) { 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 2 data tuples, expected result is empty string. + // vendor-class with vendor-id 1234 and 1 data tuples, 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 2 data tuples, expected + // vendor-class with vendor-id 4491, but has only 3 data tuples, expected // result is empty string. testVendorClassData(Option::V4, 4491, 3, 4491, 3, ""); diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index 7963a52e34..a130c35715 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -810,7 +810,7 @@ void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) { { size_t max = vendor->getTuplesNum(); if (index_ + 1 > max) { - // The index specified if out of bound, e.g. there are only + // 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_) diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index 28c444c617..ea6c9cbdf7 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -698,10 +698,10 @@ private: /// In particular, it allows retrieving enterprise-id. /// /// It can represent the following expressions: -/// vendor[4491].exist - if vendor option with enterprise-id = 4491 exists -/// vendor[*].exist - if any vendor option exists +/// 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].exist - check if suboption 1 exists for vendor 4491 +/// 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: @@ -793,7 +793,7 @@ protected: /// @brief Enterprise-id value /// - /// Yeah, I know it's technically should be called enterprise-id, but that's + /// 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_; @@ -813,8 +813,8 @@ protected: /// enterprise handling field and field type. /// /// It can represent the following expressions: -/// vendor-class[4491].exist -/// vendor-class[*].exist +/// 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 @@ -860,7 +860,7 @@ protected: /// /// If FieldType is DATA, get specified data chunk represented by index_. /// - /// If FieldType is EXISTS, return true of vendor-id matches. + /// If FieldType is EXISTS, return true if vendor-id matches. /// /// @throw EvalTypeError for any other FieldType values. /// From dbacbd0ed20089c1c2f5e444e736acae51432456 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Thu, 18 Aug 2016 16:05:43 +0200 Subject: [PATCH 11/15] [4271] Changes after review - User's Guide clearified couple things. - messages orded alphabetically - indentation increased in parser.yy - debugging message formats updated slightly ('1234' => 0x1234) - one new case in vendorClass4SpecificVendorData added - verbose_ flag in log_utils.h commented --- doc/guide/classify.xml | 12 +- src/lib/eval/eval_messages.mes | 88 +++++++-------- src/lib/eval/parser.yy | 161 +++++++++++++-------------- src/lib/eval/tests/token_unittest.cc | 32 ++++-- src/lib/testutils/log_utils.h | 9 ++ 5 files changed, 161 insertions(+), 141 deletions(-) diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index 1100b50f57..e5b5077128 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -457,12 +457,20 @@ is for the second data chunk (if present), etc. - Asterisk (*) or 0 can be used to specify wildcard enterprise-id - value, i.e. it will match any enterprise-id value. + In the vendor and vendor-class constructs Asterisk (*) or 0 can be + used to specify a wildcard enterprise-id value, i.e. it will match any + enterprise-id value. Vendor Class Identifier (option 60 in DHCPv4) can be accessed using option[60] expression. + RFC3925 and RFC3315 allow for multiple instances of vendor options + to appear in a single message. The client classification code currently + examines the first instance if more than one appear. For vendor.enterprise + and vendor-class.enterprise expressions, the value from the first instance + is returned. Please submit a feature request on Kea website if you need + support for multiple instances. +
List of Classification Expressions diff --git a/src/lib/eval/eval_messages.mes b/src/lib/eval/eval_messages.mes index 539ebac4b6..53628ee35f 100644 --- a/src/lib/eval/eval_messages.mes +++ b/src/lib/eval/eval_messages.mes @@ -107,53 +107,6 @@ 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_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 -client classification expressions. - -% 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. This message is mostly useful during -debugging of the client classification expressions. - -% 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. This message is mostly useful during debugging of the -client classification expressions. - -% EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id %1 as result '%2' -This debug message indicates that the expression has been evaluated and vendor -option was found and its enterprise-id is being reported. This message is mostly -useful during debugging of the client classification expressions. - -% 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. This message is mostly useful during debugging of the client -classification expressions. - -% 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. This message is mostly useful during -debugging of the client classification expressions. - -% 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. This message is mostly useful during debugging of the -client classification expressions. - -% EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id %1 as result '%2' -This debug message indicates that the expression has been evaluated and vendor -class option was found and its enterprise-id is being reported. This message is mostly -useful during debugging of the client classification expressions. - -% 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. This message is mostly useful during debugging of the -client classification expressions. - % 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 @@ -163,4 +116,43 @@ of chunks and value pushed are reported as debugging aid. 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. \ No newline at end of file +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 +client classification expressions. diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index f4fac66891..329091c5fd 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -166,35 +166,35 @@ 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_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); -} -; + } + | 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 { @@ -287,59 +287,58 @@ 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 -{ - // expression: vendor[1234].option[56].exists - // expression: vendor[1234].option[56].hex - // - // This token will search for vendor option with specified enterprise-id. - // If found, will search for specified suboption and finally will return - // if it exists ('exists') or its content ('hex') - 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); -} - -; + | 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 + { + // expression: vendor[1234].option[56].exists + // expression: vendor[1234].option[56].hex + // + // This token will search for vendor option with specified enterprise-id. + // If found, will search for specified suboption and finally will return + // if it exists ('exists') or its content ('hex') + 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 { diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index 23745989c6..23212910cb 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -437,6 +437,7 @@ public: /// @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, @@ -2017,9 +2018,9 @@ TEST_F(TokenTest, vendor4enterprise) { 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 '000004D2'"); + "result 0x000004D2"); addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 4294967295" - " as result 'FFFFFFFF'"); + " as result 0xFFFFFFFF"); EXPECT_TRUE(checkFile()); } @@ -2039,9 +2040,9 @@ TEST_F(TokenTest, vendor6enterprise) { 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 '000004D2'"); + "result 0x000004D2"); addString("EVAL_DEBUG_VENDOR_ENTERPRISE_ID Pushing enterprise-id 4294967295 " - "as result 'FFFFFFFF'"); + "as result 0xFFFFFFFF"); EXPECT_TRUE(checkFile()); } @@ -2283,9 +2284,9 @@ TEST_F(TokenTest, vendorClass4enterprise) { 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 '000004D2'"); + "1234 as result 0x000004D2"); addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id " - "4294967295 as result 'FFFFFFFF'"); + "4294967295 as result 0xFFFFFFFF"); EXPECT_TRUE(checkFile()); } @@ -2305,9 +2306,9 @@ TEST_F(TokenTest, vendorClass6enterprise) { 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 '000004D2'"); + "1234 as result 0x000004D2"); addString("EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID Pushing enterprise-id " - "4294967295 as result 'FFFFFFFF'"); + "4294967295 as result 0xFFFFFFFF"); EXPECT_TRUE(checkFile()); } @@ -2323,7 +2324,11 @@ TEST_F(TokenTest, vendorClass4SpecificVendorData) { 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 + // 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 @@ -2486,7 +2491,7 @@ TEST_F(TokenTest, vendorClass4DataIndex) { 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 tuples, expected result is empty string. + // 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 @@ -2499,6 +2504,11 @@ TEST_F(TokenTest, vendorClass4DataIndex) { // 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 ''"); @@ -2514,6 +2524,8 @@ TEST_F(TokenTest, vendorClass4DataIndex) { "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()); } diff --git a/src/lib/testutils/log_utils.h b/src/lib/testutils/log_utils.h index 340ef8a9b3..c7f835b389 100644 --- a/src/lib/testutils/log_utils.h +++ b/src/lib/testutils/log_utils.h @@ -64,6 +64,9 @@ public: 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; @@ -78,6 +81,12 @@ public: vector exp_strings_; static const char* LOG_FILE; + /// @brief controls whether the checkFile() should print more details. + /// + /// If set to true, checkFile() will print each expected line, each + /// logged line and will print out a failure message if those two do + /// not match. Also, a final verdict is printed. Everything is printed + /// on stdout. bool verbose_; }; From 21c5e0a81bf3c02f7ade1b63c54dedcaab2becb1 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Thu, 18 Aug 2016 16:06:01 +0200 Subject: [PATCH 12/15] [4271] parser regenerated --- src/lib/eval/parser.cc | 174 ++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc index 971771895c..542df82394 100644 --- a/src/lib/eval/parser.cc +++ b/src/lib/eval/parser.cc @@ -798,40 +798,40 @@ namespace isc { namespace eval { case 11: #line 170 "parser.yy" // lalr1.cc:859 { - // Expression: vendor-class[1234].exists - // - // This token will find option 124 (DHCPv4) or 16 (DHCPv6), and will check - // if enterprise-id equals specified value. - TokenPtr exist(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS)); - ctx.expression.push_back(exist); -} + // Expression: vendor-class[1234].exists + // + // This token will find option 124 (DHCPv4) or 16 (DHCPv6), and will check + // if enterprise-id equals specified value. + TokenPtr exist(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS)); + ctx.expression.push_back(exist); + } #line 809 "parser.cc" // lalr1.cc:859 break; case 12: #line 179 "parser.yy" // lalr1.cc:859 { - // Expression: vendor[1234].exists - // - // This token will find option 125 (DHCPv4) or 17 (DHCPv6), and will check - // if enterprise-id equals specified value. - TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS)); - ctx.expression.push_back(exist); + // Expression: vendor[1234].exists + // + // This token will find option 125 (DHCPv4) or 17 (DHCPv6), and will check + // if enterprise-id equals specified value. + TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), TokenOption::EXISTS)); + ctx.expression.push_back(exist); -} + } #line 823 "parser.cc" // lalr1.cc:859 break; case 13: #line 189 "parser.yy" // lalr1.cc:859 { - // Expression vendor[1234].option[123].exists - // - // This token will check if specified vendor option exists, has specified - // enterprise-id and if has specified suboption. - TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), TokenOption::EXISTS, yystack_[3].value.as< uint16_t > ())); - ctx.expression.push_back(exist); -} + // Expression vendor[1234].option[123].exists + // + // This token will check if specified vendor option exists, has specified + // enterprise-id and if has specified suboption. + TokenPtr exist(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), TokenOption::EXISTS, yystack_[3].value.as< uint16_t > ())); + ctx.expression.push_back(exist); + } #line 836 "parser.cc" // lalr1.cc:859 break; @@ -970,76 +970,76 @@ namespace isc { namespace eval { case 25: #line 291 "parser.yy" // lalr1.cc:859 { - // 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); -} + // expression: vendor.enterprise + // + // This token will return enterprise-id number of received vendor option. + TokenPtr vendor(new TokenVendor(ctx.getUniverse(), 0, TokenVendor::ENTERPRISE_ID)); + ctx.expression.push_back(vendor); + } #line 980 "parser.cc" // lalr1.cc:859 break; case 26: #line 299 "parser.yy" // lalr1.cc:859 { - // 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); -} + // expression: vendor-class.enterprise + // + // This token will return enterprise-id number of received vendor class option. + TokenPtr vendor(new TokenVendorClass(ctx.getUniverse(), 0, + TokenVendor::ENTERPRISE_ID)); + ctx.expression.push_back(vendor); + } #line 993 "parser.cc" // lalr1.cc:859 break; case 27: #line 308 "parser.yy" // lalr1.cc:859 { - // expression: vendor[1234].option[56].exists - // expression: vendor[1234].option[56].hex - // - // This token will search for vendor option with specified enterprise-id. - // If found, will search for specified suboption and finally will return - // if it exists ('exists') or its content ('hex') - TokenPtr opt(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), yystack_[0].value.as< TokenOption::RepresentationType > (), yystack_[3].value.as< uint16_t > ())); - ctx.expression.push_back(opt); -} + // expression: vendor[1234].option[56].exists + // expression: vendor[1234].option[56].hex + // + // This token will search for vendor option with specified enterprise-id. + // If found, will search for specified suboption and finally will return + // if it exists ('exists') or its content ('hex') + TokenPtr opt(new TokenVendor(ctx.getUniverse(), yystack_[8].value.as< uint32_t > (), yystack_[0].value.as< TokenOption::RepresentationType > (), yystack_[3].value.as< uint16_t > ())); + ctx.expression.push_back(opt); + } #line 1008 "parser.cc" // lalr1.cc:859 break; case 28: #line 319 "parser.yy" // lalr1.cc:859 { - // expression: vendor-class[1234].data - // - // Vendor class option does not have suboptions, but chunks of data (typically 1, - // but the option structure allows multiple of them). If chunk offset is not - // specified, we assume the first (0th) is requested. - TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), - TokenVendor::DATA, 0)); - ctx.expression.push_back(vendor_class); -} + // expression: vendor-class[1234].data + // + // Vendor class option does not have suboptions, but chunks of data (typically 1, + // but the option structure allows multiple of them). If chunk offset is not + // specified, we assume the first (0th) is requested. + TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[3].value.as< uint32_t > (), + TokenVendor::DATA, 0)); + ctx.expression.push_back(vendor_class); + } #line 1023 "parser.cc" // lalr1.cc:859 break; case 29: #line 330 "parser.yy" // lalr1.cc:859 { - // expression: vendor-class[1234].data[5] - // - // Vendor class option does not have suboptions, but chunks of data (typically 1, - // but the option structure allows multiple of them). This syntax specifies - // which data chunk (tuple) we want. - uint8_t index = ctx.convertUint8(yystack_[1].value.as< std::string > (), yystack_[1].location); - TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[6].value.as< uint32_t > (), - TokenVendor::DATA, index)); - ctx.expression.push_back(vendor_class); -} + // expression: vendor-class[1234].data[5] + // + // Vendor class option does not have suboptions, but chunks of data (typically 1, + // but the option structure allows multiple of them). This syntax specifies + // which data chunk (tuple) we want. + uint8_t index = ctx.convertUint8(yystack_[1].value.as< std::string > (), yystack_[1].location); + TokenPtr vendor_class(new TokenVendorClass(ctx.getUniverse(), yystack_[6].value.as< uint32_t > (), + TokenVendor::DATA, index)); + ctx.expression.push_back(vendor_class); + } #line 1039 "parser.cc" // lalr1.cc:859 break; case 30: -#line 345 "parser.yy" // lalr1.cc:859 +#line 344 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); } @@ -1047,7 +1047,7 @@ namespace isc { namespace eval { break; case 31: -#line 349 "parser.yy" // lalr1.cc:859 +#line 348 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); } @@ -1055,7 +1055,7 @@ namespace isc { namespace eval { break; case 32: -#line 355 "parser.yy" // lalr1.cc:859 +#line 354 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; } @@ -1063,7 +1063,7 @@ namespace isc { namespace eval { break; case 33: -#line 359 "parser.yy" // lalr1.cc:859 +#line 358 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; } @@ -1071,7 +1071,7 @@ namespace isc { namespace eval { break; case 34: -#line 365 "parser.yy" // lalr1.cc:859 +#line 364 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint32_t > () = ctx.convertUint32(yystack_[0].value.as< std::string > (), yystack_[0].location); } @@ -1079,7 +1079,7 @@ namespace isc { namespace eval { break; case 35: -#line 369 "parser.yy" // lalr1.cc:859 +#line 368 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint32_t > () = 0; } @@ -1087,7 +1087,7 @@ namespace isc { namespace eval { break; case 36: -#line 374 "parser.yy" // lalr1.cc:859 +#line 373 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CHADDR; } @@ -1095,7 +1095,7 @@ namespace isc { namespace eval { break; case 37: -#line 378 "parser.yy" // lalr1.cc:859 +#line 377 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HLEN; } @@ -1103,7 +1103,7 @@ namespace isc { namespace eval { break; case 38: -#line 382 "parser.yy" // lalr1.cc:859 +#line 381 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::HTYPE; } @@ -1111,7 +1111,7 @@ namespace isc { namespace eval { break; case 39: -#line 386 "parser.yy" // lalr1.cc:859 +#line 385 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::CIADDR; } @@ -1119,7 +1119,7 @@ namespace isc { namespace eval { break; case 40: -#line 390 "parser.yy" // lalr1.cc:859 +#line 389 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::GIADDR; } @@ -1127,7 +1127,7 @@ namespace isc { namespace eval { break; case 41: -#line 394 "parser.yy" // lalr1.cc:859 +#line 393 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::YIADDR; } @@ -1135,7 +1135,7 @@ namespace isc { namespace eval { break; case 42: -#line 398 "parser.yy" // lalr1.cc:859 +#line 397 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt4::FieldType > () = TokenPkt4::SIADDR; } @@ -1143,7 +1143,7 @@ namespace isc { namespace eval { break; case 43: -#line 404 "parser.yy" // lalr1.cc:859 +#line 403 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); @@ -1152,7 +1152,7 @@ namespace isc { namespace eval { break; case 44: -#line 411 "parser.yy" // lalr1.cc:859 +#line 410 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); @@ -1161,7 +1161,7 @@ namespace isc { namespace eval { break; case 45: -#line 416 "parser.yy" // lalr1.cc:859 +#line 415 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString("all")); ctx.expression.push_back(str); @@ -1170,19 +1170,19 @@ namespace isc { namespace eval { break; case 46: -#line 422 "parser.yy" // lalr1.cc:859 +#line 421 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::PEERADDR; } #line 1176 "parser.cc" // lalr1.cc:859 break; case 47: -#line 423 "parser.yy" // lalr1.cc:859 +#line 422 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenRelay6Field::FieldType > () = TokenRelay6Field::LINKADDR; } #line 1182 "parser.cc" // lalr1.cc:859 break; case 48: -#line 427 "parser.yy" // lalr1.cc:859 +#line 426 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint8_t > () = ctx.convertNestLevelNumber(yystack_[0].value.as< std::string > (), yystack_[0].location); } @@ -1190,13 +1190,13 @@ namespace isc { namespace eval { break; case 49: -#line 435 "parser.yy" // lalr1.cc:859 +#line 434 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::MSGTYPE; } #line 1196 "parser.cc" // lalr1.cc:859 break; case 50: -#line 436 "parser.yy" // lalr1.cc:859 +#line 435 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenPkt6::FieldType > () = TokenPkt6::TRANSID; } #line 1202 "parser.cc" // lalr1.cc:859 break; @@ -1629,9 +1629,9 @@ namespace isc { namespace eval { 0, 106, 106, 109, 110, 115, 120, 125, 130, 135, 155, 169, 178, 188, 199, 204, 209, 214, 219, 240, 255, 270, 275, 280, 285, 290, 298, 307, 318, 329, - 344, 348, 354, 358, 364, 368, 373, 377, 381, 385, - 389, 393, 397, 403, 410, 415, 422, 423, 426, 435, - 436 + 343, 347, 353, 357, 363, 367, 372, 376, 380, 384, + 388, 392, 396, 402, 409, 414, 421, 422, 425, 434, + 435 }; // Print the state stack on the debug stream. @@ -1667,7 +1667,7 @@ namespace isc { namespace eval { #line 13 "parser.yy" // lalr1.cc:1167 } } // isc::eval #line 1670 "parser.cc" // lalr1.cc:1167 -#line 439 "parser.yy" // lalr1.cc:1168 +#line 438 "parser.yy" // lalr1.cc:1168 void isc::eval::EvalParser::error(const location_type& loc, From 840d2f71aabdd3d113e6dec07f4d8ad31203cb10 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Thu, 18 Aug 2016 19:10:39 +0200 Subject: [PATCH 13/15] [4271] Reindent (align actions) --- src/lib/eval/lexer.ll | 76 +++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index 8b83dc0510..7cb52ee349 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -140,47 +140,47 @@ 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); -"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); -"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); +"==" 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); +"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); +"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); -"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); +"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); +"data" return isc::eval::EvalParser::make_DATA(loc); +"enterprise" return isc::eval::EvalParser::make_ENTERPRISE(loc); -. driver.error (loc, "Invalid character: " + std::string(yytext)); -<> return isc::eval::EvalParser::make_END(loc); +. driver.error (loc, "Invalid character: " + std::string(yytext)); +<> return isc::eval::EvalParser::make_END(loc); %% using namespace isc::eval; From 86ad729e81a5369613a81320d522fc4368d3d5be Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Thu, 18 Aug 2016 19:33:29 +0200 Subject: [PATCH 14/15] [4271] Fixed parser --- src/lib/eval/parser.yy | 220 ++++++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 102 deletions(-) diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 329091c5fd..d27ab66c12 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -167,33 +167,33 @@ bool_expr : "(" bool_expr ")" } } | 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); - } + { + // 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); - - } + { + // 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); - } + { + // 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 @@ -287,58 +287,61 @@ 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 - { - // expression: vendor[1234].option[56].exists - // expression: vendor[1234].option[56].hex - // - // This token will search for vendor option with specified enterprise-id. - // If found, will search for specified suboption and finally will return - // if it exists ('exists') or its content ('hex') - 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); - } - ; + | 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 { @@ -361,13 +364,14 @@ option_repr_type : TEXT ; enterprise_id : INTEGER -{ - $$ = ctx.convertUint32($1, @1); -} -| "*" -{ - $$ = 0; -} + { + $$ = ctx.convertUint32($1, @1); + } + | "*" + { + $$ = 0; + } + ; pkt4_field : CHADDR { @@ -400,17 +404,17 @@ pkt4_field : CHADDR ; 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")); @@ -418,22 +422,34 @@ length_expr : INTEGER } ; -relay6_field : PEERADDR { $$ = TokenRelay6Field::PEERADDR; } - | LINKADDR { $$ = TokenRelay6Field::LINKADDR; } +relay6_field : PEERADDR + { + $$ = TokenRelay6Field::PEERADDR; + } + | LINKADDR + { + $$ = TokenRelay6Field::LINKADDR; + } ; nest_level : INTEGER - { - $$ = ctx.convertNestLevelNumber($1, @1); - } - // Eventually we may add strings to handle different - // ways of choosing from which relay we want to extract - // an option or field. + { + $$ = ctx.convertNestLevelNumber($1, @1); + } + // Eventually we may add strings to handle different + // ways of choosing from which relay we want to extract + // an option or field. ; -pkt6_field:MSGTYPE { $$ = TokenPkt6::MSGTYPE; } - | TRANSID { $$ = TokenPkt6::TRANSID; } - ; +pkt6_field : MSGTYPE + { + $$ = TokenPkt6::MSGTYPE; + } + | TRANSID + { + $$ = TokenPkt6::TRANSID; + } + ; %% void From 4d93fc329a6e85441f6b2f79e07f5049dfa8cde3 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Thu, 18 Aug 2016 19:41:08 +0200 Subject: [PATCH 15/15] [4271] spelling --- src/lib/eval/tests/context_unittest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index 6e82e53c51..b8a6954c96 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -396,7 +396,7 @@ public: /// @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 experssions: + /// tokens are ignored. Tests expressions: /// vendor[1234].option[234].hex /// vendor[1234].option[234].exists /// @@ -481,8 +481,8 @@ public: /// @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 experssions: + /// 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