From: Francis Dupont Date: Sun, 31 Jul 2022 14:23:48 +0000 (+0200) Subject: [#2517] Added getList for option descriptors X-Git-Tag: Kea-2.3.0~63 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e12fd058170af3b193c1c627c15471653dd6747d;p=thirdparty%2Fkea.git [#2517] Added getList for option descriptors --- diff --git a/src/lib/dhcpsrv/cfg_option.h b/src/lib/dhcpsrv/cfg_option.h index fedd7cce38..d2631d6f76 100644 --- a/src/lib/dhcpsrv/cfg_option.h +++ b/src/lib/dhcpsrv/cfg_option.h @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2021 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2022 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -22,8 +22,9 @@ #include #include #include -#include #include +#include +#include namespace isc { namespace dhcp { @@ -33,6 +34,9 @@ class OptionDescriptor; /// A pointer to option descriptor. typedef boost::shared_ptr OptionDescriptorPtr; +/// A list of option descriptors. +typedef std::vector OptionDescriptorList; + /// @brief Option descriptor. /// /// Option descriptor holds instance of an option and additional information @@ -532,14 +536,15 @@ public: /// /// @note If there are multiple options with the same key, only one will /// be returned. No indication will be given of the presence of others, - /// and the instance returned is not determinable. + /// and the instance returned is not determinable. So please use + /// the next method when multiple instances of the option are expected. /// /// @param key Option space name or vendor identifier. /// @param option_code Code of the option to be returned. /// @tparam Selector one of: @c std::string or @c uint32_t /// /// @return Descriptor of the option. If option hasn't been found, the - /// descriptor holds NULL option. + /// descriptor holds null option. template OptionDescriptor get(const Selector& key, const uint16_t option_code) const { @@ -560,6 +565,40 @@ public: return (*od_itr); } + /// @brief Returns options for the specified key and option code. + /// + /// The key should be a string, in which case it specifies an option space + /// name, or an uint32_t value, in which case it specifies a vendor + /// identifier. + /// + /// @param key Option space name or vendor identifier. + /// @param option_code Code of the option to be returned. + /// @tparam Selector one of: @c std::string or @c uint32_t + /// + /// @return List of Descriptors of the option. + template + OptionDescriptorList getList(const Selector& key, + const uint16_t option_code) const { + + OptionDescriptorList list; + // Check for presence of options. + OptionContainerPtr options = getAll(key); + if (!options || options->empty()) { + return (list); + } + + // Some options present, locate the one we are interested in. + const OptionContainerTypeIndex& idx = options->get<1>(); + OptionContainerTypeRange range = idx.equal_range(option_code); + // This code copies descriptors and can be optimized not doing this. + for (OptionContainerTypeIndex::const_iterator od_itr = range.first; + od_itr != range.second; ++od_itr) { + list.push_back(*od_itr); + } + + return (list); + } + /// @brief Deletes option for the specified option space and option code. /// /// If the option is encapsulated within some non top level option space, diff --git a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc index 2e1acb2faa..2f1408a4a5 100644 --- a/src/lib/dhcpsrv/tests/cfg_option_unittest.cc +++ b/src/lib/dhcpsrv/tests/cfg_option_unittest.cc @@ -921,7 +921,7 @@ TEST_F(CfgOptionTest, get) { std::ostringstream stream; // First, try the invalid option space name. OptionDescriptor desc = cfg.get("isc", code); - // Returned descriptor should contain NULL option ptr. + // Returned descriptor should contain null option ptr. EXPECT_FALSE(desc.option_); // Now, try the valid option space. desc = cfg.get(DHCP6_OPTION_SPACE, code); @@ -931,6 +931,95 @@ TEST_F(CfgOptionTest, get) { } } +// This test verifies that multiple options can be retrieved from the +// configuration using option code and option space. +TEST_F(CfgOptionTest, getList) { + CfgOption cfg; + + // Add twice 10 options to a "dhcp4" option space in the subnet. + for (uint16_t code = 100; code < 110; ++code) { + OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF))); + ASSERT_NO_THROW(cfg.add(option, false, DHCP4_OPTION_SPACE)); + OptionPtr option2(new Option(Option::V4, code, OptionBuffer(10, 0xEE))); + ASSERT_NO_THROW(cfg.add(option2, false, DHCP4_OPTION_SPACE)); + } + + // Check that we can get each added option descriptors. + for (uint16_t code = 100; code < 110; ++code) { + std::ostringstream stream; + // First, try the invalid option space name. + OptionDescriptorList list = cfg.getList("isc", code); + // Returned descriptor list should be empty. + EXPECT_TRUE(list.empty()); + // Now, try the valid option space. + list = cfg.getList(DHCP4_OPTION_SPACE, code); + // Test that the option code matches the expected code. + ASSERT_EQ(2, list.size()); + OptionDescriptor desc = list[0]; + ASSERT_TRUE(desc.option_); + EXPECT_EQ(code, desc.option_->getType()); + OptionBuffer content = desc.option_->getData(); + ASSERT_EQ(10, content.size()); + uint8_t val = content[8]; + EXPECT_TRUE((val == 0xFF) || (val == 0xEE)); + desc = list[1]; + ASSERT_TRUE(desc.option_); + EXPECT_EQ(code, desc.option_->getType()); + content = desc.option_->getData(); + ASSERT_EQ(10, content.size()); + if (val == 0xFF) { + EXPECT_EQ(0xEE, content[4]); + } else { + EXPECT_EQ(0xFF, content[4]); + } + } +} + +// This test verifies that multiple options can be retrieved from the +// configuration using option code and vendor space. +TEST_F(CfgOptionTest, getListVendor) { + CfgOption cfg; + std::string vendor_space("vendor-12345678"); + + // Add twice 10 options to a "dhcp4" option space in the subnet. + for (uint16_t code = 100; code < 110; ++code) { + OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF))); + ASSERT_NO_THROW(cfg.add(option, false, vendor_space)); + OptionPtr option2(new Option(Option::V4, code, OptionBuffer(10, 0xEE))); + ASSERT_NO_THROW(cfg.add(option2, false, vendor_space)); + } + + // Check that we can get each added option descriptors. + for (uint16_t code = 100; code < 110; ++code) { + std::ostringstream stream; + // First, try the invalid option space name. + OptionDescriptorList list = cfg.getList(11111111, code); + // Returned descriptor list should be empty. + EXPECT_TRUE(list.empty()); + // Now, try the valid option space. + list = cfg.getList(12345678, code); + // Test that the option code matches the expected code. + ASSERT_EQ(2, list.size()); + OptionDescriptor desc = list[0]; + ASSERT_TRUE(desc.option_); + EXPECT_EQ(code, desc.option_->getType()); + OptionBuffer content = desc.option_->getData(); + ASSERT_EQ(10, content.size()); + uint8_t val = content[8]; + EXPECT_TRUE((val == 0xFF) || (val == 0xEE)); + desc = list[1]; + ASSERT_TRUE(desc.option_); + EXPECT_EQ(code, desc.option_->getType()); + content = desc.option_->getData(); + ASSERT_EQ(10, content.size()); + if (val == 0xFF) { + EXPECT_EQ(0xEE, content[4]); + } else { + EXPECT_EQ(0xFF, content[4]); + } + } +} + // This test verifies that the same options can be added to the configuration // under different option space. TEST_F(CfgOptionTest, addNonUniqueOptions) {