runtime_option_defs_.clearItems();
}
-
bool
LibDHCP::isStandardOption(const Option::Universe u, const uint16_t code) {
if (u == Option::V6) {
static OptionDefContainerPtr
getRuntimeOptionDefs(const std::string& space);
-
/// @brief Check if the specified option is a standard option.
///
/// @param u universe (V4 or V6)
std::string value;
expression_cfg->getValue(value);
try {
- EvalContext eval_ctx;
+ EvalContext eval_ctx(global_context_->universe_);
eval_ctx.parseString(value);
local_expression_.reset(new Expression());
*local_expression_ = eval_ctx.expression;
#include <eval/eval_context.h>
#include <eval/parser.h>
#include <exceptions/exceptions.h>
+#include <dhcp/option.h>
#include <fstream>
-EvalContext::EvalContext()
- : trace_scanning_(false), trace_parsing_(false)
+EvalContext::EvalContext(const Option::Universe& option_universe)
+ : trace_scanning_(false), trace_parsing_(false),
+ option_universe_(option_universe)
{
}
file_ = "<string>";
string_ = str;
scanStringBegin();
- isc::eval::EvalParser parser(*this);
+ isc::eval::EvalParser parser(*this, option_universe_);
parser.set_debug_level(trace_parsing_);
int res = parser.parse();
scanStringEnd();
{
public:
/// @brief Default constructor.
- EvalContext();
+ ///
+ /// @param option_universe Option universe: DHCPv4 or DHCPv6. This is used
+ /// by the parser to determine which option definitions set should be used
+ /// to map option names to option codes.
+ EvalContext(const Option::Universe& option_universe);
/// @brief destructor
virtual ~EvalContext();
/// @brief Method called after the last tokens are scanned from a string.
void scanStringEnd();
-
+
/// @brief Run the parser on the string specified.
///
/// @param str string to be written
/// @brief Flag determing parser debugging.
bool trace_parsing_;
-
+
+ /// @brief Option universe: DHCPv4 or DHCPv6.
+ ///
+ /// This is used by the parser to determine which option definitions
+ /// set should be used to map option name to option code.
+ Option::Universe option_universe_;
};
}; // end of isc::eval namespace
#line 51 "parser.cc" // lalr1.cc:412
// Unqualified %code blocks.
-#line 39 "parser.yy" // lalr1.cc:413
+#line 40 "parser.yy" // lalr1.cc:413
# include "eval_context.h"
-#line 67 "parser.yy" // lalr1.cc:413
+#line 72 "parser.yy" // lalr1.cc:413
namespace {
/// Build a parser object.
- EvalParser::EvalParser (EvalContext& ctx_yyarg)
+ EvalParser::EvalParser (EvalContext& ctx_yyarg, const Option::Universe& option_universe_yyarg)
:
#if YYDEBUG
yydebug_ (false),
yycdebug_ (&std::cerr),
#endif
- ctx (ctx_yyarg)
+ ctx (ctx_yyarg),
+ option_universe (option_universe_yyarg)
{}
EvalParser::~EvalParser ()
{
case 15: // "constant string"
-#line 64 "parser.yy" // lalr1.cc:636
+#line 69 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 350 "parser.cc" // lalr1.cc:636
+#line 351 "parser.cc" // lalr1.cc:636
break;
case 16: // "integer"
-#line 64 "parser.yy" // lalr1.cc:636
+#line 69 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 357 "parser.cc" // lalr1.cc:636
+#line 358 "parser.cc" // lalr1.cc:636
break;
case 17: // "constant hexstring"
-#line 64 "parser.yy" // lalr1.cc:636
+#line 69 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 364 "parser.cc" // lalr1.cc:636
+#line 365 "parser.cc" // lalr1.cc:636
break;
case 18: // TOKEN
-#line 64 "parser.yy" // lalr1.cc:636
+#line 69 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
-#line 371 "parser.cc" // lalr1.cc:636
+#line 372 "parser.cc" // lalr1.cc:636
break;
switch (yyn)
{
case 3:
-#line 105 "parser.yy" // lalr1.cc:859
+#line 110 "parser.yy" // lalr1.cc:859
{
TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq);
}
-#line 601 "parser.cc" // lalr1.cc:859
+#line 602 "parser.cc" // lalr1.cc:859
break;
case 4:
-#line 112 "parser.yy" // lalr1.cc:859
+#line 117 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
-#line 610 "parser.cc" // lalr1.cc:859
+#line 611 "parser.cc" // lalr1.cc:859
break;
case 5:
-#line 117 "parser.yy" // lalr1.cc:859
+#line 122 "parser.yy" // lalr1.cc:859
{
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(hex);
}
-#line 619 "parser.cc" // lalr1.cc:859
+#line 620 "parser.cc" // lalr1.cc:859
break;
case 6:
-#line 122 "parser.yy" // lalr1.cc:859
+#line 127 "parser.yy" // lalr1.cc:859
{
uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
TokenPtr opt(new TokenOption(numeric_code, TokenOption::TEXTUAL));
ctx.expression.push_back(opt);
}
-#line 629 "parser.cc" // lalr1.cc:859
+#line 630 "parser.cc" // lalr1.cc:859
break;
case 7:
-#line 128 "parser.yy" // lalr1.cc:859
+#line 133 "parser.yy" // lalr1.cc:859
{
uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
ctx.expression.push_back(opt);
}
-#line 639 "parser.cc" // lalr1.cc:859
+#line 640 "parser.cc" // lalr1.cc:859
break;
case 8:
-#line 134 "parser.yy" // lalr1.cc:859
+#line 139 "parser.yy" // lalr1.cc:859
+ {
+ try {
+ // This may result in exception if the specified
+ // name is unknown.
+ TokenPtr opt(new TokenOption(yystack_[3].value.as< std::string > (), option_universe,
+ TokenOption::TEXTUAL));
+ ctx.expression.push_back(opt);
+
+ } catch (const std::exception& ex) {
+ ctx.error(yystack_[3].location, ex.what());
+ }
+ }
+#line 657 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 9:
+#line 152 "parser.yy" // lalr1.cc:859
+ {
+ try {
+ // This may result in exception if the specified
+ // name is unknown.
+ TokenPtr opt(new TokenOption(yystack_[3].value.as< std::string > (), option_universe,
+ TokenOption::HEXADECIMAL));
+ ctx.expression.push_back(opt);
+
+ } catch (const std::exception& ex) {
+ ctx.error(yystack_[3].location, ex.what());
+ }
+ }
+#line 674 "parser.cc" // lalr1.cc:859
+ break;
+
+ case 10:
+#line 165 "parser.yy" // lalr1.cc:859
{
TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub);
}
-#line 648 "parser.cc" // lalr1.cc:859
+#line 683 "parser.cc" // lalr1.cc:859
break;
- case 10:
-#line 143 "parser.yy" // lalr1.cc:859
+ case 12:
+#line 174 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
-#line 657 "parser.cc" // lalr1.cc:859
+#line 692 "parser.cc" // lalr1.cc:859
break;
- case 11:
-#line 150 "parser.yy" // lalr1.cc:859
+ case 13:
+#line 181 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
-#line 666 "parser.cc" // lalr1.cc:859
+#line 701 "parser.cc" // lalr1.cc:859
break;
- case 12:
-#line 155 "parser.yy" // lalr1.cc:859
+ case 14:
+#line 186 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString("all"));
ctx.expression.push_back(str);
}
-#line 675 "parser.cc" // lalr1.cc:859
+#line 710 "parser.cc" // lalr1.cc:859
break;
-#line 679 "parser.cc" // lalr1.cc:859
+#line 714 "parser.cc" // lalr1.cc:859
default:
break;
}
const signed char
EvalParser::yypact_[] =
{
- -4, -9, -3, -10, -10, -10, 9, -10, 12, 1,
- -4, -10, -4, -2, 6, -10, 10, 2, 0, -10,
- 11, -10, -10, -6, -10, -10, 8, -10
+ -4, -1, 6, -10, -10, -10, 4, -10, 15, -9,
+ -4, -10, -4, 5, 7, 10, -10, 13, 14, 8,
+ 2, 9, -10, 16, -10, -10, -10, -10, -6, -10,
+ -10, 17, -10
};
const unsigned char
EvalParser::yydefact_[] =
{
- 0, 0, 0, 4, 5, 9, 0, 2, 0, 0,
- 0, 1, 0, 0, 0, 3, 0, 0, 0, 10,
- 0, 6, 7, 0, 12, 11, 0, 8
+ 0, 0, 0, 4, 5, 11, 0, 2, 0, 0,
+ 0, 1, 0, 0, 0, 0, 3, 0, 0, 0,
+ 0, 0, 12, 0, 8, 9, 6, 7, 0, 14,
+ 13, 0, 10
};
const signed char
const signed char
EvalParser::yydefgoto_[] =
{
- -1, 6, 7, 8, 20, 26
+ -1, 6, 7, 8, 23, 31
};
const unsigned char
EvalParser::yytable_[] =
{
- 1, 2, 24, 14, 9, 15, 21, 22, 10, 11,
- 25, 3, 16, 4, 5, 12, 17, 13, 19, 18,
- 27, 23
+ 1, 2, 29, 15, 11, 16, 13, 14, 24, 25,
+ 30, 3, 9, 4, 5, 26, 27, 10, 12, 17,
+ 19, 18, 20, 21, 22, 0, 28, 0, 0, 32
};
- const unsigned char
+ const signed char
EvalParser::yycheck_[] =
{
- 4, 5, 8, 10, 13, 12, 6, 7, 11, 0,
- 16, 15, 14, 17, 18, 3, 10, 16, 16, 9,
- 12, 10
+ 4, 5, 8, 10, 0, 12, 15, 16, 6, 7,
+ 16, 15, 13, 17, 18, 6, 7, 11, 3, 14,
+ 10, 14, 9, 9, 16, -1, 10, -1, -1, 12
};
const unsigned char
EvalParser::yystos_[] =
{
0, 4, 5, 15, 17, 18, 20, 21, 22, 13,
- 11, 0, 3, 16, 22, 22, 14, 10, 9, 16,
- 23, 6, 7, 10, 8, 16, 24, 12
+ 11, 0, 3, 15, 16, 22, 22, 14, 14, 10,
+ 9, 9, 16, 23, 6, 7, 6, 7, 10, 8,
+ 16, 24, 12
};
const unsigned char
EvalParser::yyr1_[] =
{
0, 19, 20, 21, 22, 22, 22, 22, 22, 22,
- 23, 24, 24
+ 22, 22, 23, 24, 24
};
const unsigned char
EvalParser::yyr2_[] =
{
- 0, 2, 1, 3, 1, 1, 6, 6, 8, 1,
- 1, 1, 1
+ 0, 2, 1, 3, 1, 1, 6, 6, 6, 6,
+ 8, 1, 1, 1, 1
};
const unsigned char
EvalParser::yyrline_[] =
{
- 0, 101, 101, 104, 111, 116, 121, 127, 133, 138,
- 142, 149, 154
+ 0, 106, 106, 109, 116, 121, 126, 132, 138, 151,
+ 164, 169, 173, 180, 185
};
// Print the state stack on the debug stream.
#line 21 "parser.yy" // lalr1.cc:1167
} } // isc::eval
-#line 1058 "parser.cc" // lalr1.cc:1167
-#line 161 "parser.yy" // lalr1.cc:1168
+#line 1096 "parser.cc" // lalr1.cc:1167
+#line 192 "parser.yy" // lalr1.cc:1168
void
isc::eval::EvalParser::error(const location_type& loc,
#include <string>
#include <eval/token.h>
#include <eval/eval_context_decl.h>
+#include <dhcp/option.h>
#include <boost/lexical_cast.hpp>
using namespace isc::dhcp;
using namespace isc::eval;
-#line 54 "parser.h" // lalr1.cc:392
+#line 55 "parser.h" // lalr1.cc:392
# include <cassert>
# include <cstdlib> // std::abort
#line 21 "parser.yy" // lalr1.cc:392
namespace isc { namespace eval {
-#line 131 "parser.h" // lalr1.cc:392
+#line 132 "parser.h" // lalr1.cc:392
/// Build a parser object.
- EvalParser (EvalContext& ctx_yyarg);
+ EvalParser (EvalContext& ctx_yyarg, const Option::Universe& option_universe_yyarg);
virtual ~EvalParser ();
/// Parse.
// number is the opposite. If YYTABLE_NINF, syntax error.
static const unsigned char yytable_[];
- static const unsigned char yycheck_[];
+ static const signed char yycheck_[];
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing
// symbol of state STATE-NUM.
enum
{
yyeof_ = 0,
- yylast_ = 21, ///< Last index in yytable_.
+ yylast_ = 29, ///< Last index in yytable_.
yynnts_ = 6, ///< Number of nonterminal symbols.
yyfinal_ = 11, ///< Termination state number.
yyterror_ = 1,
// User arguments.
EvalContext& ctx;
+ const Option::Universe& option_universe;
};
// Symbol number corresponding to token number t.
#line 21 "parser.yy" // lalr1.cc:392
} } // isc::eval
-#line 1087 "parser.h" // lalr1.cc:392
+#line 1089 "parser.h" // lalr1.cc:392
#include <string>
#include <eval/token.h>
#include <eval/eval_context_decl.h>
+#include <dhcp/option.h>
#include <boost/lexical_cast.hpp>
using namespace isc::dhcp;
{
# include "eval_context.h"
}
+// Option universe: DHCPv4 or DHCPv6. This is required to use correct option
+// definition set to map option names to codes.
+%parse-param { const Option::Universe& option_universe }
+
%define api.token.prefix {TOKEN_}
%token
END 0 "end of file"
TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
ctx.expression.push_back(opt);
}
+ | OPTION "[" STRING "]" DOT TEXT
+ {
+ try {
+ // This may result in exception if the specified
+ // name is unknown.
+ TokenPtr opt(new TokenOption($3, option_universe,
+ TokenOption::TEXTUAL));
+ ctx.expression.push_back(opt);
+
+ } catch (const std::exception& ex) {
+ ctx.error(@3, ex.what());
+ }
+ }
+ | OPTION "[" STRING "]" DOT HEX
+ {
+ try {
+ // This may result in exception if the specified
+ // name is unknown.
+ TokenPtr opt(new TokenOption($3, option_universe,
+ TokenOption::HEXADECIMAL));
+ ctx.expression.push_back(opt);
+
+ } catch (const std::exception& ex) {
+ ctx.error(@3, ex.what());
+ }
+ }
| SUBSTRING "(" string_expr "," start_expr "," length_expr ")"
{
TokenPtr sub(new TokenSubstring());
#include <eval/token.h>
#include <eval/eval_context.h>
#include <eval/token.h>
+#include <dhcp/option.h>
#include <dhcp/pkt4.h>
#include <boost/shared_ptr.hpp>
/// @brief checks if the given expression raises the expected message
/// when it is parsed.
void checkError(const string& expr, const string& msg) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
parsed_ = false;
try {
parsed_ = eval.parseString(expr);
// Test the parsing of a basic expression
TEST_F(EvalContextTest, basic) {
- EvalContext tmp;
+ EvalContext eval(Option::V4);
- EXPECT_NO_THROW(parsed_ = tmp.parseString("option[123].text == 'MSFT'"));
+ EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'MSFT'"));
EXPECT_TRUE(parsed_);
}
// Test the parsing of a string terminal
TEST_F(EvalContextTest, string) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ = eval.parseString("'foo' == 'bar'"));
EXPECT_TRUE(parsed_);
// Test the parsing of a basic expression using integers
TEST_F(EvalContextTest, integer) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ =
eval.parseString("substring(option[123].text, 0, 2) == '42'"));
// Test the parsing of a hexstring terminal
TEST_F(EvalContextTest, hexstring) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ = eval.parseString("0x666f6f == 'foo'"));
EXPECT_TRUE(parsed_);
// Test the parsing of a hexstring terminal with an odd number of
// hexadecimal digits
TEST_F(EvalContextTest, oddHexstring) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ = eval.parseString("0X7 == 'foo'"));
EXPECT_TRUE(parsed_);
// Test the parsing of an equal expression
TEST_F(EvalContextTest, equal) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ = eval.parseString("'foo' == 'bar'"));
EXPECT_TRUE(parsed_);
// Test the parsing of an option terminal
TEST_F(EvalContextTest, option) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'foo'"));
EXPECT_TRUE(parsed_);
checkTokenOption(eval.expression.at(0), 123);
}
+// Test parsing of an option identified by name.
+TEST_F(EvalContextTest, optionWithName) {
+ EvalContext eval(Option::V4);
+
+ // Option 'host-name' is a standard DHCPv4 option defined in the libdhcp++.
+ EXPECT_NO_THROW(parsed_ = eval.parseString("option['host-name'].text == 'foo'"));
+ EXPECT_TRUE(parsed_);
+ ASSERT_EQ(3, eval.expression.size());
+ checkTokenOption(eval.expression.at(0), 12);
+}
+
// Test parsing of an option represented as hexadecimal string.
TEST_F(EvalContextTest, optionHex) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].hex == 0x666F6F"));
EXPECT_TRUE(parsed_);
// Test the parsing of a substring expression
TEST_F(EvalContextTest, substring) {
- EvalContext eval;
+ EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ =
eval.parseString("substring('foobar',2,all) == 'obar'"));
"<string>:1.7: syntax error, "
"unexpected (, expecting [");
checkError("option['ab'].text == 'foo'",
- "<string>:1.8-11: syntax error, "
- "unexpected constant string, "
- "expecting integer");
+ "<string>:1.8-11: option 'ab' is not defined");
checkError("option[0xa].text == 'ab'",
"<string>:1.8-10: syntax error, "
"unexpected constant hexstring, "
- "expecting integer");
+ "expecting constant string or integer");
checkError("substring('foobar') == 'f'",
"<string>:1.19: syntax error, "
"unexpected ), expecting \",\"");
#include <config.h>
#include <eval/token.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
#include <dhcp/dhcp4.h>
pkt6_->addOption(option_str6_);
}
+ /// @brief Destructor.
+ ///
+ /// Removes any option definitions registered in runtime.
+ virtual ~TokenTest() {
+ LibDHCP::clearRuntimeOptionDefs();
+ }
+
TokenPtr t_; ///< Just a convenience pointer
ValueStack values_; ///< evaluated values will be stored here
OptionPtr option_str4_; ///< A string option for DHCPv4
OptionPtr option_str6_; ///< A string option for DHCPv6
+ /// @brief Create definitions of DHCPv4 options used by unit tests.
+ void createOptionDefinitions4() {
+ OptionDefSpaceContainer defs;
+ OptionDefinitionPtr opt_def4(new OptionDefinition("name-hundred4",
+ 100, "string"));
+ defs.addItem(opt_def4, "dhcp4");
+ LibDHCP::setRuntimeOptionDefs(defs);
+ }
+
+ /// @brief Create definitions of DHCPv6 options used by unit tests.
+ void createOptionDefinitions6() {
+ OptionDefSpaceContainer defs;
+ OptionDefinitionPtr opt_def6(new OptionDefinition("name-hundred6",
+ 100, "string"));
+ defs.addItem(opt_def6, "dhcp6");
+ LibDHCP::setRuntimeOptionDefs(defs);
+ }
/// @brief Verify that the substring eval works properly
///
EXPECT_EQ("hundred4", values_.top());
}
+// This test checks if a token representing an option identified by name is
+// able to extract this option from an IPv4 packet and properly store the
+// option's value.
+TEST_F(TokenTest, optionWithNameString4) {
+ // Create definition of option 100 to provide a mapping between option
+ // code and option name.
+ ASSERT_NO_THROW(createOptionDefinitions4());
+
+ // Create token for option referenced by name. The constructor should
+ // map the option name to its code.
+ TokenPtr token;
+ ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred4", Option::V4,
+ TokenOption::TEXTUAL)));
+
+ // Evaluate option in the packet.
+ ASSERT_NO_THROW(token->evaluate(*pkt4_, values_));
+ ASSERT_EQ(1, values_.size());
+
+ // Then the content of the option.
+ EXPECT_EQ("hundred4", values_.top());
+}
+
// This test checks if a token representing option value is able to extract
// the option from an IPv4 packet and properly store its value in a
// hexadecimal format.
EXPECT_EQ("0x68756E6472656434", values_.top());
}
+// This test checks if a token representing an option identified by name is
+// able to extract this option from an IPv4 packet and properly store its
+// value in the hexadecimal format.
+TEST_F(TokenTest, optionWithNameHexString4) {
+ // Create definition of option 100 to provide a mapping between option
+ // code and option name.
+ ASSERT_NO_THROW(createOptionDefinitions4());
+
+ // Create token for option referenced by name. The constructor should
+ // map the option name to its code.
+ TokenPtr token;
+ ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred4", Option::V4,
+ TokenOption::HEXADECIMAL)));
+
+ // Evaluate option in the packet.
+ ASSERT_NO_THROW(token->evaluate(*pkt4_, values_));
+ ASSERT_EQ(1, values_.size());
+
+ // Then the content of the option.
+ EXPECT_EQ("0x68756E6472656434", values_.top());
+}
+
// This test checks if a token representing an option value is able to extract
// the option from an IPv6 packet and properly store the option's value.
TEST_F(TokenTest, optionString6) {
EXPECT_EQ("hundred6", values_.top());
}
+// This test checks if a token representing an option identified by name is
+// able to extract this option from an IPv6 packet and properly store the
+// option's value.
+TEST_F(TokenTest, optionWithNameString6) {
+ // Create definition of option 100 to provide a mapping between option
+ // code and option name.
+ ASSERT_NO_THROW(createOptionDefinitions6());
+
+ // Create token for option referenced by name. The constructor should
+ // map the option name to its code.
+ TokenPtr token;
+ ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred6", Option::V6,
+ TokenOption::TEXTUAL)));
+
+ // Evaluate option in the packet.
+ ASSERT_NO_THROW(token->evaluate(*pkt6_, values_));
+ ASSERT_EQ(1, values_.size());
+
+ // Then the content of the option.
+ EXPECT_EQ("hundred6", values_.top());
+}
+
+
// This test checks if a token representing an option value is able to extract
// the option from an IPv6 packet and properly store its value in hexadecimal
// format.
EXPECT_EQ("0x68756E6472656436", values_.top());
}
+// This test checks if a token representing an option identified by name is
+// able to extract this option from an IPv6 packet and properly store its
+// value in the hexadecimal format.
+TEST_F(TokenTest, optionWithNameHexString6) {
+ // Create definition of option 100 to provide a mapping between option
+ // code and option name.
+ ASSERT_NO_THROW(createOptionDefinitions6());
+
+ // Create token for option referenced by name. The constructor should
+ // map the option name to its code.
+ TokenPtr token;
+ ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred6", Option::V6,
+ TokenOption::HEXADECIMAL)));
+
+ // Evaluate option in the packet.
+ ASSERT_NO_THROW(token->evaluate(*pkt6_, values_));
+ ASSERT_EQ(1, values_.size());
+
+ // Then the content of the option.
+ EXPECT_EQ("0x68756E6472656436", values_.top());
+}
+
// This test checks if a token representing an == operator is able to
// compare two values (with incorrectly built stack).
TEST_F(TokenTest, optionEqualInvalid) {
#include <eval/token.h>
#include <eval/eval_log.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/libdhcp++.h>
#include <util/encode/hex.h>
#include <boost/lexical_cast.hpp>
#include <cstring>
values.push(value_);
}
+TokenOption::TokenOption(const std::string& option_name,
+ const Option::Universe& option_universe,
+ const RepresentationType& rep_type)
+ : option_code_(0), representation_type_(rep_type) {
+ OptionDefinitionPtr option_def = LibDHCP::getOptionDef(option_universe,
+ option_name);
+ if (!option_def) {
+ const std::string global_space =
+ (option_universe == Option::V4) ? "dhcp4" : "dhcp6";
+ option_def = LibDHCP::getRuntimeOptionDef(global_space, option_name);
+ }
+
+ if (!option_def) {
+ isc_throw(BadValue, "option '" << option_name << "' is not defined");
+ }
+
+ option_code_ = option_def->getCode();
+}
+
+
void
TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
OptionPtr opt = pkt.getOption(option_code_);
#define TOKEN_H
#include <exceptions/exceptions.h>
+#include <dhcp/option.h>
#include <dhcp/pkt.h>
#include <stack>
+#include <string>
namespace isc {
namespace dhcp {
/// This is a structure that holds an expression converted to RPN
///
-/// For example expression: option[123] == 'foo' will be converted to:
-/// [0] = option[123] (TokenOption object)
+/// For example expression: option[123].text == 'foo' will be converted to:
+/// [0] = option[123].text (TokenOption object)
/// [1] = 'foo' (TokenString object)
/// [2] = == operator (TokenEqual object)
typedef std::vector<TokenPtr> Expression;
};
/// @brief Constructor that takes an option code as a parameter
- /// @param option_code code of the option
///
- /// Note: There is no constructor that takes option_name, as it would
- /// introduce complex dependency of the libkea-eval on libdhcpsrv.
- ///
- /// @param option_code code of the option to be represented.
+ /// @param option_code Code of the option to be represented.
/// @param rep_type Token representation type.
TokenOption(const uint16_t option_code, const RepresentationType& rep_type)
: option_code_(option_code), representation_type_(rep_type) {}
+ /// @brief Constructor that takes option name as a parameter.
+ ///
+ /// This constructor will throw exception if there is no definition using
+ /// specified option name in libdhcp++.
+ ///
+ /// @param option_name Name of the option to be represented.
+ /// @param option_universe Option universe: DHCPv4 or DHCPv6.
+ /// @param rep_type Token representation type.
+ TokenOption(const std::string& option_name,
+ const Option::Universe& option_universe,
+ const RepresentationType& rep_type);
+
/// @brief Evaluates the values of the option
///
/// This token represents a value of the option, so this method attempts