]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[219-allow-an-option-value-to-be-set-from-an-expression] Added new tests and an example
authorFrancis Dupont <fdupont@isc.org>
Fri, 4 Oct 2019 19:46:14 +0000 (21:46 +0200)
committerFrancis Dupont <fdupont@isc.org>
Fri, 25 Oct 2019 08:57:53 +0000 (10:57 +0200)
doc/sphinx/arm/hooks.rst
src/hooks/dhcp/flex_option/flex_option.dox
src/hooks/dhcp/flex_option/libloadtests/callout_unittests.cc
src/hooks/dhcp/flex_option/tests/flex_option_unittests.cc

index 23487b3c89a1673a27b61e6acab5fee4972b542c..cedcb341c051a9dea68af15544d62019ef438a8e 100644 (file)
@@ -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
index 7f444ca1f262ac9855f797f1b99bf7bd81758289..d168dcf7d82b8ceeb6cb8e7a6d6ec4ed7dccba23 100644 (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",
             "parameters": {
                 "options": [
-                   {
+                    {
                         "code": 100,
                         "add": "concat(relay6[0].option[37].hex, 'abc')"
                     }
index ecd58ac45c3b189207ef79d8258e246af225e5b8..db1cb67ffeaff1911e7a6c7f81c1291223c58d21 100644 (file)
@@ -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
index 90a8ee01bdac461948cce713e7f285153f2e159c..5126b1fdd0b130854ea496a1c42b82f6c1d4e093 100644 (file)
@@ -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