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