mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
[219-allow-an-option-value-to-be-set-from-an-expression] Added new tests and an example
This commit is contained in:
@@ -1216,14 +1216,15 @@ take a string value representing an expression.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
"Dhcp6": {
|
"Dhcp4": {
|
||||||
"hook_libraries": [
|
"hook_libraries": [
|
||||||
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
|
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"code": 100,
|
"code": 67,
|
||||||
"add": "concat(relay6[0].option[37].hex, 'abc')"
|
"add":
|
||||||
|
"ifelse(option[host-name].exists,concat(option[host-name].text,'.boot'),'')"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1232,8 +1233,14 @@ take a string value representing an expression.
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
If (and only if) the query includes a host-name option (code 12),
|
||||||
|
a boot-file-name option (code 67) is added to the response with the host
|
||||||
|
name followed by .boot for content.
|
||||||
|
|
||||||
The flexible option library supports both DHCPv4 and DHCPv6.
|
The flexible option library supports both DHCPv4 and DHCPv6.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _host-cmds:
|
.. _host-cmds:
|
||||||
|
|
||||||
host_cmds: Host Commands
|
host_cmds: Host Commands
|
||||||
|
@@ -63,7 +63,7 @@ To configure it for kea-dhcp6, the commands are simply as shown below:
|
|||||||
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
|
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"code": 100,
|
"code": 100,
|
||||||
"add": "concat(relay6[0].option[37].hex, 'abc')"
|
"add": "concat(relay6[0].option[37].hex, 'abc')"
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,8 @@
|
|||||||
#include <hooks/hooks_manager.h>
|
#include <hooks/hooks_manager.h>
|
||||||
#include <hooks/callout_manager.h>
|
#include <hooks/callout_manager.h>
|
||||||
#include <dhcp/pkt4.h>
|
#include <dhcp/pkt4.h>
|
||||||
|
#include <dhcp/pkt6.h>
|
||||||
|
#include <dhcpsrv/cfgmgr.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -114,7 +116,7 @@ TEST_F(CalloutTest, pkt4Send) {
|
|||||||
EXPECT_NO_THROW(HooksManager::callCallouts(testHooks.hook_index_pkt4_send_,
|
EXPECT_NO_THROW(HooksManager::callCallouts(testHooks.hook_index_pkt4_send_,
|
||||||
*handle));
|
*handle));
|
||||||
EXPECT_EQ(0, handle->getStatus());
|
EXPECT_EQ(0, handle->getStatus());
|
||||||
|
|
||||||
// Check the result.
|
// Check the result.
|
||||||
OptionPtr opt = response->getOption(DHO_HOST_NAME);
|
OptionPtr opt = response->getOption(DHO_HOST_NAME);
|
||||||
ASSERT_TRUE(opt);
|
ASSERT_TRUE(opt);
|
||||||
@@ -124,4 +126,49 @@ TEST_F(CalloutTest, pkt4Send) {
|
|||||||
EXPECT_EQ(0, memcmp(&buffer[0], "abc", 3));
|
EXPECT_EQ(0, memcmp(&buffer[0], "abc", 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple test which exercises the pkt6_send callout.
|
||||||
|
TEST_F(CalloutTest, pkt6Send) {
|
||||||
|
// Move to DHCPv6.
|
||||||
|
CfgMgr::instance().setFamily(AF_INET6);
|
||||||
|
|
||||||
|
// Prepare load() parameters.
|
||||||
|
ElementPtr params = Element::createMap();
|
||||||
|
ElementPtr options = Element::createList();
|
||||||
|
params->set("options", options);
|
||||||
|
ElementPtr option = Element::createMap();
|
||||||
|
options->add(option);
|
||||||
|
ElementPtr code = Element::create(D6O_BOOTFILE_URL);
|
||||||
|
option->set("code", code);
|
||||||
|
ElementPtr supersede = Element::create(string("'abc'"));
|
||||||
|
option->set("supersede", supersede);
|
||||||
|
|
||||||
|
// Load the library.
|
||||||
|
addLib(FLEX_OPTION_LIB_SO, params);
|
||||||
|
loadLibs();
|
||||||
|
|
||||||
|
// Prepare packets.
|
||||||
|
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 12345));
|
||||||
|
Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, 12345));
|
||||||
|
EXPECT_FALSE(response->getOption(D6O_BOOTFILE_URL));
|
||||||
|
|
||||||
|
// Get and setup the callout handle.
|
||||||
|
EXPECT_TRUE(HooksManager::calloutsPresent(testHooks.hook_index_pkt6_send_));
|
||||||
|
CalloutHandlePtr handle = HooksManager::createCalloutHandle();
|
||||||
|
handle->setArgument("query6", query);
|
||||||
|
handle->setArgument("response6", response);
|
||||||
|
|
||||||
|
// Execute the callout.
|
||||||
|
EXPECT_NO_THROW(HooksManager::callCallouts(testHooks.hook_index_pkt6_send_,
|
||||||
|
*handle));
|
||||||
|
EXPECT_EQ(0, handle->getStatus());
|
||||||
|
|
||||||
|
// Check the result.
|
||||||
|
OptionPtr opt = response->getOption(D6O_BOOTFILE_URL);
|
||||||
|
ASSERT_TRUE(opt);
|
||||||
|
EXPECT_EQ(D6O_BOOTFILE_URL, opt->getType());
|
||||||
|
const OptionBuffer& buffer = opt->getData();
|
||||||
|
ASSERT_EQ(3, buffer.size());
|
||||||
|
EXPECT_EQ(0, memcmp(&buffer[0], "abc", 3));
|
||||||
|
}
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
@@ -778,6 +778,8 @@ TEST_F(FlexOptionTest, processAdd) {
|
|||||||
|
|
||||||
// Verify that ADD action does not add an already existing option.
|
// Verify that ADD action does not add an already existing option.
|
||||||
TEST_F(FlexOptionTest, processAddExisting) {
|
TEST_F(FlexOptionTest, processAddExisting) {
|
||||||
|
CfgMgr::instance().setFamily(AF_INET6);
|
||||||
|
|
||||||
ElementPtr options = Element::createList();
|
ElementPtr options = Element::createList();
|
||||||
ElementPtr option = Element::createMap();
|
ElementPtr option = Element::createMap();
|
||||||
options->add(option);
|
options->add(option);
|
||||||
@@ -852,6 +854,8 @@ TEST_F(FlexOptionTest, processSupersede) {
|
|||||||
|
|
||||||
// Verify that SUPERSEDE action supersedes an already existing option.
|
// Verify that SUPERSEDE action supersedes an already existing option.
|
||||||
TEST_F(FlexOptionTest, processSupersedeExisting) {
|
TEST_F(FlexOptionTest, processSupersedeExisting) {
|
||||||
|
CfgMgr::instance().setFamily(AF_INET6);
|
||||||
|
|
||||||
ElementPtr options = Element::createList();
|
ElementPtr options = Element::createList();
|
||||||
ElementPtr option = Element::createMap();
|
ElementPtr option = Element::createMap();
|
||||||
options->add(option);
|
options->add(option);
|
||||||
@@ -916,6 +920,8 @@ TEST_F(FlexOptionTest, processSupersedeEmpty) {
|
|||||||
|
|
||||||
// Verify that REMOVE action removes an already existing option.
|
// Verify that REMOVE action removes an already existing option.
|
||||||
TEST_F(FlexOptionTest, processRemove) {
|
TEST_F(FlexOptionTest, processRemove) {
|
||||||
|
CfgMgr::instance().setFamily(AF_INET6);
|
||||||
|
|
||||||
ElementPtr options = Element::createList();
|
ElementPtr options = Element::createList();
|
||||||
ElementPtr option = Element::createMap();
|
ElementPtr option = Element::createMap();
|
||||||
options->add(option);
|
options->add(option);
|
||||||
@@ -961,6 +967,8 @@ TEST_F(FlexOptionTest, processRemoveNoOption) {
|
|||||||
|
|
||||||
// Verify that REMOVE action does nothing when the expression evaluates to false.
|
// Verify that REMOVE action does nothing when the expression evaluates to false.
|
||||||
TEST_F(FlexOptionTest, processRemoveFalse) {
|
TEST_F(FlexOptionTest, processRemoveFalse) {
|
||||||
|
CfgMgr::instance().setFamily(AF_INET6);
|
||||||
|
|
||||||
ElementPtr options = Element::createList();
|
ElementPtr options = Element::createList();
|
||||||
ElementPtr option = Element::createMap();
|
ElementPtr option = Element::createMap();
|
||||||
options->add(option);
|
options->add(option);
|
||||||
@@ -971,16 +979,46 @@ TEST_F(FlexOptionTest, processRemoveFalse) {
|
|||||||
EXPECT_NO_THROW(impl_->testConfigure(options));
|
EXPECT_NO_THROW(impl_->testConfigure(options));
|
||||||
EXPECT_TRUE(impl_->getErrMsg().empty());
|
EXPECT_TRUE(impl_->getErrMsg().empty());
|
||||||
|
|
||||||
Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 12345));
|
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 12345));
|
||||||
Pkt4Ptr response(new Pkt4(DHCPOFFER, 12345));
|
Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, 12345));
|
||||||
OptionStringPtr str(new OptionString(Option::V6, D6O_BOOTFILE_URL, "http"));
|
OptionStringPtr str(new OptionString(Option::V6, D6O_BOOTFILE_URL, "http"));
|
||||||
response->addOption(str);
|
response->addOption(str);
|
||||||
string response_txt = response->toText();
|
string response_txt = response->toText();
|
||||||
|
|
||||||
EXPECT_NO_THROW(impl_->process<Pkt4Ptr>(Option::V6, query, response));
|
EXPECT_NO_THROW(impl_->process<Pkt6Ptr>(Option::V6, query, response));
|
||||||
|
|
||||||
EXPECT_EQ(response_txt, response->toText());
|
EXPECT_EQ(response_txt, response->toText());
|
||||||
EXPECT_TRUE(response->getOption(D6O_BOOTFILE_URL));
|
EXPECT_TRUE(response->getOption(D6O_BOOTFILE_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A more complex check...
|
||||||
|
TEST_F(FlexOptionTest, processFullTest) {
|
||||||
|
ElementPtr options = Element::createList();
|
||||||
|
ElementPtr option = Element::createMap();
|
||||||
|
options->add(option);
|
||||||
|
ElementPtr code = Element::create(DHO_BOOT_FILE_NAME);
|
||||||
|
option->set("code", code);
|
||||||
|
string expr = "ifelse(option[host-name].exists,";
|
||||||
|
expr += "concat(option[host-name].text,'.boot'),'')";
|
||||||
|
ElementPtr add = Element::create(expr);
|
||||||
|
option->set("add", add);
|
||||||
|
EXPECT_NO_THROW(impl_->testConfigure(options));
|
||||||
|
EXPECT_TRUE(impl_->getErrMsg().empty());
|
||||||
|
|
||||||
|
Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 12345));
|
||||||
|
Pkt4Ptr response(new Pkt4(DHCPOFFER, 12345));
|
||||||
|
OptionStringPtr str(new OptionString(Option::V4, DHO_HOST_NAME, "foo"));
|
||||||
|
query->addOption(str);
|
||||||
|
EXPECT_FALSE(response->getOption(DHO_BOOT_FILE_NAME));
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(impl_->process<Pkt4Ptr>(Option::V4, query, response));
|
||||||
|
|
||||||
|
OptionPtr opt = response->getOption(DHO_BOOT_FILE_NAME);
|
||||||
|
ASSERT_TRUE(opt);
|
||||||
|
EXPECT_EQ(DHO_BOOT_FILE_NAME, opt->getType());
|
||||||
|
const OptionBuffer& buffer = opt->getData();
|
||||||
|
ASSERT_EQ(8, buffer.size());
|
||||||
|
EXPECT_EQ(0, memcmp(&buffer[0], "foo.boot", 8));
|
||||||
|
}
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
Reference in New Issue
Block a user