2
0
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:
Francis Dupont
2019-10-04 21:46:14 +02:00
parent 85ff03658b
commit 3a1cec329b
4 changed files with 100 additions and 8 deletions

View File

@@ -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

View File

@@ -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')"
} }

View File

@@ -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

View File

@@ -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