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
Sebastian Schrader
Kea
Commits
36d31194
Commit
36d31194
authored
Nov 09, 2015
by
Marcin Siodelski
Browse files
[4106] Allow for transmitting vendor option in the DHCPv4o6 message.
parent
7097e81a
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcpsrv/dhcp4o6_ipc.cc
View file @
36d31194
...
...
@@ -21,7 +21,7 @@
#include <dhcp/option_string.h>
#include <dhcp/option_vendor.h>
#include <dhcpsrv/dhcp4o6_ipc.h>
#include <boost/pointer_cast.hpp>
#include <errno.h>
#include <netinet/in.h>
#include <string>
...
...
@@ -138,27 +138,35 @@ Pkt6Ptr Dhcp4o6IpcBase::receive() {
// Get interface name and remote address
pkt
->
unpack
();
OptionVendorPtr
vendor
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
pkt
->
getOption
(
D6O_VENDOR_OPTS
));
// Vendor option must exist.
if
(
!
vendor
)
{
isc_throw
(
Dhcp4o6IpcError
,
"option "
<<
D6O_VENDOR_OPTS
<<
" not present in the DHCP4o6 message sent between the "
" servers"
);
// Vendor option is initially NULL. If we find the instance of the vendor
// option with the ISC enterprise id this pointer will point to it.
OptionVendorPtr
option_vendor
;
// Get all vendor option and look for the one with the ISC enterprise id.
OptionCollection
vendor_options
=
pkt
->
getOptions
(
D6O_VENDOR_OPTS
);
for
(
OptionCollection
::
const_iterator
opt
=
vendor_options
.
begin
();
opt
!=
vendor_options
.
end
();
++
opt
)
{
option_vendor
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
opt
->
second
);
if
(
option_vendor
)
{
if
(
option_vendor
->
getVendorId
()
==
ENTERPRISE_ID_ISC
)
{
break
;
}
}
else
{
option_vendor
.
reset
();
}
}
//
The v
endor option must
require appropriate enterprise-id
.
if
(
vendor
->
getVendorId
()
!=
ENTERPRISE_ID_ISC
)
{
//
V
endor option must
exist
.
if
(
!
option_vendor
)
{
isc_throw
(
Dhcp4o6IpcError
,
"option "
<<
D6O_VENDOR_OPTS
<<
" in the DHCP4o6 message contains invalid enterprise-id '"
<<
vendor
->
getVendorId
()
<<
"'. Expected enterprise-id '"
<<
ENTERPRISE_ID_ISC
<<
"'"
);
<<
" with ISC enterprise id is not present in the DHCP4o6"
" message sent between the servers"
);
}
// The option carrying interface name is required.
OptionStringPtr
ifname
=
boost
::
dynamic_pointer_cast
<
OptionString
>
(
vendor
->
getOption
(
ISC_V6_4O6_INTERFACE
));
OptionString
>
(
option_
vendor
->
getOption
(
ISC_V6_4O6_INTERFACE
));
if
(
!
ifname
)
{
isc_throw
(
Dhcp4o6IpcError
,
"option "
<<
D6O_VENDOR_OPTS
<<
" doesn't contain the "
<<
ISC_V6_4O6_INTERFACE
...
...
@@ -175,8 +183,8 @@ Pkt6Ptr Dhcp4o6IpcBase::receive() {
}
// Get the option holding source IPv6 address.
OptionCustomPtr
srcs
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
vendor
->
getOption
(
ISC_V6_4O6_SRC_ADDRESS
));
OptionCustomPtr
srcs
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
option_
vendor
->
getOption
(
ISC_V6_4O6_SRC_ADDRESS
));
if
(
!
srcs
)
{
isc_throw
(
Dhcp4o6IpcError
,
"option "
<<
D6O_VENDOR_OPTS
<<
" doesn't contain the "
<<
ISC_V6_4O6_SRC_ADDRESS
...
...
@@ -184,11 +192,21 @@ Pkt6Ptr Dhcp4o6IpcBase::receive() {
" between Kea servers"
);
}
// Update the packet and return it
static_cast
<
void
>
(
pkt
->
delOption
(
D6O_VENDOR_OPTS
));
// Update the packet.
pkt
->
setRemoteAddr
(
srcs
->
readAddress
());
pkt
->
setIface
(
iface
->
getName
());
pkt
->
setIndex
(
iface
->
getIndex
());
// Remove options that have been added by the IPC sender.
static_cast
<
void
>
(
option_vendor
->
delOption
(
ISC_V6_4O6_INTERFACE
));
static_cast
<
void
>
(
option_vendor
->
delOption
(
ISC_V6_4O6_SRC_ADDRESS
));
// If there are no more options, the IPC sender has probably created the
// vendor option, in which case we should remove it here.
if
(
option_vendor
->
getOptions
().
empty
())
{
static_cast
<
void
>
(
pkt
->
delOption
(
D6O_VENDOR_OPTS
));
}
return
(
pkt
);
}
...
...
@@ -206,17 +224,24 @@ void Dhcp4o6IpcBase::send(const Pkt6Ptr& pkt) {
" IPC socket is closed"
);
}
// Get a vendor option
OptionVendorPtr
vendor
(
new
OptionVendor
(
Option
::
V6
,
ENTERPRISE_ID_ISC
));
// Check if vendor option exists.
OptionVendorPtr
option_vendor
=
dynamic_pointer_cast
<
OptionVendor
>
(
pkt
->
getOption
(
D6O_VENDOR_OPTS
));
// If vendor option doesn't exist or its enterprise id is not ISC's
// enterprise id, let's create it.
if
(
!
option_vendor
||
(
option_vendor
->
getVendorId
()
!=
ENTERPRISE_ID_ISC
))
{
option_vendor
.
reset
(
new
OptionVendor
(
Option
::
V6
,
ENTERPRISE_ID_ISC
));
pkt
->
addOption
(
option_vendor
);
}
// Push interface name and source address in it
vendor
->
addOption
(
OptionStringPtr
(
new
OptionString
(
Option
::
V6
,
option_
vendor
->
addOption
(
OptionStringPtr
(
new
OptionString
(
Option
::
V6
,
ISC_V6_4O6_INTERFACE
,
pkt
->
getIface
())));
vendor
->
addOption
(
Option6AddrLstPtr
(
new
Option6AddrLst
(
ISC_V6_4O6_SRC_ADDRESS
,
pkt
->
getRemoteAddr
())));
pkt
->
addOption
(
vendor
);
option_vendor
->
addOption
(
Option6AddrLstPtr
(
new
Option6AddrLst
(
ISC_V6_4O6_SRC_ADDRESS
,
pkt
->
getRemoteAddr
())));
// Get packet content
OutputBuffer
&
buf
=
pkt
->
getBuffer
();
buf
.
clear
();
...
...
src/lib/dhcpsrv/tests/dhcp4o6_ipc_unittest.cc
View file @
36d31194
...
...
@@ -171,19 +171,43 @@ protected:
/// @brief Creates an instance of the DHCPv4o6 message with vendor option.
///
/// The vendor option appended to the message has ISC entprise id and
/// comprises option @c ISC_V6_4O6_INTERFACE and @c ISC_V6_4O6_SRC_ADDRESS.
/// @param msg_type Message type.
/// @param postfix Postfix to be appended to the remote address. See the
/// documentation of @c createDHCPv4o6Message for details.
///
/// @return Pointer to the created message.
static
Pkt6Ptr
createDHCPv4o6MsgWithVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
,
const
uint32_t
enterprise_id
);
/// @brief Creates an instance of the DHCPv4o6 message with ISC
/// vendor option.
///
/// This is useful to test scenarios when the IPC is forwarding messages
/// that contain options also inserted by IPC. The duplicate options are
/// allowed and IPC should deal with this with no error.
/// that contain vendor option with ISC enterprise ID.
///
/// @param msg_type Message type.
/// @param postfix Postfix to be appended to the remote address. See the
/// documentation of @c createDHCPv4o6Message for details.
///
/// @return Pointer to the created message.
static
Pkt6Ptr
createDHCPv4o6MsgWithVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
);
static
Pkt6Ptr
createDHCPv4o6MsgWithISCVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
);
/// @brief Creates an instance of the DHCPv4o6 message with vendor
/// option holding enterprise id of 32000.
///
/// This is useful to test scenarios when the IPC is forwarding messages
/// that contain some vendor option and when IPC also appends the ISC
/// vendor option to carry some DHCPv4o6 specific information.
///
/// @param msg_type Message type.
/// @param postfix Postfix to be appended to the remote address. See the
/// documentation of @c createDHCPv4o6Message for details.
///
/// @return Pointer to the created message.
static
Pkt6Ptr
createDHCPv4o6MsgWithAnyVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
);
/// @brief Creates an instance of the DHCPv4-query Message option.
///
...
...
@@ -254,28 +278,33 @@ Dhcp4o6IpcBaseTest::createDHCPv4o6Message(const uint16_t msg_type,
Pkt6Ptr
Dhcp4o6IpcBaseTest
::
createDHCPv4o6MsgWithVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
)
{
const
uint16_t
postfix
,
const
uint32_t
enterprise_id
)
{
Pkt6Ptr
pkt
=
createDHCPv4o6Message
(
msg_type
,
postfix
);
// Create vendor option with ISC enterprise id.
OptionVendorPtr
option_vendor
(
new
OptionVendor
(
Option
::
V6
,
ENTERPRISE_ID_ISC
));
// Add interface. Such interface doesn't have to exist in the system because
// IPC should not use this option when it is received. It should rather use
// the option that the sender side is appending to the message.
option_vendor
->
addOption
(
OptionStringPtr
(
new
OptionString
(
Option
::
V6
,
ISC_V6_4O6_INTERFACE
,
"non-existing"
)));
// Add some remote address.
option_vendor
->
addOption
(
Option6AddrLstPtr
(
new
Option6AddrLst
(
ISC_V6_4O6_SRC_ADDRESS
,
IOAddress
(
"3000::10"
))));
OptionVendorPtr
option_vendor
(
new
OptionVendor
(
Option
::
V6
,
enterprise_id
));
// Add some option to the vendor option.
option_vendor
->
addOption
(
OptionPtr
(
new
Option
(
Option
::
V6
,
100
)));
// Add vendor option to the message.
pkt
->
addOption
(
option_vendor
);
return
(
pkt
);
}
Pkt6Ptr
Dhcp4o6IpcBaseTest
::
createDHCPv4o6MsgWithISCVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
)
{
return
(
createDHCPv4o6MsgWithVendorOption
(
msg_type
,
postfix
,
ENTERPRISE_ID_ISC
));
}
Pkt6Ptr
Dhcp4o6IpcBaseTest
::
createDHCPv4o6MsgWithAnyVendorOption
(
const
uint16_t
msg_type
,
const
uint16_t
postfix
)
{
return
(
createDHCPv4o6MsgWithVendorOption
(
msg_type
,
postfix
,
32000
));
}
OptionPtr
Dhcp4o6IpcBaseTest
::
createDHCPv4MsgOption
(
const
int
src
)
{
...
...
@@ -311,11 +340,18 @@ Dhcp4o6IpcBaseTest::testSendReceive(const uint16_t iterations_num,
uint16_t
msg_type
=
(
src
==
6
?
DHCPV6_DHCPV4_QUERY
:
DHCPV6_DHCPV4_RESPONSE
);
std
::
vector
<
bool
>
has_vendor_option
;
// Send the number of messages configured for the test.
for
(
uint16_t
i
=
1
;
i
<=
iterations_num
;
++
i
)
{
// Create the DHCPv4o6 message.
Pkt6Ptr
pkt
=
create_msg_fun
(
msg_type
,
i
);
// Remember if the vendor option exists in the source packet. The
// received packet should also contain this option if it exists
// in the source packet.
has_vendor_option
.
push_back
(
static_cast
<
bool
>
(
pkt
->
getOption
(
D6O_VENDOR_OPTS
)));
// Actaully send the message through the IPC.
ASSERT_NO_THROW
(
ipc_src
.
send
(
pkt
))
<<
"Failed to send the message over the IPC for iteration "
<<
i
;
...
...
@@ -344,6 +380,24 @@ Dhcp4o6IpcBaseTest::testSendReceive(const uint16_t iterations_num,
// Check that encapsulated DHCPv4 message has been received.
EXPECT_TRUE
(
pkt_received
->
getOption
(
D6O_DHCPV4_MSG
));
if
(
has_vendor_option
[
i
-
1
])
{
// Make sure that the vendor option wasn't deleted when the packet was
// received.
OptionPtr
option_vendor
=
pkt_received
->
getOption
(
D6O_VENDOR_OPTS
);
ASSERT_TRUE
(
option_vendor
)
<<
"vendor option deleted in the received DHCPv4o6 packet for"
" iteration "
<<
i
;
// ISC_V6_4O6_INTERFACE shouldn't be present.
EXPECT_FALSE
(
option_vendor
->
getOption
(
ISC_V6_4O6_INTERFACE
));
// ISC_V6_4O6_SRC_ADDRESS shouldn't be present.
EXPECT_FALSE
(
option_vendor
->
getOption
(
ISC_V6_4O6_SRC_ADDRESS
));
}
else
{
EXPECT_FALSE
(
pkt_received
->
getOption
(
D6O_VENDOR_OPTS
));
}
}
}
...
...
@@ -374,22 +428,49 @@ Dhcp4o6IpcBaseTest::testReceiveError(const Pkt6Ptr& pkt) {
// This test verifies that the IPC can transmit messages between the
// DHCPv
6
and DHCPv
4
server.
// DHCPv
4
and DHCPv
6
server.
TEST_F
(
Dhcp4o6IpcBaseTest
,
send4To6
)
{
testSendReceive
(
TEST_ITERATIONS
,
ENDPOINT_TYPE_V4
,
ENDPOINT_TYPE_V6
,
&
createDHCPv4o6Message
);
}
// This test verifies t
a
ht the IPC can transmit messages between the
// DHCPv
4
and DHCPv
6
server.
// This test verifies th
a
t the IPC can transmit messages between the
// DHCPv
6
and DHCPv
4
server.
TEST_F
(
Dhcp4o6IpcBaseTest
,
send6To4
)
{
testSendReceive
(
TEST_ITERATIONS
,
ENDPOINT_TYPE_V6
,
ENDPOINT_TYPE_V4
,
&
createDHCPv4o6Message
);
}
TEST_F
(
Dhcp4o6IpcBaseTest
,
send6To4WithVendorOption
)
{
// This test verifies that the IPC will transmit message already containing
// vendor option with ISC enterprise ID, between the DHCPv6 and DHCPv4
// server.
TEST_F
(
Dhcp4o6IpcBaseTest
,
send6To4WithISCVendorOption
)
{
testSendReceive
(
TEST_ITERATIONS
,
ENDPOINT_TYPE_V6
,
ENDPOINT_TYPE_V4
,
&
createDHCPv4o6MsgWithVendorOption
);
&
createDHCPv4o6MsgWithISCVendorOption
);
}
// This test verifies that the IPC will transmit message already containing
// vendor option with ISC enterprise ID, between the DHCPv6 and DHCPv4
// server.
TEST_F
(
Dhcp4o6IpcBaseTest
,
send4To6WithISCVendorOption
)
{
testSendReceive
(
TEST_ITERATIONS
,
ENDPOINT_TYPE_V4
,
ENDPOINT_TYPE_V6
,
&
createDHCPv4o6MsgWithISCVendorOption
);
}
// This test verifies that the IPC will transmit message already containing
// vendor option with enterprise id different than ISC, between the DHCPv6
// and DHCPv4 server.
TEST_F
(
Dhcp4o6IpcBaseTest
,
send6To4WithAnyVendorOption
)
{
testSendReceive
(
TEST_ITERATIONS
,
ENDPOINT_TYPE_V6
,
ENDPOINT_TYPE_V4
,
&
createDHCPv4o6MsgWithAnyVendorOption
);
}
// This test verifies that the IPC will transmit message already containing
// vendor option with enterprise id different than ISC, between the DHCPv4
// and DHCPv6 server.
TEST_F
(
Dhcp4o6IpcBaseTest
,
send4To6WithAnyVendorOption
)
{
testSendReceive
(
TEST_ITERATIONS
,
ENDPOINT_TYPE_V4
,
ENDPOINT_TYPE_V6
,
&
createDHCPv4o6MsgWithAnyVendorOption
);
}
// This test checks that the values of the socket descriptor are correct
...
...
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