+--------------------------+-----------------+-----------------+-----------------+
| relay-id | 53 | binary | false |
+--------------------------+-----------------+-----------------+-----------------+
+ | ntp-server | 56 | empty | false |
+ +--------------------------+-----------------+-----------------+-----------------+
| v6-access-domain | 57 | fqdn | false |
+--------------------------+-----------------+-----------------+-----------------+
| sip-ua-cs-list | 58 | fqdn | true |
in the ``doc/examples/kea6`` directory. The DHCPv4 option is nearly identical, and is described
in :ref:`dnr4-options`.
+.. _ntp-server-suboptions:
+
+NTP Server Suboptions
+---------------------
+
+NTP server option is a contaier of suboptions: ntp-server-address (1), ntp-server-multicast (2)
+carrying an IPv6 address, and ntp-server-fqdn (3) carrying a FQDN in wire format defined
+in the "v6-ntp-server-suboptions" option space. Each option instance carries one and only one
+suboption as required by `RFC 5908 <https://tools.ietf.org/html/rfc5908>`__.
.. _dhcp6-custom-options:
query types) is supported. This requires the leasequery hook. See
:ref:`hooks-lease-query` for details.
+- *Network Time Protocol (NTP) Server Option for DHCPv6*:
+ `RFC 5908 <https://tools.ietf.org/html/rfc5908>`__: The NTP server option and its
+ suboptions are supported. See :ref:`ntp-server-suboptions` for details.
+
- *DHCPv6 Options for Network Boot*: `RFC 5970 <https://tools.ietf.org/html/rfc5970>`__:
The network boot options are supported.
if (!skip_pack) {
try {
+ LibDHCP::splitNtpServerOptions6(rsp->options_);
rsp->pack();
} catch (const std::exception& e) {
LOG_ERROR(options6_logger, DHCP6_PACK_FAIL)
#include <dhcp/option_definition.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_vendor_class.h>
+#include <dhcp/option_custom.h>
#include <dhcp/std_option_defs.h>
#include <dhcp/docsis3_option_defs.h>
#include <exceptions/exceptions.h>
}
}
+void
+LibDHCP::splitNtpServerOptions6(OptionCollection& options) {
+ pair<OptionCollection::const_iterator, OptionCollection::const_iterator>
+ range = options.equal_range(D6O_NTP_SERVER);
+ if (range.first == range.second) {
+ return;
+ }
+ auto ntp_servers = OptionCollection(range.first, range.second);
+ static_cast<void>(options.erase(range.first, range.second));
+ auto def = D6O_NTP_SERVER_DEF();
+ for (auto opt : ntp_servers) {
+ for (auto sub : opt.second->getOptions()) {
+ auto new_option(new OptionCustom(def, Option::V6));
+ new_option->addOption(sub.second);
+ options.insert(make_pair(D6O_NTP_SERVER, new_option));
+ }
+ }
+}
+
void
LibDHCP::OptionFactoryRegister(Option::Universe u, uint16_t opt_type,
Option::Factory* factory) {
static_cast<void>(LibDHCP::D6O_LQ_QUERY_DEF());
static_cast<void>(LibDHCP::D6O_CLIENT_DATA_DEF());
static_cast<void>(LibDHCP::D6O_LQ_RELAY_DATA_DEF());
+ static_cast<void>(LibDHCP::D6O_NTP_SERVER_DEF());
static_cast<void>(LibDHCP::D6O_BOOTFILE_URL_DEF());
static_cast<void>(LibDHCP::D6O_RSOO_DEF());
return (*def);
}
+const OptionDefinition&
+LibDHCP::D6O_NTP_SERVER_DEF() {
+ static OptionDefinitionPtr def =
+ LibDHCP::getOptionDef(DHCP6_OPTION_SPACE, D6O_NTP_SERVER);
+ static bool check_once(true);
+ if (check_once) {
+ isc_throw_assert(def);
+ isc_throw_assert(def->getName() == "ntp-server");
+ isc_throw_assert(def->getCode() == D6O_NTP_SERVER);
+ isc_throw_assert(def->getType() == OPT_EMPTY_TYPE);
+ isc_throw_assert(!def->getArrayType());
+ isc_throw_assert(def->getEncapsulatedSpace() == V6_NTP_SERVER_SPACE);
+ isc_throw_assert(def->getOptionSpaceName() == DHCP6_OPTION_SPACE);
+ check_once = false;
+ }
+ return (*def);
+}
+
const OptionDefinition&
LibDHCP::D6O_BOOTFILE_URL_DEF() {
static OptionDefinitionPtr def =
static void packOptions6(isc::util::OutputBuffer& buf,
const isc::dhcp::OptionCollection& options);
+ /// @brief Split NTP server option to one suboption per instance.
+ ///
+ /// See RFC 5908 for the requirement.
+ /// @param options The option container which needs to be updated with split
+ /// options.
+ static void splitNtpServerOptions6(isc::dhcp::OptionCollection& options);
+
/// @brief Parses provided buffer as DHCPv6 options and creates
/// Option objects.
///
/// @brief Get definition of D6O_LQ_RELAY_DATA option.
static const OptionDefinition& D6O_LQ_RELAY_DATA_DEF();
+ /// @brief Get definition of D6O_NTP_SERVER option.
+ static const OptionDefinition& D6O_NTP_SERVER_DEF();
+
/// @brief Get definition of D6O_BOOTFILE_URL option.
static const OptionDefinition& D6O_BOOTFILE_URL_DEF();
fqdn->toText());
// Build back the NTP server option.
- OptionDefinitionPtr opt_def =
- LibDHCP::getOptionDef(DHCP6_OPTION_SPACE, D6O_NTP_SERVER);
- ASSERT_TRUE(opt_def);
- ASSERT_NO_THROW(option.reset(new OptionCustom(*opt_def, Option::V6)));
+ auto opt_def = LibDHCP::D6O_NTP_SERVER_DEF();
+ ASSERT_NO_THROW(option.reset(new OptionCustom(opt_def, Option::V6)));
ASSERT_TRUE(option);
// Add address.
EXPECT_TRUE(memcmp(&bin[0], outbuf.getData(), bin.size()) == 0);
}
+// Check splitNtpServerOptions6.
+TEST_F(LibDhcpTest, splitNtpServerOptions6) {
+ OptionCollection col;
+ auto def = LibDHCP::D6O_NTP_SERVER_DEF();
+ OptionCustomPtr opt1(new OptionCustom(def, Option::V6));
+ OptionCustomPtr opt2(new OptionCustom(def, Option::V6));
+ OptionCustomPtr opt3(new OptionCustom(def, Option::V6));
+
+ // Fill first option with three addresses.
+ OptionDefinitionPtr addr_def =
+ LibDHCP::getOptionDef(V6_NTP_SERVER_SPACE, NTP_SUBOPTION_SRV_ADDR);
+ ASSERT_TRUE(addr_def);
+ OptionCustomPtr addr1(new OptionCustom(*addr_def, Option::V6));
+ OptionCustomPtr addr2(new OptionCustom(*addr_def, Option::V6));
+ OptionCustomPtr addr3(new OptionCustom(*addr_def, Option::V6));
+ EXPECT_NO_THROW(addr1->writeAddress(IOAddress("2001:db8::abcd")));
+ opt1->addOption(addr1);
+ EXPECT_NO_THROW(addr2->writeAddress(IOAddress("2001:db8::bcde")));
+ opt1->addOption(addr2);
+ EXPECT_NO_THROW(addr3->writeAddress(IOAddress("2001:db8::cdef")));
+ opt1->addOption(addr3);
+ col.insert(make_pair(D6O_NTP_SERVER, opt1));
+
+ // Leave second option empty.
+ col.insert(make_pair(D6O_NTP_SERVER, opt2));
+
+ // Fill third option with a FQDN.
+ OptionDefinitionPtr fqdn_def =
+ LibDHCP::getOptionDef(V6_NTP_SERVER_SPACE, NTP_SUBOPTION_SRV_FQDN);
+ ASSERT_TRUE(fqdn_def);
+ OptionCustomPtr fqdn(new OptionCustom(*fqdn_def, Option::V6));
+ EXPECT_NO_THROW(fqdn->writeFqdn("foo.bar."));
+ opt3->addOption(fqdn);
+ col.insert(make_pair(D6O_NTP_SERVER, opt3));
+
+ // Insert another option.
+ OptionPtr opts(new OptionString(Option::V6, D6O_BOOTFILE_URL, "foobar"));
+ col.insert(make_pair(D6O_BOOTFILE_URL, opts));
+
+ // Split them: expect 5 options (opt1 -> 3, opt2 -> 0, opt3 -> 1 and opts).
+ ASSERT_EQ(4, col.size());
+ ASSERT_NO_THROW(LibDHCP::splitNtpServerOptions6(col));
+ EXPECT_EQ(5, col.size());
+}
+
} // namespace