Commit 3a1cec32 authored by Francis Dupont's avatar Francis Dupont
Browse files

[219-allow-an-option-value-to-be-set-from-an-expression] Added new tests and an example

parent 85ff0365
...@@ -1216,14 +1216,15 @@ take a string value representing an expression. ...@@ -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. ...@@ -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: ...@@ -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 @@ ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment