Skip to content
GitLab
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
0f7a029e
Commit
0f7a029e
authored
Mar 20, 2015
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac3768'
parents
1a04bbea
38d6de2b
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/tests/dhcp4_client.cc
View file @
0f7a029e
...
...
@@ -49,6 +49,7 @@ Dhcp4Client::Dhcp4Client(const Dhcp4Client::State& state) :
curr_transid_
(
0
),
dest_addr_
(
"255.255.255.255"
),
hwaddr_
(
generateHWAddr
()),
clientid_
(),
iface_name_
(
"eth0"
),
relay_addr_
(
"192.0.2.2"
),
requested_options_
(),
...
...
@@ -66,6 +67,7 @@ Dhcp4Client::Dhcp4Client(boost::shared_ptr<NakedDhcpv4Srv> srv,
dest_addr_
(
"255.255.255.255"
),
fqdn_
(),
hwaddr_
(
generateHWAddr
()),
clientid_
(),
iface_name_
(
"eth0"
),
relay_addr_
(
"192.0.2.2"
),
requested_options_
(),
...
...
@@ -84,6 +86,54 @@ Dhcp4Client::addRequestedAddress(const asiolink::IOAddress& addr) {
}
}
void
Dhcp4Client
::
appendClientId
()
{
if
(
!
context_
.
query_
)
{
isc_throw
(
Dhcp4ClientError
,
"pointer to the query must not be NULL"
" when adding Client Identifier option"
);
}
if
(
clientid_
)
{
OptionPtr
opt
(
new
Option
(
Option
::
V4
,
DHO_DHCP_CLIENT_IDENTIFIER
,
clientid_
->
getClientId
()));
context_
.
query_
->
addOption
(
opt
);
}
}
void
Dhcp4Client
::
appendName
()
{
if
(
!
context_
.
query_
)
{
isc_throw
(
Dhcp4ClientError
,
"pointer to the query must not be NULL"
" when adding FQDN or Hostname option"
);
}
if
(
fqdn_
)
{
context_
.
query_
->
addOption
(
fqdn_
);
}
else
if
(
hostname_
)
{
context_
.
query_
->
addOption
(
hostname_
);
}
}
void
Dhcp4Client
::
appendPRL
()
{
if
(
!
context_
.
query_
)
{
isc_throw
(
Dhcp4ClientError
,
"pointer to the query must not be NULL"
" when adding option codes to the PRL option"
);
}
else
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
);
}
}
void
Dhcp4Client
::
applyConfiguration
()
{
Pkt4Ptr
resp
=
context_
.
response_
;
...
...
@@ -150,9 +200,11 @@ void
Dhcp4Client
::
doDiscover
(
const
boost
::
shared_ptr
<
IOAddress
>&
requested_addr
)
{
context_
.
query_
=
createMsg
(
DHCPDISCOVER
);
// Request options if any.
include
PRL
();
append
PRL
();
// Include FQDN or Hostname.
includeName
();
appendName
();
// Include Client Identifier
appendClientId
();
if
(
requested_addr
)
{
addRequestedAddress
(
*
requested_addr
);
}
...
...
@@ -178,7 +230,7 @@ void
Dhcp4Client
::
doInform
(
const
bool
set_ciaddr
)
{
context_
.
query_
=
createMsg
(
DHCPINFORM
);
// Request options if any.
include
PRL
();
append
PRL
();
// 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.
...
...
@@ -241,9 +293,11 @@ Dhcp4Client::doRequest() {
}
// Request options if any.
include
PRL
();
append
PRL
();
// Include FQDN or Hostname.
includeName
();
appendName
();
// Include Client Identifier
appendClientId
();
// Send the message to the server.
sendMsg
(
context_
.
query_
);
// Expect response.
...
...
@@ -254,6 +308,16 @@ Dhcp4Client::doRequest() {
}
}
void
Dhcp4Client
::
includeClientId
(
const
std
::
string
&
clientid
)
{
if
(
clientid
.
empty
())
{
clientid_
.
reset
();
}
else
{
clientid_
=
ClientId
::
fromText
(
clientid
);
}
}
void
Dhcp4Client
::
includeFQDN
(
const
uint8_t
flags
,
const
std
::
string
&
fqdn_name
,
Option4ClientFqdn
::
DomainNameType
fqdn_type
)
{
...
...
@@ -266,39 +330,6 @@ Dhcp4Client::includeHostname(const std::string& name) {
hostname_
.
reset
(
new
OptionString
(
Option
::
V4
,
DHO_HOST_NAME
,
name
));
}
void
Dhcp4Client
::
includeName
()
{
if
(
!
context_
.
query_
)
{
isc_throw
(
Dhcp4ClientError
,
"pointer to the query must not be NULL"
" when adding FQDN or Hostname option"
);
}
if
(
fqdn_
)
{
context_
.
query_
->
addOption
(
fqdn_
);
}
else
if
(
hostname_
)
{
context_
.
query_
->
addOption
(
hostname_
);
}
}
void
Dhcp4Client
::
includePRL
()
{
if
(
!
context_
.
query_
)
{
isc_throw
(
Dhcp4ClientError
,
"pointer to the query must not be NULL"
" when adding option codes to the PRL option"
);
}
else
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
);
}
}
HWAddrPtr
Dhcp4Client
::
generateHWAddr
(
const
uint8_t
htype
)
const
{
...
...
@@ -339,7 +370,6 @@ Dhcp4Client::requestOptions(const uint8_t option1, const uint8_t option2,
requestOption
(
option3
);
}
Pkt4Ptr
Dhcp4Client
::
receiveOneMsg
()
{
// Return empty pointer if server hasn't responded.
...
...
@@ -385,7 +415,11 @@ Dhcp4Client::sendMsg(const Pkt4Ptr& msg) {
void
Dhcp4Client
::
setHWAddress
(
const
std
::
string
&
hwaddr_str
)
{
hwaddr_
.
reset
(
new
HWAddr
(
HWAddr
::
fromText
(
hwaddr_str
)));
if
(
hwaddr_str
.
empty
())
{
hwaddr_
.
reset
();
}
else
{
hwaddr_
.
reset
(
new
HWAddr
(
HWAddr
::
fromText
(
hwaddr_str
)));
}
}
}
// end of namespace isc::dhcp::test
...
...
src/bin/dhcp4/tests/dhcp4_client.h
View file @
0f7a029e
...
...
@@ -217,6 +217,15 @@ public:
return
(
srv_
);
}
/// @brief Creates the client id from the client id in the textual format.
///
/// The generated client id will be added to the client's messages to the
/// server.
///
/// @param clientid Client id in the textual format. Use the empty client id
/// value to not include the client id.
void
includeClientId
(
const
std
::
string
&
clientid
);
/// @brief Creates an instance of the Client FQDN option to be included
/// in the client's message.
///
...
...
@@ -285,7 +294,8 @@ public:
/// @brief Sets the explicit hardware address for the client.
///
/// @param hwaddr_str String representation of the HW address.
/// @param hwaddr_str String representation of the HW address. Use an
/// empty string to set the NULL hardware address.
void
setHWAddress
(
const
std
::
string
&
hwaddr_str
);
/// @brief Sets the interface over which the messages should be sent.
...
...
@@ -360,12 +370,19 @@ private:
/// @return An instance of the message created.
Pkt4Ptr
createMsg
(
const
uint8_t
msg_type
);
/// @brief Includes the Client Identifier option in the client's message.
///
/// This function creates an instance of the Client Identifier option
/// if the client identifier has been specified and includes this
/// option in the client's message to the server.
void
appendClientId
();
/// @brief Includes FQDN or Hostname option in the client's message.
///
/// This method checks if @c fqdn_ or @c hostname_ is specified and
/// includes it in the client's message. If both are specified, the
/// @c fqdn_ will be used.
void
include
Name
();
void
append
Name
();
/// @brief Include PRL Option in the query message.
///
...
...
@@ -373,7 +390,7 @@ private:
/// 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
include
PRL
();
void
append
PRL
();
/// @brief Simulates reception of the message from the server.
///
...
...
@@ -407,6 +424,9 @@ private:
/// @brief Current hardware address of the client.
HWAddrPtr
hwaddr_
;
/// @brief Current client identifier.
ClientIdPtr
clientid_
;
/// @brief Interface to be used to send the messages.
std
::
string
iface_name_
;
...
...
src/bin/dhcp4/tests/dora_unittest.cc
View file @
0f7a029e
...
...
@@ -173,6 +173,71 @@ public:
IfaceMgr
::
instance
().
openSockets4
();
}
/// @brief Test that server doesn't allocate the lease for a client
/// which has the same address or client identifier as another client.
///
/// This test checks the server's behavior in the following scenario:
/// - Client A identifies itself to the server using the hardware address
/// and client identifier or only one of those.
/// - Client A performs the 4-way exchange and obtains a lease from the server.
/// - Client B uses the same HW address or client identifier as the client A.
/// - Client B uses both HW address and client identifier if the client A is using
/// only one of them. Client B uses one of the HW address or client
/// identifier if the client A is using both.
/// - Client B sends the DHCPDISCOVER to the server.
/// The server determines that there is a lease for the client A using the
/// same HW address as the client B. Server discards the client's message and
/// doesn't offer the lease for the client B to prevent allocation of the
/// lease without a unique identifier.
/// - The client sends the DHCPREQUEST and the server sends the DHCPNAK for the
/// same reason.
/// - The client A renews its address successfully.
///
/// The specific test cases using this test must make sure that one of the
/// provided parameters is an empty string. This simulates the situation where
/// one of the clients has only one of the identifiers and the other one has
/// two.
///
/// @param hwaddr_a HW address of client A.
/// @param clientid_a Client id of client A.
/// @param hwaddr_b HW address of client B.
/// @param clientid_b Client id of client B.
void
oneAllocationOverlapTest
(
const
std
::
string
&
hwaddr_a
,
const
std
::
string
&
clientid_a
,
const
std
::
string
&
hwaddr_b
,
const
std
::
string
&
clientid_b
);
/// @brief Test that server can allocate the lease for a client having
/// the same HW Address or client id as another client.
///
/// This test checks the server behavior in the following situation:
/// - Client A identifies itself to the server using client identifier
/// and the hardware address and requests allocation of the new lease.
/// - Server allocates the lease to the client.
/// - Client B has a different hardware address or client identifier than
/// the client A, but the other identifier is equal to the corresponding
/// identifier of the client A.
/// - Client B sends DHCPDISCOVER.
/// - Server should determine that the client B is not client A, because
/// it is using a different hadrware address or client identifier.
/// As a consequence, the server should offer a different address to the
/// client B.
/// - The client B performs the 4-way exchange again, and the server
/// allocates a new address to the client, which should be different
/// than the address used by the client A.
/// - Client B is in the renewing state and it successfully renews its
/// address.
/// - The client A also renews its address successfully.
///
/// @param hwaddr_a HW address of client A.
/// @param clientid_a Client id of client A.
/// @param hwaddr_b HW address of client B.
/// @param clientid_b Client id of client B.
void
twoAllocationsOverlapTest
(
const
std
::
string
&
hwaddr_a
,
const
std
::
string
&
clientid_a
,
const
std
::
string
&
hwaddr_b
,
const
std
::
string
&
clientid_b
);
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig
iface_mgr_test_config_
;
...
...
@@ -441,6 +506,188 @@ TEST_F(DORATest, ciaddr) {
EXPECT_EQ
(
"0.0.0.0"
,
resp
->
getCiaddr
().
toText
());
}
void
DORATest
::
twoAllocationsOverlapTest
(
const
std
::
string
&
hwaddr_a
,
const
std
::
string
&
clientid_a
,
const
std
::
string
&
hwaddr_b
,
const
std
::
string
&
clientid_b
)
{
// Allocate a lease by client A using the 4-way exchange.
Dhcp4Client
client_a
(
Dhcp4Client
::
SELECTING
);
client_a
.
includeClientId
(
clientid_a
);
client_a
.
setHWAddress
(
hwaddr_a
);
configure
(
DORA_CONFIGS
[
0
],
*
client_a
.
getServer
());
ASSERT_NO_THROW
(
client_a
.
doDORA
());
// Make sure that the server responded.
ASSERT_TRUE
(
client_a
.
getContext
().
response_
);
Pkt4Ptr
resp_a
=
client_a
.
getContext
().
response_
;
// Make sure that the server has responded with DHCPACK.
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp_a
->
getType
()));
// Make sure that the lease has been recorded by the server.
Lease4Ptr
lease_a
=
LeaseMgrFactory
::
instance
().
getLease4
(
client_a
.
config_
.
lease_
.
addr_
);
ASSERT_TRUE
(
lease_a
);
// Create client B.
Dhcp4Client
client_b
(
client_a
.
getServer
(),
Dhcp4Client
::
SELECTING
);
client_b
.
setHWAddress
(
hwaddr_b
);
client_b
.
includeClientId
(
clientid_b
);
// Send DHCPDISCOVER and expect the response.
ASSERT_NO_THROW
(
client_b
.
doDiscover
());
Pkt4Ptr
resp_b
=
client_b
.
getContext
().
response_
;
// Make sure that the server has responded with DHCPOFFER.
ASSERT_EQ
(
DHCPOFFER
,
static_cast
<
int
>
(
resp_b
->
getType
()));
// The offered address should be different than the address which
// was obtained by the client A.
ASSERT_NE
(
resp_b
->
getYiaddr
(),
client_a
.
config_
.
lease_
.
addr_
);
// Make sure that the client A lease hasn't been modified.
lease_a
=
LeaseMgrFactory
::
instance
().
getLease4
(
client_a
.
config_
.
lease_
.
addr_
);
ASSERT_TRUE
(
lease_a
);
// Now that we know that the server will avoid assigning the same
// address that the client A has, use the 4-way exchange to actually
// allocate some address.
ASSERT_NO_THROW
(
client_b
.
doDORA
());
// Make sure that the server responded.
ASSERT_TRUE
(
client_b
.
getContext
().
response_
);
resp_b
=
client_b
.
getContext
().
response_
;
// Make sure that the server has responded with DHCPACK.
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp_b
->
getType
()));
// Again, make sure the assigned addresses are different.
ASSERT_NE
(
client_b
.
config_
.
lease_
.
addr_
,
client_a
.
config_
.
lease_
.
addr_
);
// Make sure that the client A still has a lease.
lease_a
=
LeaseMgrFactory
::
instance
().
getLease4
(
client_a
.
config_
.
lease_
.
addr_
);
ASSERT_TRUE
(
lease_a
);
// Make sure that the client B has a lease.
Lease4Ptr
lease_b
=
LeaseMgrFactory
::
instance
().
getLease4
(
client_b
.
config_
.
lease_
.
addr_
);
ASSERT_TRUE
(
lease_b
);
// Client B should be able to renew its address.
client_b
.
setState
(
Dhcp4Client
::
RENEWING
);
ASSERT_NO_THROW
(
client_b
.
doRequest
());
ASSERT_TRUE
(
client_b
.
getContext
().
response_
);
resp_b
=
client_b
.
getContext
().
response_
;
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp_b
->
getType
()));
ASSERT_NE
(
client_b
.
config_
.
lease_
.
addr_
,
client_a
.
config_
.
lease_
.
addr_
);
// Client A should also be able to renew its address.
client_a
.
setState
(
Dhcp4Client
::
RENEWING
);
ASSERT_NO_THROW
(
client_a
.
doRequest
());
ASSERT_TRUE
(
client_a
.
getContext
().
response_
);
resp_b
=
client_a
.
getContext
().
response_
;
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp_b
->
getType
()));
ASSERT_NE
(
client_a
.
config_
.
lease_
.
addr_
,
client_b
.
config_
.
lease_
.
addr_
);
}
void
DORATest
::
oneAllocationOverlapTest
(
const
std
::
string
&
hwaddr_a
,
const
std
::
string
&
clientid_a
,
const
std
::
string
&
hwaddr_b
,
const
std
::
string
&
clientid_b
)
{
// Allocate a lease by client A using the 4-way exchange.
Dhcp4Client
client_a
(
Dhcp4Client
::
SELECTING
);
client_a
.
includeClientId
(
clientid_a
);
client_a
.
setHWAddress
(
hwaddr_a
);
configure
(
DORA_CONFIGS
[
0
],
*
client_a
.
getServer
());
ASSERT_NO_THROW
(
client_a
.
doDORA
());
// Make sure that the server responded.
ASSERT_TRUE
(
client_a
.
getContext
().
response_
);
Pkt4Ptr
resp_a
=
client_a
.
getContext
().
response_
;
// Make sure that the server has responded with DHCPACK.
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp_a
->
getType
()));
Lease4Ptr
lease_a
=
LeaseMgrFactory
::
instance
().
getLease4
(
client_a
.
config_
.
lease_
.
addr_
);
ASSERT_TRUE
(
lease_a
);
// Client B sends a DHCPDISCOVER.
Dhcp4Client
client_b
(
client_a
.
getServer
(),
Dhcp4Client
::
SELECTING
);
client_b
.
setHWAddress
(
hwaddr_b
);
client_b
.
includeClientId
(
clientid_b
);
// Client A and Client B have one common identifier (HW address
// or client identifier) and one of them is missing the other
// identifier. The allocation engine can't offer an address for
// the client which has the same identifier as the other client and
// which doesn't have any other (unique) identifier. It should
// discard the DHCPDISCOVER.
ASSERT_NO_THROW
(
client_b
.
doDiscover
());
Pkt4Ptr
resp_b
=
client_b
.
getContext
().
response_
;
ASSERT_FALSE
(
resp_b
);
// Now repeat the same test but send the DHCPREQUEST. This time the
// server should send the DHCPNAK.
client_b
.
config_
.
lease_
.
addr_
=
IOAddress
::
IPV4_ZERO_ADDRESS
();
client_b
.
setState
(
Dhcp4Client
::
INIT_REBOOT
);
ASSERT_NO_THROW
(
client_b
.
doRequest
());
resp_b
=
client_b
.
getContext
().
response_
;
ASSERT_TRUE
(
resp_b
);
ASSERT_EQ
(
DHCPNAK
,
static_cast
<
int
>
(
resp_b
->
getType
()));
// Client A should also be able to renew its address.
client_a
.
setState
(
Dhcp4Client
::
RENEWING
);
ASSERT_NO_THROW
(
client_a
.
doRequest
());
ASSERT_TRUE
(
client_a
.
getContext
().
response_
);
resp_b
=
client_a
.
getContext
().
response_
;
ASSERT_EQ
(
DHCPACK
,
static_cast
<
int
>
(
resp_b
->
getType
()));
ASSERT_NE
(
client_a
.
config_
.
lease_
.
addr_
,
client_b
.
config_
.
lease_
.
addr_
);
}
// This test checks the server behavior in the following situation:
// - Client A identifies itself to the server using client identifier
// and the hardware address and requests allocation of the new lease.
// - Server allocates the lease to the client.
// - Client B has a different hardware address but is using the same
// client identifier as Client A.
// - Client B sends DHCPDISCOVER.
// - Server should determine that the client B is not client A, because
// it is using a different hadrware address, even though they use the
// same client identifier. As a consequence, the server should offer
// a different address to the client B.
// - The client B performs the 4-way exchange again and the server
// allocates a new address to the client, which should be different
// than the address used by the client A.
// - Client B is in the renewing state and it successfully renews its
// address.
// - Client A also renews its address successfully.
TEST_F
(
DORATest
,
twoAllocationsOverlap1
)
{
twoAllocationsOverlapTest
(
"01:02:03:04:05:06"
,
"12:34"
,
"02:02:03:03:04:04"
,
"12:34"
);
}
// This test is similar to twoAllocationsOverlap1, but the
// clients differ by client identifier.
TEST_F
(
DORATest
,
twoAllocationsOverlap2
)
{
twoAllocationsOverlapTest
(
"01:02:03:04:05:06"
,
"12:34"
,
"01:02:03:04:05:06"
,
"22:34"
);
}
// This test checks the server behavior in the following situation:
// - Client A identifies itself to the server using the hardware address
// and client identifier.
// - Client A performs the 4-way exchange and obtains a lease from the server.
// - Client B uses the same HW address as the client A, but it doesn't use
// the client identifier.
// - Client B sends the DHCPDISCOVER to the server.
// The server determines that there is a lease for the client A using the
// same HW address as the client B. Server discards the client's message and
// doesn't offer the lease for the client B to prevent allocation of the
// lease without a unique identifier.
// - The client sends the DHCPREQUEST and the server sends the DHCPNAK for the
// same reason.
// - Client A renews its address successfully.
TEST_F
(
DORATest
,
oneAllocationOverlap1
)
{
oneAllocationOverlapTest
(
"01:02:03:04:05:06"
,
"12:34"
,
"01:02:03:04:05:06"
,
""
);
}
// This test is similar to oneAllocationOverlap2 but this time the client A
// uses no client identifier, and the client B uses the HW address and the
// client identifier. The server behaves as previously.
TEST_F
(
DORATest
,
oneAllocationOverlap2
)
{
oneAllocationOverlapTest
(
"01:02:03:04:05:06"
,
""
,
"01:02:03:04:05:06"
,
"12:34"
);
}
// This is a simple test for the host reservation. It creates a reservation
// for an address for a single client, identified by the HW address. The
// test verifies that the client using this HW address will obtain a
...
...
src/lib/dhcpsrv/alloc_engine.cc
View file @
0f7a029e
...
...
@@ -1235,6 +1235,71 @@ hasAddressReservation(const AllocEngine::ClientContext4& ctx) {
return
(
ctx
.
host_
&&
!
ctx
.
host_
->
getIPv4Reservation
().
isV4Zero
());
}
/// @brief Check if there is a lease for the client which message is processed.
///
/// This function searches the lease database to find existing lease for the client.
/// It finds the lease using the client's HW address first. If the lease exists and
/// appears to belong to the client the lease is returned. Otherwise, the function
/// will search for the lease using the client identifier (if supplied). If the
/// lease exists and appears to belong to the client, it is returned.
///
/// This function also identifies the conflicts between existing leases and the
/// lease to be allocated for the client, when the client is using a HW address
/// or client identifier which is already in use by the client having a lease in
/// the database. If the client uses an identifier which is already used by another
/// client and no other unique identifier which could be used to identify the client's
/// lease this function signals the conflict by returning 'true'.
///
/// @param ctx Client context.
/// @param [out] client_lease Client's lease found in the database.
///
/// @return true if there is a conflict of identifiers (HW address or client id)
/// between the client which message is being processed and the client which has
/// a lease in the database. When the value 'true' is returned, the caller should
/// cease the lease allocation for the client.
bool
matchClientLease
(
const
AllocEngine
::
ClientContext4
&
ctx
,
Lease4Ptr
&
client_lease
)
{
// Obtain the sole instance of the LeaseMgr.
LeaseMgr
&
lease_mgr
=
LeaseMgrFactory
::
instance
();
// The server should hand out existing lease to the client, so we have to check
// if there is one. First, try to use the client's HW address.
client_lease
=
lease_mgr
.
getLease4
(
*
ctx
.
hwaddr_
,
ctx
.
subnet_
->
getID
());
// If there is no lease for this HW address or the lease doesn't seem to be ours,
// we will have to use the client identifier. Note that in some situations two
// clients may use the same HW address so even if we find the lease for the HW
// address it doesn't mean it is ours, because client identifier may not match.
if
(
ctx
.
clientid_
&&
((
!
client_lease
)
||
(
client_lease
&&
!
ctx
.
myLease
(
*
client_lease
))))
{
// Check if the lease is in conflict with the lease that we want to allocate.
// If the lease is in conflict because of using overlapping HW address or
// client identifier, we can't allocate the lease for this client.
if
(
client_lease
&&
ctx
.
isInConflict
(
*
client_lease
))
{
return
(
true
);
}
// There is no lease or the lease we found is not conflicting with the lease
// which we have found for the HW address, so there is still a chance that
// we will allocate the lease. Check if there is a lease using the client
// identifier.
client_lease
=
lease_mgr
.
getLease4
(
*
ctx
.
clientid_
,
ctx
.
subnet_
->
getID
());
}
// Check if the lease we have found belongs to us.
if
(
client_lease
&&
!
ctx
.
myLease
(
*
client_lease
))
{
// If the lease doesn't belong to us, check if we can add new lease for
// the client which message we're processing, or its identifiers are
// in conflict with this lease.
if
(
ctx
.
isInConflict
(
*
client_lease
))
{
return
(
true
);
}
// If there is no conflict we can proceed and try to find the appropriate
// lease but we don't use the one we found, because it is assigned to
// someone else. Reset the pointer to indicate that we're not
// renewing this lease.
client_lease
.
reset
();
}
return
(
false
);
}
}
// end of anonymous namespace
namespace
isc
{
...
...
@@ -1286,6 +1351,14 @@ AllocEngine::ClientContext4::myLease(const Lease4& lease) const {
return
(
true
);
}
bool
AllocEngine
::
ClientContext4
::
isInConflict
(
const
Lease4
&
lease
)
const
{
return
((
!
(
hwaddr_
&&
lease
.
hwaddr_
)
&&
(
clientid_
&&
lease
.
client_id_
)
&&
(
*
clientid_
==
*
lease
.
client_id_
))
||
(
!
(
clientid_
&&
lease
.
client_id_
)
&&
(
hwaddr_
&&
lease
.
hwaddr_
)
&&
(
hwaddr_
->
hwaddr_
==
lease
.
hwaddr_
->
hwaddr_
)));
}
Lease4Ptr
AllocEngine
::
allocateLease4
(
ClientContext4
&
ctx
)
{
// The NULL pointer indicates that the old lease didn't exist. It may
...
...
@@ -1340,15 +1413,13 @@ AllocEngine::findReservation(ClientContext4& ctx) {
Lease4Ptr
AllocEngine
::
discoverLease4
(
AllocEngine
::
ClientContext4
&
ctx
)
{
// Obtain the sole instance of the LeaseMgr.
LeaseMgr
&
lease_mgr
=
LeaseMgrFactory
::
instance
();
// Check if the client has any lease already. This information is needed
// to either return this lease to the client or to return it as an old
// (existing) lease if a different one is offered.
Lease4Ptr
client_lease
=
lease_mgr
.
getLease4
(
*
ctx
.
hwaddr_
,
ctx
.
subnet_
->
getID
());
if
(
!
client_lease
&&
ctx
.
clientid_
)
{
client_lease
=
lease_mgr
.
getLease4
(
*
ctx
.
clientid_
,
ctx
.
subnet_
->
getID
());
// Find an existing lease for this client. This function will return true
// if there is a conflict with existing lease and the allocation should
// not be continued.
Lease4Ptr
client_lease
;
bool
conflict
=
matchClientLease
(
ctx
,
client_lease
);
if
(
conflict
)
{
return
(
Lease4Ptr
());