mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 05:27:55 +00:00
[219-allow-an-option-value-to-be-set-from-an-expression] Added new tests and an example
This commit is contained in:
parent
85ff03658b
commit
3a1cec329b
@ -1216,14 +1216,15 @@ take a string value representing an expression.
|
||||
|
||||
::
|
||||
|
||||
"Dhcp6": {
|
||||
"Dhcp4": {
|
||||
"hook_libraries": [
|
||||
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
|
||||
"parameters": {
|
||||
"options": [
|
||||
{
|
||||
"code": 100,
|
||||
"add": "concat(relay6[0].option[37].hex, 'abc')"
|
||||
"code": 67,
|
||||
"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.
|
||||
|
||||
|
||||
|
||||
.. _host-cmds:
|
||||
|
||||
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",
|
||||
"parameters": {
|
||||
"options": [
|
||||
{
|
||||
{
|
||||
"code": 100,
|
||||
"add": "concat(relay6[0].option[37].hex, 'abc')"
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <hooks/hooks_manager.h>
|
||||
#include <hooks/callout_manager.h>
|
||||
#include <dhcp/pkt4.h>
|
||||
#include <dhcp/pkt6.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <errno.h>
|
||||
@ -114,7 +116,7 @@ TEST_F(CalloutTest, pkt4Send) {
|
||||
EXPECT_NO_THROW(HooksManager::callCallouts(testHooks.hook_index_pkt4_send_,
|
||||
*handle));
|
||||
EXPECT_EQ(0, handle->getStatus());
|
||||
|
||||
|
||||
// Check the result.
|
||||
OptionPtr opt = response->getOption(DHO_HOST_NAME);
|
||||
ASSERT_TRUE(opt);
|
||||
@ -124,4 +126,49 @@ TEST_F(CalloutTest, pkt4Send) {
|
||||
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
|
||||
|
@ -778,6 +778,8 @@ TEST_F(FlexOptionTest, processAdd) {
|
||||
|
||||
// Verify that ADD action does not add an already existing option.
|
||||
TEST_F(FlexOptionTest, processAddExisting) {
|
||||
CfgMgr::instance().setFamily(AF_INET6);
|
||||
|
||||
ElementPtr options = Element::createList();
|
||||
ElementPtr option = Element::createMap();
|
||||
options->add(option);
|
||||
@ -852,6 +854,8 @@ TEST_F(FlexOptionTest, processSupersede) {
|
||||
|
||||
// Verify that SUPERSEDE action supersedes an already existing option.
|
||||
TEST_F(FlexOptionTest, processSupersedeExisting) {
|
||||
CfgMgr::instance().setFamily(AF_INET6);
|
||||
|
||||
ElementPtr options = Element::createList();
|
||||
ElementPtr option = Element::createMap();
|
||||
options->add(option);
|
||||
@ -916,6 +920,8 @@ TEST_F(FlexOptionTest, processSupersedeEmpty) {
|
||||
|
||||
// Verify that REMOVE action removes an already existing option.
|
||||
TEST_F(FlexOptionTest, processRemove) {
|
||||
CfgMgr::instance().setFamily(AF_INET6);
|
||||
|
||||
ElementPtr options = Element::createList();
|
||||
ElementPtr option = Element::createMap();
|
||||
options->add(option);
|
||||
@ -961,6 +967,8 @@ TEST_F(FlexOptionTest, processRemoveNoOption) {
|
||||
|
||||
// Verify that REMOVE action does nothing when the expression evaluates to false.
|
||||
TEST_F(FlexOptionTest, processRemoveFalse) {
|
||||
CfgMgr::instance().setFamily(AF_INET6);
|
||||
|
||||
ElementPtr options = Element::createList();
|
||||
ElementPtr option = Element::createMap();
|
||||
options->add(option);
|
||||
@ -971,16 +979,46 @@ TEST_F(FlexOptionTest, processRemoveFalse) {
|
||||
EXPECT_NO_THROW(impl_->testConfigure(options));
|
||||
EXPECT_TRUE(impl_->getErrMsg().empty());
|
||||
|
||||
Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 12345));
|
||||
Pkt4Ptr response(new Pkt4(DHCPOFFER, 12345));
|
||||
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 12345));
|
||||
Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, 12345));
|
||||
OptionStringPtr str(new OptionString(Option::V6, D6O_BOOTFILE_URL, "http"));
|
||||
response->addOption(str);
|
||||
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_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
|
||||
|
Loading…
x
Reference in New Issue
Block a user