Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Adam Osuchowski
Kea
Commits
46868726
Commit
46868726
authored
May 08, 2013
by
Tomek Mrugalski
🛰
Browse files
[2898] Second part of changes after review
parent
a19cdcff
Changes
7
Hide whitespace changes
Inline
Side-by-side
doc/guide/bind10-guide.xml
View file @
46868726
...
...
@@ -4871,43 +4871,54 @@ should include options from the isc option space:
<section
id=
"dhcp6-relays"
>
<title>
DHCPv6 Relays
</title>
<para>
DHCPv6 server supports remote clients connected via relays. Server
that has many subnets defined and receives a request from client, must
select appropriate subnet for it. Remote clients there are two
mechanisms that can be used here. The first one is based on
interface-id options. While forwarding client's message, relays may
insert interface-id option that identifies the interface on which the
client message was received on. Some relays allow configuration of
that parameter, but it is sometimes hardcoded. This may range from
very simple (e.g. "vlan100") to very cryptic. One example used by real
hardware was "ISAM144|299|ipv6|nt:vp:1:110"). This may seem
meaningless, but that information is sufficient for its
purpose. Server may use it to select appropriate subnet and the relay
will know which interface to use for response transmission when it
gets that value back. This value must be unique in the whole
network. Server configuration must match whatever values are inserted
by the relays.
A DHCPv6 server with multiple subnets defined must select the
appropriate subnet when it receives a request from client. For clients
connected via relays, two mechanisms are used.
</para>
<para>
The
second way in which server may pick the proper subnet is by using
linkaddr field in the RELAY_FORW message. Name of this field is somewhat
misleading. It does not contain link-layer address, but an
address that
is
used to identify a link. Th
is typically is a global address. Kea
server checks if that address belongs
to a
ny
defined subnet
6. I
f it does,
that subnet is selected for client's
request.
The
first uses the linkaddr field in the RELAY_FORW message. The name
of this field is somewhat misleading in that it does not contain link-layer
address: instead, it holds an address (typically a global
address
)
that
is
used to identify a link. Th
e DHCPv6 server checks if the address belongs
to a defined subnet
and, i
f it does,
that subnet is selected for the client's
request.
</para>
<para>
It should be noted that "interface" that defines which local network
interface can be used to access a given subnet and "interface-id" that
specify the content of the interface-id option used by relays are mutually
exclusive. A subnet cannot be both reachable locally (direct traffic) and
via relays (remote traffic). Specifying both is a configuration error and
Kea server will refuse such configuration.
The second mechanism is based on interface-id options. While forwarding client's
message, relays may insert an interface-id option into the message that
identifies the interface on the relay that received client message. (Some
relays allow configuration of that parameter, but it is sometimes
hardcoded and may range from very simple (e.g. "vlan100") to very cryptic:
one example seen on real hardware was "ISAM144|299|ipv6|nt:vp:1:110"). The
server can use this information to select the appropriate subnet.
The information is also returned to the relay which then knows which
interface to use to transmit the response to the client. In order to
use this successfully, the relay interface IDs must be unique within
the network, and the server configuration must match those values.
</para>
<para>
When configuring the DHCPv6 server, it should be noted that two
similarly-named parameters can be configured for a subnet:
<itemizedlist>
<listitem><simpara>
"interface" defines which local network interface can be used
to access a given subnet.
</simpara></listitem>
<listitem><simpara>
"interface-id" specifies the content of the interface-id option
used by relays to identify the interface on the relay to which
the response packet is sent.
</simpara></listitem>
</itemizedlist>
The two are mutually exclusive: a subnet cannot be both reachable locally
(direct traffic) and via relays (remote traffic). Specifying both is a
configuration error and the DHCPv6 server will refuse such a configuration.
</para>
<para>
To specify interface-id with value "vlan123", the following commands can
be used:
<screen>
<screen>
>
<userinput>
config add Dhcp6/subnet6
</userinput>
>
<userinput>
config set Dhcp6/subnet6[0]/subnet "2001:db8:beef::/48"
</userinput>
>
<userinput>
config set Dhcp6/subnet6[0]/pool [ "2001:db8:beef::/48" ]
</userinput>
...
...
src/lib/dhcp/pkt6.cc
View file @
46868726
...
...
@@ -73,56 +73,58 @@ uint16_t Pkt6::len() {
}
OptionPtr
Pkt6
::
getAnyRelayOption
(
uint16_t
opt_type
,
RelaySearchOrder
order
)
{
int
start
=
0
;
int
end
=
0
;
int
direction
=
0
;
if
(
relay_info_
.
empty
())
{
//
t
here's no relay info, this is a direct message
//
T
here's no relay info, this is a direct message
return
(
OptionPtr
());
}
int
start
=
0
;
// First relay to check
int
end
=
0
;
// Last relay to check
int
direction
=
0
;
// How we going to iterate: forward or backward?
switch
(
order
)
{
case
RELAY_SEARCH_FROM_CLIENT
:
//
s
earch backwards
//
S
earch backwards
start
=
relay_info_
.
size
()
-
1
;
end
=
0
;
direction
=
-
1
;
break
;
case
RELAY_SEARCH_FROM_SERVER
:
//
s
earch forward
//
S
earch forward
start
=
0
;
end
=
relay_info_
.
size
()
-
1
;
direction
=
1
;
break
;
case
RELAY_
SEARCH
_FIRST
:
//
l
ook at the innermost relay only
case
RELAY_
GET
_FIRST
:
//
L
ook at the innermost relay only
start
=
relay_info_
.
size
()
-
1
;
end
=
start
;
direction
=
0
;
direction
=
1
;
break
;
case
RELAY_
SEARCH
_LAST
:
//
l
ook at the outermost relay only
case
RELAY_
GET
_LAST
:
//
L
ook at the outermost relay only
start
=
0
;
end
=
0
;
direction
=
0
;
direction
=
1
;
}
//
t
his is a tricky loop. It must go from start to end, but it must work in
//
T
his is a tricky loop. It must go from start to end, but it must work in
// both directions (start > end; or start < end). We can't use regular
// exit condition, because we don't know whether to use i <= end or i >= end
for
(
int
i
=
start
;
;
i
+=
direction
)
{
// exit condition, because we don't know whether to use i <= end or i >= end.
// That's why we check if in the next iteration we would go past the
// list (end + direction). It is similar to STL concept of end pointing
// to a place after the last element
for
(
int
i
=
start
;
i
!=
end
+
direction
;
i
+=
direction
)
{
OptionPtr
opt
=
getRelayOption
(
opt_type
,
i
);
if
(
opt
)
{
return
(
opt
);
}
if
(
i
==
end
)
{
break
;
}
}
return
getRelayOption
(
opt_type
,
end
);
// We iterated over specified relays and haven't found what we were
// looking for
return
(
OptionPtr
());
}
...
...
@@ -539,27 +541,28 @@ const char* Pkt6::getName() const {
void
Pkt6
::
copyRelayInfo
(
const
Pkt6Ptr
&
question
)
{
//
w
e use index rather than iterator, because we need that as a parameter
//
W
e use index rather than iterator, because we need that as a parameter
// passed to getRelayOption()
for
(
int
i
=
0
;
i
<
question
->
relay_info_
.
size
();
++
i
)
{
RelayInfo
x
;
x
.
msg_type_
=
DHCPV6_RELAY_REPL
;
x
.
hop_count_
=
question
->
relay_info_
[
i
].
hop_count_
;
x
.
linkaddr_
=
question
->
relay_info_
[
i
].
linkaddr_
;
x
.
peeraddr_
=
question
->
relay_info_
[
i
].
peeraddr_
;
// Is there interface-id option in this nesting level
if there is,
// we need to echo it back
RelayInfo
info
;
info
.
msg_type_
=
DHCPV6_RELAY_REPL
;
info
.
hop_count_
=
question
->
relay_info_
[
i
].
hop_count_
;
info
.
linkaddr_
=
question
->
relay_info_
[
i
].
linkaddr_
;
info
.
peeraddr_
=
question
->
relay_info_
[
i
].
peeraddr_
;
// Is there
an
interface-id option in this nesting level
?
//
If there is,
we need to echo it back
OptionPtr
opt
=
question
->
getRelayOption
(
D6O_INTERFACE_ID
,
i
);
// taken from question->RelayInfo_[i].options_
if
(
opt
)
{
x
.
options_
.
insert
(
pair
<
int
,
boost
::
shared_ptr
<
Option
>
>
(
opt
->
getType
(),
opt
));
info
.
options_
.
insert
(
make_pair
(
opt
->
getType
(),
opt
));
}
/// @todo:
i
mplement support for ERO (Echo Request Option, RFC4994)
/// @todo:
I
mplement support for ERO (Echo Request Option, RFC4994)
// add this relay-repl info to our message
relay_info_
.
push_back
(
x
);
// Add this relay-forw info (client's message) to our relay-repl
// message (server's response)
relay_info_
.
push_back
(
info
);
}
}
...
...
src/lib/dhcp/pkt6.h
View file @
46868726
...
...
@@ -60,14 +60,14 @@ public:
/// relay closest to the server (i.e. outermost in the encapsulated
/// message, which also means it was the last relay that relayed
/// the received message and will be the first one to process
/// server's response). RELAY_
SEARCH
_FIRST
is
option from
the first
///
rela
y (closest to the client), RELAY_
SEARCH_LAST is the
/// last relay (closest to the server).
/// server's response). RELAY_
GET
_FIRST
will try to get
option from
///
the first relay onl
y (closest to the client), RELAY_
GET_LAST will
///
try to get option form the the
last relay (closest to the server).
enum
RelaySearchOrder
{
RELAY_SEARCH_FROM_CLIENT
=
1
,
RELAY_SEARCH_FROM_SERVER
=
2
,
RELAY_
SEARCH
_FIRST
=
3
,
RELAY_
SEARCH
_LAST
=
4
RELAY_
GET
_FIRST
=
3
,
RELAY_
GET
_LAST
=
4
};
/// @brief structure that describes a single relay information
...
...
@@ -226,12 +226,12 @@ public:
/// @return pointer to the option (or NULL if there is no such option)
OptionPtr
getRelayOption
(
uint16_t
option_code
,
uint8_t
nesting_level
);
/// @brief
r
eturn
s
first instance of a specified option
/// @brief
R
eturn first instance of a specified option
///
/// When client's packet traverses multiple relays, each passing relay
///
may
insert extra options. This method allows
getting
specific instance
/// o
f a given option (
closest to the client, closest to the server,
etc.)
/// See @ref RelaySearchOrder for detailed description.
/// When
a
client's packet traverses multiple relays, each passing relay
may
/// insert extra options. This method allows
the
specific instance
of a given
/// o
ption to be obtained (e.g.
closest to the client, closest to the server,
///
etc.)
See @ref RelaySearchOrder for
a
detailed description.
///
/// @param option_code searched option
/// @param order option search order (see @ref RelaySearchOrder)
...
...
src/lib/dhcp/tests/pkt6_unittest.cc
View file @
46868726
...
...
@@ -609,8 +609,14 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
// First check that the getAnyRelayOption does not confuse client options
// and relay options
OptionPtr
opt
=
msg
->
getAnyRelayOption
(
300
,
Pkt6
::
RELAY_SEARCH_FROM_CLIENT
);
// 300 is a client option, present in the message itself.
OptionPtr
opt
=
msg
->
getAnyRelayOption
(
300
,
Pkt6
::
RELAY_SEARCH_FROM_CLIENT
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
300
,
Pkt6
::
RELAY_SEARCH_FROM_SERVER
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
300
,
Pkt6
::
RELAY_GET_FIRST
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
300
,
Pkt6
::
RELAY_GET_LAST
);
EXPECT_FALSE
(
opt
);
// Option 200 is added in every relay.
...
...
@@ -628,12 +634,12 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
EXPECT_TRUE
(
opt
->
equal
(
relay1_opt1
));
// We just want option from the first relay (closest to the client)
opt
=
msg
->
getAnyRelayOption
(
200
,
Pkt6
::
RELAY_
SEARCH
_FIRST
);
opt
=
msg
->
getAnyRelayOption
(
200
,
Pkt6
::
RELAY_
GET
_FIRST
);
ASSERT_TRUE
(
opt
);
EXPECT_TRUE
(
opt
->
equal
(
relay3_opt1
));
// We just want option from the last relay (closest to the server)
opt
=
msg
->
getAnyRelayOption
(
200
,
Pkt6
::
RELAY_
SEARCH
_LAST
);
opt
=
msg
->
getAnyRelayOption
(
200
,
Pkt6
::
RELAY_
GET
_LAST
);
ASSERT_TRUE
(
opt
);
EXPECT_TRUE
(
opt
->
equal
(
relay1_opt1
));
...
...
@@ -647,12 +653,24 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
ASSERT_TRUE
(
opt
);
EXPECT_TRUE
(
opt
->
equal
(
relay2_opt1
));
opt
=
msg
->
getAnyRelayOption
(
100
,
Pkt6
::
RELAY_SEARCH_FIRST
);
opt
=
msg
->
getAnyRelayOption
(
100
,
Pkt6
::
RELAY_GET_FIRST
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
100
,
Pkt6
::
RELAY_GET_LAST
);
EXPECT_FALSE
(
opt
);
// Finally, try to get an option that does not exist
opt
=
msg
->
getAnyRelayOption
(
500
,
Pkt6
::
RELAY_GET_FIRST
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
1
00
,
Pkt6
::
RELAY_
SEARCH
_LAST
);
opt
=
msg
->
getAnyRelayOption
(
5
00
,
Pkt6
::
RELAY_
GET
_LAST
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
500
,
Pkt6
::
RELAY_SEARCH_FROM_SERVER
);
EXPECT_FALSE
(
opt
);
opt
=
msg
->
getAnyRelayOption
(
500
,
Pkt6
::
RELAY_SEARCH_FROM_CLIENT
);
EXPECT_FALSE
(
opt
);
}
}
src/lib/dhcpsrv/cfgmgr.cc
View file @
46868726
...
...
@@ -183,7 +183,8 @@ Subnet6Ptr CfgMgr::getSubnet6(OptionPtr iface_id_option) {
return
(
Subnet6Ptr
());
}
// If there is more than one, we need to choose the proper one
// Let's iterate over all subnets and for those that have interface-id
// defined, check if the interface-id is equal to what we are looking for
for
(
Subnet6Collection
::
iterator
subnet
=
subnets6_
.
begin
();
subnet
!=
subnets6_
.
end
();
++
subnet
)
{
if
(
(
*
subnet
)
->
getInterfaceId
()
&&
...
...
src/lib/dhcpsrv/dhcpsrv_messages.mes
View file @
46868726
...
...
@@ -105,14 +105,14 @@ This is a debug message reporting that the DHCP configuration manager
has returned the specified IPv6 subnet for a packet received over
given interface. This particular subnet was selected, because it
was specified as being directly reachable over given interface. (see
'interface' parameter in subnet6 definition).
'interface' parameter in
the
subnet6 definition).
% DHCPSRV_CFGMGR_SUBNET6_IFACE_ID selected subnet %1 (interface-id match) for incoming packet
This is a debug message reporting that the DHCP configuration manager
has returned the specified IPv6 subnet for a received packet. This particular
subnet was selected, because value of interface-id option matched what was
configured in server's interface-id option for that selected subnet6.
(see 'interface-id' parameter in subnet6 definition).
(see 'interface-id' parameter in
the
subnet6 definition).
% DHCPSRV_CLOSE_DB closing currently open %1 database
This is a debug message, issued when the DHCP server closes the currently
...
...
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
View file @
46868726
...
...
@@ -49,7 +49,7 @@ TEST(ValueStorageTest, BooleanTesting) {
EXPECT_FALSE
(
testStore
.
getParam
(
"firstBool"
));
EXPECT_TRUE
(
testStore
.
getParam
(
"secondBool"
));
// Verify that we can update param
a
ters.
// Verify that we can update param
e
ters.
testStore
.
setParam
(
"firstBool"
,
true
);
testStore
.
setParam
(
"secondBool"
,
false
);
...
...
@@ -437,6 +437,10 @@ TEST_F(CfgMgrTest, subnet6Interface) {
// Now we have only one subnet, any request will be served from it
EXPECT_EQ
(
subnet1
,
cfg_mgr
.
getSubnet6
(
"foo"
));
// Check that the interface name is checked even when there is
// only one subnet defined.
EXPECT_FALSE
(
cfg_mgr
.
getSubnet6
(
"bar"
));
// If we have only a single subnet and the request came from a local
// address, let's use that subnet
EXPECT_EQ
(
subnet1
,
cfg_mgr
.
getSubnet6
(
IOAddress
(
"fe80::dead:beef"
)));
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment