From 556f6591bed33a424d02e47b8f15df8467ff04d4 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Mon, 3 Jul 2017 23:09:12 +0200 Subject: [PATCH] [5288] Added option-data in DHCPv4 pools --- doc/examples/kea4/multiple-options.json | 18 +- doc/guide/dhcp4-srv.xml | 51 +++ src/bin/dhcp4/tests/config_parser_unittest.cc | 151 +++++++++ src/bin/dhcp4/tests/get_config_unittest.cc | 298 +++++++++++++++--- .../dhcp4/tests/get_config_unittest.cc.skel | 2 +- src/lib/dhcpsrv/cfg_subnets4.cc | 4 +- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 6 - src/lib/dhcpsrv/tests/pool_unittest.cc | 54 +++- 8 files changed, 523 insertions(+), 61 deletions(-) diff --git a/doc/examples/kea4/multiple-options.json b/doc/examples/kea4/multiple-options.json index f48012a96d..c417365b69 100644 --- a/doc/examples/kea4/multiple-options.json +++ b/doc/examples/kea4/multiple-options.json @@ -32,9 +32,11 @@ // clients connected to this subnet. The first two options are // identified by the name. The third option is identified by the // option code. +// There is an address pool defined within this subnet. Pool +// specific value for option domain-name-servers is defined +// for the pool. "subnet4": [ { - "pools": [ { "pool": "192.0.2.10 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", "interface": "ethX", "option-data": [ @@ -124,9 +126,17 @@ "name": "default-ip-ttl", "data": "0xf0" } - ] - } - ] + ], + "pools": [ { + "pool": "192.0.2.10 - 192.0.2.200", + "option-data": [ + { + "name": "domain-name-servers", + "data": "192.0.2.3, 192.0.2.4" + } + ] + } ] + } ] }, // The following configures logging. It assumes that messages with at diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml index ff3873ac9a..e4af768777 100644 --- a/doc/guide/dhcp4-srv.xml +++ b/doc/guide/dhcp4-srv.xml @@ -1057,6 +1057,57 @@ temporarily override a list of interface names and listen on all interfaces. + + In some cases it is useful to associate some options with an + address pool from which a client is assigned a lease. Pool + specific option values override subnet specific and global + option values. If the client is assigned multiple leases from + different pools, the server will assign options from all pools + from which the leases have been obtained. However, if the + particular option is specified in multiple pools from which + the client obtains the leases, only one instance of this + option will be handed out to the client. The server's + administrator must not try to prioritize assignment of pool + specific options by trying to order pools declarations in the + server configuration. Future Kea releases may change the order + in which options are assigned from the pools without any + notice. + + + + The following configuration snippet demonstrates how to specify the + DNS servers option, which will be assigned to a client only if the + client obtains an address from the given pool: + +"Dhcp4": { + "subnet4": [ + { + "pools": [ + { + "pool": "192.0.2.1 - 192.0.2.200", + "option-data": [ + { + "name": "domain-name-servers", + "code": 6, + "space": "dhcp4", + "csv-format": true, + "data": "192.0.2.3" + }, + ... + ], + ... + }, + ... + ], + ... + }, + ... + ], + ... +} + + + The currently supported standard DHCPv4 options are listed in . diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index f997ef2535..3dc3bc8e1b 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -2739,6 +2739,157 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) { testOption(*range2.first, 23, foo2_expected, sizeof(foo2_expected)); } +// This test verifies that it is possible to specify options on +// pool levels. +TEST_F(Dhcp4ParserTest, optionDataSinglePool) { + ConstElementPtr x; + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"pools\": [ { " + " \"pool\": \"192.0.2.1 - 192.0.2.100\"," + " \"option-data\": [ {" + " \"name\": \"dhcp-message\"," + " \"data\": \"ABCDEF0105\"," + " \"csv-format\": false" + " }," + " {" + " \"name\": \"default-ip-ttl\"," + " \"data\": \"01\"," + " \"csv-format\": false" + " } ]" + " } ]," + " \"subnet\": \"192.0.2.0/24\"" + " } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP4(config)); + extractConfig(config); + + EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json)); + checkResult(x, 0); + + Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()-> + selectSubnet(IOAddress("192.0.2.24"), classify_); + ASSERT_TRUE(subnet); + + PoolPtr pool = subnet->getPool(Lease::TYPE_V4, IOAddress("192.0.2.24"), false); + ASSERT_TRUE(pool); + Pool4Ptr pool4 = boost::dynamic_pointer_cast(pool); + ASSERT_TRUE(pool4); + + OptionContainerPtr options = pool4->getCfgOption()->getAll("dhcp4"); + ASSERT_EQ(2, options->size()); + + // Get the search index. Index #1 is to search using option code. + const OptionContainerTypeIndex& idx = options->get<1>(); + + // Get the options for specified index. Expecting one option to be + // returned but in theory we may have multiple options with the same + // code so we get the range. + std::pair range = + idx.equal_range(56); + // Expect a single option with the code equal to 100. + ASSERT_EQ(1, std::distance(range.first, range.second)); + const uint8_t foo_expected[] = { + 0xAB, 0xCD, 0xEF, 0x01, 0x05 + }; + // Check if option is valid in terms of code and carried data. + testOption(*range.first, 56, foo_expected, sizeof(foo_expected)); + + range = idx.equal_range(23); + ASSERT_EQ(1, std::distance(range.first, range.second)); + // Do another round of testing with second option. + const uint8_t foo2_expected[] = { + 0x01 + }; + testOption(*range.first, 23, foo2_expected, sizeof(foo2_expected)); +} + +TEST_F(Dhcp4ParserTest, optionDataMultiplePools) { + ConstElementPtr x; + string config = "{ " + genIfaceConfig() + "," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet4\": [ { " + " \"pools\": [ { " + " \"pool\": \"192.0.2.1 - 192.0.2.100\"," + " \"option-data\": [ {" + " \"name\": \"dhcp-message\"," + " \"data\": \"ABCDEF0105\"," + " \"csv-format\": false" + " } ]" + " }," + " {" + " \"pool\": \"192.0.2.200 - 192.0.2.250\"," + " \"option-data\": [ {" + " \"name\": \"default-ip-ttl\"," + " \"data\": \"01\"," + " \"csv-format\": false" + " } ]" + " } ]," + " \"subnet\": \"192.0.2.0/24\"" + " } ]," + "\"valid-lifetime\": 4000 }"; + + ConstElementPtr json; + ASSERT_NO_THROW(json = parseDHCP4(config)); + extractConfig(config); + + EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json)); + checkResult(x, 0); + + Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()-> + selectSubnet(IOAddress("192.0.2.24"), classify_); + ASSERT_TRUE(subnet); + + PoolPtr pool1 = subnet->getPool(Lease::TYPE_V4, IOAddress("192.0.2.24"), false); + ASSERT_TRUE(pool1); + Pool4Ptr pool41 = boost::dynamic_pointer_cast(pool1); + ASSERT_TRUE(pool41); + + OptionContainerPtr options1 = pool41->getCfgOption()->getAll("dhcp4"); + ASSERT_EQ(1, options1->size()); + + // Get the search index. Index #1 is to search using option code. + const OptionContainerTypeIndex& idx1 = options1->get<1>(); + + // Get the options for specified index. Expecting one option to be + // returned but in theory we may have multiple options with the same + // code so we get the range. + std::pair range1 = + idx1.equal_range(56); + // Expect a single option with the code equal to 100. + ASSERT_EQ(1, std::distance(range1.first, range1.second)); + const uint8_t foo_expected[] = { + 0xAB, 0xCD, 0xEF, 0x01, 0x05 + }; + // Check if option is valid in terms of code and carried data. + testOption(*range1.first, 56, foo_expected, sizeof(foo_expected)); + + // Test another pool in the same way. + PoolPtr pool2 = subnet->getPool(Lease::TYPE_V4, IOAddress("192.0.2.240"), false); + ASSERT_TRUE(pool2); + Pool4Ptr pool42 = boost::dynamic_pointer_cast(pool2); + ASSERT_TRUE(pool42); + + OptionContainerPtr options2 = pool42->getCfgOption()->getAll("dhcp4"); + ASSERT_EQ(1, options2->size()); + + const OptionContainerTypeIndex& idx2 = options2->get<1>(); + std::pair range2 = + idx2.equal_range(23); + ASSERT_EQ(1, std::distance(range2.first, range2.second)); + const uint8_t foo2_expected[] = { + 0x01 + }; + testOption(*range2.first, 23, foo2_expected, sizeof(foo2_expected)); +} // Verify that empty option name is rejected in the configuration. diff --git a/src/bin/dhcp4/tests/get_config_unittest.cc b/src/bin/dhcp4/tests/get_config_unittest.cc index 5c4bff4879..ef0fc38028 100644 --- a/src/bin/dhcp4/tests/get_config_unittest.cc +++ b/src/bin/dhcp4/tests/get_config_unittest.cc @@ -816,6 +816,73 @@ const char* EXTRACTED_CONFIGS[] = { " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" " },\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet4\": [\n" +" {\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"ABCDEF0105\",\n" +" \"name\": \"dhcp-message\"\n" +" },\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"01\",\n" +" \"name\": \"default-ip-ttl\"\n" +" }\n" +" ],\n" +" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.2.0/24\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 31 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ]\n" +" },\n" +" \"rebind-timer\": 2000,\n" +" \"renew-timer\": 1000,\n" +" \"subnet4\": [\n" +" {\n" +" \"pools\": [\n" +" {\n" +" \"option-data\": [\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"ABCDEF0105\",\n" +" \"name\": \"dhcp-message\"\n" +" }\n" +" ],\n" +" \"pool\": \"192.0.2.1 - 192.0.2.100\"\n" +" },\n" +" {\n" +" \"option-data\": [\n" +" {\n" +" \"csv-format\": false,\n" +" \"data\": \"01\",\n" +" \"name\": \"default-ip-ttl\"\n" +" }\n" +" ],\n" +" \"pool\": \"192.0.2.200 - 192.0.2.250\"\n" +" }\n" +" ],\n" +" \"subnet\": \"192.0.2.0/24\"\n" +" }\n" +" ],\n" +" \"valid-lifetime\": 4000\n" +" }\n", + // CONFIGURATION 32 +"{\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ]\n" +" },\n" " \"option-data\": [\n" " {\n" " \"data\": \"1234\",\n" @@ -846,7 +913,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 31 + // CONFIGURATION 33 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -897,7 +964,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 3000\n" " }\n", - // CONFIGURATION 32 + // CONFIGURATION 34 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -932,7 +999,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 33 + // CONFIGURATION 35 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -967,7 +1034,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 34 + // CONFIGURATION 36 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"eth0\", \"eth1\" ]\n" @@ -976,7 +1043,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 35 + // CONFIGURATION 37 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"eth0\", \"*\", \"eth1\" ]\n" @@ -985,7 +1052,7 @@ const char* EXTRACTED_CONFIGS[] = { " \"renew-timer\": 1000,\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 36 + // CONFIGURATION 38 "{\n" " \"dhcp-ddns\": {\n" " \"always-include-fqdn\": true,\n" @@ -1020,7 +1087,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 37 + // CONFIGURATION 39 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1045,7 +1112,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 38 + // CONFIGURATION 40 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1143,7 +1210,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 39 + // CONFIGURATION 41 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1184,7 +1251,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 40 + // CONFIGURATION 42 "{\n" " \"rebind-timer\": 2000,\n" " \"renew-timer\": 1000,\n" @@ -1227,21 +1294,21 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 41 + // CONFIGURATION 43 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 42 + // CONFIGURATION 44 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 43 + // CONFIGURATION 45 "{\n" " \"decline-probation-period\": 12345,\n" " \"interfaces-config\": {\n" @@ -1249,7 +1316,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 44 + // CONFIGURATION 46 "{\n" " \"expired-leases-processing\": {\n" " \"flush-reclaimed-timer-wait-time\": 35,\n" @@ -1264,7 +1331,7 @@ const char* EXTRACTED_CONFIGS[] = { " },\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 45 + // CONFIGURATION 47 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1283,7 +1350,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 46 + // CONFIGURATION 48 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1303,7 +1370,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 47 + // CONFIGURATION 49 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1323,7 +1390,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 48 + // CONFIGURATION 50 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1344,7 +1411,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 49 + // CONFIGURATION 51 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1364,7 +1431,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 50 + // CONFIGURATION 52 "{\n" " \"client-classes\": [\n" " {\n" @@ -1394,7 +1461,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 51 + // CONFIGURATION 53 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1413,7 +1480,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 52 + // CONFIGURATION 54 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1433,7 +1500,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 53 + // CONFIGURATION 55 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -1457,7 +1524,7 @@ const char* EXTRACTED_CONFIGS[] = { " ],\n" " \"valid-lifetime\": 4000\n" " }\n", - // CONFIGURATION 54 + // CONFIGURATION 56 "{\n" " \"interfaces-config\": {\n" " \"interfaces\": [ \"*\" ]\n" @@ -3780,6 +3847,141 @@ const char* UNPARSED_CONFIGS[] = { " \"lease-database\": {\n" " \"type\": \"memfile\"\n" " },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"subnet4\": [\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"id\": 1,\n" +" \"interface\": \"\",\n" +" \"match-client-id\": true,\n" +" \"next-server\": \"0.0.0.0\",\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-address\": \"0.0.0.0\"\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservation-mode\": \"all\",\n" +" \"reservations\": [ ],\n" +" \"subnet\": \"192.0.2.0/24\",\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ]\n" +" }\n", + // CONFIGURATION 31 +"{\n" +" \"decline-probation-period\": 86400,\n" +" \"dhcp-ddns\": {\n" +" \"always-include-fqdn\": false,\n" +" \"enable-updates\": false,\n" +" \"generated-prefix\": \"myhost\",\n" +" \"max-queue-size\": 1024,\n" +" \"ncr-format\": \"JSON\",\n" +" \"ncr-protocol\": \"UDP\",\n" +" \"override-client-update\": false,\n" +" \"override-no-update\": false,\n" +" \"qualifying-suffix\": \"\",\n" +" \"replace-client-name\": \"never\",\n" +" \"sender-ip\": \"0.0.0.0\",\n" +" \"sender-port\": 0,\n" +" \"server-ip\": \"127.0.0.1\",\n" +" \"server-port\": 53001\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"echo-client-id\": true,\n" +" \"expired-leases-processing\": {\n" +" \"flush-reclaimed-timer-wait-time\": 25,\n" +" \"hold-reclaimed-time\": 3600,\n" +" \"max-reclaim-leases\": 100,\n" +" \"max-reclaim-time\": 250,\n" +" \"reclaim-timer-wait-time\": 10,\n" +" \"unwarned-reclaim-cycles\": 5\n" +" },\n" +" \"hooks-libraries\": [ ],\n" +" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ]\n" +" },\n" +" \"lease-database\": {\n" +" \"type\": \"memfile\"\n" +" },\n" +" \"option-data\": [ ],\n" +" \"option-def\": [ ],\n" +" \"subnet4\": [\n" +" {\n" +" \"4o6-interface\": \"\",\n" +" \"4o6-interface-id\": \"\",\n" +" \"4o6-subnet\": \"\",\n" +" \"id\": 1,\n" +" \"interface\": \"\",\n" +" \"match-client-id\": true,\n" +" \"next-server\": \"0.0.0.0\",\n" +" \"option-data\": [ ],\n" +" \"pools\": [\n" +" {\n" +" \"pool\": \"192.0.2.1-192.0.2.100\"\n" +" },\n" +" {\n" +" \"pool\": \"192.0.2.200-192.0.2.250\"\n" +" }\n" +" ],\n" +" \"rebind-timer\": 2000,\n" +" \"relay\": {\n" +" \"ip-address\": \"0.0.0.0\"\n" +" },\n" +" \"renew-timer\": 1000,\n" +" \"reservation-mode\": \"all\",\n" +" \"reservations\": [ ],\n" +" \"subnet\": \"192.0.2.0/24\",\n" +" \"valid-lifetime\": 4000\n" +" }\n" +" ]\n" +" }\n", + // CONFIGURATION 32 +"{\n" +" \"decline-probation-period\": 86400,\n" +" \"dhcp-ddns\": {\n" +" \"always-include-fqdn\": false,\n" +" \"enable-updates\": false,\n" +" \"generated-prefix\": \"myhost\",\n" +" \"max-queue-size\": 1024,\n" +" \"ncr-format\": \"JSON\",\n" +" \"ncr-protocol\": \"UDP\",\n" +" \"override-client-update\": false,\n" +" \"override-no-update\": false,\n" +" \"qualifying-suffix\": \"\",\n" +" \"replace-client-name\": \"never\",\n" +" \"sender-ip\": \"0.0.0.0\",\n" +" \"sender-port\": 0,\n" +" \"server-ip\": \"127.0.0.1\",\n" +" \"server-port\": 53001\n" +" },\n" +" \"dhcp4o6-port\": 0,\n" +" \"echo-client-id\": true,\n" +" \"expired-leases-processing\": {\n" +" \"flush-reclaimed-timer-wait-time\": 25,\n" +" \"hold-reclaimed-time\": 3600,\n" +" \"max-reclaim-leases\": 100,\n" +" \"max-reclaim-time\": 250,\n" +" \"reclaim-timer-wait-time\": 10,\n" +" \"unwarned-reclaim-cycles\": 5\n" +" },\n" +" \"hooks-libraries\": [ ],\n" +" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n" +" \"interfaces-config\": {\n" +" \"interfaces\": [ \"*\" ]\n" +" },\n" +" \"lease-database\": {\n" +" \"type\": \"memfile\"\n" +" },\n" " \"option-data\": [\n" " {\n" " \"code\": 1,\n" @@ -3818,7 +4020,7 @@ const char* UNPARSED_CONFIGS[] = { " ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 31 + // CONFIGURATION 33 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -3925,7 +4127,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 32 + // CONFIGURATION 34 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4004,7 +4206,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 33 + // CONFIGURATION 35 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4088,7 +4290,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 34 + // CONFIGURATION 36 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4129,7 +4331,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 35 + // CONFIGURATION 37 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4170,7 +4372,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 36 + // CONFIGURATION 38 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4236,7 +4438,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 37 + // CONFIGURATION 39 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4302,7 +4504,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 38 + // CONFIGURATION 40 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4513,7 +4715,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 39 + // CONFIGURATION 41 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4608,7 +4810,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 40 + // CONFIGURATION 42 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4746,7 +4948,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 41 + // CONFIGURATION 43 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4787,7 +4989,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 42 + // CONFIGURATION 44 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4828,7 +5030,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 43 + // CONFIGURATION 45 "{\n" " \"decline-probation-period\": 12345,\n" " \"dhcp-ddns\": {\n" @@ -4869,7 +5071,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 44 + // CONFIGURATION 46 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4910,7 +5112,7 @@ const char* UNPARSED_CONFIGS[] = { " \"option-def\": [ ],\n" " \"subnet4\": [ ]\n" " }\n", - // CONFIGURATION 45 + // CONFIGURATION 47 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -4976,7 +5178,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 46 + // CONFIGURATION 48 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5042,7 +5244,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 47 + // CONFIGURATION 49 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5108,7 +5310,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 48 + // CONFIGURATION 50 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5174,7 +5376,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 49 + // CONFIGURATION 51 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5240,7 +5442,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 50 + // CONFIGURATION 52 "{\n" " \"client-classes\": [\n" " {\n" @@ -5329,7 +5531,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 51 + // CONFIGURATION 53 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5395,7 +5597,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 52 + // CONFIGURATION 54 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5462,7 +5664,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 53 + // CONFIGURATION 55 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" @@ -5533,7 +5735,7 @@ const char* UNPARSED_CONFIGS[] = { " }\n" " ]\n" " }\n", - // CONFIGURATION 54 + // CONFIGURATION 56 "{\n" " \"decline-probation-period\": 86400,\n" " \"dhcp-ddns\": {\n" diff --git a/src/bin/dhcp4/tests/get_config_unittest.cc.skel b/src/bin/dhcp4/tests/get_config_unittest.cc.skel index 59ac527a1d..477fbc0b43 100644 --- a/src/bin/dhcp4/tests/get_config_unittest.cc.skel +++ b/src/bin/dhcp4/tests/get_config_unittest.cc.skel @@ -340,6 +340,6 @@ TEST_P(Dhcp4GetConfigTest, run) { /// Define the parametrized test loop INSTANTIATE_TEST_CASE_P(Dhcp4GetConfigTest, Dhcp4GetConfigTest, - ::testing::Range(0UL, max_config_counter)); + ::testing::Range(static_cast(0), max_config_counter)); }; diff --git a/src/lib/dhcpsrv/cfg_subnets4.cc b/src/lib/dhcpsrv/cfg_subnets4.cc index df70d79517..136f213d45 100644 --- a/src/lib/dhcpsrv/cfg_subnets4.cc +++ b/src/lib/dhcpsrv/cfg_subnets4.cc @@ -335,7 +335,9 @@ CfgSubnets4::toElement() const { if (!isNull(context)) { pool_map->set("user-context", context); } - // Set pool options (not yet supported) + // Set pool options + ConstCfgOptionPtr opts = (*pool)->getCfgOption(); + pool_map->set("option-data", opts->toElement()); // Push on the pool list pool_list->add(pool_map); } diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 3b7f8f2986..73ceb07bbf 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -749,12 +749,6 @@ PoolParser::parse(PoolStoragePtr pools, ConstElementPtr option_data = pool_structure->get("option-data"); if (option_data) { try { - // Currently we don't support specifying options for the DHCPv4 server. - if (address_family == AF_INET) { - isc_throw(DhcpConfigError, "option-data is not supported for DHCPv4" - " address pools"); - } - CfgOptionPtr cfg = pool->getCfgOption(); OptionDataListParser option_parser(address_family); option_parser.parse(cfg, option_data); diff --git a/src/lib/dhcpsrv/tests/pool_unittest.cc b/src/lib/dhcpsrv/tests/pool_unittest.cc index 143522d361..8da257fe59 100644 --- a/src/lib/dhcpsrv/tests/pool_unittest.cc +++ b/src/lib/dhcpsrv/tests/pool_unittest.cc @@ -120,6 +120,58 @@ TEST(Pool4Test, toText) { EXPECT_EQ("type=V4, 192.0.2.128-192.0.2.143", pool2.toText()); } +// This test checks that it is possible to specify pool specific options. +TEST(Pool4Test, addOptions) { + // Create a pool to add options to it. + Pool4Ptr pool(new Pool4(IOAddress("192.0.2.0"), + IOAddress("192.0.2.255"))); + + // Differentiate options by their codes (100-109) + for (uint16_t code = 100; code < 110; ++code) { + OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF))); + ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "dhcp4")); + } + + // Add 7 options to another option space. The option codes partially overlap + // with option codes that we have added to dhcp4 option space. + for (uint16_t code = 105; code < 112; ++code) { + OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF))); + ASSERT_NO_THROW(pool->getCfgOption()->add(option, false, "isc")); + } + + // Get options from the pool and check if all 10 are there. + OptionContainerPtr options = pool->getCfgOption()->getAll("dhcp4"); + ASSERT_TRUE(options); + ASSERT_EQ(10, options->size()); + + // Validate codes of options added to dhcp4 option space. + uint16_t expected_code = 100; + for (OptionContainer::const_iterator option_desc = options->begin(); + option_desc != options->end(); ++option_desc) { + ASSERT_TRUE(option_desc->option_); + EXPECT_EQ(expected_code, option_desc->option_->getType()); + ++expected_code; + } + + options = pool->getCfgOption()->getAll("isc"); + ASSERT_TRUE(options); + ASSERT_EQ(7, options->size()); + + // Validate codes of options added to isc option space. + expected_code = 105; + for (OptionContainer::const_iterator option_desc = options->begin(); + option_desc != options->end(); ++option_desc) { + ASSERT_TRUE(option_desc->option_); + EXPECT_EQ(expected_code, option_desc->option_->getType()); + ++expected_code; + } + + // Try to get options from a non-existing option space. + options = pool->getCfgOption()->getAll("abcd"); + ASSERT_TRUE(options); + EXPECT_TRUE(options->empty()); +} + TEST(Pool6Test, constructor_first_last) { // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool @@ -329,7 +381,7 @@ TEST(Pool6Test, unique_id) { } // Simple check if toText returns reasonable values -TEST(Pool6Test,toText) { +TEST(Pool6Test, toText) { Pool6 pool1(Lease::TYPE_NA, IOAddress("2001:db8::1"), IOAddress("2001:db8::2")); EXPECT_EQ("type=IA_NA, 2001:db8::1-2001:db8::2, delegated_len=128", -- 2.47.2