Skip to content

Commit f90d50b

Browse files
authored
[dhcp6] implement DHCPv6 Prefix Delegation (PD) client (openthread#11584)
This commit introduces the `Dhcp6PdClient` class, which implements DHCPv6 Prefix Delegation (PD) client functionality. It integrates with `BorderRouter::RoutingManager` and its `PdPrefixManager` sub-component. The CMake `OT_BORDER_ROUTING_DHCP6_PD_CLIENT` mapped to `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` config enables this feature. Previously, the platform layer was expected to implement client functionality, acquiring and providing the delegated prefix(es) to the OT stack using `otPlatBorderRouter*` callbacks. This approach continues to be supported. The `Dhcp6PdClient` feature adds native support for this functionality in the OpenThread core. The `Dhcp6PdClient` implementation follows RFC 8415, focusing on prefix delegation and all required behaviors. The client follows the standard four-message Solicit/Advertise/Request/Reply exchange to obtain a delegated prefix, followed by a two-message Renew/Reply or Rebind/Reply exchange to extend the lifetime of the delegated prefix. When the prefix is no longer needed, a two-message Release/Reply exchange ends its lease. The current client implementation does not support the optional "Reconfigure Accept" mechanism. A set of `otPlatInfraIfDhcp6PdClient*` platform APIs are also introduced for use by the `Dhcp6PdClient`. These APIs are used to enable or disable listening for DHCPv6 messages and to handle sending and receiving them on the standard client and server UDP ports (546 and 547), effectively acting as a UDP socket. This commit also includes a comprehensive unit test covering various aspects of `Dhcp6PdClient`, including common behaviors and many specific edge cases.
1 parent faadc5b commit f90d50b

24 files changed

Lines changed: 5029 additions & 49 deletions

etc/cmake/options.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ ot_option(OT_BORDER_AGENT_MESHCOP_SERVICE OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP
180180
ot_option(OT_BORDER_ROUTER OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE "border router")
181181
ot_option(OT_BORDER_ROUTING OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE "border routing")
182182
ot_option(OT_BORDER_ROUTING_DHCP6_PD OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE "dhcpv6 pd support in border routing")
183+
ot_option(OT_BORDER_ROUTING_DHCP6_PD_CLIENT OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE "dhcp6 pd client")
183184
ot_option(OT_BORDER_ROUTING_COUNTERS OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE "border routing counters")
184185
ot_option(OT_CHANNEL_MANAGER OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE "channel manager")
185186
ot_option(OT_CHANNEL_MANAGER_CSL OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE "channel manager for csl channel")

examples/platforms/simulation/infra_if.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,28 @@ otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
214214
return OT_ERROR_NONE;
215215
}
216216

217+
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE
218+
219+
void otPlatInfraIfDhcp6PdClientSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
220+
{
221+
OT_UNUSED_VARIABLE(aInstance);
222+
OT_UNUSED_VARIABLE(aEnable);
223+
OT_UNUSED_VARIABLE(aInfraIfIndex);
224+
}
225+
226+
void otPlatInfraIfDhcp6PdClientSend(otInstance *aInstance,
227+
otMessage *aMessage,
228+
otIp6Address *aDestAddress,
229+
uint32_t aInfraIfIndex)
230+
{
231+
OT_UNUSED_VARIABLE(aInstance);
232+
OT_UNUSED_VARIABLE(aDestAddress);
233+
OT_UNUSED_VARIABLE(aInfraIfIndex);
234+
otMessageFree(aMessage);
235+
}
236+
237+
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE
238+
217239
//---------------------------------------------------------------------------------------------------------------------
218240
// platformInfraIf
219241

include/openthread/instance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" {
5252
*
5353
* @note This number versions both OpenThread platform and user APIs.
5454
*/
55-
#define OPENTHREAD_API_VERSION (512)
55+
#define OPENTHREAD_API_VERSION (513)
5656

5757
/**
5858
* @addtogroup api-instance

include/openthread/platform/border_routing.h

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,39 +45,53 @@ extern "C" {
4545
#endif
4646

4747
/**
48-
* Handles ICMP6 RA messages received on the Thread interface on the platform.
48+
* Callback from the platform to report DHCPv6 Prefix Delegation (PD) prefixes.
4949
*
50-
* The `aMessage` should point to a buffer of a valid ICMPv6 message (without IP headers) with router advertisement as
51-
* the value of type field of the message.
50+
* Requires `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` and `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE` to
51+
* be enabled, while `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` should be disabled.
5252
*
53-
* When DHCPv6 PD is disabled, the message will be dropped silently.
53+
* When `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` is enabled, the OpenThread stack's native DHCPv6
54+
* PD client will be used. Otherwise, the platform layer is expected to interact with DHCPv6 servers to acquire
55+
* and provide the delegated prefix(es) using this callback or `otPlatBorderRoutingProcessDhcp6PdPrefix()`.
5456
*
55-
* Note: RA messages will not be forwarded into Thread networks, while for many platforms, RA messages is the way of
56-
* distributing a prefix and other infomations to the downstream network. The typical usecase of this function is to
57-
* handle the router advertisement messages sent by the platform as a result of DHCPv6 Prefix Delegation.
57+
* In this function, an ICMPv6 Router Advertisement (received on the platform's Thread interface) is passed to the
58+
* OpenThread stack. This RA message is intended as a mechanism to distribute DHCPv6 PD prefixes to a Thread Border
59+
* Router. Each Prefix Information Option (PIO) in the RA is evaluated as a candidate DHCPv6 PD prefix.
5860
*
59-
* Requires `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE`.
61+
* This function can be called again to renew/refresh the lifetimes of PD prefixes or to signal their deprecation
62+
* (by setting a zero "preferred lifetime") or removal (by setting a zero "valid lifetime").
63+
*
64+
* Important note: it is not expected that the RA message will contain all currently valid PD prefixes. The OT stack
65+
* will parse the RA and process all included PIOs as PD prefix candidates. Any previously reported PD prefix (from an
66+
* earlier call to this function or `otPlatBorderRoutingProcessDhcp6PdPrefix()`) that does not appear in the new RA
67+
* remains unchanged (i.e., it will be assumed valid until its previously indicated lifetime expires).
68+
*
69+
* The `aMessage` should point to a buffer containing the ICMPv6 message payload (excluding the IP headers but
70+
* including the ICMPv6 header) with "Router Advertisement" (code 134) as the value of the `Type` field in the ICMPv6
71+
* header.
6072
*
6173
* @param[in] aInstance A pointer to an OpenThread instance.
62-
* @param[in] aMessage A pointer to an ICMPv6 RouterAdvertisement message.
63-
* @param[in] aLength The length of ICMPv6 RouterAdvertisement message.
74+
* @param[in] aMessage A pointer to an ICMPv6 Router Advertisement message.
75+
* @param[in] aLength The length of the ICMPv6 Router Advertisement message.
6476
*/
6577
extern void otPlatBorderRoutingProcessIcmp6Ra(otInstance *aInstance, const uint8_t *aMessage, uint16_t aLength);
6678

6779
/**
68-
* Process a prefix received from the DHCPv6 PD Server. The prefix is received on
69-
* the DHCPv6 PD client callback and provided to the Routing Manager via this
70-
* API.
80+
* Callback to report a single DHCPv6 Prefix Delegation (PD) prefix.
81+
*
82+
* Requires `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` and `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE` to
83+
* be enabled, while `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` should be disabled.
7184
*
72-
* The prefix lifetime can be updated by calling the function again with updated time values.
73-
* If the preferred lifetime of the prefix is set to 0, the prefix becomes deprecated.
74-
* When this function is called multiple times, the smallest prefix is preferred as this rule allows
75-
* choosing a GUA instead of a ULA.
85+
* When `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` is enabled, the OpenThread stack's native DHCPv6
86+
* PD client will be used. Otherwise, the platform layer is expected to interact with DHCPv6 servers to acquire
87+
* and provide the delegated prefix(es) using this callback or `otPlatBorderRoutingProcessIcmp6Ra()`.
7688
*
77-
* Requires `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE`.
89+
* This function can be called again to renew/refresh the lifetimes of PD prefixes or to signal their deprecation
90+
* (by setting a zero "preferred lifetime") or removal (by setting a zero "valid lifetime"). This function may be
91+
* called multiple times to provide different PD prefixes.
7892
*
79-
* @param[in] aInstance A pointer to an OpenThread instance.
80-
* @param[in] aPrefixInfo A pointer to the prefix information structure
93+
* @param[in] aInstance A pointer to an OpenThread instance.
94+
* @param[in] aPrefixInfo A pointer to the prefix information structure.
8195
*/
8296
extern void otPlatBorderRoutingProcessDhcp6PdPrefix(otInstance *aInstance,
8397
const otBorderRoutingPrefixTableEntry *aPrefixInfo);

include/openthread/platform/infra_if.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <openthread/error.h>
4242
#include <openthread/instance.h>
4343
#include <openthread/ip6.h>
44+
#include <openthread/message.h>
4445

4546
#ifdef __cplusplus
4647
extern "C" {
@@ -183,6 +184,66 @@ otError otPlatGetInfraIfLinkLayerAddress(otInstance *aInstanc
183184
uint32_t aIfIndex,
184185
otPlatInfraIfLinkLayerAddress *aInfraIfLinkLayerAddress);
185186

187+
//---------------------------------------------------------------------------------------------------------------------
188+
// DHCPv6 Prefix Delegation platform APIs (`OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE`)
189+
190+
/**
191+
* Enables or disables listening for DHCPv6 Prefix Delegation (PD) messages on client.
192+
*
193+
* This function is only used when `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` is enabled.
194+
*
195+
* When enabled, the platform must open a UDP socket on the specified infrastructure interface, binding to the DHCPv6
196+
* client port 546 to receive messages from DHCPv6 servers.
197+
*
198+
* @param[in] aInstance The OpenThread instance.
199+
* @param[in] aEnable A boolean to enable (`true`) or disable (`false`) listening.
200+
* @param[in] aInfraIfIndex The index of the infrastructure interface to operate on.
201+
*
202+
*/
203+
void otPlatInfraIfDhcp6PdClientSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex);
204+
205+
/**
206+
* Sends a DHCPv6 message to a unicast or multicast destination address.
207+
*
208+
* This function is only used when `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` is enabled.
209+
*
210+
* The platform is responsible for constructing a UDP datagram with the given DHCPv6 message as its payload. The
211+
* datagram must be sent from the DHCPv6 client port (546) to the server port (547) on the specified infrastructure
212+
* interface. The destination IPv6 address can be a unicast address or the multicast `All_DHCP_Relay_Agents_and_Servers`
213+
* address (`ff02::1:2`).
214+
*
215+
* This function passes the ownership of @p aMessage to the platform layer. Platform MUST then free the message
216+
* when no longer needed.
217+
*
218+
* @param[in] aInstance The OpenThread instance.
219+
* @param[in] aMessage An `otMessage` containing the DHCPv6 payload. Ownership is passed to the platform layer.
220+
* @param[in] aDestAddress The IPv6 multicast or unicast destination address.
221+
* @param[in] aInfraIfIndex The index of the infrastructure interface from which to send the message.
222+
*/
223+
void otPlatInfraIfDhcp6PdClientSend(otInstance *aInstance,
224+
otMessage *aMessage,
225+
otIp6Address *aDestAddress,
226+
uint32_t aInfraIfIndex);
227+
228+
/**
229+
* Callback from the platform to notify the OpenThread stack of a received DHCPv6 message.
230+
*
231+
* This function is provided when `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` is enabled.
232+
*
233+
* The platform calls this function whenever a DHCPv6 message is received on the client port (546) while listening on
234+
* this port is enabled (refer to `otPlatInfraIfDhcp6PdClientSetListeningEnabled()`).
235+
*
236+
* The platform is responsible for allocating the `otMessage` to pass the received UDP payload. Ownership of the
237+
* @p aMessage is passed to the OpenThread stack (which will free it once no longer needed).
238+
239+
* @param[in] aInstance The OpenThread instance.
240+
* @param[in] aMessage The `otMessage` containing the received DHCPv6 payload. Ownership is passed to OT stack.
241+
* @param[in] aInfraIfIndex The index of the infrastructure interface from which the message was received..
242+
*/
243+
extern void otPlatInfraIfDhcp6PdClientHandleReceived(otInstance *aInstance,
244+
otMessage *aMessage,
245+
uint32_t aInfraIfIndex);
246+
186247
/**
187248
* @}
188249
*/

src/core/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ openthread_core_files = [
374374
"backbone_router/multicast_listeners_table.hpp",
375375
"backbone_router/ndproxy_table.cpp",
376376
"backbone_router/ndproxy_table.hpp",
377+
"border_router/dhcp6_pd_client.cpp",
378+
"border_router/dhcp6_pd_client.hpp",
377379
"border_router/infra_if.cpp",
378380
"border_router/infra_if.hpp",
379381
"border_router/routing_manager.cpp",

src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ set(COMMON_SOURCES
9494
backbone_router/bbr_manager.cpp
9595
backbone_router/multicast_listeners_table.cpp
9696
backbone_router/ndproxy_table.cpp
97+
border_router/dhcp6_pd_client.cpp
9798
border_router/infra_if.cpp
9899
border_router/routing_manager.cpp
99100
coap/coap.cpp

0 commit comments

Comments
 (0)