From: Tomek Mrugalski Date: Thu, 25 Jan 2018 14:59:32 +0000 (+0100) Subject: [5514] Revert "[5191] Remove experimental lightweight 4over6 option" X-Git-Tag: trac5524_base~12^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=641bcbadbe21cbf2c671b7e4437a3314f77c8041;p=thirdparty%2Fkea.git [5514] Revert "[5191] Remove experimental lightweight 4over6 option" This reverts commit 401a5a52077789088e48047d2ee4c67c37a07894. # Conflicts: # doc/guide/dhcp6-srv.xml # src/lib/dhcp/dhcp6.h # src/lib/dhcp/std_option_defs.h # src/lib/dhcp/tests/libdhcp++_unittest.cc --- diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml index f0b96148c7..c5c7851442 100644 --- a/doc/guide/dhcp6-srv.xml +++ b/doc/guide/dhcp6-srv.xml @@ -1315,6 +1315,14 @@ temporarily override a list of interface names and listen on all interfaces. inf-max-rt83uint32false dhcp4o6-server-addr88ipv6-addresstrue +s46-rule89record (uint8, uint8, uint8, ipv4-address, ipv6-prefix)false +s46-br90ipv6-addressfalse +s46-dmr91ipv6-prefixfalse +s46-v4v6bind92record (ipv4-address, ipv6-prefix)false +s46-portparams93record(uint8, psid)false +s46-cont-mape94emptyfalse +s46-cont-mapt95emptyfalse +s46-cont-lw96emptyfalse v6-captive-portal103stringfalse ipv6-address-andsf143ipv6-addresstrue @@ -1351,6 +1359,187 @@ temporarily override a list of interface names and listen on all interfaces. +
+ Common Softwire46 Options + + Softwire46 options are involved in IPv4 over IPv6 provisioning by + means of tunneling or translation as specified in the + RFC 7598. + The following sections provide configuration examples of these + options. + + +
+ Softwire46 Container Options + + S46 container options group rules and optional port parameters + for a specified domain. There are three container options specified + in the "dhcp6" (top level) option space: MAP-E Container option, + MAP-T Container option and S46 Lightweight 4over6 Container option. + These options only contain encapsulated options specified below. + They do not include any data fields. + + + + In order to configure the server to send specific container option + along with all encapsulated options, the container option must be + included in the server configuration as shown below: + +"Dhcp6": { + ... + "option-data": [ + { + "name": "s46-cont-mape" + } ], + ... +} + + + This configuration will cause the server to include MAP-E Container + option to the client. Use "s46-cont-mapt" or "s46-cont-lw" for the + MAP-T Container and S46 Lightweight 4over6 Container options + respectively. + + + + All remaining softwire options described below are included in one + of the container options. Thus, they have to be included in appropriate + option spaces by selecting a "space" name, which specifies in which + option they are supposed to be included. + +
+ +
+ S46 Rule Option + + The S46 Rule option is used for conveying the Basic Mapping Rule (BMR) + and Forwarding Mapping Rule (FMR). + +{ + "space": "s46-cont-mape-options", + "name": "s46-rule", + "data": "128, 0, 24, 192.0.2.0, 2001:db8:1::/64" +} + + Other possible "space" value is "s46-cont-mapt-options". + + + + The S46 Rule option conveys a number of parameters: + + + + flags, an unsigned 8 bits integer, with + currently only the most significant bit specified. It denotes whether + the rule can be used for forwarding (128) or not (0). + + + + + ea-len, an 8 bits long Embedded Address length. Allowed values + range from 0 to 48. + + + + IPv4 prefix length, 8 bits long; expresses the prefix length of the + Rule IPv4 prefix specified in the ipv4-prefix field. Allowed + values range from 0 to 32. + + + + IPv4 prefix, a fixed-length 32-bit field that specifies the IPv4 + prefix for the S46 rule. The bits in the prefix after prefix4-len + number of bits are reserved and MUST be initialized to zero by the + sender and ignored by the receiver. + + + + IPv6 prefix in prefix/length notation that specifies the IPv6 domain + prefix for the S46 rule. The field is padded on the right with zero + bits up to the nearest octet boundary when prefix6-len is not evenly + divisible by 8. + + + + +
+
+ S46 BR Option + + The S46 BR option is used to convey the IPv6 address of the + Border Relay. This option is mandatory in the MAP-E + Container option and not permitted in the MAP-T and + S46 Lightweight 4over6 Container options. + +{ + "space": "s46-cont-mape-options", + "name": "s46-br", + "data": "2001:db8:cafe::1", +} + + Other possible "space" value is "s46-cont-lw-options". + +
+ +
+ S46 DMR Option + + The S46 DMR option is used to convey values for the Default + Mapping Rule (DMR). This option is mandatory in the MAP-T + container option and not permitted in the MAP-E and S46 + Lightweight 4over6 Container options. + +{ + "space": "s46-cont-mapt-options", + "name": "s46-dmr", + "data": "2001:db8:cafe::/64", +} + + This option must not be included in other containers. + +
+ +
+ S46 IPv4/IPv6 Address Binding option. + + The S46 IPv4/IPv6 Address Binding option may be used to specify + the full or shared IPv4 address of the Customer Edge (CE). + The IPv6 prefix field is used by the CE to identify the + correct prefix to use for the tunnel source. + +{ + "space": "s46-cont-lw", + "name": "s46-v4v6bind", + "data": "192.0.2.3, 2001:db8:1:cafe::/64" +} + + This option must not be included in other containers. + +
+
+ S46 Port Parameters + + The S46 Port Parameters option specifies optional port set + information that MAY be provided to CEs + +{ + "space": "s46-rule-options", + "name": "s46-portparams", + "data": "2, 3/4", +} + + Other possible "space" value is "s46-v4v6bind" to include + this option in the S46 IPv4/IPv6 Address Binding option. + + + Note that the second value in the example above specifies the + PSID and PSID length fields in the format of PSID/PSID length. + This is equivalent to the values of PSID-len=4 and + PSID=12288 conveyed in the S46 Port Parameters option. + +
+
+
Custom DHCPv6 Options It is possible to define options in addition to the standard ones. @@ -4609,18 +4798,20 @@ autogenerated IDs are not stable across configuration changes. - Let's consider an example where certain parameters are supposed - to be delivered to clients in form of additional options, - and the values of those options are correlated to delegated - prefixes. It seems reasonable to keep those parameters with - the the definition of the PD pool. On the other hand, this - functionality is is not part of the base Kea code so Kea will - not understand any hook-specific keywords in that definition. - The solution to this problem is to use user context. For - each PD pool that is expected to be used with this feature, - a "user context" is defined. This is a structure that holds the - parameters used by the hook library when it is loaded. - An example configuration could look as follows: + Let's consider a lightweight 4over6 deployment as an example. It is an + IPv6 transition technology that allows mapping IPv6 prefix into full + or parts of IPv4 addresses. In DHCP context, these are certain + parameters that are supposed to be delivered to clients in form of + additional options. Values of those options are correlated to + delegated prefixes, so it is reasonable to keep those parameters + together with the PD pool. On the other hand, lightweight 4over6 is + not a commonly used feature, so it is not a part of the base Kea + code. The solution to this problem is to use user context. For each PD + pool that is expected to be used for lightweight 4over6, user context + with extra parameters is defined. Those extra parameters will be used + by hook library that would be loaded only when dynamic calculation of + the lightweight 4over6 option is actually needed. An example + configuration looks as follows: "Dhcp6": { "subnet6": [ { @@ -4634,7 +4825,11 @@ autogenerated IDs are not stable across configuration changes. "user-context": { "threshold-percent": 85, "v4-network": "192.168.0.0/16", - "v4-overflow": "10.0.0.0/16" + "v4-overflow": "10.0.0.0/16", + "lw4over6-sharing-ratio": 64, + "lw4over6-v4-pool": "192.0.2.0/24", + "lw4over6-sysports-exclude": true, + "lw4over6-bind-prefix-len": 56 } } ], "subnet": "2001:db8::/32", @@ -4736,6 +4931,13 @@ autogenerated IDs are not stable across configuration changes. 7550: All recommendations related to the DHCPv6 server operation are supported. + + DHCPv6 Options for Configuration of Softwire + Address and Port-Mapped Clients, + RFC + 7598: All options specified in this specification are + supported by the DHCPv6 server. +
diff --git a/src/lib/dhcp/dhcp6.h b/src/lib/dhcp/dhcp6.h index 5783b15e1d..cf28ba2bb2 100644 --- a/src/lib/dhcp/dhcp6.h +++ b/src/lib/dhcp/dhcp6.h @@ -106,14 +106,14 @@ enum DHCPv6OptionType { // D6O_V6_PCP_SERVER = 86, /* RFC7291 */ D6O_DHCPV4_MSG = 87, /* RFC7341 */ D6O_DHCPV4_O_DHCPV6_SERVER = 88, /* RFC7341 */ -// D6O_S46_RULE = 89, /* RFC7598 */ -// D6O_S46_BR = 90, /* RFC7598 */ -// D6O_S46_DMR = 91, /* RFC7598 */ -// D6O_S46_V4V6BIND = 92, /* RFC7598 */ -// D6O_S46_PORTPARAMS = 93, /* RFC7598 */ -// D6O_S46_CONT_MAPE = 94, /* RFC7598 */ -// D6O_S46_CONT_MAPT = 95, /* RFC7598 */ -// D6O_S46_CONT_LW = 96, /* RFC7598 */ + D6O_S46_RULE = 89, /* RFC7598 */ + D6O_S46_BR = 90, /* RFC7598 */ + D6O_S46_DMR = 91, /* RFC7598 */ + D6O_S46_V4V6BIND = 92, /* RFC7598 */ + D6O_S46_PORTPARAMS = 93, /* RFC7598 */ + D6O_S46_CONT_MAPE = 94, /* RFC7598 */ + D6O_S46_CONT_MAPT = 95, /* RFC7598 */ + D6O_S46_CONT_LW = 96, /* RFC7598 */ // D6O_4RD = 97, /* RFC7600 */ // D6O_4RD_MAP_RULE = 98, /* RFC7600 */ // D6O_4RD_NON_MAP_RULE = 99, /* RFC7600 */ diff --git a/src/lib/dhcp/std_option_defs.h b/src/lib/dhcp/std_option_defs.h index 69cd4cc8b7..8b16b7316e 100644 --- a/src/lib/dhcp/std_option_defs.h +++ b/src/lib/dhcp/std_option_defs.h @@ -454,6 +454,12 @@ const OptionDefParams STANDARD_V6_OPTION_DEFINITIONS[] = { RECORD_DEF(SIGNATURE_RECORDS), "" }, { "timestamp", D6O_TIMESTAMP, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" }, + { "s46-cont-mape", D6O_S46_CONT_MAPE, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, + MAPE_V6_OPTION_SPACE }, + { "s46-cont-mapt", D6O_S46_CONT_MAPT, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, + MAPT_V6_OPTION_SPACE }, + { "s46-cont-lw", D6O_S46_CONT_LW, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, + LW_V6_OPTION_SPACE } // @todo There is still a bunch of options for which we have to provide // definitions but we don't do it because they are not really @@ -465,6 +471,14 @@ const int STANDARD_V6_OPTION_DEFINITIONS_SIZE = sizeof(STANDARD_V6_OPTION_DEFINITIONS) / sizeof(STANDARD_V6_OPTION_DEFINITIONS[0]); +// Option definitions that belong to two or more option spaces are defined here. +const OptionDefParams OPTION_DEF_PARAMS_S46_BR = { "s46-br", D6O_S46_BR, + OPT_IPV6_ADDRESS_TYPE, false, NO_RECORD_DEF, "" }; +const OptionDefParams OPTION_DEF_PARAMS_S46_RULE = { "s46-rule", D6O_S46_RULE, + OPT_RECORD_TYPE, false, RECORD_DEF(S46_RULE), V4V6_RULE_OPTION_SPACE }; +const OptionDefParams OPTION_DEF_PARAMS_S46_PORTPARAMS = { "s46-portparams", + D6O_S46_PORTPARAMS, OPT_RECORD_TYPE, false, RECORD_DEF(S46_PORTPARAMS), "" }; + /// @brief Definitions of vendor-specific DHCPv6 options, defined by ISC. /// 4o6-* options are used for inter-process communication. For details, see /// http://kea.isc.org/wiki/Dhcp4o6Design @@ -484,43 +498,52 @@ const int ISC_V6_OPTION_DEFINITIONS_SIZE = /// @brief MAPE option definitions const OptionDefParams MAPE_V6_OPTION_DEFINITIONS[] = { + OPTION_DEF_PARAMS_S46_BR, + OPTION_DEF_PARAMS_S46_RULE }; const int MAPE_V6_OPTION_DEFINITIONS_SIZE = sizeof(MAPE_V6_OPTION_DEFINITIONS) / - sizeof(const OptionDefParams); + sizeof(MAPE_V6_OPTION_DEFINITIONS[0]); /// @brief MAPT option definitions const OptionDefParams MAPT_V6_OPTION_DEFINITIONS[] = { + OPTION_DEF_PARAMS_S46_RULE, + { "s46-dmr", D6O_S46_DMR, OPT_IPV6_PREFIX_TYPE, false, NO_RECORD_DEF, "" } }; const int MAPT_V6_OPTION_DEFINITIONS_SIZE = sizeof(MAPT_V6_OPTION_DEFINITIONS) / - sizeof(const OptionDefParams); + sizeof(MAPT_V6_OPTION_DEFINITIONS[0]); /// @brief LW option definitions const OptionDefParams LW_V6_OPTION_DEFINITIONS[] = { + OPTION_DEF_PARAMS_S46_BR, + { "s46-v4v6bind", D6O_S46_V4V6BIND, OPT_RECORD_TYPE, false, + RECORD_DEF(S46_V4V6BIND), V4V6_BIND_OPTION_SPACE } }; const int LW_V6_OPTION_DEFINITIONS_SIZE = sizeof(LW_V6_OPTION_DEFINITIONS) / - sizeof(const OptionDefParams); + sizeof(LW_V6_OPTION_DEFINITIONS[0]); /// @brief Rule option definitions const OptionDefParams V4V6_RULE_OPTION_DEFINITIONS[] = { + OPTION_DEF_PARAMS_S46_PORTPARAMS }; const int V4V6_RULE_OPTION_DEFINITIONS_SIZE = sizeof(V4V6_RULE_OPTION_DEFINITIONS) / - sizeof(const OptionDefParams); + sizeof(V4V6_RULE_OPTION_DEFINITIONS[0]); /// @brief Bind option definitions const OptionDefParams V4V6_BIND_OPTION_DEFINITIONS[] = { + OPTION_DEF_PARAMS_S46_PORTPARAMS }; const int V4V6_BIND_OPTION_DEFINITIONS_SIZE = sizeof(V4V6_BIND_OPTION_DEFINITIONS) / - sizeof(const OptionDefParams); + sizeof(V4V6_BIND_OPTION_DEFINITIONS[0]); } // unnamed namespace diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index fc0f383786..8d257ac5c1 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -1750,6 +1750,33 @@ TEST_F(LibDhcpTest, stdOptionDefs6) { LibDhcpTest::testStdOptionDefs6(D6O_TIMESTAMP, begin, begin + 8, typeid(Option)); + + // RFC7598 options + LibDhcpTest::testOptionDefs6(MAPE_V6_OPTION_SPACE, D6O_S46_RULE, begin, end, + typeid(OptionCustom), "s46-rule-options"); + LibDhcpTest::testOptionDefs6(MAPT_V6_OPTION_SPACE, D6O_S46_RULE, begin, end, + typeid(OptionCustom), "s46-rule-options"); + LibDhcpTest::testOptionDefs6(MAPE_V6_OPTION_SPACE, D6O_S46_BR, begin, end, + typeid(OptionCustom)); + LibDhcpTest::testOptionDefs6(LW_V6_OPTION_SPACE, D6O_S46_BR, begin, end, + typeid(OptionCustom)); + LibDhcpTest::testOptionDefs6(MAPT_V6_OPTION_SPACE, D6O_S46_DMR, begin, end, + typeid(OptionCustom)); + LibDhcpTest::testOptionDefs6(LW_V6_OPTION_SPACE, D6O_S46_V4V6BIND, begin, + end, typeid(OptionCustom), + "s46-v4v6bind-options"); + LibDhcpTest::testOptionDefs6(V4V6_RULE_OPTION_SPACE, D6O_S46_PORTPARAMS, + begin, end, typeid(OptionCustom), ""); + LibDhcpTest::testStdOptionDefs6(D6O_S46_CONT_MAPE, begin, end, + typeid(OptionCustom), + "s46-cont-mape-options"); + LibDhcpTest::testStdOptionDefs6(D6O_S46_CONT_MAPT, begin, end, + typeid(OptionCustom), + "s46-cont-mapt-options"); + LibDhcpTest::testStdOptionDefs6(D6O_S46_CONT_LW, begin, end, + typeid(OptionCustom), + "s46-cont-lw-options"); + } // This test checks if the DHCPv6 option definition can be searched by diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc index 9ce068d667..d79d6d2877 100644 --- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc @@ -937,6 +937,56 @@ TEST_F(ParseConfigTest, optionDataCSVFormatWithOptionDef) { cfg2.runCfgOptionsTest(family_, config); } +// This test verifies that definitions of standard encapsulated +// options can be used. +TEST_F(ParseConfigTest, encapsulatedOptionData) { + std::string config = + "{ \"option-data\": [ {" + " \"space\": \"s46-cont-mape-options\"," + " \"name\": \"s46-rule\"," + " \"data\": \"1, 0, 24, 192.0.2.0, 2001:db8:1::/64\"" + " } ]" + "}"; + + // Make sure that we're using correct universe. + family_ = AF_INET6; + int rcode = 0; + ASSERT_NO_THROW(rcode = parseConfiguration(config)); + ASSERT_EQ(0, rcode); + + // Verify that the option data is correct. + OptionCustomPtr s46_rule = boost::dynamic_pointer_cast + (getOptionPtr(MAPE_V6_OPTION_SPACE, D6O_S46_RULE)); + ASSERT_TRUE(s46_rule); + + uint8_t flags; + uint8_t ea_len; + uint8_t prefix4_len; + IOAddress ipv4_prefix(IOAddress::IPV4_ZERO_ADDRESS()); + PrefixTuple ipv6_prefix(PrefixLen(0), IOAddress::IPV6_ZERO_ADDRESS());; + + ASSERT_NO_THROW({ + flags = s46_rule->readInteger(0); + ea_len = s46_rule->readInteger(1); + prefix4_len = s46_rule->readInteger(2); + ipv4_prefix = s46_rule->readAddress(3); + ipv6_prefix = s46_rule->readPrefix(4); + }); + + EXPECT_EQ(1, flags); + EXPECT_EQ(0, ea_len); + EXPECT_EQ(24, prefix4_len); + EXPECT_EQ("192.0.2.0", ipv4_prefix.toText()); + EXPECT_EQ(64, ipv6_prefix.first.asUnsigned()); + EXPECT_EQ("2001:db8:1::", ipv6_prefix.second.toText()); + + ElementPtr expected = Element::fromJSON(config); + ElementPtr opt_data = expected->get("option-data")->getNonConst(0); + opt_data->set("code", Element::create(D6O_S46_RULE)); + CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg()); + cfg.runCfgOptionsTest(family_, expected); +} + // This test checks behavior of the configuration parser for option data // for different values of csv-format parameter and when there is no // option definition.