Commit 01495d15 authored by Francis Dupont's avatar Francis Dupont

[5287] Updated clasify doc

parent f5e88bca
......@@ -484,9 +484,12 @@
"relay6[nest]" allows access to the encapsulations used by any DHCPv6
relays that forwarded the packet. The "nest" level specifies the relay
from which to extract the information, with a value of 0 indicating
the relay closest to the DHCPv6 server. If the requested encapsulation
doesn't exist an empty string "" is returned. This expression is
allowed in DHCPv6 only.
the relay closest to the DHCPv6 server. Negative values allow to
specify relays counted from the DHCPv6 client, -1 indicating the
relay closest. In general negative "nest" level is the same than
the number of relays + "nest" level.
If the requested encapsulation doesn't exist an empty string ""
is returned. This expression is allowed in DHCPv6 only.
</para></listitem>
<listitem><para>
......
......@@ -96,15 +96,15 @@ EvalContext::convertOptionName(const std::string& option_name,
return (option_def->getCode());
}
uint8_t
int8_t
EvalContext::convertNestLevelNumber(const std::string& nest_level,
const isc::eval::location& loc)
{
uint8_t n = convertUint8(nest_level, loc);
int8_t n = convertInt8(nest_level, loc);
if (option_universe_ == Option::V6) {
if (n >= HOP_COUNT_LIMIT) {
if ((n < - HOP_COUNT_LIMIT) || (n >= HOP_COUNT_LIMIT)) {
error(loc, "Nest level has invalid value in "
+ nest_level + ". Allowed range: 0..31");
+ nest_level + ". Allowed range: -32..31");
}
} else {
error(loc, "Nest level invalid for DHCPv4 packets");
......@@ -123,7 +123,26 @@ EvalContext::convertUint8(const std::string& number,
} catch (const boost::bad_lexical_cast &) {
error(loc, "Invalid integer value in " + number);
}
if (n < 0 || n >= std::numeric_limits<uint8_t>::max()) {
if (n < 0 || n > std::numeric_limits<uint8_t>::max()) {
error(loc, "Invalid value in "
+ number + ". Allowed range: 0..255");
}
return (static_cast<uint8_t>(n));
}
int8_t
EvalContext::convertInt8(const std::string& number,
const isc::eval::location& loc)
{
int n = 0;
try {
n = boost::lexical_cast<int>(number);
} catch (const boost::bad_lexical_cast &) {
error(loc, "Invalid integer value in " + number);
}
if (n < std::numeric_limits<int8_t>::min() ||
n > std::numeric_limits<int8_t>::max()) {
error(loc, "Invalid value in "
+ number + ". Allowed range: 0..255");
}
......
......@@ -133,15 +133,24 @@ public:
static uint8_t convertUint8(const std::string& number,
const isc::eval::location& loc);
/// @brief Attempts to convert string to signed 8bit integer
///
/// @param number string to be converted
/// @param loc the location of the token
/// @return the integer value
/// @throw EvalParseError if conversion fails or the value is out of range.
static int8_t convertInt8(const std::string& number,
const isc::eval::location& loc);
/// @brief Nest level conversion
///
/// @param nest_level a string representing the integer nesting level
/// @param loc the location of the token
/// @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,
const isc::eval::location& loc);
/// the range -32..31
int8_t convertNestLevelNumber(const std::string& nest_level,
const isc::eval::location& loc);
/// @brief Converts integer to string representation
///
......
......@@ -96,7 +96,7 @@ using namespace isc::eval;
%type <uint32_t> integer_expr
%type <TokenOption::RepresentationType> option_repr_type
%type <TokenRelay6Field::FieldType> relay6_field
%type <uint8_t> nest_level
%type <int8_t> nest_level
%type <TokenPkt::MetadataType> pkt_metadata
%type <TokenPkt4::FieldType> pkt4_field
%type <TokenPkt6::FieldType> pkt6_field
......
......@@ -151,7 +151,7 @@ public:
/// @param expected_code expected option code
/// @param expected_repr expected representation (text, hex, exists)
void checkTokenRelay6Option(const TokenPtr& token,
uint8_t expected_level,
int8_t expected_level,
uint16_t expected_code,
TokenOption::RepresentationType expected_repr) {
ASSERT_TRUE(token);
......@@ -174,7 +174,7 @@ public:
/// @param exp_repr expected representation to be parsed
/// @param exp_tokens expected number of tokens
void testRelay6Option(const std::string& expr,
uint8_t exp_level,
int8_t exp_level,
uint16_t exp_code,
TokenOption::RepresentationType exp_repr,
int exp_tokens) {
......@@ -345,7 +345,7 @@ public:
/// @param expected_code expected option code
/// @param expected_repr expected representation (text, hex, exists)
void checkTokenRelay6Field(const TokenPtr& token,
uint8_t expected_level,
int8_t expected_level,
TokenRelay6Field::FieldType expected_type) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenRelay6Field> opt =
......@@ -365,7 +365,7 @@ public:
/// @param exp_type expected field type to be parsed
/// @param exp_tokens expected number of tokens
void testRelay6Field(const std::string& expr,
uint8_t exp_level,
int8_t exp_level,
TokenRelay6Field::FieldType exp_type,
int exp_tokens) {
EvalContext eval(Option::V6);
......@@ -934,7 +934,15 @@ TEST_F(EvalContextTest, relay6OptionHex) {
2, 85, TokenOption::HEXADECIMAL, 3);
}
// Test the nest level of a relay6 option should be in [0..32[
// Test the parsing of a relay6 option in reverse order
TEST_F(EvalContextTest, relay6OptionReverse) {
EvalContext eval(Option::V6);
testRelay6Option("relay6[-1].option[123].text == 'foo'",
-1, 123, TokenOption::TEXTUAL, 3);
}
// Test the nest level of a relay6 option should be in [-32..32[
TEST_F(EvalContextTest, relay6OptionLimits) {
EvalContext eval(Option::V6);
......@@ -946,11 +954,14 @@ TEST_F(EvalContextTest, relay6OptionLimits) {
checkError("relay6[32].option[123].text == 'foo'",
"<string>:1.8-9: Nest level has invalid value in 32. "
"Allowed range: 0..31");
"Allowed range: -32..31");
// min nest level is minus hop count limit
testRelay6Option("relay6[-32].option[123].text == 'foo'",
-32, 123, TokenOption::TEXTUAL, 3);
// next level must be a positive number
checkError("relay6[-1].option[123].text == 'foo'",
"<string>:1.8-9: Invalid value in -1. Allowed range: 0..255");
checkError("relay6[-33].option[123].text == 'foo'",
"<string>:1.8-10: Nest level has invalid value in -33. Allowed range: -32..31");
}
// Verify that relay6[13].option is not usable in v4
......@@ -1041,7 +1052,7 @@ TEST_F(EvalContextTest, relay6FieldPeerAddr) {
1, TokenRelay6Field::PEERADDR, 3);
}
// Verify that relay6[13].<field> is not usable in v4
// Verify that relay6[0].<field> is not usable in v4
TEST_F(EvalContextTest, relay6FieldError) {
universe_ = Option::V4;
......
......@@ -128,7 +128,7 @@ public:
/// @param test_level The nesting level
/// @param test_code The code of the option to extract
/// @param result_addr The expected result of the address as a string
void verifyRelay6Option(const uint8_t test_level,
void verifyRelay6Option(const int8_t test_level,
const uint16_t test_code,
const TokenOption::RepresentationType& test_rep,
const std::string& result_string) {
......@@ -159,7 +159,7 @@ public:
/// @param test_level The nesting level
/// @param test_field The type of the field to extract
/// @param result_addr The expected result of the address as a string
void verifyRelay6Eval(const uint8_t test_level,
void verifyRelay6Eval(const int8_t test_level,
const TokenRelay6Field::FieldType test_field,
const int result_len,
const uint8_t result_addr[]) {
......@@ -1135,6 +1135,21 @@ TEST_F(TokenTest, relay6Option) {
// Level 2, no encapsulation so no options
verifyRelay6Option(2, 100, TokenOption::TEXTUAL, "");
// Level -1, the same than level 1
verifyRelay6Option(-1, 100, TokenOption::TEXTUAL, "hundred.one");
verifyRelay6Option(-1, 101, TokenOption::TEXTUAL, "");
verifyRelay6Option(-1, 102, TokenOption::TEXTUAL, "hundredtwo.one");
// Level -2, the same than level 0
verifyRelay6Option(-2, 100, TokenOption::TEXTUAL, "hundred.zero");
verifyRelay6Option(-2, 100, TokenOption::EXISTS, "true");
verifyRelay6Option(-2, 101, TokenOption::TEXTUAL, "hundredone.zero");
verifyRelay6Option(-2, 102, TokenOption::TEXTUAL, "");
verifyRelay6Option(-2, 102, TokenOption::EXISTS, "false");
// Level -3, no encapsulation so no options
verifyRelay6Option(-3, 100, TokenOption::TEXTUAL, "");
// Check that the debug output was correct. Add the strings
// to the test vector in the class and then call checkFile
// for comparison
......@@ -1150,6 +1165,18 @@ TEST_F(TokenTest, relay6Option) {
addString("EVAL_DEBUG_OPTION Pushing option 100 with value ''");
addString("EVAL_DEBUG_OPTION Pushing option 100 with value 'hundred.one'");
addString("EVAL_DEBUG_OPTION Pushing option 101 with value ''");
addString("EVAL_DEBUG_OPTION Pushing option 102 with value 'hundredtwo.one'");
addString("EVAL_DEBUG_OPTION Pushing option 100 with value 'hundred.zero'");
addString("EVAL_DEBUG_OPTION Pushing option 100 with value 'true'");
addString("EVAL_DEBUG_OPTION Pushing option 101 with value 'hundredone.zero'");
addString("EVAL_DEBUG_OPTION Pushing option 102 with value ''");
addString("EVAL_DEBUG_OPTION Pushing option 102 with value 'false'");
addString("EVAL_DEBUG_OPTION Pushing option 100 with value ''");
EXPECT_TRUE(checkFile());
}
......@@ -1465,6 +1492,17 @@ TEST_F(TokenTest, relay6Field) {
// Level 2 has no encapsulation so the address should be zero length
verifyRelay6Eval(2, TokenRelay6Field::LINKADDR, 0, zeroaddr);
// Level -1 is the same than level 1
verifyRelay6Eval(-1, TokenRelay6Field::LINKADDR, 16, linkaddr);
verifyRelay6Eval(-1, TokenRelay6Field::PEERADDR, 16, peeraddr);
// Level -2 is the same than level 0
verifyRelay6Eval(-2, TokenRelay6Field::LINKADDR, 16, zeroaddr);
verifyRelay6Eval(-2, TokenRelay6Field::PEERADDR, 16, zeroaddr);
// Level -3 has no encapsulation so the address should be zero length
verifyRelay6Eval(-3, TokenRelay6Field::LINKADDR, 0, zeroaddr);
// Lets check that the layout of the address returned by the
// token matches that of the TokenIpAddress
TokenPtr trelay;
......@@ -1496,8 +1534,19 @@ TEST_F(TokenTest, relay6Field) {
"with value 0x00010000000000000000000000000001");
addString("EVAL_DEBUG_RELAY6 Pushing PKT6 relay field peeraddr nest 1 "
"with value 0x00010000000000000000000000000002");
addString("EVAL_DEBUG_RELAY6_RANGE Pushing PKT6 relay field linkaddr nest 2 "
"with value 0x");
addString("EVAL_DEBUG_RELAY6_RANGE Pushing PKT6 relay field linkaddr "
"nest 2 with value 0x");
addString("EVAL_DEBUG_RELAY6 Pushing PKT6 relay field linkaddr nest -1 "
"with value 0x00010000000000000000000000000001");
addString("EVAL_DEBUG_RELAY6 Pushing PKT6 relay field peeraddr nest -1 "
"with value 0x00010000000000000000000000000002");
addString("EVAL_DEBUG_RELAY6 Pushing PKT6 relay field linkaddr nest -2 "
"with value 0x00000000000000000000000000000000");
addString("EVAL_DEBUG_RELAY6 Pushing PKT6 relay field peeraddr nest -2 "
"with value 0x00000000000000000000000000000000");
addString("EVAL_DEBUG_RELAY6_RANGE Pushing PKT6 relay field linkaddr "
"nest -3 with value 0x");
addString("EVAL_DEBUG_RELAY6 Pushing PKT6 relay field linkaddr nest 1 "
"with value 0x00010000000000000000000000000001");
......
// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -179,7 +179,17 @@ OptionPtr TokenRelay6Option::getOption(Pkt& pkt) {
try {
// Now that we have the right type of packet we can
// get the option and return it.
return(pkt6.getRelayOption(option_code_, nest_level_));
if (nest_level_ >= 0) {
uint8_t nesting_level = static_cast<uint8_t>(nest_level_);
return(pkt6.getRelayOption(option_code_, nesting_level));
} else {
int nesting_level = pkt6.relay_info_.size() + nest_level_;
if (nesting_level < 0) {
return (OptionPtr());
}
return(pkt6.getRelayOption(option_code_,
static_cast<uint8_t>(nesting_level)));
}
}
catch (const isc::OutOfRange&) {
// The only exception we expect is OutOfRange if the nest
......@@ -383,18 +393,29 @@ TokenRelay6Field::evaluate(Pkt& pkt, ValueStack& values) {
// Check if it's a Pkt6. If it's not the dynamic_cast will
// throw std::bad_cast.
const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
uint8_t relay_level;
try {
switch (type_) {
if (nest_level_ >= 0) {
relay_level = static_cast<uint8_t>(nest_level_);
} else {
int nesting_level = pkt6.relay_info_.size() + nest_level_;
if (nesting_level < 0) {
// Don't throw OutOfRange here
nesting_level = 32;
}
relay_level = static_cast<uint8_t>(nesting_level);
}
switch (type_) {
// Now that we have the right type of packet we can
// get the option and return it.
case LINKADDR:
type_str = "linkaddr";
binary = pkt6.getRelay6LinkAddress(nest_level_).toBytes();
binary = pkt6.getRelay6LinkAddress(relay_level).toBytes();
break;
case PEERADDR:
type_str = "peeraddr";
binary = pkt6.getRelay6PeerAddress(nest_level_).toBytes();
binary = pkt6.getRelay6PeerAddress(relay_level).toBytes();
break;
}
} catch (const isc::OutOfRange&) {
......@@ -404,7 +425,7 @@ TokenRelay6Field::evaluate(Pkt& pkt, ValueStack& values) {
// Log what we pushed
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6_RANGE)
.arg(type_str)
.arg(unsigned(nest_level_))
.arg(int(nest_level_))
.arg("0x");
return;
}
......@@ -422,7 +443,7 @@ TokenRelay6Field::evaluate(Pkt& pkt, ValueStack& values) {
// Log what we pushed
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6)
.arg(type_str)
.arg(unsigned(nest_level_))
.arg(int(nest_level_))
.arg(toHex(value));
}
......
......@@ -338,7 +338,8 @@ protected:
/// exist or the option is not found an empty string ("") is returned
/// (or "false" when the representation is EXISTS).
///
/// The nesting level can go from 0 (closest to the server) to 31
/// The nesting level can go from 0 (closest to the server) to 31,
/// or from -1 (closest to the client) to -32
class TokenRelay6Option : public TokenOption {
public:
/// @brief Constructor that takes a nesting level and an option
......@@ -347,7 +348,7 @@ public:
/// @param nest_level the nesting for which relay to examine.
/// @param option_code code of the option.
/// @param rep_type Token representation type.
TokenRelay6Option(const uint8_t nest_level, const uint16_t option_code,
TokenRelay6Option(const int8_t nest_level, const uint16_t option_code,
const RepresentationType& rep_type)
:TokenOption(option_code, rep_type), nest_level_(nest_level) {}
......@@ -358,7 +359,7 @@ public:
///
/// @return nest-level of the relay block this token expects to use
/// for extraction.
uint8_t getNest() const {
int8_t getNest() const {
return (nest_level_);
}
......@@ -368,7 +369,7 @@ protected:
/// @return option instance if available
virtual OptionPtr getOption(Pkt& pkt);
uint8_t nest_level_; ///< nesting level of the relay block to use
int8_t nest_level_; ///< nesting level of the relay block to use
};
/// @brief Token that represents meta data of a DHCP packet.
......@@ -534,7 +535,8 @@ private:
/// is always returned as a 16 byte IPv6 address. As the relay may not have
/// set the field it may be 0s.
///
/// The nesting level can go from 0 (closest to the server) to 31.
/// The nesting level can go from 0 (closest to the server) to 31,
/// or from -1 (closest to the client) to -32
class TokenRelay6Field : public Token {
public:
......@@ -549,7 +551,7 @@ public:
///
/// @param nest_level the nesting level for which relay to examine.
/// @param type which field to extract.
TokenRelay6Field(const uint8_t nest_level, const FieldType type)
TokenRelay6Field(const int8_t nest_level, const FieldType type)
: nest_level_(nest_level), type_(type) {}
/// @brief Extracts the specified field from the requested relay
......@@ -568,7 +570,7 @@ public:
///
/// @return nest-level of the relay block this token expects to use
/// for extraction.
uint8_t getNest() const {
int8_t getNest() const {
return (nest_level_);
}
......@@ -584,7 +586,7 @@ public:
protected:
/// @brief Specifies field of the DHCPv6 relay option to get
uint8_t nest_level_; ///< nesting level of the relay block to use
int8_t nest_level_; ///< nesting level of the relay block to use
FieldType type_; ///< field to get
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment