2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 13:37:55 +00:00

[master] kea-dhpc4/6 now support relay ip-addresses

Merges in branch 'trac5535'
This commit is contained in:
Thomas Markwalder 2018-04-27 10:00:59 -04:00
commit f4601abdb6
42 changed files with 5196 additions and 4731 deletions

View File

@ -3995,20 +3995,20 @@ for each subnet. Here's an example:
{
"name": "kakapo",
<userinput>"relay": {
"ip-address": "192.3.5.6"
"ip-addresses": [ "192.3.5.6" ]
}</userinput>,
"subnet4": [
{
"subnet": "192.0.2.0/26",
<userinput>"relay": {
"ip-address": "192.1.1.1"
"ip-addresses": [ "192.1.1.1" ]
}</userinput>,
"pools": [ { "pool": "192.0.2.63 - 192.0.2.63" } ]
},
{
"subnet": "10.0.0.0/24",
<userinput>"relay": {
"ip-address": "192.2.2.2"
"ip-addresses": [ "192.2.2.2" ]
}</userinput>,
"pools": [ { "pool": "10.0.0.16 - 10.0.0.16" } ]
}
@ -4138,7 +4138,6 @@ desired outcome if one desires to service only clients of known properties
"interface" or "relay" parameter. All subnets belonging to this shared
network will inherit those parameters.
</para>
</section>
<section>
@ -4311,7 +4310,7 @@ autogenerated IDs are not stable across configuration changes.</para>
"subnet": "192.0.2.0/24",
"pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
<userinput>"relay": {
"ip-address": "10.0.0.1"
"ip-addresses": [ "10.0.0.1" ]
}</userinput>,
...
}
@ -4321,8 +4320,17 @@ autogenerated IDs are not stable across configuration changes.</para>
</screen>
</para>
<para>If "relay" is specified, the "ip-address" parameter within
<para>If "relay" is specified, the "ip-addresses" parameter within
it is mandatory.</para>
<note>
<para>
As of Kea 1.4, the "ip-address" parameter has been deprecated in favor
of "ip-addresses" which supports specifying a list of addresses.
Configuration parsing, will honor the singular form for now but users are
encouraged to migrate.
</para>
</note>
</section>
@ -4351,14 +4359,14 @@ autogenerated IDs are not stable across configuration changes.</para>
"pools": [ { "pool": "10.1.1.2 - 10.1.1.20" } ],
<userinput>"client-class" "docsis3.0",
"relay": {
"ip-address": "10.1.1.1"
"ip-addresses": [ "10.1.1.1 ]"
}</userinput>
},
{
"subnet": "192.0.2.0/24",
"pools": [ { "pool": "192.0.2.10 - 192.0.2.20" } ],
<userinput>"relay": {
"ip-address": "10.1.1.1"
"ip-addresses": [ "10.1.1.1" ]
}</userinput>
}
],

View File

@ -3496,7 +3496,7 @@ If not specified, the default value is:
// Subnets from this shared network will be selected for clients
// communicating via relay agent having the specified IP address.
"relay": {
"ip-address": "2001:db8:2:34::1"
"ip-addresses": [ "2001:db8:2:34::1" ]
},
// This starts a list of subnets in this shared network.
@ -3523,7 +3523,7 @@ If not specified, the default value is:
"subnet": "2001:db9::/48",
"pools": [ { "pool": "2001:db9::/64" } ],
"relay": {
"ip-address": "2001:db8:1:2::1"
"ip-addresses": [ "2001:db8:1:2::1" ]
}
}
]
@ -3555,7 +3555,7 @@ If not specified, the default value is:
{
"name": "lab-network3",
"relay": {
"ip-address": "2001:db8:2:34::1"
"ip-addresses": [ "2001:db8:2:34::1" ]
},
// This applies to all subnets in this shared network, unless
@ -3671,13 +3671,13 @@ for each subnet. Here's an example:
{
"name": "kakapo",
<userinput>"relay": {
"ip-address": "2001:db8::abcd"
"ip-addresses": [ "2001:db8::abcd" ]
}</userinput>,
"subnet6": [
{
"subnet": "2001:db8::/64",
<userinput>"relay": {
"ip-address": "2001:db8::1234"
"ip-addresses": [ "2001:db8::1234" ]
}</userinput>,
"pools": [ { "pool": "2001:db8::1 - 2001:db8::ffff" } ]
},
@ -3685,7 +3685,7 @@ for each subnet. Here's an example:
"subnet": "3ffe:abcd::/64",
"pools": [ { "pool": "3ffe:abcd::1 - 3ffe:abcd::ffff" } ],
<userinput>"relay": {
"ip-address": "3ffe:abcd::cafe"
"ip-addresses": [ "3ffe:abcd::cafe" ]
}</userinput>
}
]
@ -3730,7 +3730,7 @@ as long as it is valid IPv6 address.</para>
{
"name": "galah",
"relay": {
"ip-address": "2001:db8:2:34::1"
"ip-address": [ "2001:db8:2:34::1" ]
},
"subnet6": [
{
@ -3781,7 +3781,7 @@ as long as it is valid IPv6 address.</para>
{
"name": "galah",
"relay": {
"ip-address": "2001:db8:2:34::1"
"ip-addresses": [ "2001:db8:2:34::1" ]
},
"subnet6": [
{
@ -3833,7 +3833,7 @@ desired outcome if one desires to service only clients of known properties
{
"name": "frog",
"relay": {
"ip-address": "2001:db8:2:34::1"
"ip-addresses": [ "2001:db8:2:34::1" ]
},
"subnet6": [
{
@ -4252,7 +4252,7 @@ autogenerated IDs are not stable across configuration changes.
}
],
<userinput>"relay": {
"ip-address": "3000::1"
"ip-addresses": [ "3000::1" ]
}</userinput>
}
]
@ -4260,9 +4260,18 @@ autogenerated IDs are not stable across configuration changes.
</screen>
</para>
<para>If "relay" is specified, the "ip-address" parameter within
<para>If "relay" is specified, the "ip-addresses" parameter within
it is mandatory.</para>
<note>
<para>
As of Kea 1.4, the "ip-address" parameter in "relay" has been deprecated
in favor of "ip-addresses" which supports specifying a list of addresses.
Configuration parsing, will honor the singular form for now but users are
encouraged to migrate.
</para>
</note>
</section>
<section xml:id="dhcp6-client-class-relay">
@ -4293,7 +4302,7 @@ autogenerated IDs are not stable across configuration changes.
],
<userinput>"client-class": "VENDOR_CLASS_docsis3.0",
"relay": {
"ip-address": "3000::1"
"ip-addresses": [ "3000::1" ]
}</userinput>
},
@ -4305,7 +4314,7 @@ autogenerated IDs are not stable across configuration changes.
}
],
<userinput>"relay": {
"ip-address": "3000::1"
"ip-addresses": [ "3000::1" ]
}</userinput>
}
]

File diff suppressed because it is too large Load Diff

View File

@ -1052,6 +1052,15 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"ip-addresses\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::RELAY:
return isc::dhcp::Dhcp4Parser::make_IP_ADDRESSES(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("ip-addresses", driver.loc_);
}
}
\"hooks-libraries\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::DHCP4:

File diff suppressed because it is too large Load Diff

View File

@ -441,70 +441,71 @@ namespace isc { namespace dhcp {
TOKEN_FLEX_ID = 348,
TOKEN_RELAY = 349,
TOKEN_IP_ADDRESS = 350,
TOKEN_HOOKS_LIBRARIES = 351,
TOKEN_LIBRARY = 352,
TOKEN_PARAMETERS = 353,
TOKEN_EXPIRED_LEASES_PROCESSING = 354,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 355,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 356,
TOKEN_HOLD_RECLAIMED_TIME = 357,
TOKEN_MAX_RECLAIM_LEASES = 358,
TOKEN_MAX_RECLAIM_TIME = 359,
TOKEN_UNWARNED_RECLAIM_CYCLES = 360,
TOKEN_DHCP4O6_PORT = 361,
TOKEN_CONTROL_SOCKET = 362,
TOKEN_SOCKET_TYPE = 363,
TOKEN_SOCKET_NAME = 364,
TOKEN_DHCP_DDNS = 365,
TOKEN_ENABLE_UPDATES = 366,
TOKEN_QUALIFYING_SUFFIX = 367,
TOKEN_SERVER_IP = 368,
TOKEN_SERVER_PORT = 369,
TOKEN_SENDER_IP = 370,
TOKEN_SENDER_PORT = 371,
TOKEN_MAX_QUEUE_SIZE = 372,
TOKEN_NCR_PROTOCOL = 373,
TOKEN_NCR_FORMAT = 374,
TOKEN_ALWAYS_INCLUDE_FQDN = 375,
TOKEN_OVERRIDE_NO_UPDATE = 376,
TOKEN_OVERRIDE_CLIENT_UPDATE = 377,
TOKEN_REPLACE_CLIENT_NAME = 378,
TOKEN_GENERATED_PREFIX = 379,
TOKEN_TCP = 380,
TOKEN_JSON = 381,
TOKEN_WHEN_PRESENT = 382,
TOKEN_NEVER = 383,
TOKEN_ALWAYS = 384,
TOKEN_WHEN_NOT_PRESENT = 385,
TOKEN_LOGGING = 386,
TOKEN_LOGGERS = 387,
TOKEN_OUTPUT_OPTIONS = 388,
TOKEN_OUTPUT = 389,
TOKEN_DEBUGLEVEL = 390,
TOKEN_SEVERITY = 391,
TOKEN_FLUSH = 392,
TOKEN_MAXSIZE = 393,
TOKEN_MAXVER = 394,
TOKEN_DHCP6 = 395,
TOKEN_DHCPDDNS = 396,
TOKEN_CONTROL_AGENT = 397,
TOKEN_TOPLEVEL_JSON = 398,
TOKEN_TOPLEVEL_DHCP4 = 399,
TOKEN_SUB_DHCP4 = 400,
TOKEN_SUB_INTERFACES4 = 401,
TOKEN_SUB_SUBNET4 = 402,
TOKEN_SUB_POOL4 = 403,
TOKEN_SUB_RESERVATION = 404,
TOKEN_SUB_OPTION_DEFS = 405,
TOKEN_SUB_OPTION_DEF = 406,
TOKEN_SUB_OPTION_DATA = 407,
TOKEN_SUB_HOOKS_LIBRARY = 408,
TOKEN_SUB_DHCP_DDNS = 409,
TOKEN_SUB_LOGGING = 410,
TOKEN_STRING = 411,
TOKEN_INTEGER = 412,
TOKEN_FLOAT = 413,
TOKEN_BOOLEAN = 414
TOKEN_IP_ADDRESSES = 351,
TOKEN_HOOKS_LIBRARIES = 352,
TOKEN_LIBRARY = 353,
TOKEN_PARAMETERS = 354,
TOKEN_EXPIRED_LEASES_PROCESSING = 355,
TOKEN_RECLAIM_TIMER_WAIT_TIME = 356,
TOKEN_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 357,
TOKEN_HOLD_RECLAIMED_TIME = 358,
TOKEN_MAX_RECLAIM_LEASES = 359,
TOKEN_MAX_RECLAIM_TIME = 360,
TOKEN_UNWARNED_RECLAIM_CYCLES = 361,
TOKEN_DHCP4O6_PORT = 362,
TOKEN_CONTROL_SOCKET = 363,
TOKEN_SOCKET_TYPE = 364,
TOKEN_SOCKET_NAME = 365,
TOKEN_DHCP_DDNS = 366,
TOKEN_ENABLE_UPDATES = 367,
TOKEN_QUALIFYING_SUFFIX = 368,
TOKEN_SERVER_IP = 369,
TOKEN_SERVER_PORT = 370,
TOKEN_SENDER_IP = 371,
TOKEN_SENDER_PORT = 372,
TOKEN_MAX_QUEUE_SIZE = 373,
TOKEN_NCR_PROTOCOL = 374,
TOKEN_NCR_FORMAT = 375,
TOKEN_ALWAYS_INCLUDE_FQDN = 376,
TOKEN_OVERRIDE_NO_UPDATE = 377,
TOKEN_OVERRIDE_CLIENT_UPDATE = 378,
TOKEN_REPLACE_CLIENT_NAME = 379,
TOKEN_GENERATED_PREFIX = 380,
TOKEN_TCP = 381,
TOKEN_JSON = 382,
TOKEN_WHEN_PRESENT = 383,
TOKEN_NEVER = 384,
TOKEN_ALWAYS = 385,
TOKEN_WHEN_NOT_PRESENT = 386,
TOKEN_LOGGING = 387,
TOKEN_LOGGERS = 388,
TOKEN_OUTPUT_OPTIONS = 389,
TOKEN_OUTPUT = 390,
TOKEN_DEBUGLEVEL = 391,
TOKEN_SEVERITY = 392,
TOKEN_FLUSH = 393,
TOKEN_MAXSIZE = 394,
TOKEN_MAXVER = 395,
TOKEN_DHCP6 = 396,
TOKEN_DHCPDDNS = 397,
TOKEN_CONTROL_AGENT = 398,
TOKEN_TOPLEVEL_JSON = 399,
TOKEN_TOPLEVEL_DHCP4 = 400,
TOKEN_SUB_DHCP4 = 401,
TOKEN_SUB_INTERFACES4 = 402,
TOKEN_SUB_SUBNET4 = 403,
TOKEN_SUB_POOL4 = 404,
TOKEN_SUB_RESERVATION = 405,
TOKEN_SUB_OPTION_DEFS = 406,
TOKEN_SUB_OPTION_DEF = 407,
TOKEN_SUB_OPTION_DATA = 408,
TOKEN_SUB_HOOKS_LIBRARY = 409,
TOKEN_SUB_DHCP_DDNS = 410,
TOKEN_SUB_LOGGING = 411,
TOKEN_STRING = 412,
TOKEN_INTEGER = 413,
TOKEN_FLOAT = 414,
TOKEN_BOOLEAN = 415
};
};
@ -995,6 +996,10 @@ namespace isc { namespace dhcp {
symbol_type
make_IP_ADDRESS (const location_type& l);
static inline
symbol_type
make_IP_ADDRESSES (const location_type& l);
static inline
symbol_type
make_HOOKS_LIBRARIES (const location_type& l);
@ -1456,12 +1461,12 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 933, ///< Last index in yytable_.
yynnts_ = 352, ///< Number of nonterminal symbols.
yylast_ = 935, ///< Last index in yytable_.
yynnts_ = 353, ///< Number of nonterminal symbols.
yyfinal_ = 28, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 160 ///< Number of tokens.
yyntokens_ = 161 ///< Number of tokens.
};
@ -1519,9 +1524,9 @@ namespace isc { namespace dhcp {
125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, 159
155, 156, 157, 158, 159, 160
};
const unsigned int user_token_number_max_ = 414;
const unsigned int user_token_number_max_ = 415;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
@ -1554,30 +1559,30 @@ namespace isc { namespace dhcp {
{
switch (other.type_get ())
{
case 175: // value
case 179: // map_value
case 217: // socket_type
case 220: // outbound_interface_value
case 236: // db_type
case 320: // hr_mode
case 467: // ncr_protocol_value
case 475: // replace_client_name_value
case 176: // value
case 180: // map_value
case 218: // socket_type
case 221: // outbound_interface_value
case 237: // db_type
case 321: // hr_mode
case 469: // ncr_protocol_value
case 477: // replace_client_name_value
value.copy< ElementPtr > (other.value);
break;
case 159: // "boolean"
case 160: // "boolean"
value.copy< bool > (other.value);
break;
case 158: // "floating point"
case 159: // "floating point"
value.copy< double > (other.value);
break;
case 157: // "integer"
case 158: // "integer"
value.copy< int64_t > (other.value);
break;
case 156: // "constant string"
case 157: // "constant string"
value.copy< std::string > (other.value);
break;
@ -1598,30 +1603,30 @@ namespace isc { namespace dhcp {
(void) v;
switch (this->type_get ())
{
case 175: // value
case 179: // map_value
case 217: // socket_type
case 220: // outbound_interface_value
case 236: // db_type
case 320: // hr_mode
case 467: // ncr_protocol_value
case 475: // replace_client_name_value
case 176: // value
case 180: // map_value
case 218: // socket_type
case 221: // outbound_interface_value
case 237: // db_type
case 321: // hr_mode
case 469: // ncr_protocol_value
case 477: // replace_client_name_value
value.copy< ElementPtr > (v);
break;
case 159: // "boolean"
case 160: // "boolean"
value.copy< bool > (v);
break;
case 158: // "floating point"
case 159: // "floating point"
value.copy< double > (v);
break;
case 157: // "integer"
case 158: // "integer"
value.copy< int64_t > (v);
break;
case 156: // "constant string"
case 157: // "constant string"
value.copy< std::string > (v);
break;
@ -1701,30 +1706,30 @@ namespace isc { namespace dhcp {
// Type destructor.
switch (yytype)
{
case 175: // value
case 179: // map_value
case 217: // socket_type
case 220: // outbound_interface_value
case 236: // db_type
case 320: // hr_mode
case 467: // ncr_protocol_value
case 475: // replace_client_name_value
case 176: // value
case 180: // map_value
case 218: // socket_type
case 221: // outbound_interface_value
case 237: // db_type
case 321: // hr_mode
case 469: // ncr_protocol_value
case 477: // replace_client_name_value
value.template destroy< ElementPtr > ();
break;
case 159: // "boolean"
case 160: // "boolean"
value.template destroy< bool > ();
break;
case 158: // "floating point"
case 159: // "floating point"
value.template destroy< double > ();
break;
case 157: // "integer"
case 158: // "integer"
value.template destroy< int64_t > ();
break;
case 156: // "constant string"
case 157: // "constant string"
value.template destroy< std::string > ();
break;
@ -1751,30 +1756,30 @@ namespace isc { namespace dhcp {
super_type::move(s);
switch (this->type_get ())
{
case 175: // value
case 179: // map_value
case 217: // socket_type
case 220: // outbound_interface_value
case 236: // db_type
case 320: // hr_mode
case 467: // ncr_protocol_value
case 475: // replace_client_name_value
case 176: // value
case 180: // map_value
case 218: // socket_type
case 221: // outbound_interface_value
case 237: // db_type
case 321: // hr_mode
case 469: // ncr_protocol_value
case 477: // replace_client_name_value
value.move< ElementPtr > (s.value);
break;
case 159: // "boolean"
case 160: // "boolean"
value.move< bool > (s.value);
break;
case 158: // "floating point"
case 159: // "floating point"
value.move< double > (s.value);
break;
case 157: // "integer"
case 158: // "integer"
value.move< int64_t > (s.value);
break;
case 156: // "constant string"
case 157: // "constant string"
value.move< std::string > (s.value);
break;
@ -1848,7 +1853,8 @@ namespace isc { namespace dhcp {
375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
405, 406, 407, 408, 409, 410, 411, 412, 413, 414
405, 406, 407, 408, 409, 410, 411, 412, 413, 414,
415
};
return static_cast<token_type> (yytoken_number_[type]);
}
@ -2417,6 +2423,12 @@ namespace isc { namespace dhcp {
return symbol_type (token::TOKEN_IP_ADDRESS, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_IP_ADDRESSES (const location_type& l)
{
return symbol_type (token::TOKEN_IP_ADDRESSES, l);
}
Dhcp4Parser::symbol_type
Dhcp4Parser::make_HOOKS_LIBRARIES (const location_type& l)
{
@ -2804,7 +2816,7 @@ namespace isc { namespace dhcp {
#line 14 "dhcp4_parser.yy" // lalr1.cc:377
} } // isc::dhcp
#line 2808 "dhcp4_parser.h" // lalr1.cc:377
#line 2820 "dhcp4_parser.h" // lalr1.cc:377

View File

@ -145,6 +145,7 @@ using namespace std;
RELAY "relay"
IP_ADDRESS "ip-address"
IP_ADDRESSES "ip-addresses"
HOOKS_LIBRARIES "hooks-libraries"
LIBRARY "library"
@ -1586,6 +1587,16 @@ ip_address: IP_ADDRESS {
ctx.leave();
};
ip_addresses: IP_ADDRESSES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("ip-addresses", l);
ctx.stack_.push_back(l);
ctx.enter(ctx.NO_KEYWORD);
} COLON list_strings {
ctx.stack_.pop_back();
ctx.leave();
};
duid: DUID {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
@ -1657,13 +1668,9 @@ relay: RELAY {
ctx.leave();
};
relay_map: IP_ADDRESS {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
ElementPtr ip(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("ip-address", ip);
ctx.leave();
};
relay_map: ip_address
| ip_addresses
;
// --- end of relay definitions ------------------------------

View File

@ -1,4 +1,3 @@
// Generated 201804111443
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,3 @@
// Generated 201804111443
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -1,4 +1,3 @@
// Generated 201804111443
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++

View File

@ -260,7 +260,7 @@ public:
void checkResult(ConstElementPtr status, int expected_code) {
ASSERT_TRUE(status);
comment_ = parseAnswer(rcode_, status);
EXPECT_EQ(expected_code, rcode_);
EXPECT_EQ(expected_code, rcode_) << "error text:" << comment_->stringValue();
}
/// @brief Convenience method for running configuration
@ -1377,7 +1377,7 @@ TEST_F(Dhcp4ParserTest, nextServerOverride) {
"\"renew-timer\": 1000, "
"\"next-server\": \"192.0.0.1\", "
"\"server-hostname\": \"nohost\","
"\"boot-file-name\": \"nofile\","
"\"boot-file-name\": \"nofile\","
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"next-server\": \"1.2.3.4\", "
@ -4089,9 +4089,53 @@ TEST_F(Dhcp4ParserTest, subnetRelayInfo) {
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
EXPECT_EQ("192.0.2.123", subnet->getRelayInfo().addr_.toText());
EXPECT_TRUE(subnet->hasRelays());
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("192.0.2.123")));
}
// This test checks if it is possible to specify a list of relays
TEST_F(Dhcp4ParserTest, subnetRelayInfoList) {
ConstElementPtr status;
// A config with relay information.
string config = "{ " + genIfaceConfig() + "," +
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
" \"renew-timer\": 1, "
" \"rebind-timer\": 2, "
" \"valid-lifetime\": 4,"
" \"relay\": { "
" \"ip-addresses\": [ \"192.0.3.123\", \"192.0.3.124\" ]"
" },"
" \"subnet\": \"192.0.2.0/24\" } ],"
"\"valid-lifetime\": 4000 }";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP4(config));
extractConfig(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
// returned value should be 0 (configuration success)
checkResult(status, 0);
SubnetSelector selector;
selector.giaddr_ = IOAddress("192.0.2.200");
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(selector);
ASSERT_TRUE(subnet);
EXPECT_TRUE(subnet->hasRelays());
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("192.0.3.123")));
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("192.0.3.124")));
}
// Goal of this test is to verify that multiple subnets can be configured
// with defined client classes.
TEST_F(Dhcp4ParserTest, classifySubnets) {
@ -5652,7 +5696,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ(IOAddress("1.2.3.4"), s->getSiaddr());
EXPECT_EQ("foo", s->getSname());
EXPECT_EQ("bar", s->getFilename());
EXPECT_EQ(IOAddress("5.6.7.8"), s->getRelayInfo().addr_);
EXPECT_TRUE(s->hasRelayAddress(IOAddress("5.6.7.8")));
EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode());
// For the second subnet, the renew-timer should be 100, because it
@ -5667,7 +5711,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ(IOAddress("11.22.33.44"), s->getSiaddr());
EXPECT_EQ("some-name.example.org", s->getSname());
EXPECT_EQ("bootfile.efi", s->getFilename());
EXPECT_EQ(IOAddress("55.66.77.88"), s->getRelayInfo().addr_);
EXPECT_TRUE(s->hasRelayAddress(IOAddress("55.66.77.88")));
EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode());
// Ok, now check the second shared subnet.
@ -5686,7 +5730,7 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) {
EXPECT_EQ(IOAddress("0.0.0.0"), s->getSiaddr());
EXPECT_TRUE(s->getSname().empty());
EXPECT_TRUE(s->getFilename().empty());
EXPECT_EQ(IOAddress("0.0.0.0"), s->getRelayInfo().addr_);
EXPECT_FALSE(s->hasRelays());
EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode());
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1196,6 +1196,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"ip-addresses\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::RESERVATIONS:
case isc::dhcp::Parser6Context::RELAY:
return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("ip-addresses", driver.loc_);

File diff suppressed because it is too large Load Diff

View File

@ -1480,8 +1480,8 @@ namespace isc { namespace dhcp {
enum
{
yyeof_ = 0,
yylast_ = 979, ///< Last index in yytable_.
yynnts_ = 366, ///< Number of nonterminal symbols.
yylast_ = 981, ///< Last index in yytable_.
yynnts_ = 367, ///< Number of nonterminal symbols.
yyfinal_ = 30, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
@ -1582,9 +1582,9 @@ namespace isc { namespace dhcp {
case 185: // map_value
case 235: // db_type
case 318: // hr_mode
case 453: // duid_type
case 486: // ncr_protocol_value
case 494: // replace_client_name_value
case 454: // duid_type
case 487: // ncr_protocol_value
case 495: // replace_client_name_value
value.copy< ElementPtr > (other.value);
break;
@ -1625,9 +1625,9 @@ namespace isc { namespace dhcp {
case 185: // map_value
case 235: // db_type
case 318: // hr_mode
case 453: // duid_type
case 486: // ncr_protocol_value
case 494: // replace_client_name_value
case 454: // duid_type
case 487: // ncr_protocol_value
case 495: // replace_client_name_value
value.copy< ElementPtr > (v);
break;
@ -1727,9 +1727,9 @@ namespace isc { namespace dhcp {
case 185: // map_value
case 235: // db_type
case 318: // hr_mode
case 453: // duid_type
case 486: // ncr_protocol_value
case 494: // replace_client_name_value
case 454: // duid_type
case 487: // ncr_protocol_value
case 495: // replace_client_name_value
value.template destroy< ElementPtr > ();
break;
@ -1776,9 +1776,9 @@ namespace isc { namespace dhcp {
case 185: // map_value
case 235: // db_type
case 318: // hr_mode
case 453: // duid_type
case 486: // ncr_protocol_value
case 494: // replace_client_name_value
case 454: // duid_type
case 487: // ncr_protocol_value
case 495: // replace_client_name_value
value.move< ElementPtr > (s.value);
break;

View File

@ -1684,11 +1684,15 @@ relay: RELAY {
ctx.leave();
};
relay_map: IP_ADDRESS {
relay_map: ip_address
| ip_addresses
;
ip_address: IP_ADDRESS {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
ElementPtr ip(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("ip-address", ip);
ElementPtr addr(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("ip-address", addr);
ctx.leave();
};

View File

@ -1,4 +1,3 @@
// Generated 201804111534
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,3 @@
// Generated 201804111534
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -1,4 +1,3 @@
// Generated 201804111534
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++

View File

@ -4142,7 +4142,43 @@ TEST_F(Dhcp6ParserTest, subnetRelayInfo) {
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
selectSubnet(IOAddress("2001:db8:1::1"), classify_);
ASSERT_TRUE(subnet);
EXPECT_EQ("2001:db8:1::abcd", subnet->getRelayInfo().addr_.toText());
EXPECT_TRUE(subnet->hasRelays());
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("2001:db8:1::abcd")));
}
// This test checks if it is possible to specify a list of relays
TEST_F(Dhcp6ParserTest, subnetRelayInfoList) {
// A config with relay information.
string config = "{ " + genIfaceConfig() + ","
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ],"
" \"relay\": { "
" \"ip-addresses\": [ \"2001:db9::abcd\", \"2001:db9::abce\" ]"
" },"
" \"subnet\": \"2001:db8:1::/64\" } ],"
"\"preferred-lifetime\": 3000, "
"\"valid-lifetime\": 4000 }";
ConstElementPtr json;
ASSERT_NO_THROW(json = parseDHCP6(config));
extractConfig(config);
ConstElementPtr status;
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
// returned value should be 0 (configuration success)
checkResult(status, 0);
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
selectSubnet(IOAddress("2001:db9::abcd"), classify_, true);
ASSERT_TRUE(subnet);
EXPECT_TRUE(subnet->hasRelays());
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("2001:db9::abcd")));
EXPECT_TRUE(subnet->hasRelayAddress(IOAddress("2001:db9::abce")));
}
// Goal of this test is to verify that multiple subnets can be configured
@ -6008,7 +6044,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) {
ASSERT_TRUE(s);
ASSERT_TRUE(s->getInterfaceId());
EXPECT_TRUE(iface_id1.equals(s->getInterfaceId()));
EXPECT_EQ(IOAddress("1111::1"), s->getRelayInfo().addr_);
EXPECT_TRUE(s->hasRelayAddress(IOAddress("1111::1")));
EXPECT_TRUE(s->getRapidCommit());
EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode());
@ -6019,7 +6055,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) {
s = checkSubnet(*subs, "2001:db2::/48", 100, 200, 300, 400);
ASSERT_TRUE(s->getInterfaceId());
EXPECT_TRUE(iface_id2.equals(s->getInterfaceId()));
EXPECT_EQ(IOAddress("2222::2"), s->getRelayInfo().addr_);
EXPECT_TRUE(s->hasRelayAddress(IOAddress("2222::2")));
EXPECT_TRUE(s->getRapidCommit());
EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode());
@ -6034,7 +6070,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) {
// This subnet should derive its renew-timer from global scope.
s = checkSubnet(*subs, "2001:db3::/48", 1, 2, 3, 4);
EXPECT_FALSE(s->getInterfaceId());
EXPECT_EQ(IOAddress("::"), s->getRelayInfo().addr_);
EXPECT_FALSE(s->hasRelays());
EXPECT_FALSE(s->getRapidCommit());
EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode());
}

File diff suppressed because it is too large Load Diff

View File

@ -137,17 +137,16 @@ CfgSubnets4::selectSubnet(const SubnetSelector& selector) const {
// If relay information is specified for this subnet, it must match.
// Otherwise, we ignore this subnet.
if (!(*subnet)->getRelayInfo().addr_.isV4Zero()) {
if (selector.giaddr_ != (*subnet)->getRelayInfo().addr_) {
if ((*subnet)->hasRelays()) {
if (!(*subnet)->hasRelayAddress(selector.giaddr_)) {
continue;
}
} else {
// Relay information is not specified on the subnet level,
// so let's try matching on the shared network level.
SharedNetwork4Ptr network;
(*subnet)->getSharedNetwork(network);
if (!network || (selector.giaddr_ != network->getRelayInfo().addr_)) {
if (!network || !(network->hasRelayAddress(selector.giaddr_))) {
continue;
}
}

View File

@ -116,16 +116,17 @@ CfgSubnets6::selectSubnet(const asiolink::IOAddress& address,
for (Subnet6Collection::const_iterator subnet = subnets_.begin();
subnet != subnets_.end(); ++subnet) {
// If the specified address matches the relay address, return this
// If the specified address matches a relay address, return this
// subnet.
if (is_relay_address &&
((*subnet)->getRelayInfo().addr_ == address) &&
((*subnet)->hasRelayAddress(address)) &&
(*subnet)->clientSupported(client_classes)) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
DHCPSRV_CFGMGR_SUBNET6_RELAY)
.arg((*subnet)->toText()).arg(address.toText());
return (*subnet);
}
}
}

View File

@ -84,6 +84,12 @@ This warning message is issued on an attempt to configure multiple options with
same option code for the particular subnet. Adding multiple options is uncommon
for DHCPv6, but it is not prohibited.
% DHCPSRV_CFGMGR_RELAY_IP_ADDRESS_DEPRECATED "relay" uses "ip-address", which has been deprecated, please use "ip-addresses": %1
This is debug message issued when the "relay" element being parse
contains "ip-address" rather than its replacement, "ip-addresses".
The server will still honor the value but users are encouraged to
move to the new list parameter.
% DHCPSRV_CFGMGR_SOCKET_RAW_UNSUPPORTED use of raw sockets is unsupported on this OS, UDP sockets will be used
This warning message is logged when the user specified that the
DHCPv4 server should use the raw sockets to receive the DHCP

View File

@ -16,8 +16,56 @@ using namespace isc::data;
namespace isc {
namespace dhcp {
Network::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr)
:addr_(addr) {
void
Network::RelayInfo::addAddress(const asiolink::IOAddress& addr) {
if (containsAddress(addr)) {
isc_throw (BadValue, "RelayInfo already contains address: "
<< addr.toText());
}
addresses_.push_back(addr);
}
bool
Network::RelayInfo::hasAddresses() const {
return (!addresses_.empty());
}
bool
Network::RelayInfo::containsAddress(const asiolink::IOAddress& addr) const {
for (auto address = addresses_.begin(); address != addresses_.end();
++address) {
if ((*address) == addr) {
return (true);
}
}
return (false);
}
const IOAddressList&
Network::RelayInfo::getAddresses() const {
return (addresses_);
}
void
Network::addRelayAddress(const asiolink::IOAddress& addr) {
relay_.addAddress(addr);
}
bool
Network::hasRelays() const {
return (relay_.hasAddresses());
}
bool
Network::hasRelayAddress(const asiolink::IOAddress& addr) const {
return (relay_.containsAddress(addr));
}
const IOAddressList&
Network::getRelayAddresses() const {
return (relay_.getAddresses());
}
bool
@ -61,11 +109,15 @@ Network::toElement() const {
map->set("interface", Element::create(iface));
}
// Set relay info
const RelayInfo& relay_info = getRelayInfo();
ElementPtr relay = Element::createMap();
relay->set("ip-address", Element::create(relay_info.addr_.toText()));
map->set("relay", relay);
ElementPtr relay_map = Element::createMap();
ElementPtr address_list = Element::createList();
const IOAddressList addresses = getRelayAddresses();
for (auto address = addresses.begin(); address != addresses.end(); ++address) {
address_list->add(Element::create((*address).toText()));
}
relay_map->set("ip-addresses", address_list);
map->set("relay", relay_map);
// Set client-class
const ClientClass& cclass = getClientClass();

View File

@ -24,6 +24,9 @@
namespace isc {
namespace dhcp {
/// List of IOAddresses
typedef std::vector<isc::asiolink::IOAddress> IOAddressList;
/// @brief Common interface representing a network to which the DHCP clients
/// are connected.
///
@ -44,24 +47,42 @@ namespace dhcp {
/// derived classes.
class Network : public virtual UserContext, public data::CfgToElement {
public:
/// @brief Holds optional information about relay.
///
/// In some cases it is beneficial to have additional information about
/// a relay configured in the subnet. For now, the structure holds only
/// IP address, but there may potentially be additional parameters added
/// IP addresses, but there may potentially be additional parameters added
/// later, e.g. relay interface-id or relay-id.
struct RelayInfo {
class RelayInfo {
public:
/// @brief default and the only constructor
/// @brief Adds an address to the list of addresses
///
/// @param addr an IP address of the relay (may be :: or 0.0.0.0)
RelayInfo(const isc::asiolink::IOAddress& addr);
/// @param addr address to add
/// @throw BadValue if the address is already in the list
void addAddress(const asiolink::IOAddress& addr);
/// @brief IP address of the relay
isc::asiolink::IOAddress addr_;
/// @brief Returns const reference to the list of addresses
///
/// @return const reference to the list of addresses
const IOAddressList& getAddresses() const;
/// @brief Indicates whether or not the address list has entries
///
/// @return True if the address list is not empty
bool hasAddresses() const;
/// @brief Checks the address list for the given address
///
/// @return True if the address is found in the address list
bool containsAddress(const asiolink::IOAddress& addr) const;
private:
/// @brief List of relay IP addresses
IOAddressList addresses_;
};
/// @brief Specifies allowed host reservation mode.
///
typedef enum {
@ -88,8 +109,7 @@ public:
/// @brief Constructor.
Network()
: iface_name_(), relay_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
client_class_(""), t1_(0), t2_(0), valid_(0),
: iface_name_(), client_class_(""), t1_(0), t2_(0), valid_(0),
host_reservation_mode_(HR_ALL), cfg_option_(new CfgOption()) {
}
@ -151,6 +171,28 @@ public:
return (relay_);
}
/// @brief Adds an address to the list addresses in the network's relay info
///
/// @param addr address of the relay
/// @throw BadValue if the address is already in the list
void addRelayAddress(const asiolink::IOAddress& addr);
/// @brief Returns the list of relay addresses from the network's relay info
///
/// @return const reference to the list of addresses
const IOAddressList& getRelayAddresses() const;
/// @brief Indicates if network's relay info has relay addresses
///
/// @return True the relay list is not empty, false otherwise
bool hasRelays() const;
/// @brief Tests if the network's relay info contains the given address
///
/// @param address address to search for in the relay list
/// @return True if a relay with the given address is found, false otherwise
bool hasRelayAddress(const asiolink::IOAddress& address) const;
/// @brief Checks whether this network supports client that belongs to
/// specified classes.
///
@ -363,7 +405,6 @@ public:
/// @brief Constructor.
Network6()
: Network(), preferred_(0), interface_id_(), rapid_commit_(false) {
setRelayInfo(asiolink::IOAddress::IPV6_ZERO_ADDRESS());
}
/// @brief Returns preferred lifetime (in seconds)

View File

@ -233,23 +233,81 @@ RelayInfoParser::RelayInfoParser(const Option::Universe& family)
};
void
RelayInfoParser::parse(const isc::dhcp::Network::RelayInfoPtr& cfg,
ConstElementPtr relay_info) {
// There is only one parameter which is mandatory
IOAddress ip = getAddress(relay_info, "ip-address");
RelayInfoParser::parse(const isc::dhcp::Network::RelayInfoPtr& relay_info,
ConstElementPtr relay_elem) {
// Check if the address family matches.
if ((ip.isV4() && family_ != Option::V4) ||
(ip.isV6() && family_ != Option::V6) ) {
isc_throw(DhcpConfigError, "ip-address field " << ip.toText()
<< " does not have IP address of expected family type: "
<< (family_ == Option::V4 ? "IPv4" : "IPv6")
<< " (" << getPosition("ip-address", relay_info) << ")");
if (relay_elem->getType() != Element::map) {
isc_throw(DhcpConfigError, "relay must be a map");
}
// Ok, we're done with parsing. Let's store the result in the structure
// we were given as configuration storage.
*cfg = isc::dhcp::Network::RelayInfo(ip);
ConstElementPtr address = relay_elem->get("ip-address");
ConstElementPtr addresses = relay_elem->get("ip-addresses");
if (address && addresses) {
isc_throw(DhcpConfigError,
"specify either ip-address or ip-addresses, not both");
}
if (!address && !addresses) {
isc_throw(DhcpConfigError, "ip-addresses is required");
}
// Create our resultant RelayInfo structure
*relay_info = isc::dhcp::Network::RelayInfo();
if (address) {
addAddress("ip-address", getString(relay_elem, "ip-address"),
relay_elem, relay_info);
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_CFGMGR_RELAY_IP_ADDRESS_DEPRECATED)
.arg(getPosition("ip-address", relay_elem));
return;
}
if (addresses->getType() != Element::list) {
isc_throw(DhcpConfigError, "ip-addresses must be a list "
<< " (" << getPosition("ip-addresses", relay_elem) << ")");
}
BOOST_FOREACH(ConstElementPtr address_element, addresses->listValue()) {
addAddress("ip-addresses", address_element->stringValue(),
relay_elem, relay_info);
}
}
void
RelayInfoParser::addAddress(const std::string& name,
const std::string& address_str,
ConstElementPtr relay_elem,
const isc::dhcp::Network::RelayInfoPtr& relay_info) {
boost::scoped_ptr<isc::asiolink::IOAddress> ip;
try {
ip.reset(new isc::asiolink::IOAddress(address_str));
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, "address " << address_str
<< " is not a valid: "
<< (family_ == Option::V4 ? "IPv4" : "IPv6")
<< "address"
<< " (" << getPosition(name, relay_elem) << ")");
}
// Check if the address family matches.
if ((ip->isV4() && family_ != Option::V4) ||
(ip->isV6() && family_ != Option::V6) ) {
isc_throw(DhcpConfigError, "address " << address_str
<< " is not a: "
<< (family_ == Option::V4 ? "IPv4" : "IPv6")
<< "address"
<< " (" << getPosition(name, relay_elem) << ")");
}
try {
relay_info->addAddress(*ip);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, "cannot add address: " << address_str
<< "to relay info: " << ex.what()
<< " (" << getPosition(name, relay_elem) << ")");
}
}
//****************************** PoolParser ********************************
@ -431,8 +489,7 @@ SubnetConfigParser::SubnetConfigParser(uint16_t family)
: pools_(new PoolStorage()),
address_family_(family),
options_(new CfgOption()) {
string addr = family == AF_INET ? "0.0.0.0" : "::";
relay_info_.reset(new isc::dhcp::Network::RelayInfo(IOAddress(addr)));
relay_info_.reset(new isc::dhcp::Network::RelayInfo());
}
SubnetPtr
@ -698,7 +755,7 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params,
try {
std::string hr_mode = getString(params, "reservation-mode");
subnet4->setHostReservationMode(hrModeFromText(hr_mode));
} catch (const BadValue& ex) {
} catch (const BadValue& ex) {
isc_throw(DhcpConfigError, "Failed to process specified value "
" of reservation-mode parameter: " << ex.what()
<< "(" << getPosition("reservation-mode", params) << ")");
@ -879,7 +936,7 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
OptionDataListParser opts_parser(AF_INET6);
opts_parser.parse(options_, option_data);
}
ConstElementPtr user_context = pd_pool_->get("user-context");
if (user_context) {
user_context_ = user_context;
@ -921,7 +978,7 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
pool_->allowClientClass(cclass);
}
}
if (class_list) {
const std::vector<data::ElementPtr>& classes = class_list->listValue();
for (auto cclass = classes.cbegin();
@ -991,7 +1048,6 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) {
sn6ptr->setRelayInfo(*relay_info_);
}
// Parse Host Reservations for this subnet if any.
ConstElementPtr reservations = subnet->get("reservations");
if (reservations) {
@ -1097,7 +1153,7 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params,
try {
std::string hr_mode = getString(params, "reservation-mode");
subnet6->setHostReservationMode(hrModeFromText(hr_mode));
} catch (const BadValue& ex) {
} catch (const BadValue& ex) {
isc_throw(DhcpConfigError, "Failed to process specified value "
" of reservation-mode parameter: " << ex.what()
<< "(" << getPosition("reservation-mode", params) << ")");
@ -1214,9 +1270,9 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
std::string sender_ip_str = getString(client_config, "sender-ip");
uint32_t sender_port = getUint32(client_config, "sender-port");
uint32_t sender_port = getUint32(client_config, "sender-port");
uint32_t max_queue_size = getUint32(client_config, "max-queue-size");
uint32_t max_queue_size = getUint32(client_config, "max-queue-size");
dhcp_ddns::NameChangeProtocol ncr_protocol =
getProtocol(client_config, "ncr-protocol");
@ -1245,7 +1301,7 @@ D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
if (client_config->contains("qualifying-suffix")) {
qualifying_suffix = getString(client_config, "qualifying-suffix");
found_qualifying_suffix = true;
}
}
IOAddress sender_ip(0);
if (sender_ip_str.empty()) {

View File

@ -397,12 +397,32 @@ public:
///
/// The elements currently supported are:
/// -# ip-address
/// -# ip-addresses
///
/// @param cfg configuration will be stored here
/// @param relay_info JSON structure holding relay parameters to parse
void parse(const isc::dhcp::Network::RelayInfoPtr& cfg,
isc::data::ConstElementPtr relay_info);
/// Note that ip-address and ip-addresses are mutually exclusive, with
/// former being deprecated. The use of ip-address will cause an debug
/// log to be emitted, reminded users to switch.
///
/// @param relay_info configuration will be stored here
/// @param relay_elem Element tree containing the relay and its members
/// @throw isc::dhcp::DhcpConfigError if both or neither of ip-address
/// and ip-addresses are specified.
void parse(const isc::dhcp::Network::RelayInfoPtr& relay_info,
isc::data::ConstElementPtr relay_elem);
/// @brief Attempts to add an IP address to list of relay addresses
///
/// @param name name of the element supplying the address string, (either
/// "ip-address" or "ip-addresses")
/// @param address string form of the IP address to add
/// @param relay_elem parent relay element (needed for position info)
/// @param relay_info RelayInfo to which the address should be added
/// @throw isc::dhcp::DhcpConfigError if the address string is not a valid
/// IP address, is an address of the wrong family, or is already in the
/// relay address list
void addAddress(const std::string& name, const std::string& address_str,
isc::data::ConstElementPtr relay_elem,
const isc::dhcp::Network::RelayInfoPtr& relay_info);
private:
/// Protocol family (IPv4 or IPv6)

View File

@ -89,6 +89,15 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) {
}
}
if (shared_network_data->contains("relay")) {
auto relay_parms = shared_network_data->get("relay");
if (relay_parms) {
RelayInfoParser parser(Option::V4);
Network::RelayInfoPtr relay_info(new Network::RelayInfo());
parser.parse(relay_info, relay_parms);
shared_network->setRelayInfo(*relay_info);
}
}
} catch (const DhcpConfigError&) {
// Position was already added
throw;
@ -164,6 +173,15 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) {
}
}
if (shared_network_data->contains("relay")) {
auto relay_parms = shared_network_data->get("relay");
if (relay_parms) {
RelayInfoParser parser(Option::V6);
Network::RelayInfoPtr relay_info(new Network::RelayInfo());
parser.parse(relay_info, relay_parms);
shared_network->setRelayInfo(*relay_info);
}
}
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what() << " ("
<< shared_network_data->getPosition() << ")");

View File

@ -231,8 +231,7 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
<< " specified in subnet4");
}
// Relay info.
setRelayInfo(IOAddress::IPV4_ZERO_ADDRESS());
// Timers.
setT1(t1);
setT2(t2);
@ -602,8 +601,6 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
<< " specified in subnet6");
}
// Relay info.
setRelayInfo(RelayInfo(IOAddress::IPV6_ZERO_ADDRESS()));
// Timers.
setT1(t1);
setT2(t2);

View File

@ -111,6 +111,9 @@ TEST(CfgSharedNetworks4Test, unparse) {
SharedNetwork4Ptr network2(new SharedNetwork4("dog"));
network1->setIface("eth0");
network1->addRelayAddress(IOAddress("198.16.1.1"));
network1->addRelayAddress(IOAddress("198.16.1.2"));
network2->setIface("eth1");
CfgSharedNetworks4 cfg;
@ -125,9 +128,7 @@ TEST(CfgSharedNetworks4Test, unparse) {
" \"name\": \"dog\",\n"
" \"option-data\": [ ],\n"
" \"rebind-timer\": 0,\n"
" \"relay\": {\n"
" \"ip-address\": \"0.0.0.0\"\n"
" },\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"renew-timer\": 0,\n"
" \"reservation-mode\": \"all\","
" \"subnet4\": [ ],\n"
@ -139,9 +140,7 @@ TEST(CfgSharedNetworks4Test, unparse) {
" \"name\": \"frog\",\n"
" \"option-data\": [ ],\n"
" \"rebind-timer\": 0,\n"
" \"relay\": {\n"
" \"ip-address\": \"0.0.0.0\"\n"
" },\n"
" \"relay\": { \"ip-addresses\": [ \"198.16.1.1\", \"198.16.1.2\" ] },\n"
" \"renew-timer\": 0,\n"
" \"reservation-mode\": \"all\","
" \"subnet4\": [ ],\n"

View File

@ -111,6 +111,8 @@ TEST(CfgSharedNetworks6Test, unparse) {
SharedNetwork6Ptr network2(new SharedNetwork6("dog"));
network1->setIface("eth0");
network1->addRelayAddress(IOAddress("2001:db8:1::1"));
network1->addRelayAddress(IOAddress("2001:db8:1::2"));
network2->setIface("eth1");
CfgSharedNetworks6 cfg;
@ -126,9 +128,7 @@ TEST(CfgSharedNetworks6Test, unparse) {
" \"preferred-lifetime\": 0,\n"
" \"rapid-commit\": false,\n"
" \"rebind-timer\": 0,\n"
" \"relay\": {\n"
" \"ip-address\": \"::\"\n"
" },\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"renew-timer\": 0,\n"
" \"reservation-mode\": \"all\","
" \"subnet6\": [ ],\n"
@ -141,9 +141,7 @@ TEST(CfgSharedNetworks6Test, unparse) {
" \"preferred-lifetime\": 0,\n"
" \"rapid-commit\": false,\n"
" \"rebind-timer\": 0,\n"
" \"relay\": {\n"
" \"ip-address\": \"::\"\n"
" },\n"
" \"relay\": { \"ip-addresses\": [ \"2001:db8:1::1\", \"2001:db8:1::2\" ] },\n"
" \"renew-timer\": 0,\n"
" \"reservation-mode\": \"all\","
" \"subnet6\": [ ],\n"

View File

@ -414,7 +414,7 @@ TEST(CfgSubnets4Test, selectSubnetByOptionSelect) {
// Over relay-info too
selector.giaddr_ = IOAddress("10.0.0.1");
subnet2->setRelayInfo(IOAddress("10.0.0.1"));
subnet2->addRelayAddress(IOAddress("10.0.0.1"));
EXPECT_EQ(subnet3, cfg.selectSubnet(selector));
selector.option_select_ = IOAddress("0.0.0.0");
EXPECT_EQ(subnet2, cfg.selectSubnet(selector));
@ -450,9 +450,9 @@ TEST(CfgSubnets4Test, selectSubnetByRelayAddress) {
EXPECT_FALSE(cfg.selectSubnet(selector));
// Now specify relay info
subnet1->setRelayInfo(IOAddress("10.0.0.1"));
subnet2->setRelayInfo(IOAddress("10.0.0.2"));
subnet3->setRelayInfo(IOAddress("10.0.0.3"));
subnet1->addRelayAddress(IOAddress("10.0.0.1"));
subnet2->addRelayAddress(IOAddress("10.0.0.2"));
subnet3->addRelayAddress(IOAddress("10.0.0.3"));
// And try again. This time relay-info is there and should match.
selector.giaddr_ = IOAddress("10.0.0.1");
@ -485,9 +485,9 @@ TEST(CfgSubnets4Test, selectSharedNetworkByRelayAddressNetworkLevel) {
// Now specify relay info. Note that for the second subnet we specify
// relay info on the network level.
subnet1->setRelayInfo(IOAddress("10.0.0.1"));
network->setRelayInfo(IOAddress("10.0.0.2"));
subnet3->setRelayInfo(IOAddress("10.0.0.3"));
subnet1->addRelayAddress(IOAddress("10.0.0.1"));
network->addRelayAddress(IOAddress("10.0.0.2"));
subnet3->addRelayAddress(IOAddress("10.0.0.3"));
// And try again. This time relay-info is there and should match.
selector.giaddr_ = IOAddress("10.0.0.1");
@ -524,9 +524,9 @@ TEST(CfgSubnets4Test, selectSharedNetworkByRelayAddressSubnetLevel) {
// Now specify relay info. Note that for the second subnet we specify
// relay info on the network level.
subnet1->setRelayInfo(IOAddress("10.0.0.1"));
subnet2->setRelayInfo(IOAddress("10.0.0.2"));
subnet3->setRelayInfo(IOAddress("10.0.0.3"));
subnet1->addRelayAddress(IOAddress("10.0.0.1"));
subnet2->addRelayAddress(IOAddress("10.0.0.2"));
subnet3->addRelayAddress(IOAddress("10.0.0.3"));
// And try again. This time relay-info is there and should match.
selector.giaddr_ = IOAddress("10.0.0.1");
@ -737,7 +737,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3, 125));
subnet1->allowClientClass("foo");
subnet2->setIface("lo");
subnet2->setRelayInfo(IOAddress("10.0.0.1"));
subnet2->addRelayAddress(IOAddress("10.0.0.1"));
subnet3->setIface("eth1");
subnet3->requireClientClass("foo");
subnet3->requireClientClass("bar");
@ -757,13 +757,13 @@ TEST(CfgSubnets4Test, unparseSubnet) {
" \"comment\": \"foo\",\n"
" \"id\": 123,\n"
" \"subnet\": \"192.0.2.0/26\",\n"
" \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"valid-lifetime\": 3,\n"
" \"client-class\": \"foo\",\n"
" \"4o6-interface\": \"\",\n"
@ -775,7 +775,6 @@ TEST(CfgSubnets4Test, unparseSubnet) {
"},{\n"
" \"id\": 124,\n"
" \"subnet\": \"192.0.2.64/26\",\n"
" \"relay\": { \"ip-address\": \"10.0.0.1\" },\n"
" \"interface\": \"lo\",\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
@ -783,6 +782,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ \"10.0.0.1\" ] },\n"
" \"valid-lifetime\": 3,\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
@ -794,7 +794,6 @@ TEST(CfgSubnets4Test, unparseSubnet) {
"},{\n"
" \"id\": 125,\n"
" \"subnet\": \"192.0.2.128/26\",\n"
" \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
" \"interface\": \"eth1\",\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
@ -802,6 +801,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"valid-lifetime\": 3,\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"
@ -840,13 +840,13 @@ TEST(CfgSubnets4Test, unparsePool) {
"{\n"
" \"id\": 123,\n"
" \"subnet\": \"192.0.2.0/24\",\n"
" \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
" \"match-client-id\": true,\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"server-hostname\": \"\",\n"
" \"boot-file-name\": \"\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"valid-lifetime\": 3,\n"
" \"4o6-interface\": \"\",\n"
" \"4o6-interface-id\": \"\",\n"

View File

@ -132,9 +132,9 @@ TEST(CfgSubnets6Test, selectSubnetByRelayAddress) {
EXPECT_FALSE(cfg.selectSubnet(selector));
// Now specify relay information.
subnet1->setRelayInfo(IOAddress("2001:db8:ff::1"));
subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
subnet3->setRelayInfo(IOAddress("2001:db8:ff::3"));
subnet1->addRelayAddress(IOAddress("2001:db8:ff::1"));
subnet2->addRelayAddress(IOAddress("2001:db8:ff::2"));
subnet3->addRelayAddress(IOAddress("2001:db8:ff::3"));
// And try again. This time relay-info is there and should match.
selector.first_relay_linkaddr_ = IOAddress("2001:db8:ff::1");
@ -436,7 +436,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
subnet1->setInterfaceId(ifaceid);
subnet1->allowClientClass("foo");
subnet2->setIface("lo");
subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
subnet2->addRelayAddress(IOAddress("2001:db8:ff::2"));
subnet3->setIface("eth1");
subnet3->requireClientClass("foo");
subnet3->requireClientClass("bar");
@ -456,10 +456,10 @@ TEST(CfgSubnets6Test, unparseSubnet) {
" \"comment\": \"foo\",\n"
" \"id\": 123,\n"
" \"subnet\": \"2001:db8:1::/48\",\n"
" \"relay\": { \"ip-address\": \"::\" },\n"
" \"interface-id\": \"relay.eth0\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"preferred-lifetime\": 3,\n"
" \"valid-lifetime\": 4,\n"
" \"rapid-commit\": false,\n"
@ -471,10 +471,10 @@ TEST(CfgSubnets6Test, unparseSubnet) {
"},{\n"
" \"id\": 124,\n"
" \"subnet\": \"2001:db8:2::/48\",\n"
" \"relay\": { \"ip-address\": \"2001:db8:ff::2\" },\n"
" \"interface\": \"lo\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ \"2001:db8:ff::2\" ] },\n"
" \"preferred-lifetime\": 3,\n"
" \"valid-lifetime\": 4,\n"
" \"rapid-commit\": false,\n"
@ -486,10 +486,10 @@ TEST(CfgSubnets6Test, unparseSubnet) {
"},{\n"
" \"id\": 125,\n"
" \"subnet\": \"2001:db8:3::/48\",\n"
" \"relay\": { \"ip-address\": \"::\" },\n"
" \"interface\": \"eth1\",\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"preferred-lifetime\": 3,\n"
" \"valid-lifetime\": 4,\n"
" \"rapid-commit\": false,\n"
@ -531,9 +531,9 @@ TEST(CfgSubnets6Test, unparsePool) {
"{\n"
" \"id\": 123,\n"
" \"subnet\": \"2001:db8:1::/48\",\n"
" \"relay\": { \"ip-address\": \"::\" },\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"preferred-lifetime\": 3,\n"
" \"valid-lifetime\": 4,\n"
" \"rapid-commit\": false,\n"
@ -586,9 +586,9 @@ TEST(CfgSubnets6Test, unparsePdPool) {
"{\n"
" \"id\": 123,\n"
" \"subnet\": \"2001:db8:1::/48\",\n"
" \"relay\": { \"ip-address\": \"::\" },\n"
" \"renew-timer\": 1,\n"
" \"rebind-timer\": 2,\n"
" \"relay\": { \"ip-addresses\": [ ] },\n"
" \"preferred-lifetime\": 3,\n"
" \"valid-lifetime\": 4,\n"
" \"rapid-commit\": false,\n"

View File

@ -2220,14 +2220,13 @@ TEST_F(ParseConfigTest, validRelayInfo4) {
" }";
ElementPtr json = Element::fromJSON(config_str);
// We need to set the default ip-address to something.
Network::RelayInfoPtr result(new Network::RelayInfo(asiolink::IOAddress("0.0.0.0")));
// Create an "empty" RelayInfo to hold the parsed result.
Network::RelayInfoPtr result(new Network::RelayInfo());
RelayInfoParser parser(Option::V4);
// Subnet4 parser will pass 0.0.0.0 to the RelayInfoParser
EXPECT_NO_THROW(parser.parse(result, json));
EXPECT_EQ("192.0.2.1", result->addr_.toText());
EXPECT_TRUE(result->containsAddress(IOAddress("192.0.2.1")));
}
/// @brief Checks that a bogus relay info structure for IPv4 is rejected.
@ -2253,8 +2252,8 @@ TEST_F(ParseConfigTest, bogusRelayInfo4) {
" }";
ElementPtr json_bogus3 = Element::fromJSON(config_str_bogus3);
// We need to set the default ip-address to something.
Network::RelayInfoPtr result(new Network::RelayInfo(IOAddress::IPV4_ZERO_ADDRESS()));
// Create an "empty" RelayInfo to hold the parsed result.
Network::RelayInfoPtr result(new Network::RelayInfo());
RelayInfoParser parser(Option::V4);
@ -2278,13 +2277,13 @@ TEST_F(ParseConfigTest, validRelayInfo6) {
" }";
ElementPtr json = Element::fromJSON(config_str);
// We need to set the default ip-address to something.
Network::RelayInfoPtr result(new Network::RelayInfo(asiolink::IOAddress("::")));
// Create an "empty" RelayInfo to hold the parsed result.
Network::RelayInfoPtr result(new Network::RelayInfo());
RelayInfoParser parser(Option::V6);
// Subnet4 parser will pass :: to the RelayInfoParser
EXPECT_NO_THROW(parser.parse(result, json));
EXPECT_EQ("2001:db8::1", result->addr_.toText());
EXPECT_TRUE(result->containsAddress(IOAddress("2001:db8::1")));
}
/// @brief Checks that a valid relay info structure for IPv6 can be handled
@ -2310,8 +2309,8 @@ TEST_F(ParseConfigTest, bogusRelayInfo6) {
" }";
ElementPtr json_bogus3 = Element::fromJSON(config_str_bogus3);
// We need to set the default ip-address to something.
Network::RelayInfoPtr result(new Network::RelayInfo(asiolink::IOAddress("::")));
// Create an "empty" RelayInfo to hold the parsed result.
Network::RelayInfoPtr result(new Network::RelayInfo());
RelayInfoParser parser(Option::V6);

View File

@ -21,15 +21,97 @@ using namespace isc::data;
using namespace isc::dhcp;
namespace {
class SharedNetworkParserTest : public ::testing::Test {
public:
/// @brief Structure for describing a single relay test scenario
struct RelayTest {
/// @brief Description of the test scenario, used for logging
std::string description_;
/// @brief JSON configuration body of the "relay" element
std::string json_content_;
/// @brief indicates if parsing should pass or fail
bool should_parse_;
/// @brief list of addresses expected after parsing
IOAddressList addresses_;
};
/// @brief virtual destructor
virtual ~SharedNetworkParserTest(){};
/// @brief Fetch valid shared network configuration JSON text
virtual std::string getWorkingConfig() const = 0;
ElementPtr makeTestConfig(const std::string& name, const std::string& json_content) {
// Create working config element tree
ElementPtr config = Element::fromJSON(getWorkingConfig());
// Create test element contents
ElementPtr content = Element::fromJSON(json_content);
// Add the test element to working config
config->set(name, content);
return (config);
}
/// @brief Executes a single "relay" parsing scenario
///
/// Each test pass consists of the following steps:
/// -# Attempt to parse the given JSON text
/// -# If parsing is expected to fail and it does return otherwise fatal fail
/// -# If parsing is expected to succeed, fatal fail if it does not
/// -# Verify the network's relay address list matches the expected list
/// in size and content.
///
/// @param test RelayTest which describes the test to conduct
void relayTest(const RelayTest& test) {
ElementPtr test_config;
ASSERT_NO_THROW(test_config =
makeTestConfig("relay", test.json_content_));
// Init our ref to a place holder
Network4 dummy;
Network& network = dummy;
// If parsing should fail, call parse expecting a throw.
if (!test.should_parse_) {
ASSERT_THROW(network = parseIntoNetwork(test_config), DhcpConfigError);
// No throw so test outcome is correct, nothing else to do.
return;
}
// Should parse without error, let's see if it does.
ASSERT_NO_THROW(network = parseIntoNetwork(test_config));
// It parsed, are the number of entries correct?
ASSERT_EQ(test.addresses_.size(), network.getRelayAddresses().size());
// Are the expected addresses in the list?
for (auto exp_address = test.addresses_.begin(); exp_address != test.addresses_.end();
++exp_address) {
EXPECT_TRUE(network.hasRelayAddress(*exp_address))
<< " expected address: " << (*exp_address).toText() << " not found" ;
}
}
/// @brief Attempts to parse the given configuration into a shared network
///
/// Virtual function used by relayTest() to parse a test configuration.
/// Implementation should not catch parsing exceptions.
///
/// @param test_config JSON configuration text to parse
/// @return A reference to the Network created if parsing is successful
virtual Network& parseIntoNetwork(ConstElementPtr test_config) = 0;
};
/// @brief Test fixture class for SharedNetwork4Parser class.
class SharedNetwork4ParserTest : public ::testing::Test {
class SharedNetwork4ParserTest : public SharedNetworkParserTest {
public:
/// @brief Creates valid shared network configuration.
///
/// @return Valid shared network configuration.
std::string getWorkingConfig() const {
virtual std::string getWorkingConfig() const {
std::string config = "{"
" \"user-context\": { \"comment\": \"example\" },"
" \"name\": \"bird\","
@ -88,6 +170,16 @@ public:
return (config);
}
virtual Network& parseIntoNetwork(ConstElementPtr test_config) {
// Parse configuration.
SharedNetwork4Parser parser;
network_ = parser.parse(test_config);
return (*network_);
}
private:
SharedNetwork4Ptr network_;
};
// This test verifies that shared network parser for IPv4 works properly
@ -172,14 +264,96 @@ TEST_F(SharedNetwork4ParserTest, clientClassMatchClientId) {
EXPECT_FALSE(network->getMatchClientId());
}
// This test verifies that parsing of the "relay" element.
// It checks both valid and invalid scenarios.
TEST_F(SharedNetwork4ParserTest, relayInfoTests) {
// Create the vector of test scenarios.
std::vector<RelayTest> tests = {
{
"valid ip-address #1",
"{ \"ip-address\": \"192.168.2.1\" }",
true,
{ asiolink::IOAddress("192.168.2.1") }
},
{
"invalid ip-address #1",
"{ \"ip-address\": \"not an address\" }",
false,
{ }
},
{
"invalid ip-address #2",
"{ \"ip-address\": \"2001:db8::1\" }",
false,
{ }
},
{
"valid ip-addresses #1",
"{ \"ip-addresses\": [ ] }",
true,
{}
},
{
"valid ip-addresses #2",
"{ \"ip-addresses\": [ \"192.168.2.1\" ] }",
true,
{ asiolink::IOAddress("192.168.2.1") }
},
{
"valid ip-addresses #3",
"{ \"ip-addresses\": [ \"192.168.2.1\", \"192.168.2.2\" ] }",
true,
{ asiolink::IOAddress("192.168.2.1"), asiolink::IOAddress("192.168.2.2") }
},
{
"invalid ip-addresses #1",
"{ \"ip-addresses\": [ \"not an address\" ] }",
false,
{ }
},
{
"invalid ip-addresses #2",
"{ \"ip-addresses\": [ \"2001:db8::1\" ] }",
false,
{ }
},
{
"invalid both ip-address and ip-addresses",
"{"
" \"ip-address\": \"192.168.2.1\", "
" \"ip-addresses\": [ \"192.168.2.1\", \"192.168.2.2\" ]"
" }",
false,
{ }
},
{
"invalid neither ip-address nor ip-addresses",
"{}",
false,
{ }
}
};
// Iterate over the test scenarios, verifying each prescribed
// outcome.
for (auto test = tests.begin(); test != tests.end(); ++test) {
{
SCOPED_TRACE((*test).description_);
relayTest(*test);
}
}
}
/// @brief Test fixture class for SharedNetwork6Parser class.
class SharedNetwork6ParserTest : public ::testing::Test {
class SharedNetwork6ParserTest : public SharedNetworkParserTest {
public:
/// @brief Creates valid shared network configuration.
///
/// @return Valid shared network configuration.
std::string getWorkingConfig() const {
virtual std::string getWorkingConfig() const {
std::string config = "{"
" \"name\": \"bird\","
" \"interface\": \"eth1\","
@ -228,6 +402,16 @@ public:
return (config);
}
virtual Network& parseIntoNetwork(ConstElementPtr test_config) {
// Parse configuration.
SharedNetwork6Parser parser;
network_ = parser.parse(test_config);
return (*network_);
}
private:
SharedNetwork6Ptr network_;
};
// This test verifies that shared network parser for IPv4 works properly
@ -346,4 +530,85 @@ TEST_F(SharedNetwork6ParserTest, badEvalClientClasses) {
EXPECT_THROW(network = parser.parse(config_element), DhcpConfigError);
}
// This test verifies that v6 parsing of the "relay" element.
// It checks both valid and invalid scenarios.
TEST_F(SharedNetwork6ParserTest, relayInfoTests) {
// Create the vector of test scenarios.
std::vector<RelayTest> tests = {
{
"valid ip-address #1",
"{ \"ip-address\": \"2001:db8::1\" }",
true,
{ asiolink::IOAddress("2001:db8::1") }
},
{
"invalid ip-address #1",
"{ \"ip-address\": \"not an address\" }",
false,
{ }
},
{
"invalid ip-address #2",
"{ \"ip-address\": \"192.168.2.1\" }",
false,
{ }
},
{
"valid ip-addresses #1",
"{ \"ip-addresses\": [ ] }",
true,
{}
},
{
"valid ip-addresses #2",
"{ \"ip-addresses\": [ \"2001:db8::1\" ] }",
true,
{ asiolink::IOAddress("2001:db8::1") }
},
{
"valid ip-addresses #3",
"{ \"ip-addresses\": [ \"2001:db8::1\", \"2001:db8::2\" ] }",
true,
{ asiolink::IOAddress("2001:db8::1"), asiolink::IOAddress("2001:db8::2") }
},
{
"invalid ip-addresses #1",
"{ \"ip-addresses\": [ \"not an address\" ] }",
false,
{ }
},
{
"invalid ip-addresses #2",
"{ \"ip-addresses\": [ \"192.168.1.1\" ] }",
false,
{ }
},
{
"invalid both ip-address and ip-addresses",
"{"
" \"ip-address\": \"2001:db8::1\", "
" \"ip-addresses\": [ \"2001:db8::1\", \"2001:db8::2\" ]"
" }",
false,
{ }
},
{
"invalid neither ip-address nor ip-addresses",
"{}",
false,
{ }
}
};
// Iterate over the test scenarios, verifying each prescribed
// outcome.
for (auto test = tests.begin(); test != tests.end(); ++test) {
{
SCOPED_TRACE((*test).description_);
relayTest(*test);
}
}
}
} // end of anonymous namespace

View File

@ -265,6 +265,26 @@ TEST(SharedNetwork4Test, getPreferredSubnet) {
EXPECT_EQ(subnet3->getID(), preferred->getID());
}
// This test verifies operations on the network's relay list
TEST(SharedNetwork4Test, relayInfoList) {
SharedNetwork4Ptr network(new SharedNetwork4("frog"));
EXPECT_FALSE(network->hasRelays());
EXPECT_FALSE(network->hasRelayAddress(IOAddress("192.168.2.1")));
// Add relay addresses to the network.
network->addRelayAddress(IOAddress("192.168.2.1"));
network->addRelayAddress(IOAddress("192.168.2.2"));
network->addRelayAddress(IOAddress("192.168.2.3"));
// Verify we believe we have relays and we can match them accordingly.
EXPECT_TRUE(network->hasRelays());
EXPECT_TRUE(network->hasRelayAddress(IOAddress("192.168.2.1")));
EXPECT_TRUE(network->hasRelayAddress(IOAddress("192.168.2.2")));
EXPECT_TRUE(network->hasRelayAddress(IOAddress("192.168.2.3")));
EXPECT_FALSE(network->hasRelayAddress(IOAddress("192.168.2.4")));
}
// This test verifies that unparsing shared network returns valid structure.
TEST(SharedNetwork4Test, unparse) {
SharedNetwork4Ptr network(new SharedNetwork4("frog"));
@ -281,10 +301,14 @@ TEST(SharedNetwork4Test, unparse) {
data::ElementPtr ctx = data::Element::fromJSON(uc);
network->setContext(ctx);
network->requireClientClass("foo");
network->addRelayAddress(IOAddress("192.168.2.1"));
// Add several subnets.
Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30,
SubnetID(1)));
subnet1->addRelayAddress(IOAddress("10.0.0.1"));
subnet1->addRelayAddress(IOAddress("10.0.0.2"));
Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"), 24, 10, 20, 30,
SubnetID(2)));
network->add(subnet1);
@ -298,7 +322,7 @@ TEST(SharedNetwork4Test, unparse) {
" \"option-data\": [ ],\n"
" \"rebind-timer\": 150,\n"
" \"relay\": {\n"
" \"ip-address\": \"0.0.0.0\"\n"
" \"ip-addresses\": [ \"192.168.2.1\" ]\n"
" },\n"
" \"renew-timer\": 100,\n"
" \"require-client-classes\": [ \"foo\" ],\n"
@ -317,7 +341,7 @@ TEST(SharedNetwork4Test, unparse) {
" \"pools\": [ ],\n"
" \"rebind-timer\": 20,\n"
" \"relay\": {\n"
" \"ip-address\": \"0.0.0.0\"\n"
" \"ip-addresses\": [ \"10.0.0.1\", \"10.0.0.2\" ]\n"
" },\n"
" \"renew-timer\": 10,\n"
" \"reservation-mode\": \"all\",\n"
@ -337,7 +361,7 @@ TEST(SharedNetwork4Test, unparse) {
" \"pools\": [ ],\n"
" \"rebind-timer\": 20,\n"
" \"relay\": {\n"
" \"ip-address\": \"0.0.0.0\"\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"renew-timer\": 10,\n"
" \"reservation-mode\": \"all\",\n"
@ -658,6 +682,26 @@ TEST(SharedNetwork6Test, getPreferredSubnet) {
EXPECT_EQ(subnet3->getID(), preferred->getID());
}
// This test verifies operations on the network's relay list
TEST(SharedNetwork6Test, relayInfoList) {
SharedNetwork6Ptr network(new SharedNetwork6("frog"));
EXPECT_FALSE(network->hasRelays());
EXPECT_FALSE(network->hasRelayAddress(IOAddress("2001:db8:2::1")));
// Add realy addresses to the network.
network->addRelayAddress(IOAddress("2001:db8:2::1"));
network->addRelayAddress(IOAddress("2001:db8:2::2"));
network->addRelayAddress(IOAddress("2001:db8:2::3"));
// Verify we believe we have relays and we can match them accordingly.
EXPECT_TRUE(network->hasRelays());
EXPECT_TRUE(network->hasRelayAddress(IOAddress("2001:db8:2::1")));
EXPECT_TRUE(network->hasRelayAddress(IOAddress("2001:db8:2::2")));
EXPECT_TRUE(network->hasRelayAddress(IOAddress("2001:db8:2::3")));
EXPECT_FALSE(network->hasRelayAddress(IOAddress("2001:db8:2::4")));
}
// This test verifies that unparsing shared network returns valid structure.
TEST(SharedNetwork6Test, unparse) {
SharedNetwork6Ptr network(new SharedNetwork6("frog"));
@ -673,11 +717,16 @@ TEST(SharedNetwork6Test, unparse) {
network->setContext(ctx);
network->requireClientClass("foo");
network->addRelayAddress(IOAddress("2001:db8:1::7"));
network->addRelayAddress(IOAddress("2001:db8:1::8"));
// Add several subnets.
Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 10, 20, 30,
40, SubnetID(1)));
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 16, 10, 20, 30, 40,
SubnetID(2)));
subnet2->addRelayAddress(IOAddress("2001:db8:1::8"));
network->add(subnet1);
network->add(subnet2);
@ -689,7 +738,7 @@ TEST(SharedNetwork6Test, unparse) {
" \"rapid-commit\": true,\n"
" \"rebind-timer\": 150,\n"
" \"relay\": {\n"
" \"ip-address\": \"::\"\n"
" \"ip-addresses\": [ \"2001:db8:1::7\", \"2001:db8:1::8\" ]\n"
" },\n"
" \"renew-timer\": 100,\n"
" \"require-client-classes\": [ \"foo\" ],\n"
@ -704,7 +753,7 @@ TEST(SharedNetwork6Test, unparse) {
" \"rapid-commit\": false,\n"
" \"rebind-timer\": 20,\n"
" \"relay\": {\n"
" \"ip-address\": \"::\"\n"
" \"ip-addresses\": [ ]\n"
" },\n"
" \"renew-timer\": 10,\n"
" \"reservation-mode\": \"all\",\n"
@ -720,7 +769,7 @@ TEST(SharedNetwork6Test, unparse) {
" \"rapid-commit\": false,\n"
" \"rebind-timer\": 20,\n"
" \"relay\": {\n"
" \"ip-address\": \"::\"\n"
" \"ip-addresses\": [ \"2001:db8:1::8\" ]\n"
" },\n"
" \"renew-timer\": 10,\n"
" \"reservation-mode\": \"all\",\n"

View File

@ -76,7 +76,7 @@ TEST(Subnet4Test, inRange) {
EXPECT_EQ(2000, subnet.getT2());
EXPECT_EQ(3000, subnet.getValid());
EXPECT_EQ("0.0.0.0", subnet.getRelayInfo().addr_.toText());
EXPECT_FALSE(subnet.hasRelays());
EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0")));
EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0")));
@ -87,15 +87,34 @@ TEST(Subnet4Test, inRange) {
EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255")));
}
// Checks whether the relay field has sane default and if it can
// be changed, stored and retrieved
// Checks whether the relay list is empty by default
// and basic operations function
TEST(Subnet4Test, relay) {
Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
EXPECT_EQ("0.0.0.0", subnet.getRelayInfo().addr_.toText());
// Should be empty.
EXPECT_FALSE(subnet.hasRelays());
EXPECT_EQ(0, subnet.getRelayAddresses().size());
subnet.setRelayInfo(IOAddress("192.0.123.45"));
EXPECT_EQ("192.0.123.45", subnet.getRelayInfo().addr_.toText());
// Matching should fail.
EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("192.0.123.45")));
// Should be able to add them.
subnet.addRelayAddress(IOAddress("192.0.123.45"));
subnet.addRelayAddress(IOAddress("192.0.123.46"));
// Should not be empty.
EXPECT_TRUE(subnet.hasRelays());
// Should be two in the list.
EXPECT_EQ(2, subnet.getRelayAddresses().size());
// Should be able to match them if they are there.
EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("192.0.123.45")));
EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("192.0.123.46")));
// Should not match those that are not.
EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("192.0.123.47")));
}
// Checks whether siaddr field can be set and retrieved correctly.
@ -681,16 +700,34 @@ TEST(Subnet6Test, inRange) {
EXPECT_FALSE(subnet.inRange(IOAddress("::")));
}
// Checks whether the relay field has sane default and if it can
// be changed, stored and retrieved
// Checks whether the relay list is empty by default
// and basic operations function
TEST(Subnet6Test, relay) {
Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
EXPECT_EQ("::", subnet.getRelayInfo().addr_.toText());
// Should be empty.
EXPECT_FALSE(subnet.hasRelays());
EXPECT_EQ(0, subnet.getRelayAddresses().size());
subnet.setRelayInfo(IOAddress("2001:ffff::1"));
// Matching should fail.
EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("2001:ffff::45")));
EXPECT_EQ("2001:ffff::1", subnet.getRelayInfo().addr_.toText());
// Should be able to add them.
subnet.addRelayAddress(IOAddress("2001:ffff::45"));
subnet.addRelayAddress(IOAddress("2001:ffff::46"));
// Should not be empty.
EXPECT_TRUE(subnet.hasRelays());
// Should be two in the list.
EXPECT_EQ(2, subnet.getRelayAddresses().size());
// Should be able to match them if they are there.
EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("2001:ffff::45")));
EXPECT_TRUE(subnet.hasRelayAddress(IOAddress("2001:ffff::46")));
// Should not match those that are not.
EXPECT_FALSE(subnet.hasRelayAddress(IOAddress("2001:ffff::47")));
}
// Test checks whether the number of addresses available in the pools are

View File

@ -1,4 +1,3 @@
// Generated 201804111443
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@ -1,4 +1,3 @@
// Generated 201804111443
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@ -1,4 +1,3 @@
// Generated 201804111443
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++