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
ISC Open Source Projects
Kea
Commits
1a9a8b52
Commit
1a9a8b52
authored
Jul 21, 2014
by
Marcin Siodelski
Browse files
[3320] Basic implementation of the Requested IP Address support.
parent
4852d3ec
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_srv.cc
View file @
1a9a8b52
...
...
@@ -942,7 +942,15 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
}
// client-id is not mandatory in DHCPv4
IOAddress
hint
=
question
->
getYiaddr
();
// Try to get the Requested IP Address option and use the address as a hint
// for the allocation engine. If the server doesn't already have a lease
// for this client it will try to allocate the one requested.
OptionCustomPtr
opt_requested_address
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
question
->
getOption
(
DHO_DHCP_REQUESTED_ADDRESS
));
IOAddress
hint
(
"0.0.0.0"
);
if
(
opt_requested_address
)
{
hint
=
opt_requested_address
->
readAddress
();
}
HWAddrPtr
hwaddr
=
question
->
getHWAddr
();
...
...
@@ -1078,7 +1086,7 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
}
else
{
// Allocation engine did not allocate a lease. The engine logged
// cause of that failure. The only thing left is to insert
// cause of that failure. The onl
x
y thing left is to insert
// status code to pass the sad news to the client.
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_DETAIL
,
fake_allocation
?
...
...
src/bin/dhcp4/tests/Makefile.am
View file @
1a9a8b52
...
...
@@ -90,6 +90,7 @@ dhcp4_unittests_SOURCES += fqdn_unittest.cc
dhcp4_unittests_SOURCES
+=
marker_file.cc
dhcp4_unittests_SOURCES
+=
dhcp4_client.cc dhcp4_client.h
dhcp4_unittests_SOURCES
+=
inform_unittest.cc
dhcp4_unittests_SOURCES
+=
dora_unittest.cc
if
CONFIG_BACKEND_BUNDY
# For Bundy backend, we only need to run the usual tests. There are no
...
...
src/bin/dhcp4/tests/dhcp4_client.cc
View file @
1a9a8b52
...
...
@@ -21,6 +21,8 @@
#include <boost/pointer_cast.hpp>
#include <cstdlib>
using
namespace
isc
::
asiolink
;
namespace
isc
{
namespace
dhcp
{
namespace
test
{
...
...
@@ -38,9 +40,10 @@ Dhcp4Client::Configuration::reset() {
log_servers_
.
clear
();
quotes_servers_
.
clear
();
serverid_
=
asiolink
::
IOAddress
(
"0.0.0.0"
);
lease_
=
Lease4
();
}
Dhcp4Client
::
Dhcp4Client
()
:
Dhcp4Client
::
Dhcp4Client
(
const
Dhcp4Client
::
State
&
state
)
:
config_
(),
curr_transid_
(
0
),
dest_addr_
(
"255.255.255.255"
),
...
...
@@ -49,10 +52,12 @@ Dhcp4Client::Dhcp4Client() :
requested_options_
(),
server_facing_relay_addr_
(
"10.0.0.2"
),
srv_
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>
(
new
NakedDhcpv4Srv
(
0
))),
state_
(
state
),
use_relay_
(
false
)
{
}
Dhcp4Client
::
Dhcp4Client
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>&
srv
)
:
Dhcp4Client
::
Dhcp4Client
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>&
srv
,
const
Dhcp4Client
::
State
&
state
)
:
config_
(),
curr_transid_
(
0
),
dest_addr_
(
"255.255.255.255"
),
...
...
@@ -61,6 +66,7 @@ Dhcp4Client::Dhcp4Client(boost::shared_ptr<NakedDhcpv4Srv>& srv) :
requested_options_
(),
server_facing_relay_addr_
(
"10.0.0.2"
),
srv_
(
srv
),
state_
(
state
),
use_relay_
(
false
)
{
}
...
...
@@ -104,7 +110,12 @@ Dhcp4Client::applyConfiguration() {
config_
.
serverid_
=
opt_serverid
->
readAddress
();
}
/// @todo Other possible configuration, e.g. lease.
/// @todo Set the valid lifetime, t1, t2 etc.
config_
.
lease_
=
Lease4
(
IOAddress
(
context_
.
response_
->
getYiaddr
()),
&
context_
.
response_
->
getHWAddr
()
->
hwaddr_
[
0
],
context_
.
response_
->
getHWAddr
()
->
hwaddr_
.
size
(),
0
,
0
,
0
,
0
,
0
,
time
(
NULL
),
0
,
false
,
false
,
""
);
}
void
...
...
@@ -123,21 +134,37 @@ Dhcp4Client::createMsg(const uint8_t msg_type) {
return
(
msg
);
}
void
Dhcp4Client
::
doDiscover
(
const
boost
::
shared_ptr
<
IOAddress
>&
requested_addr
)
{
context_
.
query_
=
createMsg
(
DHCPDISCOVER
);
// Request options if any.
includePRL
();
if
(
requested_addr
)
{
Option4AddrLstPtr
opt_requested_addr
(
new
Option4AddrLst
(
DHO_DHCP_REQUESTED_ADDRESS
,
IOAddress
(
*
requested_addr
)));
context_
.
query_
->
addOption
(
opt_requested_addr
);
}
// Send the message to the server.
sendMsg
(
context_
.
query_
);
// Expect response.
context_
.
response_
=
receiveOneMsg
();
}
void
Dhcp4Client
::
doDORA
(
const
boost
::
shared_ptr
<
IOAddress
>&
requested_addr
)
{
doDiscover
(
requested_addr
);
if
(
context_
.
response_
&&
(
context_
.
response_
->
getType
()
==
DHCPOFFER
))
{
doRequest
(
requested_addr
);
}
}
void
Dhcp4Client
::
doInform
(
const
bool
set_ciaddr
)
{
context_
.
query_
=
createMsg
(
DHCPINFORM
);
// Request options if any.
if
(
!
requested_options_
.
empty
())
{
// Include Parameter Request List if at least one option code
// has been specified to be requested.
OptionUint8ArrayPtr
prl
(
new
OptionUint8Array
(
Option
::
V4
,
DHO_DHCP_PARAMETER_REQUEST_LIST
));
for
(
std
::
set
<
uint8_t
>::
const_iterator
opt
=
requested_options_
.
begin
();
opt
!=
requested_options_
.
end
();
++
opt
)
{
prl
->
addValue
(
*
opt
);
}
context_
.
query_
->
addOption
(
prl
);
}
includePRL
();
// The client sending a DHCPINFORM message has an IP address obtained
// by some other means, e.g. static configuration. The lease which we
// are using here is most likely set by the createLease method.
...
...
@@ -159,6 +186,72 @@ Dhcp4Client::doInform(const bool set_ciaddr) {
}
}
void
Dhcp4Client
::
doRequest
(
const
boost
::
shared_ptr
<
IOAddress
>&
requested_addr
)
{
context_
.
query_
=
createMsg
(
DHCPREQUEST
);
// Set ciaddr.
if
((
state_
==
SELECTING
)
||
(
state_
==
INIT_REBOOT
))
{
context_
.
query_
->
setCiaddr
(
IOAddress
(
"0.0.0.0"
));
}
else
{
context_
.
query_
->
setCiaddr
(
IOAddress
(
config_
.
lease_
.
addr_
));
}
// Requested IP address.
if
((
state_
==
SELECTING
)
||
(
state_
==
INIT_REBOOT
))
{
if
(
context_
.
response_
&&
(
context_
.
response_
->
getType
()
==
DHCPOFFER
)
&&
(
context_
.
response_
->
getYiaddr
()
!=
IOAddress
(
"0.0.0.0"
)))
{
Option4AddrLstPtr
opt_requested_addr
(
new
Option4AddrLst
(
DHO_DHCP_REQUESTED_ADDRESS
,
IOAddress
(
context_
.
response_
->
getYiaddr
())));
context_
.
query_
->
addOption
(
opt_requested_addr
);
}
else
{
isc_throw
(
Dhcp4ClientError
,
"error sending the DHCPREQUEST because"
" the received DHCPOFFER message was invalid"
);
}
}
// Server identifier.
if
(
state_
==
SELECTING
)
{
if
(
context_
.
response_
)
{
OptionPtr
opt_serverid
=
context_
.
response_
->
getOption
(
DHO_DHCP_SERVER_IDENTIFIER
);
if
(
!
opt_serverid
)
{
isc_throw
(
Dhcp4ClientError
,
"missing server identifier in the"
" server's response"
);
}
context_
.
query_
->
addOption
(
opt_serverid
);
}
}
// Request options if any.
includePRL
();
// Send the message to the server.
sendMsg
(
context_
.
query_
);
// Expect response.
context_
.
response_
=
receiveOneMsg
();
// If the server has responded, store the configuration received.
if
(
context_
.
response_
)
{
applyConfiguration
();
}
}
void
Dhcp4Client
::
includePRL
()
{
if
(
!
requested_options_
.
empty
()
&&
context_
.
query_
)
{
// Include Parameter Request List if at least one option code
// has been specified to be requested.
OptionUint8ArrayPtr
prl
(
new
OptionUint8Array
(
Option
::
V4
,
DHO_DHCP_PARAMETER_REQUEST_LIST
));
for
(
std
::
set
<
uint8_t
>::
const_iterator
opt
=
requested_options_
.
begin
();
opt
!=
requested_options_
.
end
();
++
opt
)
{
prl
->
addValue
(
*
opt
);
}
context_
.
query_
->
addOption
(
prl
);
}
}
HWAddrPtr
Dhcp4Client
::
generateHWAddr
(
const
uint8_t
htype
)
const
{
if
(
htype
!=
HTYPE_ETHER
)
{
...
...
src/bin/dhcp4/tests/dhcp4_client.h
View file @
1a9a8b52
...
...
@@ -27,6 +27,13 @@ namespace isc {
namespace
dhcp
{
namespace
test
{
/// @brief General error emitted by the DHCP4 test client.
class
Dhcp4ClientError
:
public
isc
::
Exception
{
public:
Dhcp4ClientError
(
const
char
*
file
,
size_t
line
,
const
char
*
what
)
:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// @brief DHCPv4 client used for unit testing.
///
/// This class implements a DHCPv4 "client" which interoperates with the
...
...
@@ -45,6 +52,14 @@ namespace test {
class
Dhcp4Client
:
public
boost
::
noncopyable
{
public:
/// @brief States of the DHCP client.
enum
State
{
SELECTING
,
INIT_REBOOT
,
RENEWING
,
REBINDING
};
/// @brief Holds the DHCPv4 messages taking part in transaction between
/// the client and the server.
struct
Context
{
...
...
@@ -79,12 +94,16 @@ public:
};
/// @brief Creates a new client.
Dhcp4Client
();
///
/// @param Initial client's state.
Dhcp4Client
(
const
State
&
state
=
SELECTING
);
/// @brief Creates a new client that communicates with a specified server.
///
/// @param srv An instance of the DHCPv4 server to be used.
Dhcp4Client
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>&
srv
);
/// @param state Initial client's state.
Dhcp4Client
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>&
srv
,
const
State
&
state
=
SELECTING
);
/// @brief Creates a lease for the client using the specified address
/// and valid lifetime.
...
...
@@ -101,6 +120,21 @@ public:
/// @param valid_lft Valid lifetime.
void
createLease
(
const
asiolink
::
IOAddress
&
addr
,
const
uint32_t
valid_lft
);
/// @brief Sends DHCPDISCOVER message to the server and receives response.
///
/// @param requested_addr A pointer to the IP Address to be sent in the
/// Requested IP Address option or NULL if the option should not be
/// included.
void
doDiscover
(
const
boost
::
shared_ptr
<
asiolink
::
IOAddress
>&
requested_addr
=
boost
::
shared_ptr
<
asiolink
::
IOAddress
>
());
/// @brief Perform 4-way exchange with a server.
///
/// @param requested_addr A pointer to the address to be requested using the
/// Requested IP Address option.
void
doDORA
(
const
boost
::
shared_ptr
<
asiolink
::
IOAddress
>&
requested_addr
=
boost
::
shared_ptr
<
asiolink
::
IOAddress
>
());
/// @brief Sends DHCPINFORM message to the server and receives response.
///
/// This function simulates sending the DHCPINFORM message to the server
...
...
@@ -121,6 +155,14 @@ public:
/// an error occurs.
void
doInform
(
const
bool
set_ciaddr
=
true
);
/// @brief Sends DHCPREQUEST Message to the server and receives a response.
///
/// @param requested_addr A pointer to the IP Address to be sent in the
/// Requested IP Address option or NULL if the option should not be
/// included.
void
doRequest
(
const
boost
::
shared_ptr
<
asiolink
::
IOAddress
>&
requested_addr
=
boost
::
shared_ptr
<
asiolink
::
IOAddress
>
());
/// @brief Generates a hardware address used by the client.
///
/// It assigns random values to the bytes of the hardware address.
...
...
@@ -195,6 +237,16 @@ public:
dest_addr_
=
dest_addr
;
}
/// @brief Sets client state.
///
/// Depending on the current state the client's behavior is different
/// when sending Request messages as per RFC2131, section 4.3.2.
///
/// @param state New client's state.
void
setState
(
const
State
&
state
)
{
state_
=
state
;
}
/// @brief Simulate sending messages through a relay.
///
/// @param use Parameter which 'true' value indicates that client should
...
...
@@ -236,6 +288,13 @@ private:
/// @return An instance of the message created.
Pkt4Ptr
createMsg
(
const
uint8_t
msg_type
);
/// @brief Include PRL Option in the query message.
///
/// This function creates the instance of the PRL option and adds
/// option codes from the @c requested_options_ to it. It later adds
/// the PRL option to the @c context_.query_ message if it is non-NULL.
void
includePRL
();
/// @brief Simulates reception of the message from the server.
///
/// @return Received message.
...
...
@@ -274,6 +333,9 @@ private:
/// @brief Pointer to the server that the client is communicating with.
boost
::
shared_ptr
<
NakedDhcpv4Srv
>
srv_
;
/// @brief Current state of the client.
State
state_
;
/// @brief Enable relaying messages to the server.
bool
use_relay_
;
};
...
...
src/bin/dhcp4/tests/dora_unittest.cc
0 → 100644
View file @
1a9a8b52
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <dhcp/dhcp4.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcp4/tests/dhcp4_client.h>
#include <boost/shared_ptr.hpp>
using
namespace
isc
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
data
;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
dhcp
::
test
;
namespace
{
/// @brief Set of JSON configurations used throughout the DORA tests.
///
/// - Configuration 0:
/// - Used for testing direct traffic
/// - 1 subnet: 10.0.0.0/24
/// - 1 pool: 10.0.0.10-10.0.0.100
/// - Router option present: 10.0.0.200 and 10.0.0.201
/// - Domain Name Server option present: 10.0.0.202, 10.0.0.203.
/// - Log Servers option present: 192.0.2.200 and 192.0.2.201
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
///
/// - Configuration 1:
/// - Use for testing relayed messages
/// - 1 subnet: 192.0.2.0/24
/// - Router option present: 192.0.2.200 and 192.0.2.201
/// - Domain Name Server option present: 192.0.2.202, 192.0.2.203.
/// - Log Servers option present: 192.0.2.200 and 192.0.2.201
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
const
char
*
DORA_CONFIGS
[]
=
{
// Configuration 0
"{
\"
interfaces
\"
: [
\"
all
\"
],"
"
\"
valid-lifetime
\"
: 600,"
"
\"
subnet4
\"
: [ { "
"
\"
subnet
\"
:
\"
10.0.0.0/24
\"
, "
"
\"
pool
\"
: [
\"
10.0.0.10-10.0.0.100
\"
],"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
routers
\"
,"
"
\"
code
\"
: 3,"
"
\"
data
\"
:
\"
10.0.0.200,10.0.0.201
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" },"
" {"
"
\"
name
\"
:
\"
domain-name-servers
\"
,"
"
\"
code
\"
: 6,"
"
\"
data
\"
:
\"
10.0.0.202,10.0.0.203
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" },"
" {"
"
\"
name
\"
:
\"
log-servers
\"
,"
"
\"
code
\"
: 7,"
"
\"
data
\"
:
\"
10.0.0.200,10.0.0.201
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" },"
" {"
"
\"
name
\"
:
\"
cookie-servers
\"
,"
"
\"
code
\"
: 8,"
"
\"
data
\"
:
\"
10.0.0.202,10.0.0.203
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" } ]"
" } ]"
"}"
,
// Configuration 1
"{
\"
interfaces
\"
: [
\"
all
\"
],"
"
\"
valid-lifetime
\"
: 600,"
"
\"
subnet4
\"
: [ { "
"
\"
subnet
\"
:
\"
192.0.2.0/24
\"
, "
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
routers
\"
,"
"
\"
code
\"
: 3,"
"
\"
data
\"
:
\"
192.0.2.200,192.0.2.201
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" },"
" {"
"
\"
name
\"
:
\"
domain-name-servers
\"
,"
"
\"
code
\"
: 6,"
"
\"
data
\"
:
\"
192.0.2.202,192.0.2.203
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" },"
" {"
"
\"
name
\"
:
\"
log-servers
\"
,"
"
\"
code
\"
: 7,"
"
\"
data
\"
:
\"
10.0.0.200,10.0.0.201
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" },"
" {"
"
\"
name
\"
:
\"
cookie-servers
\"
,"
"
\"
code
\"
: 8,"
"
\"
data
\"
:
\"
10.0.0.202,10.0.0.203
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" } ]"
" } ]"
"}"
};
/// @brief Test fixture class for testing 4-way (DORA) exchanges.
class
DORATest
:
public
Dhcpv4SrvTest
{
public:
/// @brief Constructor.
///
/// Sets up fake interfaces.
DORATest
()
:
Dhcpv4SrvTest
(),
iface_mgr_test_config_
(
true
)
{
IfaceMgr
::
instance
().
openSockets4
();
}
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig
iface_mgr_test_config_
;
};
// This test verifies that the client in a SELECTING state can request
// a specific address and that this address will be assigned when
// available.
TEST_F
(
DORATest
,
selectingRequestAvailableAddress
)
{
Dhcp4Client
client
(
Dhcp4Client
::
SELECTING
);
// Configure DHCP server.
configure
(
DORA_CONFIGS
[
0
],
*
client
.
getServer
());
// Perform 4-way exchange with the server.
ASSERT_NO_THROW
(
client
.
doDORA
(
boost
::
shared_ptr
<
IOAddress
>
(
new
IOAddress
(
"10.0.0.50"
))));
// Make sure that the server responded.
ASSERT_TRUE
(
client
.
getContext
().
response_
);
Pkt4Ptr
resp
=
client
.
getContext
().
response_
;
// Make sure that the server has responded with DHCPACK.
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp
->
getType
()));
// Response must not be relayed.
EXPECT_FALSE
(
resp
->
isRelayed
());
// Make sure that the server id is present.
EXPECT_EQ
(
"10.0.0.1"
,
client
.
config_
.
serverid_
.
toText
());
// Make sure that the client has got the lease with the requested address.
EXPECT_EQ
(
"10.0.0.50"
,
client
.
config_
.
lease_
.
addr_
.
toText
());
}
}
// end of anonymous namespace
src/bin/dhcp4/tests/inform_unittest.cc
View file @
1a9a8b52
...
...
@@ -28,7 +28,7 @@ using namespace isc::dhcp::test;
namespace
{
/// @brief Set of JSON configurations used throughout the
Rebind
tests.
/// @brief Set of JSON configurations used throughout the
Inform
tests.
///
/// - Configuration 0:
/// - Used for testing direct traffic
...
...
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