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/linked_list.hpp"
57 #include "common/locator.hpp"
58 #include "common/message.hpp"
59 #include "common/notifier.hpp"
60 #include "common/pool.hpp"
61 #include "common/string.hpp"
62 #include "common/timer.hpp"
63 #include "net/ip6.hpp"
64 #include "net/nat64_translator.hpp"
65 #include "net/nd6.hpp"
66 #include "thread/network_data.hpp"
67 
68 namespace ot {
69 
70 namespace BorderRouter {
71 
72 /**
73  * Implements bi-directional routing between Thread and Infrastructure networks.
74  *
75  * The Border Routing manager works on both Thread interface and infrastructure interface.
76  * All ICMPv6 messages are sent/received on the infrastructure interface.
77  *
78  */
79 class RoutingManager : public InstanceLocator
80 {
81     friend class ot::Notifier;
82     friend class ot::Instance;
83 
84 public:
85     typedef NetworkData::RoutePreference       RoutePreference;     ///< Route preference (high, medium, low).
86     typedef otBorderRoutingPrefixTableIterator PrefixTableIterator; ///< Prefix Table Iterator.
87     typedef otBorderRoutingPrefixTableEntry    PrefixTableEntry;    ///< Prefix Table Entry.
88 
89     /**
90      * This constant specifies the maximum number of route prefixes that may be published by `RoutingManager`
91      * in Thread Network Data.
92      *
93      * This is used by `NetworkData::Publisher` to reserve entries for use by `RoutingManager`.
94      *
95      * The number of published entries accounts for:
96      * - Route prefix `fc00::/7` or `::/0`
97      * - One entry for NAT64 published prefix.
98      * - One extra entry for transitions.
99      *
100      */
101     static constexpr uint16_t kMaxPublishedPrefixes = 3;
102 
103     /**
104      * Represents the states of `RoutingManager`.
105      *
106      */
107     enum State : uint8_t
108     {
109         kStateUninitialized = OT_BORDER_ROUTING_STATE_UNINITIALIZED, ///< Uninitialized.
110         kStateDisabled      = OT_BORDER_ROUTING_STATE_DISABLED,      ///< Initialized but disabled.
111         kStateStopped       = OT_BORDER_ROUTING_STATE_STOPPED,       ///< Initialized & enabled, but currently stopped.
112         kStateRunning       = OT_BORDER_ROUTING_STATE_RUNNING,       ///< Initialized, enabled, and running.
113     };
114 
115     /**
116      * This enumeration represents the states of DHCPv6 PD in `RoutingManager`.
117      *
118      */
119     enum Dhcp6PdState : uint8_t
120     {
121         kDhcp6PdStateDisabled = OT_BORDER_ROUTING_STATE_DISABLED, ///< Disabled.
122         kDhcp6PdStateStopped  = OT_BORDER_ROUTING_STATE_STOPPED,  ///< Enabled, but currently stopped.
123         kDhcp6PdStateRunning  = OT_BORDER_ROUTING_STATE_RUNNING,  ///< Enabled, and running.
124     };
125 
126     /**
127      * Initializes the routing manager.
128      *
129      * @param[in]  aInstance  A OpenThread instance.
130      *
131      */
132     explicit RoutingManager(Instance &aInstance);
133 
134     /**
135      * Initializes the routing manager on given infrastructure interface.
136      *
137      * @param[in]  aInfraIfIndex      An infrastructure network interface index.
138      * @param[in]  aInfraIfIsRunning  A boolean that indicates whether the infrastructure
139      *                                interface is running.
140      *
141      * @retval  kErrorNone         Successfully started the routing manager.
142      * @retval  kErrorInvalidArgs  The index of the infra interface is not valid.
143      *
144      */
145     Error Init(uint32_t aInfraIfIndex, bool aInfraIfIsRunning);
146 
147     /**
148      * Enables/disables the Border Routing Manager.
149      *
150      * @note  The Border Routing Manager is enabled by default.
151      *
152      * @param[in]  aEnabled   A boolean to enable/disable the Border Routing Manager.
153      *
154      * @retval  kErrorInvalidState   The Border Routing Manager is not initialized yet.
155      * @retval  kErrorNone           Successfully enabled/disabled the Border Routing Manager.
156      *
157      */
158     Error SetEnabled(bool aEnabled);
159 
160     /**
161      * Indicates whether or not it is currently running.
162      *
163      * In order for the `RoutingManager` to be running it needs to be initialized and enabled, and device being
164      * attached.
165      *
166      * @retval TRUE  The RoutingManager is currently running.
167      * @retval FALSE The RoutingManager is not running.
168      *
169      */
IsRunning(void) const170     bool IsRunning(void) const { return mIsRunning; }
171 
172     /**
173      * Gets the state of `RoutingManager`.
174      *
175      * @returns The current state of `RoutingManager`.
176      *
177      */
178     State GetState(void) const;
179 
180     /**
181      * Requests the Border Routing Manager to stop.
182      *
183      * If Border Routing Manager is running, calling this method immediately stops it and triggers the preparation
184      * and sending of a final Router Advertisement (RA) message on infrastructure interface which deprecates and/or
185      * removes any previously advertised PIO/RIO prefixes. If Routing Manager is not running (or not enabled), no
186      * action is taken.
187      *
188      * Note that this method does not change whether the Routing Manager is enabled or disabled (see `SetEnabled()`).
189      * It stops the Routing Manager temporarily. After calling this method if the device role gets changes (device
190      * gets attached) and/or the infra interface state gets changed, the Routing Manager may be started again.
191      *
192      */
RequestStop(void)193     void RequestStop(void) { Stop(); }
194 
195     /**
196      * Gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement
197      * messages sent over the infrastructure link.
198      *
199      * The RIO preference is determined as follows:
200      *
201      * - If explicitly set by user by calling `SetRouteInfoOptionPreference()`, the given preference is used.
202      * - Otherwise, it is determined based on device's role: Medium preference when in router/leader role and low
203      *   preference when in child role.
204      *
205      * @returns The current Route Info Option preference.
206      *
207      */
GetRouteInfoOptionPreference(void) const208     RoutePreference GetRouteInfoOptionPreference(void) const { return mRioPreference; }
209 
210     /**
211      * Explicitly sets the preference to use when advertising Route Info Options (RIO) in Router
212      * Advertisement messages sent over the infrastructure link.
213      *
214      * After a call to this method, BR will use the given preference for all its advertised RIOs. The preference can be
215      * cleared by calling `ClearRouteInfoOptionPreference`()`.
216      *
217      * @param[in] aPreference   The route preference to use.
218      *
219      */
220     void SetRouteInfoOptionPreference(RoutePreference aPreference);
221 
222     /**
223      * Clears a previously set preference value for advertised Route Info Options.
224      *
225      * After a call to this method, BR will use device role to determine the RIO preference: Medium preference when
226      * in router/leader role and low preference when in child role.
227      *
228      */
229     void ClearRouteInfoOptionPreference(void);
230 
231     /**
232      * Gets the current preference used for published routes in Network Data.
233      *
234      * The preference is determined as follows:
235      *
236      * - If explicitly set by user by calling `SetRoutePreference()`, the given preference is used.
237      * - Otherwise, it is determined automatically by `RoutingManager` based on the device's role and link quality.
238      *
239      * @returns The current published route preference.
240      *
241      */
GetRoutePreference(void) const242     RoutePreference GetRoutePreference(void) const { return mRoutePublisher.GetPreference(); }
243 
244     /**
245      * Explicitly sets the preference of published routes in Network Data.
246      *
247      * After a call to this method, BR will use the given preference. The preference can be cleared by calling
248      * `ClearRoutePreference`()`.
249      *
250      * @param[in] aPreference   The route preference to use.
251      *
252      */
SetRoutePreference(RoutePreference aPreference)253     void SetRoutePreference(RoutePreference aPreference) { mRoutePublisher.SetPreference(aPreference); }
254 
255     /**
256      * Clears a previously set preference value for published routes in Network Data.
257      *
258      * After a call to this method, BR will determine the preference automatically based on the device's role and
259      * link quality (to the parent when acting as end-device).
260      *
261      */
ClearRoutePreference(void)262     void ClearRoutePreference(void) { mRoutePublisher.ClearPreference(); }
263 
264     /**
265      * Returns the local generated off-mesh-routable (OMR) prefix.
266      *
267      * The randomly generated 64-bit prefix will be added to the Thread Network Data if there isn't already an OMR
268      * prefix.
269      *
270      * @param[out]  aPrefix  A reference to where the prefix will be output to.
271      *
272      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
273      * @retval  kErrorNone          Successfully retrieved the OMR prefix.
274      *
275      */
276     Error GetOmrPrefix(Ip6::Prefix &aPrefix) const;
277 
278 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
279     /**
280      * Returns the platform provided off-mesh-routable (OMR) prefix.
281      *
282      * The prefix is extracted from the platform generated RA messages handled by `ProcessPlatfromGeneratedNd()`.
283      *
284      * @param[out] aPrefixInfo      A reference to where the prefix info will be output to.
285      *
286      * @retval kErrorNone           Successfully retrieved the OMR prefix.
287      * @retval kErrorNotFound       There are no valid PD prefix on this BR.
288      * @retval kErrorInvalidState   The Border Routing Manager is not initialized yet.
289      *
290      */
291     Error GetPdOmrPrefix(PrefixTableEntry &aPrefixInfo) const;
292 #endif
293 
294     /**
295      * Returns the currently favored off-mesh-routable (OMR) prefix.
296      *
297      * The favored OMR prefix can be discovered from Network Data or can be our local OMR prefix.
298      *
299      * An OMR prefix with higher preference is favored. If the preference is the same, then the smaller prefix (in the
300      * sense defined by `Ip6::Prefix`) is favored.
301      *
302      * @param[out] aPrefix         A reference to output the favored prefix.
303      * @param[out] aPreference     A reference to output the preference associated with the favored OMR prefix.
304      *
305      * @retval  kErrorInvalidState  The Border Routing Manager is not running yet.
306      * @retval  kErrorNone          Successfully retrieved the OMR prefix.
307      *
308      */
309     Error GetFavoredOmrPrefix(Ip6::Prefix &aPrefix, RoutePreference &aPreference) const;
310 
311     /**
312      * Returns the on-link prefix for the adjacent infrastructure link.
313      *
314      * The randomly generated 64-bit prefix will be advertised
315      * on the infrastructure link if there isn't already a usable
316      * on-link prefix being advertised on the link.
317      *
318      * @param[out]  aPrefix  A reference to where the prefix will be output to.
319      *
320      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
321      * @retval  kErrorNone          Successfully retrieved the local on-link prefix.
322      *
323      */
324     Error GetOnLinkPrefix(Ip6::Prefix &aPrefix) const;
325 
326     /**
327      * Returns the favored on-link prefix for the adjacent infrastructure link.
328      *
329      * The favored prefix is either a discovered prefix on the infrastructure link or the local on-link prefix.
330      *
331      * @param[out]  aPrefix  A reference to where the prefix will be output to.
332      *
333      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
334      * @retval  kErrorNone          Successfully retrieved the favored on-link prefix.
335      *
336      */
337     Error GetFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
338 
339 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
340     /**
341      * Gets the state of NAT64 prefix publishing.
342      *
343      * @retval  kStateDisabled   NAT64 is disabled.
344      * @retval  kStateNotRunning NAT64 is enabled, but is not running since routing manager is not running.
345      * @retval  kStateIdle       NAT64 is enabled, but the border router is not publishing a NAT64 prefix. Usually
346      *                           when there is another border router publishing a NAT64 prefix with higher
347      *                           priority.
348      * @retval  kStateActive     The Border router is publishing a NAT64 prefix.
349      *
350      */
GetNat64PrefixManagerState(void) const351     Nat64::State GetNat64PrefixManagerState(void) const { return mNat64PrefixManager.GetState(); }
352 
353     /**
354      * Enable or disable NAT64 prefix publishing.
355      *
356      * @param[in]  aEnabled   A boolean to enable/disable NAT64 prefix publishing.
357      *
358      */
359     void SetNat64PrefixManagerEnabled(bool aEnabled);
360 
361     /**
362      * Returns the local NAT64 prefix.
363      *
364      * @param[out]  aPrefix  A reference to where the prefix will be output to.
365      *
366      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
367      * @retval  kErrorNone          Successfully retrieved the NAT64 prefix.
368      *
369      */
370     Error GetNat64Prefix(Ip6::Prefix &aPrefix);
371 
372     /**
373      * Returns the currently favored NAT64 prefix.
374      *
375      * The favored NAT64 prefix can be discovered from infrastructure link or can be the local NAT64 prefix.
376      *
377      * @param[out] aPrefix         A reference to output the favored prefix.
378      * @param[out] aPreference     A reference to output the preference associated with the favored prefix.
379      *
380      * @retval  kErrorInvalidState  The Border Routing Manager is not initialized yet.
381      * @retval  kErrorNone          Successfully retrieved the NAT64 prefix.
382      *
383      */
384     Error GetFavoredNat64Prefix(Ip6::Prefix &aPrefix, RoutePreference &aRoutePreference);
385 
386     /**
387      * Informs `RoutingManager` of the result of the discovery request of NAT64 prefix on infrastructure
388      * interface (`InfraIf::DiscoverNat64Prefix()`).
389      *
390      * @param[in]  aPrefix  The discovered NAT64 prefix on `InfraIf`.
391      *
392      */
HandleDiscoverNat64PrefixDone(const Ip6::Prefix & aPrefix)393     void HandleDiscoverNat64PrefixDone(const Ip6::Prefix &aPrefix) { mNat64PrefixManager.HandleDiscoverDone(aPrefix); }
394 
395 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
396 
397     /**
398      * Processes a received ICMPv6 message from the infrastructure interface.
399      *
400      * Malformed or undesired messages are dropped silently.
401      *
402      * @param[in]  aPacket        The received ICMPv6 packet.
403      * @param[in]  aSrcAddress    The source address this message is sent from.
404      *
405      */
406     void HandleReceived(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
407 
408     /**
409      * Handles infrastructure interface state changes.
410      *
411      */
HandleInfraIfStateChanged(void)412     void HandleInfraIfStateChanged(void) { EvaluateState(); }
413 
414     /**
415      * Checks whether the on-mesh prefix configuration is a valid OMR prefix.
416      *
417      * @param[in] aOnMeshPrefixConfig  The on-mesh prefix configuration to check.
418      *
419      * @retval   TRUE    The prefix is a valid OMR prefix.
420      * @retval   FALSE   The prefix is not a valid OMR prefix.
421      *
422      */
423     static bool IsValidOmrPrefix(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
424 
425     /**
426      * Checks whether a given prefix is a valid OMR prefix.
427      *
428      * @param[in]  aPrefix  The prefix to check.
429      *
430      * @retval   TRUE    The prefix is a valid OMR prefix.
431      * @retval   FALSE   The prefix is not a valid OMR prefix.
432      *
433      */
434     static bool IsValidOmrPrefix(const Ip6::Prefix &aPrefix);
435 
436     /**
437      * Initializes a `PrefixTableIterator`.
438      *
439      * An iterator can be initialized again to start from the beginning of the table.
440      *
441      * When iterating over entries in the table, to ensure the entry update times are consistent, they are given
442      * relative to the time the iterator was initialized.
443      *
444      * @param[out] aIterator  The iterator to initialize.
445      *
446      */
InitPrefixTableIterator(PrefixTableIterator & aIterator) const447     void InitPrefixTableIterator(PrefixTableIterator &aIterator) const
448     {
449         mDiscoveredPrefixTable.InitIterator(aIterator);
450     }
451 
452     /**
453      * Iterates over entries in the discovered prefix table.
454      *
455      * @param[in,out] aIterator  An iterator.
456      * @param[out]    aEntry     A reference to the entry to populate.
457      *
458      * @retval kErrorNone        Got the next entry, @p aEntry is updated and @p aIterator is advanced.
459      * @retval kErrorNotFound    No more entries in the table.
460      *
461      */
GetNextPrefixTableEntry(PrefixTableIterator & aIterator,PrefixTableEntry & aEntry) const462     Error GetNextPrefixTableEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const
463     {
464         return mDiscoveredPrefixTable.GetNextEntry(aIterator, aEntry);
465     }
466 
467 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
468     /**
469      * Determines whether to enable/disable SRP server when the auto-enable mode is changed on SRP server.
470      *
471      * This should be called from `Srp::Server` when auto-enable mode is changed.
472      *
473      */
474     void HandleSrpServerAutoEnableMode(void);
475 #endif
476 
477 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
478     /**
479      * Handles a router advertisement message received on platform's Thread interface.
480      *
481      * Note: This method is a part of DHCPv6 PD support on Thread border routers. The message should be generated by the
482      * software like dnamasq, radvd, systemd-networkd on the platform as a part of the DHCPv6 prefix delegation process
483      * for distributing the prefix to the interfaces (links).
484      *
485      * @param[in] aRouterAdvert A pointer to the buffer of the router advertisement message.
486      * @param[in] aLength       The length of the router advertisement message.
487      *
488      */
ProcessPlatfromGeneratedRa(const uint8_t * aRouterAdvert,uint16_t aLength)489     void ProcessPlatfromGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength)
490     {
491         mPdPrefixManager.ProcessPlatformGeneratedRa(aRouterAdvert, aLength);
492     }
493 
494     /**
495      * Enables / Disables the functions for DHCPv6 PD.
496      *
497      * @param[in] aEnabled  Whether to accept platform generated RA messages.
498      *
499      */
SetDhcp6PdEnabled(bool aEnabled)500     void SetDhcp6PdEnabled(bool aEnabled) { return mPdPrefixManager.SetEnabled(aEnabled); }
501 
502     /**
503      * Returns the state of accpeting RouterAdvertisement messages on platform interface.
504      *
505      * @retval kDhcp6PdStateRunning  DHCPv6 PD should be enabled and running on this border router.
506      * @retval kDhcp6PdStateDisabled DHCPv6 PD should be disabled on this border router..
507      *
508      */
GetDhcp6PdState(void) const509     Dhcp6PdState GetDhcp6PdState(void) const { return mPdPrefixManager.GetState(); }
510 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
511 
512 private:
513     static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES;
514 
515     static constexpr uint8_t kOmrPrefixLength    = OT_IP6_PREFIX_BITSIZE; // The length of an OMR prefix. In bits.
516     static constexpr uint8_t kOnLinkPrefixLength = OT_IP6_PREFIX_BITSIZE; // The length of an On-link prefix. In bits.
517     static constexpr uint8_t kBrUlaPrefixLength  = 48;                    // The length of a BR ULA prefix. In bits.
518     static constexpr uint8_t kNat64PrefixLength  = 96;                    // The length of a NAT64 prefix. In bits.
519 
520     static constexpr uint16_t kOmrPrefixSubnetId   = 1; // The subnet ID of an OMR prefix within a BR ULA prefix.
521     static constexpr uint16_t kNat64PrefixSubnetId = 2; // The subnet ID of a NAT64 prefix within a BR ULA prefix.
522 
523     // The maximum number of initial Router Advertisements.
524     static constexpr uint32_t kMaxInitRtrAdvertisements = 3;
525 
526     static constexpr uint32_t kDefaultOmrPrefixLifetime    = 1800; // The default OMR prefix valid lifetime. In sec.
527     static constexpr uint32_t kDefaultOnLinkPrefixLifetime = 1800; // The default on-link prefix valid lifetime. In sec.
528     static constexpr uint32_t kDefaultNat64PrefixLifetime  = 300;  // The default NAT64 prefix valid lifetime. In sec.
529     static constexpr uint32_t kMaxRtrAdvInterval           = 600;  // Max Router Advertisement Interval. In sec.
530     static constexpr uint32_t kMinRtrAdvInterval           = kMaxRtrAdvInterval / 3; // Min RA Interval. In sec.
531     static constexpr uint32_t kMaxInitRtrAdvInterval       = 16;                     // Max Initial RA Interval. In sec.
532     static constexpr uint32_t kRaReplyJitter               = 500;  // Jitter for sending RA after rx RS. In msec.
533     static constexpr uint32_t kPolicyEvaluationMinDelay    = 2000; // Min delay for policy evaluation. In msec.
534     static constexpr uint32_t kPolicyEvaluationMaxDelay    = 4000; // Max delay for policy evaluation. In msec.
535     static constexpr uint32_t kMinDelayBetweenRtrAdvs      = 3000; // Min delay (msec) between consecutive RAs.
536 
537     // The STALE_RA_TIME in seconds. The Routing Manager will consider the prefixes
538     // and learned RA parameters STALE when they are not refreshed in STALE_RA_TIME
539     // seconds. The Routing Manager will then start Router Solicitation to verify
540     // that the STALE prefix is not being advertised anymore and remove the STALE
541     // prefix.
542     // The value is chosen in range of [`kMaxRtrAdvInterval` upper bound (1800s), `kDefaultOnLinkPrefixLifetime`].
543     static constexpr uint32_t kRtrAdvStaleTime = 1800;
544 
545     static_assert(kMinRtrAdvInterval <= 3 * kMaxRtrAdvInterval / 4, "invalid RA intervals");
546     static_assert(kDefaultOmrPrefixLifetime >= kMaxRtrAdvInterval, "invalid default OMR prefix lifetime");
547     static_assert(kDefaultOnLinkPrefixLifetime >= kMaxRtrAdvInterval, "invalid default on-link prefix lifetime");
548     static_assert(kRtrAdvStaleTime >= 1800 && kRtrAdvStaleTime <= kDefaultOnLinkPrefixLifetime,
549                   "invalid RA STALE time");
550     static_assert(kPolicyEvaluationMaxDelay > kPolicyEvaluationMinDelay,
551                   "kPolicyEvaluationMaxDelay must be larger than kPolicyEvaluationMinDelay");
552 
553     enum RouterAdvTxMode : uint8_t // Used in `SendRouterAdvertisement()`
554     {
555         kInvalidateAllPrevPrefixes,
556         kAdvPrefixesFromNetData,
557     };
558 
559     enum ScheduleMode : uint8_t // Used in `ScheduleRoutingPolicyEvaluation()`
560     {
561         kImmediately,
562         kForNextRa,
563         kAfterRandomDelay,
564         kToReplyToRs,
565     };
566 
567     void HandleDiscoveredPrefixTableChanged(void); // Declare early so we can use in `mSignalTask`
HandleDiscoveredPrefixTableEntryTimer(void)568     void HandleDiscoveredPrefixTableEntryTimer(void) { mDiscoveredPrefixTable.HandleEntryTimer(); }
HandleDiscoveredPrefixTableRouterTimer(void)569     void HandleDiscoveredPrefixTableRouterTimer(void) { mDiscoveredPrefixTable.HandleRouterTimer(); }
570 
571 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
572     class PdPrefixManager; // For DiscoveredPrefixTable::Entry
573 #endif
574 
575     class DiscoveredPrefixTable : public InstanceLocator
576     {
577         // This class maintains the discovered on-link and route prefixes
578         // from the received RA messages by processing PIO and RIO options
579         // from the message. It takes care of processing the RA message but
580         // delegates the decision whether to include or exclude a prefix to
581         // `RoutingManager` by calling its `ShouldProcessPrefixInfoOption()`
582         // and `ShouldProcessRouteInfoOption()` methods.
583         //
584         // It manages the lifetime of the discovered entries and publishes
585         // and unpublishes the prefixes in the Network Data (as external
586         // route) as they are added or removed.
587         //
588         // When there is any change in the table (an entry is added, removed,
589         // or modified), it signals the change to `RoutingManager` by calling
590         // `HandleDiscoveredPrefixTableChanged()` callback. A `Tasklet` is
591         // used for signalling which ensures that if there are multiple
592         // changes within the same flow of execution, the callback is
593         // invoked after all the changes are processed.
594 
595 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
596         friend class PdPrefixManager; // For DiscoveredPrefixTable::Entry
597 #endif
598 
599     public:
600         explicit DiscoveredPrefixTable(Instance &aInstance);
601 
602         void ProcessRouterAdvertMessage(const Ip6::Nd::RouterAdvertMessage &aRaMessage,
603                                         const Ip6::Address                 &aSrcAddress);
604         void ProcessNeighborAdvertMessage(const Ip6::Nd::NeighborAdvertMessage &aNaMessage);
605 
606         bool ContainsDefaultOrNonUlaRoutePrefix(void) const;
607         bool ContainsNonUlaOnLinkPrefix(void) const;
608         bool ContainsUlaOnLinkPrefix(void) const;
609 
610         void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const;
611 
612         void RemoveOnLinkPrefix(const Ip6::Prefix &aPrefix);
613         void RemoveRoutePrefix(const Ip6::Prefix &aPrefix);
614 
615         void RemoveAllEntries(void);
616         void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
617 
618         TimeMilli CalculateNextStaleTime(TimeMilli aNow) const;
619 
620         void  InitIterator(PrefixTableIterator &aIterator) const;
621         Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
622 
623         void HandleEntryTimer(void);
624         void HandleRouterTimer(void);
625 
626     private:
627         static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS;
628         static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES;
629 
630         class Entry : public LinkedListEntry<Entry>, public Unequatable<Entry>, private Clearable<Entry>
631         {
632             friend class LinkedListEntry<Entry>;
633             friend class Clearable<Entry>;
634 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
635             friend class PdPrefixManager;
636 #endif
637 
638         public:
639             enum Type : uint8_t
640             {
641                 kTypeOnLink,
642                 kTypeRoute,
643             };
644 
645             struct Matcher
646             {
Matcherot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Entry::Matcher647                 Matcher(const Ip6::Prefix &aPrefix, Type aType)
648                     : mPrefix(aPrefix)
649                     , mType(aType)
650                 {
651                 }
652 
653                 const Ip6::Prefix &mPrefix;
654                 Type               mType;
655             };
656 
657             struct Checker
658             {
659                 enum Mode : uint8_t
660                 {
661                     kIsUla,
662                     kIsNotUla,
663                 };
664 
Checkerot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Entry::Checker665                 Checker(Mode aMode, Type aType)
666                     : mMode(aMode)
667                     , mType(aType)
668 
669                 {
670                 }
671 
672                 Mode mMode;
673                 Type mType;
674             };
675 
676             struct ExpirationChecker
677             {
ExpirationCheckerot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Entry::ExpirationChecker678                 explicit ExpirationChecker(TimeMilli aNow)
679                     : mNow(aNow)
680                 {
681                 }
682 
683                 TimeMilli mNow;
684             };
685 
686             void               SetFrom(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader);
687             void               SetFrom(const Ip6::Nd::PrefixInfoOption &aPio);
688             void               SetFrom(const Ip6::Nd::RouteInfoOption &aRio);
GetType(void) const689             Type               GetType(void) const { return mType; }
IsOnLinkPrefix(void) const690             bool               IsOnLinkPrefix(void) const { return (mType == kTypeOnLink); }
IsRoutePrefix(void) const691             bool               IsRoutePrefix(void) const { return (mType == kTypeRoute); }
GetPrefix(void) const692             const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
GetLastUpdateTime(void) const693             const TimeMilli   &GetLastUpdateTime(void) const { return mLastUpdateTime; }
GetValidLifetime(void) const694             uint32_t           GetValidLifetime(void) const { return mValidLifetime; }
ClearValidLifetime(void)695             void               ClearValidLifetime(void) { mValidLifetime = 0; }
696             TimeMilli          GetExpireTime(void) const;
697             TimeMilli          GetStaleTime(void) const;
698             RoutePreference    GetPreference(void) const;
699             bool               operator==(const Entry &aOther) const;
700             bool               Matches(const Matcher &aMatcher) const;
701             bool               Matches(const Checker &aChecker) const;
702             bool               Matches(const ExpirationChecker &aChecker) const;
703 
704             // Methods to use when `IsOnLinkPrefix()`
GetPreferredLifetime(void) const705             uint32_t GetPreferredLifetime(void) const { return mShared.mPreferredLifetime; }
ClearPreferredLifetime(void)706             void     ClearPreferredLifetime(void) { mShared.mPreferredLifetime = 0; }
707             bool     IsDeprecated(void) const;
708             void     AdoptValidAndPreferredLifetimesFrom(const Entry &aEntry);
709 
710             // Method to use when `!IsOnlinkPrefix()`
GetRoutePreference(void) const711             RoutePreference GetRoutePreference(void) const { return mShared.mRoutePreference; }
712 
713         private:
714             static uint32_t CalculateExpireDelay(uint32_t aValidLifetime);
715 
716             Entry      *mNext;
717             Ip6::Prefix mPrefix;
718             Type        mType;
719             TimeMilli   mLastUpdateTime;
720             uint32_t    mValidLifetime;
721             union
722             {
723                 uint32_t        mPreferredLifetime; // Applicable when prefix is on-link.
724                 RoutePreference mRoutePreference;   // Applicable when prefix is not on-link
725             } mShared;
726         };
727 
728         struct Router
729         {
730             // The timeout (in msec) for router staying in active state
731             // before starting the Neighbor Solicitation (NS) probes.
732             static constexpr uint32_t kActiveTimeout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
733 
734             static constexpr uint8_t  kMaxNsProbes          = 5;    // Max number of NS probe attempts.
735             static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
736             static constexpr uint32_t kNsProbeTimeout       = 2000; // In msec. Max Wait time after last NS probe.
737             static constexpr uint32_t kJitter               = 2000; // In msec. Jitter to randomize probe starts.
738 
739             static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255");
740 
741             enum EmptyChecker : uint8_t
742             {
743                 kContainsNoEntries
744             };
745 
Matchesot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Router746             bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; }
Matchesot::BorderRouter::RoutingManager::DiscoveredPrefixTable::Router747             bool Matches(EmptyChecker) const { return mEntries.IsEmpty(); }
748 
749             Ip6::Address      mAddress;
750             LinkedList<Entry> mEntries;
751             TimeMilli         mTimeout;
752             uint8_t           mNsProbeCount;
753         };
754 
755         class Iterator : public PrefixTableIterator
756         {
757         public:
GetRouter(void) const758             const Router *GetRouter(void) const { return static_cast<const Router *>(mPtr1); }
SetRouter(const Router * aRouter)759             void          SetRouter(const Router *aRouter) { mPtr1 = aRouter; }
GetEntry(void) const760             const Entry  *GetEntry(void) const { return static_cast<const Entry *>(mPtr2); }
SetEntry(const Entry * aEntry)761             void          SetEntry(const Entry *aEntry) { mPtr2 = aEntry; }
GetInitTime(void) const762             TimeMilli     GetInitTime(void) const { return TimeMilli(mData32); }
SetInitTime(void)763             void          SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); }
764         };
765 
766         void         ProcessDefaultRoute(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, Router &aRouter);
767         void         ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, Router &aRouter);
768         void         ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter);
769         bool         Contains(const Entry::Checker &aChecker) const;
770         void         RemovePrefix(const Entry::Matcher &aMatcher);
771         void         RemoveOrDeprecateEntriesFromInactiveRouters(void);
772         void         RemoveRoutersWithNoEntries(void);
AllocateEntry(void)773         Entry       *AllocateEntry(void) { return mEntryPool.Allocate(); }
FreeEntry(Entry & aEntry)774         void         FreeEntry(Entry &aEntry) { mEntryPool.Free(aEntry); }
775         void         FreeEntries(LinkedList<Entry> &aEntries);
776         void         UpdateNetworkDataOnChangeTo(Entry &aEntry);
777         const Entry *FindFavoredEntryToPublish(const Ip6::Prefix &aPrefix) const;
778         void         RemoveExpiredEntries(void);
779         void         SignalTableChanged(void);
780         void         UpdateRouterOnRx(Router &aRouter);
781         void         SendNeighborSolicitToRouter(const Router &aRouter);
782 
783         using SignalTask  = TaskletIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableChanged>;
784         using EntryTimer  = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableEntryTimer>;
785         using RouterTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixTableRouterTimer>;
786 
787         Array<Router, kMaxRouters> mRouters;
788         Pool<Entry, kMaxEntries>   mEntryPool;
789         EntryTimer                 mEntryTimer;
790         RouterTimer                mRouterTimer;
791         SignalTask                 mSignalTask;
792     };
793 
794     class OmrPrefixManager;
795 
796     class OmrPrefix : public Clearable<OmrPrefix>
797     {
798         friend class OmrPrefixManager;
799 
800     public:
OmrPrefix(void)801         OmrPrefix(void) { Clear(); }
802 
IsEmpty(void) const803         bool               IsEmpty(void) const { return (mPrefix.GetLength() == 0); }
GetPrefix(void) const804         const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
GetPreference(void) const805         RoutePreference    GetPreference(void) const { return mPreference; }
IsDomainPrefix(void) const806         bool               IsDomainPrefix(void) const { return mIsDomainPrefix; }
807 
808     protected:
809         Ip6::Prefix     mPrefix;
810         RoutePreference mPreference;
811         bool            mIsDomainPrefix;
812     };
813 
814     class FavoredOmrPrefix : public OmrPrefix
815     {
816         friend class OmrPrefixManager;
817 
818     public:
819         bool IsInfrastructureDerived(void) const;
820 
821     private:
822         void SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
823         void SetFrom(const OmrPrefix &aOmrPrefix);
824         bool IsFavoredOver(const NetworkData::OnMeshPrefixConfig &aOmrPrefixConfig) const;
825     };
826 
827     class OmrPrefixManager : public InstanceLocator
828     {
829     public:
830         explicit OmrPrefixManager(Instance &aInstance);
831 
832         void                    Init(const Ip6::Prefix &aBrUlaPrefix);
833         void                    Start(void);
834         void                    Stop(void);
835         void                    Evaluate(void);
836         void                    UpdateDefaultRouteFlag(bool aDefaultRoute);
IsLocalAddedInNetData(void) const837         bool                    IsLocalAddedInNetData(void) const { return mIsLocalAddedInNetData; }
GetGeneratedPrefix(void) const838         const Ip6::Prefix      &GetGeneratedPrefix(void) const { return mGeneratedPrefix; }
GetLocalPrefix(void) const839         const OmrPrefix        &GetLocalPrefix(void) const { return mLocalPrefix; }
GetFavoredPrefix(void) const840         const FavoredOmrPrefix &GetFavoredPrefix(void) const { return mFavoredPrefix; }
841 
842     private:
843         static constexpr uint16_t kInfoStringSize = 85;
844 
845         typedef String<kInfoStringSize> InfoString;
846 
847         void       DetermineFavoredPrefix(void);
848         Error      AddLocalToNetData(void);
849         Error      AddOrUpdateLocalInNetData(void);
850         void       RemoveLocalFromNetData(void);
851         InfoString LocalToString(void) const;
852 
853         OmrPrefix        mLocalPrefix;
854         Ip6::Prefix      mGeneratedPrefix;
855         FavoredOmrPrefix mFavoredPrefix;
856         bool             mIsLocalAddedInNetData;
857         bool             mDefaultRoute;
858     };
859 
HandleOnLinkPrefixManagerTimer(void)860     void HandleOnLinkPrefixManagerTimer(void) { mOnLinkPrefixManager.HandleTimer(); }
861 
862     class OnLinkPrefixManager : public InstanceLocator
863     {
864     public:
865         explicit OnLinkPrefixManager(Instance &aInstance);
866 
867         // Max number of old on-link prefixes to retain to deprecate.
868         static constexpr uint16_t kMaxOldPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_OLD_ON_LINK_PREFIXES;
869 
870         void               Init(void);
871         void               Start(void);
872         void               Stop(void);
873         void               Evaluate(void);
GetLocalPrefix(void) const874         const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
GetFavoredDiscoveredPrefix(void) const875         const Ip6::Prefix &GetFavoredDiscoveredPrefix(void) const { return mFavoredDiscoveredPrefix; }
876         bool               IsInitalEvaluationDone(void) const;
877         void               HandleDiscoveredPrefixTableChanged(void);
878         bool               ShouldPublishUlaRoute(void) const;
879         void               AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage);
880         bool               IsPublishingOrAdvertising(void) const;
881         void               HandleNetDataChange(void);
882         void               HandleExtPanIdChange(void);
883         void               HandleTimer(void);
884 
885     private:
886         enum State : uint8_t // State of `mLocalPrefix`
887         {
888             kIdle,
889             kPublishing,
890             kAdvertising,
891             kDeprecating,
892         };
893 
894         struct OldPrefix
895         {
Matchesot::BorderRouter::RoutingManager::OnLinkPrefixManager::OldPrefix896             bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
897 
898             Ip6::Prefix mPrefix;
899             TimeMilli   mExpireTime;
900         };
901 
GetState(void) const902         State GetState(void) const { return mState; }
903         void  SetState(State aState);
904         void  GenerateLocalPrefix(void);
905         void  PublishAndAdvertise(void);
906         void  Deprecate(void);
907         void  ResetExpireTime(TimeMilli aNow);
908         void  AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage);
909         void  AppendOldPrefixes(Ip6::Nd::RouterAdvertMessage &aRaMessage);
910         void  DeprecateOldPrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
911         void  SavePrefix(const Ip6::Prefix &aPrefix, TimeMilli aExpireTime);
912 
913         static const char *StateToString(State aState);
914 
915         using ExpireTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleOnLinkPrefixManagerTimer>;
916 
917         Ip6::Prefix                       mLocalPrefix;
918         State                             mState;
919         TimeMilli                         mExpireTime;
920         Ip6::Prefix                       mFavoredDiscoveredPrefix;
921         Array<OldPrefix, kMaxOldPrefixes> mOldLocalPrefixes;
922         ExpireTimer                       mTimer;
923     };
924 
925     typedef Ip6::Prefix OnMeshPrefix;
926 
927     class OnMeshPrefixArray : public Array<OnMeshPrefix, kMaxOnMeshPrefixes>
928     {
929     public:
930         void Add(const OnMeshPrefix &aPrefix);
931         void MarkAsDeleted(const OnMeshPrefix &aPrefix);
932     };
933 
934 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
HandleNat64PrefixManagerTimer(void)935     void HandleNat64PrefixManagerTimer(void) { mNat64PrefixManager.HandleTimer(); }
936 
937     class Nat64PrefixManager : public InstanceLocator
938     {
939     public:
940         // This class manages the NAT64 related functions including
941         // generation of local NAT64 prefix, discovery of infra
942         // interface prefix, maintaining the discovered prefix
943         // lifetime, and selection of the NAT64 prefix to publish in
944         // Network Data.
945         //
946         // Calling methods except GenerateLocalPrefix and SetEnabled
947         // when disabled becomes no-op.
948 
949         explicit Nat64PrefixManager(Instance &aInstance);
950 
951         void         SetEnabled(bool aEnabled);
952         Nat64::State GetState(void) const;
953 
954         void Start(void);
955         void Stop(void);
956 
957         void               GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix);
GetLocalPrefix(void) const958         const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
959         const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const;
960         void               Evaluate(void);
961         void               HandleDiscoverDone(const Ip6::Prefix &aPrefix);
962         void               HandleTimer(void);
963 
964     private:
965         void Discover(void);
966         void Publish(void);
967 
968         using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>;
969 
970         bool mEnabled;
971 
972         Ip6::Prefix     mInfraIfPrefix;       // The latest NAT64 prefix discovered on the infrastructure interface.
973         Ip6::Prefix     mLocalPrefix;         // The local prefix (from BR ULA prefix).
974         Ip6::Prefix     mPublishedPrefix;     // The prefix to publish in Net Data (empty or local or from infra-if).
975         RoutePreference mPublishedPreference; // The published prefix preference.
976         Nat64Timer      mTimer;
977     };
978 #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
979 
HandleRoutePublisherTimer(void)980     void HandleRoutePublisherTimer(void) { mRoutePublisher.HandleTimer(); }
981 
982     class RoutePublisher : public InstanceLocator // Manages the routes that are published in net data
983     {
984     public:
985         explicit RoutePublisher(Instance &aInstance);
986 
Start(void)987         void Start(void) { Evaluate(); }
Stop(void)988         void Stop(void) { Unpublish(); }
989         void Evaluate(void);
990 
991         void UpdateAdvPioFlags(bool aAdvPioFlag);
992 
GetPreference(void) const993         RoutePreference GetPreference(void) const { return mPreference; }
994         void            SetPreference(RoutePreference aPreference);
995         void            ClearPreference(void);
996 
997         void HandleNotifierEvents(Events aEvents);
998         void HandleTimer(void);
999 
GetUlaPrefix(void)1000         static const Ip6::Prefix &GetUlaPrefix(void) { return AsCoreType(&kUlaPrefix); }
1001 
1002     private:
1003         static constexpr uint32_t kDelayBeforePrfUpdateOnLinkQuality3 = TimeMilli::SecToMsec(5 * 60);
1004 
1005         static const otIp6Prefix kUlaPrefix;
1006 
1007         enum State : uint8_t
1008         {
1009             kDoNotPublish,   // Do not publish any routes in network data.
1010             kPublishDefault, // Publish "::/0" route in network data.
1011             kPublishUla,     // Publish "fc00::/7" route in network data.
1012         };
1013 
1014         void DeterminePrefixFor(State aState, Ip6::Prefix &aPrefix) const;
1015         void UpdatePublishedRoute(State aNewState);
1016         void Unpublish(void);
1017         void SetPreferenceBasedOnRole(void);
1018         void UpdatePreference(RoutePreference aPreference);
1019 
1020         static const char *StateToString(State aState);
1021 
1022         using DelayTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRoutePublisherTimer>;
1023 
1024         State           mState;
1025         RoutePreference mPreference;
1026         bool            mUserSetPreference;
1027         bool            mAdvPioFlag;
1028         DelayTimer      mTimer;
1029     };
1030 
1031     struct RaInfo
1032     {
1033         // Tracks info about emitted RA messages: Number of RAs sent,
1034         // last tx time, header to use and whether the header is
1035         // discovered from receiving RAs from the host itself. This
1036         // ensures that if an entity on host is advertising certain
1037         // info in its RA header (e.g., a default route), the RAs we
1038         // emit from `RoutingManager` also include the same header.
1039 
RaInfoot::BorderRouter::RoutingManager::RaInfo1040         RaInfo(void)
1041             : mHeaderUpdateTime(TimerMilli::GetNow())
1042             , mIsHeaderFromHost(false)
1043             , mTxCount(0)
1044             , mLastTxTime(TimerMilli::GetNow() - kMinDelayBetweenRtrAdvs)
1045         {
1046         }
1047 
1048         Ip6::Nd::RouterAdvertMessage::Header mHeader;
1049         TimeMilli                            mHeaderUpdateTime;
1050         bool                                 mIsHeaderFromHost;
1051         uint32_t                             mTxCount;
1052         TimeMilli                            mLastTxTime;
1053     };
1054 
HandleRsSenderTimer(void)1055     void HandleRsSenderTimer(void) { mRsSender.HandleTimer(); }
1056 
1057     class RsSender : public InstanceLocator
1058     {
1059     public:
1060         // This class implements tx of Router Solicitation (RS)
1061         // messages to discover other routers. `Start()` schedules
1062         // a cycle of RS transmissions of `kMaxTxCount` separated
1063         // by `kTxInterval`. At the end of cycle the callback
1064         // `HandleRsSenderFinished()` is invoked to inform end of
1065         // the cycle to `RoutingManager`.
1066 
1067         explicit RsSender(Instance &aInstance);
1068 
IsInProgress(void) const1069         bool IsInProgress(void) const { return mTimer.IsRunning(); }
1070         void Start(void);
1071         void Stop(void);
1072         void HandleTimer(void);
1073 
1074     private:
1075         // All time intervals are in msec.
1076         static constexpr uint32_t kMaxStartDelay     = 1000;        // Max random delay to send the first RS.
1077         static constexpr uint32_t kTxInterval        = 4000;        // Interval between RS tx.
1078         static constexpr uint32_t kRetryDelay        = kTxInterval; // Interval to wait to retry a failed RS tx.
1079         static constexpr uint32_t kWaitOnLastAttempt = 1000;        // Wait interval after last RS tx.
1080         static constexpr uint8_t  kMaxTxCount        = 3;           // Number of RS tx in one cycle.
1081 
1082         Error SendRs(void);
1083 
1084         using RsTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRsSenderTimer>;
1085 
1086         uint8_t   mTxCount;
1087         RsTimer   mTimer;
1088         TimeMilli mStartTime;
1089     };
1090 
1091 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
HandlePdPrefixManagerTimer(void)1092     void HandlePdPrefixManagerTimer(void) { mPdPrefixManager.HandleTimer(); }
1093 
1094     class PdPrefixManager : public InstanceLocator
1095     {
1096     public:
1097         // This class implements handling (including management of the lifetime) of the prefix obtained from platform's
1098         // DHCPv6 PD client. We expect the platform will send ICMP6 RA messages to the platform's interface for the
1099         // information of the prefix.
1100         // This class manages the state of the PD prefix in OmrPrefixManager
1101 
1102         explicit PdPrefixManager(Instance &aInstance);
1103 
1104         void               SetEnabled(bool aEnabled);
IsRunning(void) const1105         bool               IsRunning(void) const { return GetState() == Dhcp6PdState::kDhcp6PdStateRunning; }
HasPrefix(void) const1106         bool               HasPrefix(void) const { return IsValidOmrPrefix(mPrefix.GetPrefix()); }
GetPrefix(void) const1107         const Ip6::Prefix &GetPrefix(void) const { return mPrefix.GetPrefix(); }
GetState(void) const1108         Dhcp6PdState       GetState(void) const
1109         {
1110             // TODO: We need to stop and inform the platform when there is already a GUA prefix advertised in the
1111             // network.
1112             return mEnabled ? kDhcp6PdStateRunning : kDhcp6PdStateDisabled;
1113         }
1114 
1115         void  ProcessPlatformGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength);
1116         Error GetPrefixInfo(PrefixTableEntry &aInfo) const;
HandleTimer(void)1117         void  HandleTimer(void) { WithdrawPrefix(); }
1118 
IsValidPdPrefix(const Ip6::Prefix & aPrefix)1119         static bool IsValidPdPrefix(const Ip6::Prefix &aPrefix)
1120         {
1121             // We should accept ULA prefix since it could be used by the internet infrastructure like NAT64.
1122             return aPrefix.GetLength() != 0 && aPrefix.GetLength() <= kOmrPrefixLength && !aPrefix.IsLinkLocal() &&
1123                    !aPrefix.IsMulticast();
1124         }
1125 
1126     private:
1127         Error Process(const Ip6::Nd::RouterAdvertMessage &aMessage);
1128         void  WithdrawPrefix(void);
1129 
1130         using PlatformOmrPrefixTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandlePdPrefixManagerTimer>;
1131 
1132         bool                         mEnabled;
1133         PlatformOmrPrefixTimer       mTimer;
1134         DiscoveredPrefixTable::Entry mPrefix;
1135     };
1136 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1137 
1138     void  EvaluateState(void);
1139     void  Start(void);
1140     void  Stop(void);
1141     void  HandleNotifierEvents(Events aEvents);
IsInitialized(void) const1142     bool  IsInitialized(void) const { return mInfraIf.IsInitialized(); }
IsEnabled(void) const1143     bool  IsEnabled(void) const { return mIsEnabled; }
1144     void  SetRioPreferenceBasedOnRole(void);
1145     void  UpdateRioPreference(RoutePreference aPreference);
1146     Error LoadOrGenerateRandomBrUlaPrefix(void);
1147 
1148     void EvaluateRoutingPolicy(void);
1149     bool IsInitalPolicyEvaluationDone(void) const;
1150     void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode);
1151     void HandleRsSenderFinished(TimeMilli aStartTime);
1152     void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode);
1153 
1154     void HandleDiscoveredPrefixStaleTimer(void);
1155 
1156     void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
1157     void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
1158     void HandleNeighborAdvertisement(const InfraIf::Icmp6Packet &aPacket);
1159     bool ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, const Ip6::Prefix &aPrefix);
1160     bool ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, const Ip6::Prefix &aPrefix);
1161     void UpdateDiscoveredPrefixTableOnNetDataChange(void);
1162     bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const;
1163     bool NetworkDataContainsUlaRoute(void) const;
1164     void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage);
1165     bool IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
1166     void ResetDiscoveredPrefixStaleTimer(void);
1167 
1168     static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
1169     static bool IsValidOnLinkPrefix(const Ip6::Nd::PrefixInfoOption &aPio);
1170     static bool IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix);
1171 
1172     static void LogPrefixInfoOption(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime);
1173     static void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference);
1174 
1175     using RoutingPolicyTimer         = TimerMilliIn<RoutingManager, &RoutingManager::EvaluateRoutingPolicy>;
1176     using DiscoveredPrefixStaleTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleDiscoveredPrefixStaleTimer>;
1177 
1178     // Indicates whether the Routing Manager is running (started).
1179     bool mIsRunning;
1180 
1181     // Indicates whether the Routing manager is enabled. The Routing
1182     // Manager will be stopped if we are disabled.
1183     bool mIsEnabled;
1184 
1185     InfraIf mInfraIf;
1186 
1187     // The /48 BR ULA prefix loaded from local persistent storage or
1188     // randomly generated if none is found in persistent storage.
1189     Ip6::Prefix mBrUlaPrefix;
1190 
1191     OmrPrefixManager mOmrPrefixManager;
1192 
1193     // List of on-mesh prefixes (discovered from Network Data) which
1194     // were advertised as RIO in the last sent RA message.
1195     OnMeshPrefixArray mAdvertisedPrefixes;
1196 
1197     RoutePreference mRioPreference;
1198     bool            mUserSetRioPreference;
1199 
1200     OnLinkPrefixManager mOnLinkPrefixManager;
1201 
1202     DiscoveredPrefixTable mDiscoveredPrefixTable;
1203 
1204     RoutePublisher mRoutePublisher;
1205 
1206 #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
1207     Nat64PrefixManager mNat64PrefixManager;
1208 #endif
1209 
1210 #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
1211     PdPrefixManager mPdPrefixManager;
1212 #endif
1213 
1214     RaInfo   mRaInfo;
1215     RsSender mRsSender;
1216 
1217     DiscoveredPrefixStaleTimer mDiscoveredPrefixStaleTimer;
1218     RoutingPolicyTimer         mRoutingPolicyTimer;
1219 };
1220 
1221 } // namespace BorderRouter
1222 
1223 DefineMapEnum(otBorderRoutingState, BorderRouter::RoutingManager::State);
1224 
1225 } // namespace ot
1226 
1227 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
1228 
1229 #endif // ROUTING_MANAGER_HPP_
1230