1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for the RA-based routing management.
32  *
33  */
34 
35 #ifndef ROUTING_MANAGER_HPP_
36 #define ROUTING_MANAGER_HPP_
37 
38 #include "openthread-core-config.h"
39 
40 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
41 
42 #if !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
43 #error "OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE is required for OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE."
44 #endif
45 
46 #if !OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
47 #error "OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE is required for OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE."
48 #endif
49 
50 #include <openthread/nat64.h>
51 #include <openthread/netdata.h>
52 
53 #include "border_router/infra_if.hpp"
54 #include "common/array.hpp"
55 #include "common/error.hpp"
56 #include "common/heap_allocatable.hpp"
57 #include "common/heap_array.hpp"
58 #include "common/linked_list.hpp"
59 #include "common/locator.hpp"
60 #include "common/message.hpp"
61 #include "common/notifier.hpp"
62 #include "common/pool.hpp"
63 #include "common/string.hpp"
64 #include "common/timer.hpp"
65 #include "net/ip6.hpp"
66 #include "net/nat64_translator.hpp"
67 #include "net/nd6.hpp"
68 #include "thread/network_data.hpp"
69 
70 namespace ot {
71 
72 namespace BorderRouter {
73 
74 /**
75  * Implements bi-directional routing between Thread and Infrastructure networks.
76  *
77  * The Border Routing manager works on both Thread interface and infrastructure interface.
78  * All ICMPv6 messages are sent/received on the infrastructure interface.
79  *
80  */
81 class RoutingManager : public InstanceLocator
82 {
83     friend class ot::Notifier;
84     friend class ot::Instance;
85 
86 public:
87     typedef NetworkData::RoutePreference       RoutePreference;     ///< Route preference (high, medium, low).
88     typedef otBorderRoutingPrefixTableIterator PrefixTableIterator; ///< Prefix Table Iterator.
89     typedef otBorderRoutingPrefixTableEntry    PrefixTableEntry;    ///< Prefix Table Entry.
90     typedef otBorderRoutingRouterEntry         RouterEntry;         ///< Router Entry.
91     typedef otPdProcessedRaInfo                PdProcessedRaInfo;   ///< Data of PdProcessedRaInfo.
92 
93     /**
94      * This constant specifies the maximum number of route prefixes that may be published by `RoutingManager`
95      * in Thread Network Data.
96      *
97      * This is used by `NetworkData::Publisher` to reserve entries for use by `RoutingManager`.
98      *
99      * The number of published entries accounts for:
100      * - Route prefix `fc00::/7` or `::/0`
101      * - One entry for NAT64 published prefix.
102      * - One extra entry for transitions.
103      *
104      */
105     static constexpr uint16_t kMaxPublishedPrefixes = 3;
106 
107     /**
108      * Represents the states of `RoutingManager`.
109      *
110      */
111     enum State : uint8_t
112     {
113         kStateUninitialized = OT_BORDER_ROUTING_STATE_UNINITIALIZED, ///< Uninitialized.
114         kStateDisabled      = OT_BORDER_ROUTING_STATE_DISABLED,      ///< Initialized but disabled.
115         kStateStopped       = OT_BORDER_ROUTING_STATE_STOPPED,       ///< Initialized & enabled, but currently stopped.
116         kStateRunning       = OT_BORDER_ROUTING_STATE_RUNNING,       ///< Initialized, enabled, and running.
117     };
118 
119     /**
120      * This enumeration represents the states of DHCPv6 PD in `RoutingManager`.
121      *
122      */
123     enum Dhcp6PdState : uint8_t
124     {
125         kDhcp6PdStateDisabled = OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED, ///< Disabled.
126         kDhcp6PdStateStopped  = OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED,  ///< Enabled, but currently stopped.
127         kDhcp6PdStateRunning  = OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING,  ///< Enabled, and running.
128     };
129 
130     /**
131      * Initializes the routing manager.
132      *
133      * @param[in]  aInstance  A OpenThread instance.
134      *
135      */
136     explicit RoutingManager(Instance &aInstance);
137 
138     /**
139      * Initializes the routing manager on given infrastructure interface.
140      *
141      * @param[in]  aInfraIfIndex      An infrastructure network interface index.
142      * @param[in]  aInfraIfIsRunning  A boolean that indicates whether the infrastructure
143      *                                interface is running.
144      *
145      * @retval  kErrorNone         Successfully started the routing manager.
146      * @retval  kErrorInvalidArgs  The index of the infra interface is not valid.
147      *
148      */
149     Error Init(uint32_t aInfraIfIndex, bool aInfraIfIsRunning);
150 
151     /**
152      * Enables/disables the Border Routing Manager.
153      *
154      * @note  The Border Routing Manager is enabled by default.
155      *
156      * @param[in]  aEnabled   A boolean to enable/disable the Border Routing Manager.
157      *
158      * @retval  kErrorInvalidState   The Border Routing Manager is not initialized yet.
159      * @retval  kErrorNone           Successfully enabled/disabled the Border Routing Manager.
160      *
161      */
162     Error SetEnabled(bool aEnabled);
163 
164     /**
165      * Indicates whether or not it is currently running.
166      *
167      * In order for the `RoutingManager` to be running it needs to be initialized and enabled, and device being
168      * attached.
169      *
170      * @retval TRUE  The RoutingManager is currently running.
171      * @retval FALSE The RoutingManager is not running.
172      *
173      */
IsRunning(void) const174     bool IsRunning(void) const { return mIsRunning; }
175 
176     /**
177      * Gets the state of `RoutingManager`.
178      *
179      * @returns The current state of `RoutingManager`.
180      *
181      */
182     State GetState(void) const;
183 
184     /**
185      * Requests the Border Routing Manager to stop.
186      *
187      * If Border Routing Manager is running, calling this method immediately stops it and triggers the preparation
188      * and sending of a final Router Advertisement (RA) message on infrastructure interface which deprecates and/or
189      * removes any previously advertised PIO/RIO prefixes. If Routing Manager is not running (or not enabled), no
190      * action is taken.
191      *
192      * Note that this method does not change whether the Routing Manager is enabled or disabled (see `SetEnabled()`).
193      * It stops the Routing Manager temporarily. After calling this method if the device role gets changes (device
194      * gets attached) and/or the infra interface state gets changed, the Routing Manager may be started again.
195      *
196      */
RequestStop(void)197     void RequestStop(void) { Stop(); }
198 
199     /**
200      * Gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement
201      * messages sent over the infrastructure link.
202      *
203      * The RIO preference is determined as follows:
204      *
205      * - If explicitly set by user by calling `SetRouteInfoOptionPreference()`, the given preference is used.
206      * - Otherwise, it is determined based on device's role: Medium preference when in router/leader role and low
207      *   preference when in child role.
208      *
209      * @returns The current Route Info Option preference.
210      *
211      */
GetRouteInfoOptionPreference(void) const212     RoutePreference GetRouteInfoOptionPreference(void) const { return mRioAdvertiser.GetPreference(); }
213 
214     /**
215      * Explicitly sets the preference to use when advertising Route Info Options (RIO) in Router
216      * Advertisement messages sent over the infrastructure link.
217      *
218      * After a call to this method, BR will use the given preference for all its advertised RIOs. The preference can be
219      * cleared by calling `ClearRouteInfoOptionPreference`()`.
220      *
221      * @param[in] aPreference   The route preference to use.
222      *
223      */
SetRouteInfoOptionPreference(RoutePreference aPreference)224     void SetRouteInfoOptionPreference(RoutePreference aPreference) { mRioAdvertiser.SetPreference(aPreference); }
225 
226     /**
227      * Clears a previously set preference value for advertised Route Info Options.
228      *
229      * After a call to this method, BR will use device role to determine the RIO preference: Medium preference when
230      * in router/leader role and low preference when in child role.
231      *
232      */
ClearRouteInfoOptionPreference(void)233     void ClearRouteInfoOptionPreference(void) { mRioAdvertiser.ClearPreference(); }
234 
235     /**
236      * Gets the current preference used for published routes in Network Data.
237      *
238      * The preference is determined as follows:
239      *
240      * - If explicitly set by user by calling `SetRoutePreference()`, the given preference is used.
241      * - Otherwise, it is determined automatically by `RoutingManager` based on the device's role and link quality.
242      *
243      * @returns The current published route preference.
244      *
245      */
GetRoutePreference(void) const246     RoutePreference GetRoutePreference(void) const { return mRoutePublisher.GetPreference(); }
247 
248     /**
249      * Explicitly sets the preference of published routes in Network Data.
250      *
251      * After a call to this method, BR will use the given preference. The preference can be cleared by calling
252      * `ClearRoutePreference`()`.
253      *
254      * @param[in] aPreference   The route preference to use.
255      *
256      */
SetRoutePreference(RoutePreference aPreference)257     void SetRoutePreference(RoutePreference aPreference) { mRoutePublisher.SetPreference(aPreference); }
258 
259     /**
260      * Clears a previously set preference value for published routes in Network Data.
261      *
262      * After a call to this method, BR will determine the preference automatically based on the device's role and
263      * link quality (to the parent when acting as end-device).
264      *
265      */
ClearRoutePreference(void)266     void ClearRoutePreference(void) { mRoutePublisher.ClearPreference(); }
267 
268     /**
269      * Returns the local generated off-mesh-routable (OMR) prefix.
270      *
271      * The randomly generated 64-bit prefix will be added to the Thread Network Data if there isn't already an OMR
272      * prefix.
273      *
274      * @param[out]  aPrefix  A reference to where the prefix will be output to.
275      *
276      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
277      * @retval  kErrorNone          Successfully retrieved the OMR prefix.
278      *
279      */
280     Error GetOmrPrefix(Ip6::Prefix &aPrefix) const;
281 
282 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
283     /**
284      * Returns the platform provided off-mesh-routable (OMR) prefix.
285      *
286      * The prefix is extracted from the platform generated RA messages handled by `ProcessPlatformGeneratedNd()`.
287      *
288      * @param[out] aPrefixInfo      A reference to where the prefix info will be output to.
289      *
290      * @retval kErrorNone           Successfully retrieved the OMR prefix.
291      * @retval kErrorNotFound       There are no valid PD prefix on this BR.
292      * @retval kErrorInvalidState   The Border Routing Manager is not initialized yet.
293      *
294      */
295     Error GetPdOmrPrefix(PrefixTableEntry &aPrefixInfo) const;
296 
297     /**
298      * Returns platform generated RA message processed information.
299      *
300      * @param[out] aPdProcessedRaInfo      A reference to where the PD processed RA info will be output to.
301      *
302      * @retval kErrorNone           Successfully retrieved the Info.
303      * @retval kErrorNotFound       There are no valid RA process info on this BR.
304      * @retval kErrorInvalidState   The Border Routing Manager is not initialized yet.
305      *
306      */
307     Error GetPdProcessedRaInfo(PdProcessedRaInfo &aPdProcessedRaInfo);
308 #endif
309 
310     /**
311      * Returns the currently favored off-mesh-routable (OMR) prefix.
312      *
313      * The favored OMR prefix can be discovered from Network Data or can be our local OMR prefix.
314      *
315      * An OMR prefix with higher preference is favored. If the preference is the same, then the smaller prefix (in the
316      * sense defined by `Ip6::Prefix`) is favored.
317      *
318      * @param[out] aPrefix         A reference to output the favored prefix.
319      * @param[out] aPreference     A reference to output the preference associated with the favored OMR prefix.
320      *
321      * @retval  kErrorInvalidState  The Border Routing Manager is not running yet.
322      * @retval  kErrorNone          Successfully retrieved the OMR prefix.
323      *
324      */
325     Error GetFavoredOmrPrefix(Ip6::Prefix &aPrefix, RoutePreference &aPreference) const;
326 
327     /**
328      * Returns the on-link prefix for the adjacent infrastructure link.
329      *
330      * The randomly generated 64-bit prefix will be advertised
331      * on the infrastructure link if there isn't already a usable
332      * on-link prefix being advertised on the link.
333      *
334      * @param[out]  aPrefix  A reference to where the prefix will be output to.
335      *
336      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
337      * @retval  kErrorNone          Successfully retrieved the local on-link prefix.
338      *
339      */
340     Error GetOnLinkPrefix(Ip6::Prefix &aPrefix) const;
341 
342     /**
343      * Returns the favored on-link prefix for the adjacent infrastructure link.
344      *
345      * The favored prefix is either a discovered prefix on the infrastructure link or the local on-link prefix.
346      *
347      * @param[out]  aPrefix  A reference to where the prefix will be output to.
348      *
349      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
350      * @retval  kErrorNone          Successfully retrieved the favored on-link prefix.
351      *
352      */
353     Error GetFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
354 
355 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
356     /**
357      * Gets the state of NAT64 prefix publishing.
358      *
359      * @retval  kStateDisabled   NAT64 is disabled.
360      * @retval  kStateNotRunning NAT64 is enabled, but is not running since routing manager is not running.
361      * @retval  kStateIdle       NAT64 is enabled, but the border router is not publishing a NAT64 prefix. Usually
362      *                           when there is another border router publishing a NAT64 prefix with higher
363      *                           priority.
364      * @retval  kStateActive     The Border router is publishing a NAT64 prefix.
365      *
366      */
GetNat64PrefixManagerState(void) const367     Nat64::State GetNat64PrefixManagerState(void) const { return mNat64PrefixManager.GetState(); }
368 
369     /**
370      * Enable or disable NAT64 prefix publishing.
371      *
372      * @param[in]  aEnabled   A boolean to enable/disable NAT64 prefix publishing.
373      *
374      */
375     void SetNat64PrefixManagerEnabled(bool aEnabled);
376 
377     /**
378      * Returns the local NAT64 prefix.
379      *
380      * @param[out]  aPrefix  A reference to where the prefix will be output to.
381      *
382      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
383      * @retval  kErrorNone          Successfully retrieved the NAT64 prefix.
384      *
385      */
386     Error GetNat64Prefix(Ip6::Prefix &aPrefix);
387 
388     /**
389      * Returns the currently favored NAT64 prefix.
390      *
391      * The favored NAT64 prefix can be discovered from infrastructure link or can be the local NAT64 prefix.
392      *
393      * @param[out] aPrefix           A reference to output the favored prefix.
394      * @param[out] aRoutePreference  A reference to output the preference associated with the favored prefix.
395      *
396      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
397      * @retval  kErrorNone          Successfully retrieved the NAT64 prefix.
398      *
399      */
400     Error GetFavoredNat64Prefix(Ip6::Prefix &aPrefix, RoutePreference &aRoutePreference);
401 
402     /**
403      * Informs `RoutingManager` of the result of the discovery request of NAT64 prefix on infrastructure
404      * interface (`InfraIf::DiscoverNat64Prefix()`).
405      *
406      * @param[in]  aPrefix  The discovered NAT64 prefix on `InfraIf`.
407      *
408      */
HandleDiscoverNat64PrefixDone(const Ip6::Prefix & aPrefix)409     void HandleDiscoverNat64PrefixDone(const Ip6::Prefix &aPrefix) { mNat64PrefixManager.HandleDiscoverDone(aPrefix); }
410 
411 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
412 
413     /**
414      * Processes a received ICMPv6 message from the infrastructure interface.
415      *
416      * Malformed or undesired messages are dropped silently.
417      *
418      * @param[in]  aPacket        The received ICMPv6 packet.
419      * @param[in]  aSrcAddress    The source address this message is sent from.
420      *
421      */
422     void HandleReceived(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
423 
424     /**
425      * Handles infrastructure interface state changes.
426      *
427      */
HandleInfraIfStateChanged(void)428     void HandleInfraIfStateChanged(void) { EvaluateState(); }
429 
430     /**
431      * Checks whether the on-mesh prefix configuration is a valid OMR prefix.
432      *
433      * @param[in] aOnMeshPrefixConfig  The on-mesh prefix configuration to check.
434      *
435      * @retval   TRUE    The prefix is a valid OMR prefix.
436      * @retval   FALSE   The prefix is not a valid OMR prefix.
437      *
438      */
439     static bool IsValidOmrPrefix(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
440 
441     /**
442      * Checks whether a given prefix is a valid OMR prefix.
443      *
444      * @param[in]  aPrefix  The prefix to check.
445      *
446      * @retval   TRUE    The prefix is a valid OMR prefix.
447      * @retval   FALSE   The prefix is not a valid OMR prefix.
448      *
449      */
450     static bool IsValidOmrPrefix(const Ip6::Prefix &aPrefix);
451 
452     /**
453      * Initializes a `PrefixTableIterator`.
454      *
455      * An iterator can be initialized again to start from the beginning of the table.
456      *
457      * When iterating over entries in the table, to ensure the entry update times are consistent, they are given
458      * relative to the time the iterator was initialized.
459      *
460      * @param[out] aIterator  The iterator to initialize.
461      *
462      */
InitPrefixTableIterator(PrefixTableIterator & aIterator) const463     void InitPrefixTableIterator(PrefixTableIterator &aIterator) const
464     {
465         mDiscoveredPrefixTable.InitIterator(aIterator);
466     }
467 
468     /**
469      * Iterates over entries in the discovered prefix table.
470      *
471      * @param[in,out] aIterator  An iterator.
472      * @param[out]    aEntry     A reference to the entry to populate.
473      *
474      * @retval kErrorNone        Got the next entry, @p aEntry is updated and @p aIterator is advanced.
475      * @retval kErrorNotFound    No more entries in the table.
476      *
477      */
GetNextPrefixTableEntry(PrefixTableIterator & aIterator,PrefixTableEntry & aEntry) const478     Error GetNextPrefixTableEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const
479     {
480         return mDiscoveredPrefixTable.GetNextEntry(aIterator, aEntry);
481     }
482 
483     /**
484      * Iterates over discovered router entries on infrastructure link.
485      *
486      * @param[in,out] aIterator  An iterator.
487      * @param[out]    aEntry     A reference to the entry to populate.
488      *
489      * @retval kErrorNone        Got the next router info, @p aEntry is updated and @p aIterator is advanced.
490      * @retval kErrorNotFound    No more routers.
491      *
492      */
GetNextRouterEntry(PrefixTableIterator & aIterator,RouterEntry & aEntry) const493     Error GetNextRouterEntry(PrefixTableIterator &aIterator, RouterEntry &aEntry) const
494     {
495         return mDiscoveredPrefixTable.GetNextRouter(aIterator, aEntry);
496     }
497 
498 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
499     /**
500      * Determines whether to enable/disable SRP server when the auto-enable mode is changed on SRP server.
501      *
502      * This should be called from `Srp::Server` when auto-enable mode is changed.
503      *
504      */
505     void HandleSrpServerAutoEnableMode(void);
506 #endif
507 
508 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
509     /**
510      * Handles a router advertisement message received on platform's Thread interface.
511      *
512      * Note: This method is a part of DHCPv6 PD support on Thread border routers. The message should be generated by the
513      * software like dnamasq, radvd, systemd-networkd on the platform as a part of the DHCPv6 prefix delegation process
514      * for distributing the prefix to the interfaces (links).
515      *
516      * @param[in] aRouterAdvert A pointer to the buffer of the router advertisement message.
517      * @param[in] aLength       The length of the router advertisement message.
518      *
519      */
ProcessPlatformGeneratedRa(const uint8_t * aRouterAdvert,uint16_t aLength)520     void ProcessPlatformGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength)
521     {
522         mPdPrefixManager.ProcessPlatformGeneratedRa(aRouterAdvert, aLength);
523     }
524 
525     /**
526      * Enables / Disables the functions for DHCPv6 PD.
527      *
528      * @param[in] aEnabled  Whether to accept platform generated RA messages.
529      *
530      */
SetDhcp6PdEnabled(bool aEnabled)531     void SetDhcp6PdEnabled(bool aEnabled) { return mPdPrefixManager.SetEnabled(aEnabled); }
532 
533     /**
534      * Returns the state of accpeting RouterAdvertisement messages on platform interface.
535      *
536      * @retval kDhcp6PdStateRunning  DHCPv6 PD should be enabled and running on this border router.
537      * @retval kDhcp6PdStateDisabled DHCPv6 PD should be disabled on this border router..
538      *
539      */
GetDhcp6PdState(void) const540     Dhcp6PdState GetDhcp6PdState(void) const { return mPdPrefixManager.GetState(); }
541 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
542 
543 private:
544     static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES;
545 
546     static constexpr uint8_t kOmrPrefixLength    = OT_IP6_PREFIX_BITSIZE; // The length of an OMR prefix. In bits.
547     static constexpr uint8_t kOnLinkPrefixLength = OT_IP6_PREFIX_BITSIZE; // The length of an On-link prefix. In bits.
548     static constexpr uint8_t kBrUlaPrefixLength  = 48;                    // The length of a BR ULA prefix. In bits.
549     static constexpr uint8_t kNat64PrefixLength  = 96;                    // The length of a NAT64 prefix. In bits.
550 
551     static constexpr uint16_t kOmrPrefixSubnetId   = 1; // The subnet ID of an OMR prefix within a BR ULA prefix.
552     static constexpr uint16_t kNat64PrefixSubnetId = 2; // The subnet ID of a NAT64 prefix within a BR ULA prefix.
553 
554     // The maximum number of initial Router Advertisements.
555     static constexpr uint32_t kMaxInitRtrAdvertisements = 3;
556 
557     static constexpr uint32_t kDefaultOmrPrefixLifetime    = 1800; // The default OMR prefix valid lifetime. In sec.
558     static constexpr uint32_t kDefaultOnLinkPrefixLifetime = 1800; // The default on-link prefix valid lifetime. In sec.
559     static constexpr uint32_t kDefaultNat64PrefixLifetime  = 300;  // The default NAT64 prefix valid lifetime. In sec.
560     static constexpr uint32_t kMaxRtrAdvInterval           = 600;  // Max Router Advertisement Interval. In sec.
561     static constexpr uint32_t kMinRtrAdvInterval           = kMaxRtrAdvInterval / 3; // Min RA Interval. In sec.
562     static constexpr uint32_t kMaxInitRtrAdvInterval       = 16;                     // Max Initial RA Interval. In sec.
563     static constexpr uint32_t kRaReplyJitter               = 500;  // Jitter for sending RA after rx RS. In msec.
564     static constexpr uint32_t kPolicyEvaluationMinDelay    = 2000; // Min delay for policy evaluation. In msec.
565     static constexpr uint32_t kPolicyEvaluationMaxDelay    = 4000; // Max delay for policy evaluation. In msec.
566     static constexpr uint32_t kMinDelayBetweenRtrAdvs      = 3000; // Min delay (msec) between consecutive RAs.
567 
568     // The STALE_RA_TIME in seconds. The Routing Manager will consider the prefixes
569     // and learned RA parameters STALE when they are not refreshed in STALE_RA_TIME
570     // seconds. The Routing Manager will then start Router Solicitation to verify
571     // that the STALE prefix is not being advertised anymore and remove the STALE
572     // prefix.
573     // The value is chosen in range of [`kMaxRtrAdvInterval` upper bound (1800s), `kDefaultOnLinkPrefixLifetime`].
574     static constexpr uint32_t kRtrAdvStaleTime = 1800;
575 
576     static_assert(kMinRtrAdvInterval <= 3 * kMaxRtrAdvInterval / 4, "invalid RA intervals");
577     static_assert(kDefaultOmrPrefixLifetime >= kMaxRtrAdvInterval, "invalid default OMR prefix lifetime");
578     static_assert(kDefaultOnLinkPrefixLifetime >= kMaxRtrAdvInterval, "invalid default on-link prefix lifetime");
579     static_assert(kRtrAdvStaleTime >= 1800 && kRtrAdvStaleTime <= kDefaultOnLinkPrefixLifetime,
580                   "invalid RA STALE time");
581     static_assert(kPolicyEvaluationMaxDelay > kPolicyEvaluationMinDelay,
582                   "kPolicyEvaluationMaxDelay must be larger than kPolicyEvaluationMinDelay");
583 
584     enum RouterAdvTxMode : uint8_t // Used in `SendRouterAdvertisement()`
585     {
586         kInvalidateAllPrevPrefixes,
587         kAdvPrefixesFromNetData,
588     };
589 
590     enum ScheduleMode : uint8_t // Used in `ScheduleRoutingPolicyEvaluation()`
591     {
592         kImmediately,
593         kForNextRa,
594         kAfterRandomDelay,
595         kToReplyToRs,
596     };
597 
598     void HandleDiscoveredPrefixTableChanged(void); // Declare early so we can use in `mSignalTask`
HandleDiscoveredPrefixTableEntryTimer(void)599     void HandleDiscoveredPrefixTableEntryTimer(void) { mDiscoveredPrefixTable.HandleEntryTimer(); }
HandleDiscoveredPrefixTableRouterTimer(void)600     void HandleDiscoveredPrefixTableRouterTimer(void) { mDiscoveredPrefixTable.HandleRouterTimer(); }
601 
602 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
603     class PdPrefixManager; // For DiscoveredPrefixTable::Entry
604 #endif
605 
606     class DiscoveredPrefixTable : public InstanceLocator
607     {
608         // This class maintains the discovered on-link and route prefixes
609         // from the received RA messages by processing PIO and RIO options
610         // from the message. It takes care of processing the RA message but
611         // delegates the decision whether to include or exclude a prefix to
612         // `RoutingManager` by calling its `ShouldProcessPrefixInfoOption()`
613         // and `ShouldProcessRouteInfoOption()` methods.
614         //
615         // It manages the lifetime of the discovered entries and publishes
616         // and unpublishes the prefixes in the Network Data (as external
617         // route) as they are added or removed.
618         //
619         // When there is any change in the table (an entry is added, removed,
620         // or modified), it signals the change to `RoutingManager` by calling
621         // `HandleDiscoveredPrefixTableChanged()` callback. A `Tasklet` is
622         // used for signalling which ensures that if there are multiple
623         // changes within the same flow of execution, the callback is
624         // invoked after all the changes are processed.
625 
626 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
627         friend class PdPrefixManager; // For DiscoveredPrefixTable::Entry
628 #endif
629 
630     public:
631         explicit DiscoveredPrefixTable(Instance &aInstance);
632 
633         void ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvertMessage &aRaMessage,
634                                         const Ip6::Address                 &aSrcAddress);
635         void ProcessNeighborAdvertMessage(const Ip6::Nd::NeighborAdvertMessage &aNaMessage);
636 
637         bool ContainsDefaultOrNonUlaRoutePrefix(void) const;
638         bool ContainsNonUlaOnLinkPrefix(void) const;
639         bool ContainsUlaOnLinkPrefix(void) const;
640 
641         void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
642 
643         void RemoveOnLinkPrefix(const Ip6::Prefix &aPrefix);
644         void RemoveRoutePrefix(const Ip6::Prefix &aPrefix);
645 
646         void RemoveAllEntries(void);
647         void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
648 
649         TimeMilli CalculateNextStaleTime(TimeMilli aNow) const;
650 
651         void DetermineAndSetFlags(Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
652 
653         void  InitIterator(PrefixTableIterator &aIterator) const;
654         Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
655         Error GetNextRouter(PrefixTableIterator &aIterator, RouterEntry &aEntry) const;
656 
657         void HandleEntryTimer(void);
658         void HandleRouterTimer(void);
659 
660     private:
661 #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
662         static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS;
663         static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES;
664 #endif
665 
666         class Entry : public LinkedListEntry<Entry>,
667                       public Unequatable<Entry>,
668 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
669                       public Heap::Allocatable<Entry>,
670 #endif
671                       private Clearable<Entry>
672         {
673             friend class LinkedListEntry<Entry>;
674             friend class Clearable<Entry>;
675 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
676             friend class PdPrefixManager;
677 #endif
678 
679         public:
680             enum Type : uint8_t
681             {
682                 kTypeOnLink,
683                 kTypeRoute,
684             };
685 
686             struct Matcher
687             {
Matcherot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Entry::Matcher688                 Matcher(const Ip6::Prefix &aPrefix, Type aType)
689                     : mPrefix(aPrefix)
690                     , mType(aType)
691                 {
692                 }
693 
694                 const Ip6::Prefix &mPrefix;
695                 Type               mType;
696             };
697 
698             struct Checker
699             {
700                 enum Mode : uint8_t
701                 {
702                     kIsUla,
703                     kIsNotUla,
704                 };
705 
Checkerot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Entry::Checker706                 Checker(Mode aMode, Type aType)
707                     : mMode(aMode)
708                     , mType(aType)
709 
710                 {
711                 }
712 
713                 Mode mMode;
714                 Type mType;
715             };
716 
717             struct ExpirationChecker
718             {
ExpirationCheckerot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Entry::ExpirationChecker719                 explicit ExpirationChecker(TimeMilli aNow)
720                     : mNow(aNow)
721                 {
722                 }
723 
724                 TimeMilli mNow;
725             };
726 
727             void               SetFrom(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader);
728             void               SetFrom(const Ip6::Nd::PrefixInfoOption &aPio);
729             void               SetFrom(const Ip6::Nd::RouteInfoOption &aRio);
GetType(void) const730             Type               GetType(void) const { return mType; }
IsOnLinkPrefix(void) const731             bool               IsOnLinkPrefix(void) const { return (mType == kTypeOnLink); }
IsRoutePrefix(void) const732             bool               IsRoutePrefix(void) const { return (mType == kTypeRoute); }
GetPrefix(void) const733             const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
GetLastUpdateTime(void) const734             const TimeMilli   &GetLastUpdateTime(void) const { return mLastUpdateTime; }
GetValidLifetime(void) const735             uint32_t           GetValidLifetime(void) const { return mValidLifetime; }
ClearValidLifetime(void)736             void               ClearValidLifetime(void) { mValidLifetime = 0; }
737             TimeMilli          GetExpireTime(void) const;
738             TimeMilli          GetStaleTime(void) const;
739             RoutePreference    GetPreference(void) const;
740             bool               operator==(const Entry &aOther) const;
741             bool               Matches(const Matcher &aMatcher) const;
742             bool               Matches(const Checker &aChecker) const;
743             bool               Matches(const ExpirationChecker &aChecker) const;
744 
745             // Methods to use when `IsOnLinkPrefix()`
GetPreferredLifetime(void) const746             uint32_t GetPreferredLifetime(void) const { return mShared.mPreferredLifetime; }
ClearPreferredLifetime(void)747             void     ClearPreferredLifetime(void) { mShared.mPreferredLifetime = 0; }
748             bool     IsDeprecated(void) const;
749             void     AdoptValidAndPreferredLifetimesFrom(const Entry &aEntry);
750 
751             // Method to use when `!IsOnlinkPrefix()`
GetRoutePreference(void) const752             RoutePreference GetRoutePreference(void) const { return mShared.mRoutePreference; }
753 
754         private:
755             static uint32_t CalculateExpireDelay(uint32_t aValidLifetime);
756 
757             Entry      *mNext;
758             Ip6::Prefix mPrefix;
759             Type        mType;
760             TimeMilli   mLastUpdateTime;
761             uint32_t    mValidLifetime;
762             union
763             {
764                 uint32_t        mPreferredLifetime; // Applicable when prefix is on-link.
765                 RoutePreference mRoutePreference;   // Applicable when prefix is not on-link
766             } mShared;
767         };
768 
769         struct Router : public LinkedListEntry<Router>,
770 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
771                         public Heap::Allocatable<Router>,
772 #endif
773                         public Clearable<Router>
774         {
775             // The timeout (in msec) for router staying in active state
776             // before starting the Neighbor Solicitation (NS) probes.
777             static constexpr uint32_t kActiveTimeout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
778 
779             static constexpr uint8_t  kMaxNsProbes          = 5;    // Max number of NS probe attempts.
780             static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
781             static constexpr uint32_t kNsProbeTimeout       = 2000; // In msec. Max Wait time after last NS probe.
782             static constexpr uint32_t kJitter               = 2000; // In msec. Jitter to randomize probe starts.
783 
784             static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255");
785 
786             enum EmptyChecker : uint8_t
787             {
788                 kContainsNoEntriesOrFlags
789             };
790 
Matchesot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Router791             bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; }
792             bool Matches(EmptyChecker aChecker) const;
793             void CopyInfoTo(RouterEntry &aEntry) const;
794 
795             Router           *mNext;
796             Ip6::Address      mAddress;
797             LinkedList<Entry> mEntries;
798             TimeMilli         mTimeout;
799             uint8_t           mNsProbeCount;
800             bool              mManagedAddressConfigFlag : 1;
801             bool              mOtherConfigFlag : 1;
802             bool              mStubRouterFlag : 1;
803         };
804 
805         class Iterator : public PrefixTableIterator
806         {
807         public:
808             enum AdvanceMode : uint8_t
809             {
810                 kToNextEntry,
811                 kToNextRouter,
812             };
813 
814             void Init(const LinkedList<Router> &aRouters);
815             void Advance(AdvanceMode aMode);
816 
GetRouter(void) const817             const Router *GetRouter(void) const { return static_cast<const Router *>(mPtr1); }
GetEntry(void) const818             const Entry  *GetEntry(void) const { return static_cast<const Entry *>(mPtr2); }
GetInitTime(void) const819             TimeMilli     GetInitTime(void) const { return TimeMilli(mData32); }
820 
821         private:
SetRouter(const Router * aRouter)822             void SetRouter(const Router *aRouter) { mPtr1 = aRouter; }
SetEntry(const Entry * aEntry)823             void SetEntry(const Entry *aEntry) { mPtr2 = aEntry; }
SetInitTime(void)824             void SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); }
825         };
826 
827         void         ProcessRaHeader(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, Router &aRouter);
828         void         ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, Router &aRouter);
829         void         ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter);
830         void         ProcessRaFlagsExtOption(const Ip6::Nd::RaFlagsExtOption &aFlagsOption, Router &aRouter);
831         bool         Contains(const Entry::Checker &aChecker) const;
832         void         RemovePrefix(const Entry::Matcher &aMatcher);
833         void         RemoveOrDeprecateEntriesFromInactiveRouters(void);
834         void         RemoveRoutersWithNoEntriesOrFlags(void);
835         void         FreeRouters(LinkedList<Router> &aRouters);
836         void         FreeEntries(LinkedList<Entry> &aEntries);
837         void         UpdateNetworkDataOnChangeTo(Entry &aEntry);
838         const Entry *FindFavoredEntryToPublish(const Ip6::Prefix &aPrefix) const;
839         void         RemoveExpiredEntries(void);
840         void         SignalTableChanged(void);
841         void         UpdateRouterOnRx(Router &aRouter);
842         void         SendNeighborSolicitToRouter(const Router &aRouter);
843 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
AllocateRouter(void)844         Router *AllocateRouter(void) { return Router::Allocate(); }
AllocateEntry(void)845         Entry  *AllocateEntry(void) { return Entry::Allocate(); }
FreeRouter(Router & aRouter)846         void    FreeRouter(Router &aRouter) { aRouter.Free(); }
FreeEntry(Entry & aEntry)847         void    FreeEntry(Entry &aEntry) { aEntry.Free(); }
848 #else
AllocateRouter(void)849         Router *AllocateRouter(void) { return mRouterPool.Allocate(); }
AllocateEntry(void)850         Entry  *AllocateEntry(void) { return mEntryPool.Allocate(); }
FreeRouter(Router & aRouter)851         void    FreeRouter(Router &aRouter) { mRouterPool.Free(aRouter); }
FreeEntry(Entry & aEntry)852         void    FreeEntry(Entry &aEntry) { mEntryPool.Free(aEntry); }
853 #endif
854 
855         using SignalTask  = TaskletIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableChanged>;
856         using EntryTimer  = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableEntryTimer>;
857         using RouterTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableRouterTimer>;
858 
859         LinkedList<Router> mRouters;
860         EntryTimer         mEntryTimer;
861         RouterTimer        mRouterTimer;
862         SignalTask         mSignalTask;
863 #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
864         Pool<Entry, kMaxEntries>  mEntryPool;
865         Pool<Router, kMaxRouters> mRouterPool;
866 #endif
867     };
868 
869     class OmrPrefixManager;
870 
871     class OmrPrefix : public Clearable<OmrPrefix>
872     {
873         friend class OmrPrefixManager;
874 
875     public:
OmrPrefix(void)876         OmrPrefix(void) { Clear(); }
877 
IsEmpty(void) const878         bool               IsEmpty(void) const { return (mPrefix.GetLength() == 0); }
GetPrefix(void) const879         const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
GetPreference(void) const880         RoutePreference    GetPreference(void) const { return mPreference; }
IsDomainPrefix(void) const881         bool               IsDomainPrefix(void) const { return mIsDomainPrefix; }
882 
883     protected:
884         Ip6::Prefix     mPrefix;
885         RoutePreference mPreference;
886         bool            mIsDomainPrefix;
887     };
888 
889     class FavoredOmrPrefix : public OmrPrefix
890     {
891         friend class OmrPrefixManager;
892 
893     public:
894         bool IsInfrastructureDerived(void) const;
895 
896     private:
897         void SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
898         void SetFrom(const OmrPrefix &aOmrPrefix);
899         bool IsFavoredOver(const NetworkData::OnMeshPrefixConfig &aOmrPrefixConfig) const;
900     };
901 
902     class OmrPrefixManager : public InstanceLocator
903     {
904     public:
905         explicit OmrPrefixManager(Instance &aInstance);
906 
907         void                    Init(const Ip6::Prefix &aBrUlaPrefix);
908         void                    Start(void);
909         void                    Stop(void);
910         void                    Evaluate(void);
911         void                    UpdateDefaultRouteFlag(bool aDefaultRoute);
912         bool                    ShouldAdvertiseLocalAsRio(void) const;
GetGeneratedPrefix(void) const913         const Ip6::Prefix      &GetGeneratedPrefix(void) const { return mGeneratedPrefix; }
GetLocalPrefix(void) const914         const OmrPrefix        &GetLocalPrefix(void) const { return mLocalPrefix; }
GetFavoredPrefix(void) const915         const FavoredOmrPrefix &GetFavoredPrefix(void) const { return mFavoredPrefix; }
916 
917     private:
918         static constexpr uint16_t kInfoStringSize = 85;
919 
920         typedef String<kInfoStringSize> InfoString;
921 
922         void       DetermineFavoredPrefix(void);
923         Error      AddLocalToNetData(void);
924         Error      AddOrUpdateLocalInNetData(void);
925         void       RemoveLocalFromNetData(void);
926         InfoString LocalToString(void) const;
927 
928         OmrPrefix        mLocalPrefix;
929         Ip6::Prefix      mGeneratedPrefix;
930         FavoredOmrPrefix mFavoredPrefix;
931         bool             mIsLocalAddedInNetData;
932         bool             mDefaultRoute;
933     };
934 
HandleOnLinkPrefixManagerTimer(void)935     void HandleOnLinkPrefixManagerTimer(void) { mOnLinkPrefixManager.HandleTimer(); }
936 
937     class OnLinkPrefixManager : public InstanceLocator
938     {
939     public:
940         explicit OnLinkPrefixManager(Instance &aInstance);
941 
942         // Max number of old on-link prefixes to retain to deprecate.
943         static constexpr uint16_t kMaxOldPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_OLD_ON_LINK_PREFIXES;
944 
945         void               Init(void);
946         void               Start(void);
947         void               Stop(void);
948         void               Evaluate(void);
GetLocalPrefix(void) const949         const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
GetFavoredDiscoveredPrefix(void) const950         const Ip6::Prefix &GetFavoredDiscoveredPrefix(void) const { return mFavoredDiscoveredPrefix; }
951         bool               IsInitalEvaluationDone(void) const;
952         void               HandleDiscoveredPrefixTableChanged(void);
953         bool               ShouldPublishUlaRoute(void) const;
954         void               AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage);
955         bool               IsPublishingOrAdvertising(void) const;
956         void               HandleNetDataChange(void);
957         void               HandleExtPanIdChange(void);
958         void               HandleTimer(void);
959 
960     private:
961         enum State : uint8_t // State of `mLocalPrefix`
962         {
963             kIdle,
964             kPublishing,
965             kAdvertising,
966             kDeprecating,
967         };
968 
969         struct OldPrefix
970         {
Matchesot::BorderRouter::RoutingManager::OnLinkPrefixManager::OldPrefix971             bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
972 
973             Ip6::Prefix mPrefix;
974             TimeMilli   mExpireTime;
975         };
976 
GetState(void) const977         State GetState(void) const { return mState; }
978         void  SetState(State aState);
979         void  GenerateLocalPrefix(void);
980         void  PublishAndAdvertise(void);
981         void  Deprecate(void);
982         void  ResetExpireTime(TimeMilli aNow);
983         void  AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage);
984         void  AppendOldPrefixes(Ip6::Nd::RouterAdvertMessage &aRaMessage);
985         void  DeprecateOldPrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
986         void  SavePrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
987 
988         static const char *StateToString(State aState);
989 
990         using ExpireTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleOnLinkPrefixManagerTimer>;
991 
992         Ip6::Prefix                       mLocalPrefix;
993         State                             mState;
994         TimeMilli                         mExpireTime;
995         Ip6::Prefix                       mFavoredDiscoveredPrefix;
996         Array<OldPrefix, kMaxOldPrefixes> mOldLocalPrefixes;
997         ExpireTimer                       mTimer;
998     };
999 
HandleRioAdvertiserimer(void)1000     void HandleRioAdvertiserimer(void) { mRioAdvertiser.HandleTimer(); }
1001 
1002     class RioAdvertiser : public InstanceLocator
1003     {
1004         // Manages the list of prefixes advertised as RIO in emitted
1005         // RA. The RIO prefixes are discovered from on-mesh prefixes in
1006         // network data including OMR prefix from `OmrPrefixManager`.
1007         // It also handles deprecating removed prefixes.
1008 
1009     public:
1010         explicit RioAdvertiser(Instance &aInstance);
1011 
GetPreference(void) const1012         RoutePreference GetPreference(void) const { return mPreference; }
1013         void            SetPreference(RoutePreference aPreference);
1014         void            ClearPreference(void);
1015         void            HandleRoleChanged(void);
1016         void            AppendRios(Ip6::Nd::RouterAdvertMessage &aRaMessage);
1017         void            InvalidatPrevRios(Ip6::Nd::RouterAdvertMessage &aRaMessage);
HasAdvertised(const Ip6::Prefix & aPrefix) const1018         bool            HasAdvertised(const Ip6::Prefix &aPrefix) const { return mPrefixes.ContainsMatching(aPrefix); }
GetAdvertisedRioCount(void) const1019         uint16_t        GetAdvertisedRioCount(void) const { return mPrefixes.GetLength(); }
1020         void            HandleTimer(void);
1021 
1022     private:
1023         static constexpr uint32_t kDeprecationTime = TimeMilli::SecToMsec(300);
1024 
1025         struct RioPrefix : public Clearable<RioPrefix>
1026         {
Matchesot::BorderRouter::RoutingManager::RioAdvertiser::RioPrefix1027             bool Matches(const Ip6::Prefix &aPrefix) const { return (mPrefix == aPrefix); }
1028 
1029             Ip6::Prefix mPrefix;
1030             bool        mIsDeprecating;
1031             TimeMilli   mExpirationTime;
1032         };
1033 
1034         struct RioPrefixArray :
1035 #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
1036             public Heap::Array<RioPrefix>
1037 #else
1038             public Array<RioPrefix, 2 * kMaxOnMeshPrefixes>
1039 #endif
1040         {
1041             void Add(const Ip6::Prefix &aPrefix);
1042         };
1043 
1044         void SetPreferenceBasedOnRole(void);
1045         void UpdatePreference(RoutePreference aPreference);
1046         void AppendRio(const Ip6::Prefix &aPrefix, uint32_t aRouteLifetime, Ip6::Nd::RouterAdvertMessage &aRaMessage);
1047 
1048         using RioTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRioAdvertiserimer>;
1049 
1050         RioPrefixArray  mPrefixes;
1051         RioTimer        mTimer;
1052         RoutePreference mPreference;
1053         bool            mUserSetPreference;
1054     };
1055 
1056 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
HandleNat64PrefixManagerTimer(void)1057     void HandleNat64PrefixManagerTimer(void) { mNat64PrefixManager.HandleTimer(); }
1058 
1059     class Nat64PrefixManager : public InstanceLocator
1060     {
1061     public:
1062         // This class manages the NAT64 related functions including
1063         // generation of local NAT64 prefix, discovery of infra
1064         // interface prefix, maintaining the discovered prefix
1065         // lifetime, and selection of the NAT64 prefix to publish in
1066         // Network Data.
1067         //
1068         // Calling methods except GenerateLocalPrefix and SetEnabled
1069         // when disabled becomes no-op.
1070 
1071         explicit Nat64PrefixManager(Instance &aInstance);
1072 
1073         void         SetEnabled(bool aEnabled);
1074         Nat64::State GetState(void) const;
1075 
1076         void Start(void);
1077         void Stop(void);
1078 
1079         void               GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix);
GetLocalPrefix(void) const1080         const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
1081         const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const;
1082         void               Evaluate(void);
1083         void               HandleDiscoverDone(const Ip6::Prefix &aPrefix);
1084         void               HandleTimer(void);
1085 
1086     private:
1087         void Discover(void);
1088         void Publish(void);
1089 
1090         using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>;
1091 
1092         bool mEnabled;
1093 
1094         Ip6::Prefix     mInfraIfPrefix;       // The latest NAT64 prefix discovered on the infrastructure interface.
1095         Ip6::Prefix     mLocalPrefix;         // The local prefix (from BR ULA prefix).
1096         Ip6::Prefix     mPublishedPrefix;     // The prefix to publish in Net Data (empty or local or from infra-if).
1097         RoutePreference mPublishedPreference; // The published prefix preference.
1098         Nat64Timer      mTimer;
1099     };
1100 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
1101 
HandleRoutePublisherTimer(void)1102     void HandleRoutePublisherTimer(void) { mRoutePublisher.HandleTimer(); }
1103 
1104     class RoutePublisher : public InstanceLocator // Manages the routes that are published in net data
1105     {
1106     public:
1107         explicit RoutePublisher(Instance &aInstance);
1108 
Start(void)1109         void Start(void) { Evaluate(); }
Stop(void)1110         void Stop(void) { Unpublish(); }
1111         void Evaluate(void);
1112 
1113         void UpdateAdvPioFlags(bool aAdvPioFlag);
1114 
GetPreference(void) const1115         RoutePreference GetPreference(void) const { return mPreference; }
1116         void            SetPreference(RoutePreference aPreference);
1117         void            ClearPreference(void);
1118 
1119         void HandleNotifierEvents(Events aEvents);
1120         void HandleTimer(void);
1121 
GetUlaPrefix(void)1122         static const Ip6::Prefix &GetUlaPrefix(void) { return AsCoreType(&kUlaPrefix); }
1123 
1124     private:
1125         static constexpr uint32_t kDelayBeforePrfUpdateOnLinkQuality3 = TimeMilli::SecToMsec(5 * 60);
1126 
1127         static const otIp6Prefix kUlaPrefix;
1128 
1129         enum State : uint8_t
1130         {
1131             kDoNotPublish,   // Do not publish any routes in network data.
1132             kPublishDefault, // Publish "::/0" route in network data.
1133             kPublishUla,     // Publish "fc00::/7" route in network data.
1134         };
1135 
1136         void DeterminePrefixFor(State aState, Ip6::Prefix &aPrefix) const;
1137         void UpdatePublishedRoute(State aNewState);
1138         void Unpublish(void);
1139         void SetPreferenceBasedOnRole(void);
1140         void UpdatePreference(RoutePreference aPreference);
1141 
1142         static const char *StateToString(State aState);
1143 
1144         using DelayTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRoutePublisherTimer>;
1145 
1146         State           mState;
1147         RoutePreference mPreference;
1148         bool            mUserSetPreference;
1149         bool            mAdvPioFlag;
1150         DelayTimer      mTimer;
1151     };
1152 
1153     struct RaInfo
1154     {
1155         // Tracks info about emitted RA messages: Number of RAs sent,
1156         // last tx time, header to use and whether the header is
1157         // discovered from receiving RAs from the host itself. This
1158         // ensures that if an entity on host is advertising certain
1159         // info in its RA header (e.g., a default route), the RAs we
1160         // emit from `RoutingManager` also include the same header.
1161 
RaInfoot::BorderRouter::RoutingManager::RaInfo1162         RaInfo(void)
1163             : mHeaderUpdateTime(TimerMilli::GetNow())
1164             , mIsHeaderFromHost(false)
1165             , mTxCount(0)
1166             , mLastTxTime(TimerMilli::GetNow() - kMinDelayBetweenRtrAdvs)
1167         {
1168         }
1169 
1170         Ip6::Nd::RouterAdvertMessage::Header mHeader;
1171         TimeMilli                            mHeaderUpdateTime;
1172         bool                                 mIsHeaderFromHost;
1173         uint32_t                             mTxCount;
1174         TimeMilli                            mLastTxTime;
1175     };
1176 
HandleRsSenderTimer(void)1177     void HandleRsSenderTimer(void) { mRsSender.HandleTimer(); }
1178 
1179     class RsSender : public InstanceLocator
1180     {
1181     public:
1182         // This class implements tx of Router Solicitation (RS)
1183         // messages to discover other routers. `Start()` schedules
1184         // a cycle of RS transmissions of `kMaxTxCount` separated
1185         // by `kTxInterval`. At the end of cycle the callback
1186         // `HandleRsSenderFinished()` is invoked to inform end of
1187         // the cycle to `RoutingManager`.
1188 
1189         explicit RsSender(Instance &aInstance);
1190 
IsInProgress(void) const1191         bool IsInProgress(void) const { return mTimer.IsRunning(); }
1192         void Start(void);
1193         void Stop(void);
1194         void HandleTimer(void);
1195 
1196     private:
1197         // All time intervals are in msec.
1198         static constexpr uint32_t kMaxStartDelay     = 1000;        // Max random delay to send the first RS.
1199         static constexpr uint32_t kTxInterval        = 4000;        // Interval between RS tx.
1200         static constexpr uint32_t kRetryDelay        = kTxInterval; // Interval to wait to retry a failed RS tx.
1201         static constexpr uint32_t kWaitOnLastAttempt = 1000;        // Wait interval after last RS tx.
1202         static constexpr uint8_t  kMaxTxCount        = 3;           // Number of RS tx in one cycle.
1203 
1204         Error SendRs(void);
1205 
1206         using RsTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRsSenderTimer>;
1207 
1208         uint8_t   mTxCount;
1209         RsTimer   mTimer;
1210         TimeMilli mStartTime;
1211     };
1212 
1213 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
HandlePdPrefixManagerTimer(void)1214     void HandlePdPrefixManagerTimer(void) { mPdPrefixManager.HandleTimer(); }
1215 
1216     class PdPrefixManager : public InstanceLocator
1217     {
1218     public:
1219         // This class implements handling (including management of the lifetime) of the prefix obtained from platform's
1220         // DHCPv6 PD client. We expect the platform will send ICMP6 RA messages to the platform's interface for the
1221         // information of the prefix.
1222         // This class manages the state of the PD prefix in OmrPrefixManager
1223 
1224         explicit PdPrefixManager(Instance &aInstance);
1225 
1226         void               SetEnabled(bool aEnabled);
Start(void)1227         void               Start(void) { StartStop(/* aStart= */ true); }
Stop(void)1228         void               Stop(void) { StartStop(/* aStart= */ false); }
IsRunning(void) const1229         bool               IsRunning(void) const { return GetState() == Dhcp6PdState::kDhcp6PdStateRunning; }
HasPrefix(void) const1230         bool               HasPrefix(void) const { return IsValidOmrPrefix(mPrefix.GetPrefix()); }
GetPrefix(void) const1231         const Ip6::Prefix &GetPrefix(void) const { return mPrefix.GetPrefix(); }
1232         Dhcp6PdState       GetState(void) const;
1233 
1234         void  ProcessPlatformGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength);
1235         Error GetPrefixInfo(PrefixTableEntry &aInfo) const;
1236         Error GetProcessedRaInfo(PdProcessedRaInfo &aPdProcessedRaInfo) const;
HandleTimer(void)1237         void  HandleTimer(void) { WithdrawPrefix(); }
1238 
1239         static const char *StateToString(Dhcp6PdState aState);
1240 
IsValidPdPrefix(const Ip6::Prefix & aPrefix)1241         static bool IsValidPdPrefix(const Ip6::Prefix &aPrefix)
1242         {
1243             // We should accept ULA prefix since it could be used by the internet infrastructure like NAT64.
1244             return aPrefix.GetLength() != 0 && aPrefix.GetLength() <= kOmrPrefixLength && !aPrefix.IsLinkLocal() &&
1245                    !aPrefix.IsMulticast();
1246         }
1247 
1248     private:
1249         Error Process(const Ip6::Nd::RouterAdvertMessage &aMessage);
1250         void  EvaluateStateChange(Dhcp6PdState aOldState);
1251         void  WithdrawPrefix(void);
1252         void  StartStop(bool aStart);
1253 
1254         using PlatformOmrPrefixTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandlePdPrefixManagerTimer>;
1255 
1256         bool                         mEnabled;
1257         bool                         mIsRunning;
1258         uint32_t                     mNumPlatformPioProcessed;
1259         uint32_t                     mNumPlatformRaReceived;
1260         TimeMilli                    mLastPlatformRaTime;
1261         PlatformOmrPrefixTimer       mTimer;
1262         DiscoveredPrefixTable::Entry mPrefix;
1263     };
1264 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1265 
1266     void  EvaluateState(void);
1267     void  Start(void);
1268     void  Stop(void);
1269     void  HandleNotifierEvents(Events aEvents);
IsInitialized(void) const1270     bool  IsInitialized(void) const { return mInfraIf.IsInitialized(); }
IsEnabled(void) const1271     bool  IsEnabled(void) const { return mIsEnabled; }
1272     Error LoadOrGenerateRandomBrUlaPrefix(void);
1273 
1274     void EvaluateRoutingPolicy(void);
1275     bool IsInitalPolicyEvaluationDone(void) const;
1276     void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode);
1277     void HandleRsSenderFinished(TimeMilli aStartTime);
1278     void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode);
1279 
1280     void HandleDiscoveredPrefixStaleTimer(void);
1281 
1282     void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
1283     void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
1284     void HandleNeighborAdvertisement(const InfraIf::Icmp6Packet &aPacket);
1285     bool ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, const Ip6::Prefix &aPrefix);
1286     bool ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, const Ip6::Prefix &aPrefix);
1287     void UpdateDiscoveredPrefixTableOnNetDataChange(void);
1288     bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const;
1289     bool NetworkDataContainsUlaRoute(void) const;
1290     void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage);
1291     bool IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
1292     void ResetDiscoveredPrefixStaleTimer(void);
1293 
1294     static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
1295     static bool IsValidOnLinkPrefix(const Ip6::Nd::PrefixInfoOption &aPio);
1296     static bool IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix);
1297 
1298     static void LogPrefixInfoOption(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime);
1299     static void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference);
1300 
1301     using RoutingPolicyTimer         = TimerMilliIn<RoutingManager, &RoutingManager::EvaluateRoutingPolicy>;
1302     using DiscoveredPrefixStaleTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixStaleTimer>;
1303 
1304     // Indicates whether the Routing Manager is running (started).
1305     bool mIsRunning;
1306 
1307     // Indicates whether the Routing manager is enabled. The Routing
1308     // Manager will be stopped if we are disabled.
1309     bool mIsEnabled;
1310 
1311     InfraIf mInfraIf;
1312 
1313     // The /48 BR ULA prefix loaded from local persistent storage or
1314     // randomly generated if none is found in persistent storage.
1315     Ip6::Prefix mBrUlaPrefix;
1316 
1317     OmrPrefixManager mOmrPrefixManager;
1318 
1319     RioAdvertiser   mRioAdvertiser;
1320     RoutePreference mRioPreference;
1321     bool            mUserSetRioPreference;
1322 
1323     OnLinkPrefixManager mOnLinkPrefixManager;
1324 
1325     DiscoveredPrefixTable mDiscoveredPrefixTable;
1326 
1327     RoutePublisher mRoutePublisher;
1328 
1329 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
1330     Nat64PrefixManager mNat64PrefixManager;
1331 #endif
1332 
1333 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1334     PdPrefixManager mPdPrefixManager;
1335 #endif
1336 
1337     RaInfo   mRaInfo;
1338     RsSender mRsSender;
1339 
1340     DiscoveredPrefixStaleTimer mDiscoveredPrefixStaleTimer;
1341     RoutingPolicyTimer         mRoutingPolicyTimer;
1342 };
1343 
1344 } // namespace BorderRouter
1345 
1346 DefineMapEnum(otBorderRoutingState, BorderRouter::RoutingManager::State);
1347 
1348 } // namespace ot
1349 
1350 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
1351 
1352 #endif // ROUTING_MANAGER_HPP_
1353