1 /*
2  *  Copyright (c) 2018, 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 #include "router_table.hpp"
30 
31 #if OPENTHREAD_FTD
32 
33 #include "common/code_utils.hpp"
34 #include "common/locator_getters.hpp"
35 #include "common/log.hpp"
36 #include "common/timer.hpp"
37 #include "instance/instance.hpp"
38 #include "thread/mle.hpp"
39 #include "thread/mle_router.hpp"
40 #include "thread/network_data_leader.hpp"
41 #include "thread/thread_netif.hpp"
42 
43 namespace ot {
44 
45 RegisterLogModule("RouterTable");
46 
RouterTable(Instance & aInstance)47 RouterTable::RouterTable(Instance &aInstance)
48     : InstanceLocator(aInstance)
49     , mRouters(aInstance)
50     , mChangedTask(aInstance)
51     , mRouterIdSequenceLastUpdated(0)
52     , mRouterIdSequence(Random::NonCrypto::GetUint8())
53 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
54     , mMinRouterId(0)
55     , mMaxRouterId(Mle::kMaxRouterId)
56 #endif
57 {
58     Clear();
59 }
60 
Clear(void)61 void RouterTable::Clear(void)
62 {
63     ClearNeighbors();
64     mRouterIdMap.Clear();
65     mRouters.Clear();
66     SignalTableChanged();
67 }
68 
IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv & aRouteTlv) const69 bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const
70 {
71     return (GetActiveRouterCount() == 0) ||
72            SerialNumber::IsGreater(aRouteTlv.GetRouterIdSequence(), GetRouterIdSequence());
73 }
74 
ClearNeighbors(void)75 void RouterTable::ClearNeighbors(void)
76 {
77     for (Router &router : mRouters)
78     {
79         if (router.IsStateValid())
80         {
81             Get<NeighborTable>().Signal(NeighborTable::kRouterRemoved, router);
82             SignalTableChanged();
83         }
84 
85         router.SetState(Neighbor::kStateInvalid);
86     }
87 }
88 
AddRouter(uint8_t aRouterId)89 Router *RouterTable::AddRouter(uint8_t aRouterId)
90 {
91     // Add a new `Router` entry to `mRouters` array with given
92     // `aRouterId` and update the `mRouterIdMap`.
93 
94     Router *router = mRouters.PushBack();
95 
96     VerifyOrExit(router != nullptr);
97 
98     router->Clear();
99     router->SetRloc16(Mle::Rloc16FromRouterId(aRouterId));
100     router->SetNextHopToInvalid();
101 
102     mRouterIdMap.SetIndex(aRouterId, mRouters.IndexOf(*router));
103     SignalTableChanged();
104 
105 exit:
106     return router;
107 }
108 
RemoveRouter(Router & aRouter)109 void RouterTable::RemoveRouter(Router &aRouter)
110 {
111     // Remove an existing `aRouter` entry from `mRouters` and update the
112     // `mRouterIdMap`.
113 
114     if (aRouter.IsStateValid())
115     {
116         Get<NeighborTable>().Signal(NeighborTable::kRouterRemoved, aRouter);
117     }
118 
119     mRouterIdMap.Release(aRouter.GetRouterId());
120     mRouters.Remove(aRouter);
121 
122     // Removing `aRouter` from `mRouters` array will replace it with
123     // the last entry in the array (if not already the last entry) so
124     // we update the index in `mRouteIdMap` for the moved entry.
125 
126     if (IsAllocated(aRouter.GetRouterId()))
127     {
128         mRouterIdMap.SetIndex(aRouter.GetRouterId(), mRouters.IndexOf((aRouter)));
129     }
130 
131     SignalTableChanged();
132 }
133 
Allocate(void)134 Router *RouterTable::Allocate(void)
135 {
136     Router *router           = nullptr;
137     uint8_t numAvailable     = 0;
138     uint8_t selectedRouterId = Mle::kInvalidRouterId;
139 
140     VerifyOrExit(!mRouters.IsFull());
141 
142 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
143     for (uint8_t routerId = mMinRouterId; routerId <= mMaxRouterId; routerId++)
144 #else
145     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
146 #endif
147     {
148         if (mRouterIdMap.CanAllocate(routerId))
149         {
150             numAvailable++;
151 
152             // Randomly select a router ID as we iterate through the
153             // list using Reservoir algorithm: We replace the
154             // selected ID with current entry in the list with
155             // probably `1/numAvailable`.
156 
157             if (Random::NonCrypto::GetUint8InRange(0, numAvailable) == 0)
158             {
159                 selectedRouterId = routerId;
160             }
161         }
162     }
163 
164     VerifyOrExit(selectedRouterId != Mle::kInvalidRouterId);
165 
166     router = Allocate(selectedRouterId);
167     OT_ASSERT(router != nullptr);
168 
169 exit:
170     return router;
171 }
172 
Allocate(uint8_t aRouterId)173 Router *RouterTable::Allocate(uint8_t aRouterId)
174 {
175     Router *router = nullptr;
176 
177     VerifyOrExit(aRouterId <= Mle::kMaxRouterId && mRouterIdMap.CanAllocate(aRouterId));
178 
179     router = AddRouter(aRouterId);
180     VerifyOrExit(router != nullptr);
181 
182     router->SetLastHeard(TimerMilli::GetNow());
183 
184     mRouterIdSequence++;
185     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
186     Get<Mle::MleRouter>().ResetAdvertiseInterval();
187 
188     LogNote("Allocate router id %d", aRouterId);
189 
190 exit:
191     return router;
192 }
193 
Release(uint8_t aRouterId)194 Error RouterTable::Release(uint8_t aRouterId)
195 {
196     Error   error = kErrorNone;
197     Router *router;
198 
199     OT_ASSERT(aRouterId <= Mle::kMaxRouterId);
200 
201     VerifyOrExit(Get<Mle::MleRouter>().IsLeader(), error = kErrorInvalidState);
202 
203     router = FindRouterById(aRouterId);
204     VerifyOrExit(router != nullptr, error = kErrorNotFound);
205 
206     RemoveRouter(*router);
207 
208     for (Router &otherRouter : mRouters)
209     {
210         if (otherRouter.GetNextHop() == aRouterId)
211         {
212             otherRouter.SetNextHopToInvalid();
213         }
214     }
215 
216     mRouterIdSequence++;
217     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
218 
219     Get<AddressResolver>().RemoveEntriesForRouterId(aRouterId);
220     Get<NetworkData::Leader>().RemoveBorderRouter(Mle::Rloc16FromRouterId(aRouterId),
221                                                   NetworkData::Leader::kMatchModeRouterId);
222     Get<Mle::MleRouter>().ResetAdvertiseInterval();
223 
224     LogNote("Release router id %d", aRouterId);
225 
226 exit:
227     return error;
228 }
229 
RemoveRouterLink(Router & aRouter)230 void RouterTable::RemoveRouterLink(Router &aRouter)
231 {
232     if (aRouter.GetLinkQualityOut() != kLinkQuality0)
233     {
234         aRouter.SetLinkQualityOut(kLinkQuality0);
235         aRouter.SetLastHeard(TimerMilli::GetNow());
236         SignalTableChanged();
237     }
238 
239     for (Router &router : mRouters)
240     {
241         if (router.GetNextHop() == aRouter.GetRouterId())
242         {
243             router.SetNextHopToInvalid();
244             SignalTableChanged();
245 
246             if (GetLinkCost(router) >= Mle::kMaxRouteCost)
247             {
248                 Get<Mle::MleRouter>().ResetAdvertiseInterval();
249             }
250         }
251     }
252 
253     if (aRouter.GetNextHop() == Mle::kInvalidRouterId)
254     {
255         Get<Mle::MleRouter>().ResetAdvertiseInterval();
256 
257         // Clear all EID-to-RLOC entries associated with the router.
258         Get<AddressResolver>().RemoveEntriesForRouterId(aRouter.GetRouterId());
259     }
260 }
261 
FindRouter(const Router::AddressMatcher & aMatcher) const262 const Router *RouterTable::FindRouter(const Router::AddressMatcher &aMatcher) const
263 {
264     return mRouters.FindMatching(aMatcher);
265 }
266 
FindNeighbor(uint16_t aRloc16)267 Router *RouterTable::FindNeighbor(uint16_t aRloc16)
268 {
269     Router *router = nullptr;
270 
271     VerifyOrExit(!Get<Mle::Mle>().HasRloc16(aRloc16));
272     router = FindRouter(Router::AddressMatcher(aRloc16, Router::kInStateValid));
273 
274 exit:
275     return router;
276 }
277 
FindNeighbor(const Mac::ExtAddress & aExtAddress)278 Router *RouterTable::FindNeighbor(const Mac::ExtAddress &aExtAddress)
279 {
280     return FindRouter(Router::AddressMatcher(aExtAddress, Router::kInStateValid));
281 }
282 
FindNeighbor(const Mac::Address & aMacAddress)283 Router *RouterTable::FindNeighbor(const Mac::Address &aMacAddress)
284 {
285     return FindRouter(Router::AddressMatcher(aMacAddress, Router::kInStateValid));
286 }
287 
FindRouterById(uint8_t aRouterId) const288 const Router *RouterTable::FindRouterById(uint8_t aRouterId) const
289 {
290     const Router *router = nullptr;
291 
292     VerifyOrExit(aRouterId <= Mle::kMaxRouterId);
293 
294     VerifyOrExit(IsAllocated(aRouterId));
295     router = &mRouters[mRouterIdMap.GetIndex(aRouterId)];
296 
297 exit:
298     return router;
299 }
300 
FindRouterByRloc16(uint16_t aRloc16) const301 const Router *RouterTable::FindRouterByRloc16(uint16_t aRloc16) const
302 {
303     return FindRouterById(Mle::RouterIdFromRloc16(aRloc16));
304 }
305 
FindNextHopOf(const Router & aRouter) const306 const Router *RouterTable::FindNextHopOf(const Router &aRouter) const { return FindRouterById(aRouter.GetNextHop()); }
307 
FindRouter(const Mac::ExtAddress & aExtAddress)308 Router *RouterTable::FindRouter(const Mac::ExtAddress &aExtAddress)
309 {
310     return FindRouter(Router::AddressMatcher(aExtAddress, Router::kInStateAny));
311 }
312 
GetRouterInfo(uint16_t aRouterId,Router::Info & aRouterInfo)313 Error RouterTable::GetRouterInfo(uint16_t aRouterId, Router::Info &aRouterInfo)
314 {
315     Error   error = kErrorNone;
316     Router *router;
317     uint8_t routerId;
318 
319     if (aRouterId <= Mle::kMaxRouterId)
320     {
321         routerId = static_cast<uint8_t>(aRouterId);
322     }
323     else
324     {
325         VerifyOrExit(Mle::IsRouterRloc16(aRouterId), error = kErrorInvalidArgs);
326         routerId = Mle::RouterIdFromRloc16(aRouterId);
327         VerifyOrExit(routerId <= Mle::kMaxRouterId, error = kErrorInvalidArgs);
328     }
329 
330     router = FindRouterById(routerId);
331     VerifyOrExit(router != nullptr, error = kErrorNotFound);
332 
333     aRouterInfo.SetFrom(*router);
334 
335 exit:
336     return error;
337 }
338 
GetLeader(void) const339 const Router *RouterTable::GetLeader(void) const { return FindRouterById(Get<Mle::MleRouter>().GetLeaderId()); }
340 
GetLeaderAge(void) const341 uint32_t RouterTable::GetLeaderAge(void) const
342 {
343     return (!mRouters.IsEmpty()) ? Time::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated) : 0xffffffff;
344 }
345 
GetNeighborCount(LinkQuality aLinkQuality) const346 uint8_t RouterTable::GetNeighborCount(LinkQuality aLinkQuality) const
347 {
348     uint8_t count = 0;
349 
350     for (const Router &router : mRouters)
351     {
352         if (router.IsStateValid() && (router.GetLinkQualityIn() >= aLinkQuality))
353         {
354             count++;
355         }
356     }
357 
358     return count;
359 }
360 
GetLinkCost(const Router & aRouter) const361 uint8_t RouterTable::GetLinkCost(const Router &aRouter) const
362 {
363     uint8_t rval = Mle::kMaxRouteCost;
364 
365     VerifyOrExit(!Get<Mle::Mle>().HasRloc16(aRouter.GetRloc16()) && aRouter.IsStateValid());
366 
367     rval = CostForLinkQuality(aRouter.GetTwoWayLinkQuality());
368 
369 exit:
370     return rval;
371 }
372 
GetLinkCost(uint8_t aRouterId) const373 uint8_t RouterTable::GetLinkCost(uint8_t aRouterId) const
374 {
375     uint8_t       rval = Mle::kMaxRouteCost;
376     const Router *router;
377 
378     router = FindRouterById(aRouterId);
379 
380     // `nullptr` aRouterId indicates non-existing next hop, hence return kMaxRouteCost for it.
381     VerifyOrExit(router != nullptr);
382 
383     rval = GetLinkCost(*router);
384 
385 exit:
386     return rval;
387 }
388 
GetPathCost(uint16_t aDestRloc16) const389 uint8_t RouterTable::GetPathCost(uint16_t aDestRloc16) const
390 {
391     uint8_t  pathCost;
392     uint16_t nextHopRloc16;
393 
394     GetNextHopAndPathCost(aDestRloc16, nextHopRloc16, pathCost);
395 
396     return pathCost;
397 }
398 
GetPathCostToLeader(void) const399 uint8_t RouterTable::GetPathCostToLeader(void) const { return GetPathCost(Get<Mle::Mle>().GetLeaderRloc16()); }
400 
GetNextHopAndPathCost(uint16_t aDestRloc16,uint16_t & aNextHopRloc16,uint8_t & aPathCost) const401 void RouterTable::GetNextHopAndPathCost(uint16_t aDestRloc16, uint16_t &aNextHopRloc16, uint8_t &aPathCost) const
402 {
403     const Router *router;
404     const Router *nextHop;
405 
406     aPathCost      = Mle::kMaxRouteCost;
407     aNextHopRloc16 = Mle::kInvalidRloc16;
408 
409     VerifyOrExit(Get<Mle::Mle>().IsAttached());
410 
411     if (Get<Mle::Mle>().HasRloc16(aDestRloc16))
412     {
413         // Destination is this device, return cost as zero.
414         aPathCost      = 0;
415         aNextHopRloc16 = aDestRloc16;
416         ExitNow();
417     }
418 
419     router  = FindRouterById(Mle::RouterIdFromRloc16(aDestRloc16));
420     nextHop = (router != nullptr) ? FindNextHopOf(*router) : nullptr;
421 
422     if (Get<Mle::MleRouter>().IsChild())
423     {
424         const Router &parent = Get<Mle::Mle>().GetParent();
425         bool          destIsParentOrItsChild;
426 
427         if (parent.IsStateValid())
428         {
429             aNextHopRloc16 = parent.GetRloc16();
430         }
431 
432         // If destination is our parent or another child of our
433         // parent, we use the link cost to our parent. Otherwise we
434         // check if we have a next hop towards the destination and
435         // add its cost to the link cost to parent.
436 
437         destIsParentOrItsChild = Mle::RouterIdMatch(aDestRloc16, parent.GetRloc16());
438 
439         VerifyOrExit(destIsParentOrItsChild || (nextHop != nullptr));
440 
441         aPathCost = CostForLinkQuality(parent.GetLinkQualityIn());
442 
443         if (!destIsParentOrItsChild)
444         {
445             aPathCost += router->GetCost();
446         }
447 
448         // The case where destination itself is a child is handled at
449         // the end (after `else` block).
450     }
451     else // Role is router or leader
452     {
453         if (Get<Mle::Mle>().HasMatchingRouterIdWith(aDestRloc16))
454         {
455             // Destination is a one of our children.
456 
457             const Child *child = Get<ChildTable>().FindChild(aDestRloc16, Child::kInStateAnyExceptInvalid);
458 
459             VerifyOrExit(child != nullptr);
460             aNextHopRloc16 = aDestRloc16;
461             aPathCost      = CostForLinkQuality(child->GetLinkQualityIn());
462             ExitNow();
463         }
464 
465         VerifyOrExit(router != nullptr);
466 
467         aPathCost = GetLinkCost(*router);
468 
469         if (aPathCost < Mle::kMaxRouteCost)
470         {
471             aNextHopRloc16 = router->GetRloc16();
472         }
473 
474         if (nextHop != nullptr)
475         {
476             // Determine whether direct link or forwarding hop link
477             // through `nextHop` has a lower path cost.
478 
479             uint8_t nextHopPathCost = router->GetCost() + GetLinkCost(*nextHop);
480 
481             if (nextHopPathCost < aPathCost)
482             {
483                 aPathCost      = nextHopPathCost;
484                 aNextHopRloc16 = nextHop->GetRloc16();
485             }
486         }
487     }
488 
489     if (Mle::IsChildRloc16(aDestRloc16))
490     {
491         // Destination is a child. we assume best link quality
492         // between destination and its parent router.
493 
494         aPathCost += kCostForLinkQuality3;
495     }
496 
497 exit:
498     return;
499 }
500 
GetNextHop(uint16_t aDestRloc16) const501 uint16_t RouterTable::GetNextHop(uint16_t aDestRloc16) const
502 {
503     uint8_t  pathCost;
504     uint16_t nextHopRloc16;
505 
506     GetNextHopAndPathCost(aDestRloc16, nextHopRloc16, pathCost);
507 
508     return nextHopRloc16;
509 }
510 
UpdateRouterIdSet(uint8_t aRouterIdSequence,const Mle::RouterIdSet & aRouterIdSet)511 void RouterTable::UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet)
512 {
513     bool shouldAdd = false;
514 
515     mRouterIdSequence            = aRouterIdSequence;
516     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
517 
518     // Remove all previously allocated routers that are now removed in
519     // new `aRouterIdSet`.
520 
521     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
522     {
523         if (IsAllocated(routerId) == aRouterIdSet.Contains(routerId))
524         {
525             continue;
526         }
527 
528         if (IsAllocated(routerId))
529         {
530             Router *router = FindRouterById(routerId);
531 
532             OT_ASSERT(router != nullptr);
533             router->SetNextHopToInvalid();
534             RemoveRouterLink(*router);
535             RemoveRouter(*router);
536         }
537         else
538         {
539             shouldAdd = true;
540         }
541     }
542 
543     VerifyOrExit(shouldAdd);
544 
545     // Now add all new routers in `aRouterIdSet`.
546 
547     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
548     {
549         if (!IsAllocated(routerId) && aRouterIdSet.Contains(routerId))
550         {
551             AddRouter(routerId);
552         }
553     }
554 
555     Get<Mle::MleRouter>().ResetAdvertiseInterval();
556 
557 exit:
558     return;
559 }
560 
UpdateRoutes(const Mle::RouteTlv & aRouteTlv,uint8_t aNeighborId)561 void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId)
562 {
563     Router          *neighbor;
564     Mle::RouterIdSet finitePathCostIdSet;
565     uint8_t          linkCostToNeighbor;
566 
567     neighbor = FindRouterById(aNeighborId);
568     VerifyOrExit(neighbor != nullptr);
569 
570     // Before updating the routes, we track which routers have finite
571     // path cost. After the update we check again to see if any path
572     // cost changed from finite to infinite or vice versa to decide
573     // whether to reset the  MLE Advertisement interval.
574 
575     finitePathCostIdSet.Clear();
576 
577     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
578     {
579         if (GetPathCost(Mle::Rloc16FromRouterId(routerId)) < Mle::kMaxRouteCost)
580         {
581             finitePathCostIdSet.Add(routerId);
582         }
583     }
584 
585     // Find the entry corresponding to our Router ID in the received
586     // `aRouteTlv` to get the `LinkQualityIn` from the perspective of
587     // neighbor. We use this to update our `LinkQualityOut` to the
588     // neighbor.
589 
590     for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
591          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
592     {
593         if (!Get<Mle::Mle>().MatchesRouterId(routerId))
594         {
595             continue;
596         }
597 
598         if (aRouteTlv.IsRouterIdSet(routerId))
599         {
600             LinkQuality linkQuality = aRouteTlv.GetLinkQualityIn(index);
601 
602             if (neighbor->GetLinkQualityOut() != linkQuality)
603             {
604                 neighbor->SetLinkQualityOut(linkQuality);
605                 SignalTableChanged();
606             }
607         }
608 
609         break;
610     }
611 
612     linkCostToNeighbor = GetLinkCost(*neighbor);
613 
614     for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
615          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
616     {
617         Router *router;
618         Router *nextHop;
619         uint8_t cost;
620 
621         if (!aRouteTlv.IsRouterIdSet(routerId))
622         {
623             continue;
624         }
625 
626         router = FindRouterById(routerId);
627 
628         if (router == nullptr || Get<Mle::Mle>().HasRloc16(router->GetRloc16()) || router == neighbor)
629         {
630             continue;
631         }
632 
633         nextHop = FindNextHopOf(*router);
634 
635         cost = aRouteTlv.GetRouteCost(index);
636         cost = (cost == 0) ? Mle::kMaxRouteCost : cost;
637 
638         if ((nextHop == nullptr) || (nextHop == neighbor))
639         {
640             // `router` has no next hop or next hop is neighbor (sender)
641 
642             if (cost + linkCostToNeighbor < Mle::kMaxRouteCost)
643             {
644                 if (router->SetNextHopAndCost(aNeighborId, cost))
645                 {
646                     SignalTableChanged();
647                 }
648             }
649             else if (nextHop == neighbor)
650             {
651                 router->SetNextHopToInvalid();
652                 router->SetLastHeard(TimerMilli::GetNow());
653                 SignalTableChanged();
654             }
655         }
656         else
657         {
658             uint8_t curCost = router->GetCost() + GetLinkCost(*nextHop);
659             uint8_t newCost = cost + linkCostToNeighbor;
660 
661             if (newCost < curCost)
662             {
663                 router->SetNextHopAndCost(aNeighborId, cost);
664                 SignalTableChanged();
665             }
666         }
667     }
668 
669     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
670     {
671         bool oldCostFinite = finitePathCostIdSet.Contains(routerId);
672         bool newCostFinite = (GetPathCost(Mle::Rloc16FromRouterId(routerId)) < Mle::kMaxRouteCost);
673 
674         if (newCostFinite != oldCostFinite)
675         {
676             Get<Mle::MleRouter>().ResetAdvertiseInterval();
677             break;
678         }
679     }
680 
681 exit:
682     return;
683 }
684 
UpdateRoutesOnFed(const Mle::RouteTlv & aRouteTlv,uint8_t aParentId)685 void RouterTable::UpdateRoutesOnFed(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId)
686 {
687     for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
688          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
689     {
690         Router *router;
691         uint8_t cost;
692         uint8_t nextHopId;
693 
694         if (!aRouteTlv.IsRouterIdSet(routerId) || (routerId == aParentId))
695         {
696             continue;
697         }
698 
699         router = FindRouterById(routerId);
700 
701         if (router == nullptr)
702         {
703             continue;
704         }
705 
706         cost      = aRouteTlv.GetRouteCost(index);
707         nextHopId = (cost == 0) ? Mle::kInvalidRouterId : aParentId;
708 
709         if (router->SetNextHopAndCost(nextHopId, cost))
710         {
711             SignalTableChanged();
712         }
713     }
714 }
715 
FillRouteTlv(Mle::RouteTlv & aRouteTlv,const Neighbor * aNeighbor) const716 void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighbor) const
717 {
718     uint8_t          routerIdSequence = mRouterIdSequence;
719     Mle::RouterIdSet routerIdSet;
720     uint8_t          routerIndex;
721 
722     mRouterIdMap.GetAsRouterIdSet(routerIdSet);
723 
724     if ((aNeighbor != nullptr) && Mle::IsRouterRloc16(aNeighbor->GetRloc16()))
725     {
726         // Sending a Link Accept message that may require truncation
727         // of Route64 TLV.
728 
729         uint8_t routerCount = mRouters.GetLength();
730 
731         if (routerCount > kMaxRoutersInRouteTlvForLinkAccept)
732         {
733             for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
734             {
735                 if (routerCount <= kMaxRoutersInRouteTlvForLinkAccept)
736                 {
737                     break;
738                 }
739 
740                 if (Get<Mle::Mle>().MatchesRouterId(routerId) || (routerId == aNeighbor->GetRouterId()) ||
741                     (routerId == Get<Mle::Mle>().GetLeaderId()))
742                 {
743                     // Route64 TLV must contain this device and the
744                     // neighboring router to ensure that at least this
745                     // link can be established.
746                     continue;
747                 }
748 
749                 if (routerIdSet.Contains(routerId))
750                 {
751                     routerIdSet.Remove(routerId);
752                     routerCount--;
753                 }
754             }
755 
756             // Ensure that the neighbor will process the current
757             // Route64 TLV in a subsequent message exchange
758             routerIdSequence -= kLinkAcceptSequenceRollback;
759         }
760     }
761 
762     aRouteTlv.SetRouterIdSequence(routerIdSequence);
763     aRouteTlv.SetRouterIdMask(routerIdSet);
764 
765     routerIndex = 0;
766 
767     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
768     {
769         uint16_t routerRloc16;
770 
771         if (!routerIdSet.Contains(routerId))
772         {
773             continue;
774         }
775 
776         routerRloc16 = Mle::Rloc16FromRouterId(routerId);
777 
778         if (Get<Mle::Mle>().HasRloc16(routerRloc16))
779         {
780             aRouteTlv.SetRouteData(routerIndex, kLinkQuality0, kLinkQuality0, 1);
781         }
782         else
783         {
784             const Router *router = FindRouterById(routerId);
785             uint8_t       pathCost;
786 
787             OT_ASSERT(router != nullptr);
788 
789             pathCost = GetPathCost(routerRloc16);
790 
791             if (pathCost >= Mle::kMaxRouteCost)
792             {
793                 pathCost = 0;
794             }
795 
796             aRouteTlv.SetRouteData(routerIndex, router->GetLinkQualityIn(), router->GetLinkQualityOut(), pathCost);
797         }
798 
799         routerIndex++;
800     }
801 
802     aRouteTlv.SetRouteDataLength(routerIndex);
803 }
804 
HandleTimeTick(void)805 void RouterTable::HandleTimeTick(void)
806 {
807     mRouterIdMap.HandleTimeTick();
808 
809     VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
810 
811     // Update router id sequence
812     if (GetLeaderAge() >= kRouterIdSequencePeriod)
813     {
814         mRouterIdSequence++;
815         mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
816     }
817 
818 exit:
819     return;
820 }
821 
822 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
GetRouterIdRange(uint8_t & aMinRouterId,uint8_t & aMaxRouterId) const823 void RouterTable::GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const
824 {
825     aMinRouterId = mMinRouterId;
826     aMaxRouterId = mMaxRouterId;
827 }
828 
SetRouterIdRange(uint8_t aMinRouterId,uint8_t aMaxRouterId)829 Error RouterTable::SetRouterIdRange(uint8_t aMinRouterId, uint8_t aMaxRouterId)
830 {
831     Error error = kErrorNone;
832 
833     VerifyOrExit(aMinRouterId <= aMaxRouterId, error = kErrorInvalidArgs);
834     VerifyOrExit(aMaxRouterId <= Mle::kMaxRouterId, error = kErrorInvalidArgs);
835     mMinRouterId = aMinRouterId;
836     mMaxRouterId = aMaxRouterId;
837 
838 exit:
839     return error;
840 }
841 #endif
842 
GetAsRouterIdSet(Mle::RouterIdSet & aRouterIdSet) const843 void RouterTable::RouterIdMap::GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const
844 {
845     aRouterIdSet.Clear();
846 
847     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
848     {
849         if (IsAllocated(routerId))
850         {
851             aRouterIdSet.Add(routerId);
852         }
853     }
854 }
855 
HandleTimeTick(void)856 void RouterTable::RouterIdMap::HandleTimeTick(void)
857 {
858     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
859     {
860         // If Router ID is not allocated the `mIndexes` tracks the
861         // remaining reuse delay time in seconds.
862 
863         if (!IsAllocated(routerId) && (mIndexes[routerId] > 0))
864         {
865             mIndexes[routerId]--;
866         }
867     }
868 }
869 
SignalTableChanged(void)870 void RouterTable::SignalTableChanged(void) { mChangedTask.Post(); }
871 
HandleTableChanged(void)872 void RouterTable::HandleTableChanged(void)
873 {
874 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
875     LogRouteTable();
876 #endif
877 
878 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
879     Get<Utils::HistoryTracker>().RecordRouterTableChange();
880 #endif
881 
882     Get<Mle::MleRouter>().UpdateAdvertiseInterval();
883 }
884 
885 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
LogRouteTable(void) const886 void RouterTable::LogRouteTable(void) const
887 {
888     static constexpr uint16_t kStringSize = 128;
889 
890     LogInfo("Route table");
891 
892     for (const Router &router : mRouters)
893     {
894         String<kStringSize> string;
895 
896         string.Append("    %2d 0x%04x", router.GetRouterId(), router.GetRloc16());
897 
898         if (Get<Mle::Mle>().HasRloc16(router.GetRloc16()))
899         {
900             string.Append(" - me");
901         }
902         else if (Get<Mle::Mle>().IsChild() && (router.GetRloc16() == Get<Mle::Mle>().GetParent().GetRloc16()))
903         {
904             string.Append(" - parent");
905         }
906         else
907         {
908             if (router.IsStateValid())
909             {
910                 string.Append(" - nbr{lq[i/o]:%d/%d cost:%d}", router.GetLinkQualityIn(), router.GetLinkQualityOut(),
911                               GetLinkCost(router));
912             }
913 
914             if (router.GetNextHop() != Mle::kInvalidRouterId)
915             {
916                 string.Append(" - nexthop{%d cost:%d}", router.GetNextHop(), router.GetCost());
917             }
918         }
919 
920         if (router.GetRouterId() == Get<Mle::Mle>().GetLeaderId())
921         {
922             string.Append(" - leader");
923         }
924 
925         LogInfo("%s", string.AsCString());
926     }
927 }
928 #endif
929 
930 } // namespace ot
931 
932 #endif // OPENTHREAD_FTD
933