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(aRloc16 != Get<Mle::MleRouter>().GetRloc16());
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::IsActiveRouter(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(aRouter.GetRloc16() != Get<Mle::MleRouter>().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
400 {
401     return GetPathCost(Mle::Rloc16FromRouterId(Get<Mle::Mle>().GetLeaderId()));
402 }
403 
GetNextHopAndPathCost(uint16_t aDestRloc16,uint16_t & aNextHopRloc16,uint8_t & aPathCost) const404 void RouterTable::GetNextHopAndPathCost(uint16_t aDestRloc16, uint16_t &aNextHopRloc16, uint8_t &aPathCost) const
405 {
406     uint8_t       destRouterId;
407     const Router *router;
408     const Router *nextHop;
409 
410     aPathCost      = Mle::kMaxRouteCost;
411     aNextHopRloc16 = Mle::kInvalidRloc16;
412 
413     VerifyOrExit(Get<Mle::Mle>().IsAttached());
414 
415     if (aDestRloc16 == Get<Mle::Mle>().GetRloc16())
416     {
417         // Destination is this device, return cost as zero.
418         aPathCost      = 0;
419         aNextHopRloc16 = aDestRloc16;
420         ExitNow();
421     }
422 
423     destRouterId = Mle::RouterIdFromRloc16(aDestRloc16);
424 
425     router  = FindRouterById(destRouterId);
426     nextHop = (router != nullptr) ? FindNextHopOf(*router) : nullptr;
427 
428     if (Get<Mle::MleRouter>().IsChild())
429     {
430         const Router &parent = Get<Mle::Mle>().GetParent();
431 
432         if (parent.IsStateValid())
433         {
434             aNextHopRloc16 = parent.GetRloc16();
435         }
436 
437         // If destination is our parent or another child of our
438         // parent, we use the link cost to our parent. Otherwise we
439         // check if we have a next hop towards the destination and
440         // add its cost to the link cost to parent.
441 
442         VerifyOrExit((destRouterId == parent.GetRouterId()) || (nextHop != nullptr));
443 
444         aPathCost = CostForLinkQuality(parent.GetLinkQualityIn());
445 
446         if (destRouterId != parent.GetRouterId())
447         {
448             aPathCost += router->GetCost();
449         }
450 
451         // The case where destination itself is a child is handled at
452         // the end (after `else` block).
453     }
454     else // Role is router or leader
455     {
456         if (destRouterId == Mle::RouterIdFromRloc16(Get<Mle::Mle>().GetRloc16()))
457         {
458             // Destination is a one of our children.
459 
460             const Child *child = Get<ChildTable>().FindChild(aDestRloc16, Child::kInStateAnyExceptInvalid);
461 
462             VerifyOrExit(child != nullptr);
463             aNextHopRloc16 = aDestRloc16;
464             aPathCost      = CostForLinkQuality(child->GetLinkQualityIn());
465             ExitNow();
466         }
467 
468         VerifyOrExit(router != nullptr);
469 
470         aPathCost = GetLinkCost(*router);
471 
472         if (aPathCost < Mle::kMaxRouteCost)
473         {
474             aNextHopRloc16 = router->GetRloc16();
475         }
476 
477         if (nextHop != nullptr)
478         {
479             // Determine whether direct link or forwarding hop link
480             // through `nextHop` has a lower path cost.
481 
482             uint8_t nextHopPathCost = router->GetCost() + GetLinkCost(*nextHop);
483 
484             if (nextHopPathCost < aPathCost)
485             {
486                 aPathCost      = nextHopPathCost;
487                 aNextHopRloc16 = nextHop->GetRloc16();
488             }
489         }
490     }
491 
492     if (!Mle::IsActiveRouter(aDestRloc16))
493     {
494         // Destination is a child. we assume best link quality
495         // between destination and its parent router.
496 
497         aPathCost += kCostForLinkQuality3;
498     }
499 
500 exit:
501     return;
502 }
503 
GetNextHop(uint16_t aDestRloc16) const504 uint16_t RouterTable::GetNextHop(uint16_t aDestRloc16) const
505 {
506     uint8_t  pathCost;
507     uint16_t nextHopRloc16;
508 
509     GetNextHopAndPathCost(aDestRloc16, nextHopRloc16, pathCost);
510 
511     return nextHopRloc16;
512 }
513 
UpdateRouterIdSet(uint8_t aRouterIdSequence,const Mle::RouterIdSet & aRouterIdSet)514 void RouterTable::UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet)
515 {
516     bool shouldAdd = false;
517 
518     mRouterIdSequence            = aRouterIdSequence;
519     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
520 
521     // Remove all previously allocated routers that are now removed in
522     // new `aRouterIdSet`.
523 
524     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
525     {
526         if (IsAllocated(routerId) == aRouterIdSet.Contains(routerId))
527         {
528             continue;
529         }
530 
531         if (IsAllocated(routerId))
532         {
533             Router *router = FindRouterById(routerId);
534 
535             OT_ASSERT(router != nullptr);
536             router->SetNextHopToInvalid();
537             RemoveRouterLink(*router);
538             RemoveRouter(*router);
539         }
540         else
541         {
542             shouldAdd = true;
543         }
544     }
545 
546     VerifyOrExit(shouldAdd);
547 
548     // Now add all new routers in `aRouterIdSet`.
549 
550     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
551     {
552         if (!IsAllocated(routerId) && aRouterIdSet.Contains(routerId))
553         {
554             AddRouter(routerId);
555         }
556     }
557 
558     Get<Mle::MleRouter>().ResetAdvertiseInterval();
559 
560 exit:
561     return;
562 }
563 
UpdateRoutes(const Mle::RouteTlv & aRouteTlv,uint8_t aNeighborId)564 void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId)
565 {
566     Router          *neighbor;
567     Mle::RouterIdSet finitePathCostIdSet;
568     uint8_t          linkCostToNeighbor;
569 
570     neighbor = FindRouterById(aNeighborId);
571     VerifyOrExit(neighbor != nullptr);
572 
573     // Before updating the routes, we track which routers have finite
574     // path cost. After the update we check again to see if any path
575     // cost changed from finite to infinite or vice versa to decide
576     // whether to reset the  MLE Advertisement interval.
577 
578     finitePathCostIdSet.Clear();
579 
580     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
581     {
582         if (GetPathCost(Mle::Rloc16FromRouterId(routerId)) < Mle::kMaxRouteCost)
583         {
584             finitePathCostIdSet.Add(routerId);
585         }
586     }
587 
588     // Find the entry corresponding to our Router ID in the received
589     // `aRouteTlv` to get the `LinkQualityIn` from the perspective of
590     // neighbor. We use this to update our `LinkQualityOut` to the
591     // neighbor.
592 
593     for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
594          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
595     {
596         if (routerId != Mle::RouterIdFromRloc16(Get<Mle::Mle>().GetRloc16()))
597         {
598             continue;
599         }
600 
601         if (aRouteTlv.IsRouterIdSet(routerId))
602         {
603             LinkQuality linkQuality = aRouteTlv.GetLinkQualityIn(index);
604 
605             if (neighbor->GetLinkQualityOut() != linkQuality)
606             {
607                 neighbor->SetLinkQualityOut(linkQuality);
608                 SignalTableChanged();
609             }
610         }
611 
612         break;
613     }
614 
615     linkCostToNeighbor = GetLinkCost(*neighbor);
616 
617     for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
618          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
619     {
620         Router *router;
621         Router *nextHop;
622         uint8_t cost;
623 
624         if (!aRouteTlv.IsRouterIdSet(routerId))
625         {
626             continue;
627         }
628 
629         router = FindRouterById(routerId);
630 
631         if (router == nullptr || router->GetRloc16() == Get<Mle::Mle>().GetRloc16() || router == neighbor)
632         {
633             continue;
634         }
635 
636         nextHop = FindNextHopOf(*router);
637 
638         cost = aRouteTlv.GetRouteCost(index);
639         cost = (cost == 0) ? Mle::kMaxRouteCost : cost;
640 
641         if ((nextHop == nullptr) || (nextHop == neighbor))
642         {
643             // `router` has no next hop or next hop is neighbor (sender)
644 
645             if (cost + linkCostToNeighbor < Mle::kMaxRouteCost)
646             {
647                 if (router->SetNextHopAndCost(aNeighborId, cost))
648                 {
649                     SignalTableChanged();
650                 }
651             }
652             else if (nextHop == neighbor)
653             {
654                 router->SetNextHopToInvalid();
655                 router->SetLastHeard(TimerMilli::GetNow());
656                 SignalTableChanged();
657             }
658         }
659         else
660         {
661             uint8_t curCost = router->GetCost() + GetLinkCost(*nextHop);
662             uint8_t newCost = cost + linkCostToNeighbor;
663 
664             if (newCost < curCost)
665             {
666                 router->SetNextHopAndCost(aNeighborId, cost);
667                 SignalTableChanged();
668             }
669         }
670     }
671 
672     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
673     {
674         bool oldCostFinite = finitePathCostIdSet.Contains(routerId);
675         bool newCostFinite = (GetPathCost(Mle::Rloc16FromRouterId(routerId)) < Mle::kMaxRouteCost);
676 
677         if (newCostFinite != oldCostFinite)
678         {
679             Get<Mle::MleRouter>().ResetAdvertiseInterval();
680             break;
681         }
682     }
683 
684 exit:
685     return;
686 }
687 
UpdateRoutesOnFed(const Mle::RouteTlv & aRouteTlv,uint8_t aParentId)688 void RouterTable::UpdateRoutesOnFed(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId)
689 {
690     for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId;
691          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
692     {
693         Router *router;
694         uint8_t cost;
695         uint8_t nextHopId;
696 
697         if (!aRouteTlv.IsRouterIdSet(routerId) || (routerId == aParentId))
698         {
699             continue;
700         }
701 
702         router = FindRouterById(routerId);
703 
704         if (router == nullptr)
705         {
706             continue;
707         }
708 
709         cost      = aRouteTlv.GetRouteCost(index);
710         nextHopId = (cost == 0) ? Mle::kInvalidRouterId : aParentId;
711 
712         if (router->SetNextHopAndCost(nextHopId, cost))
713         {
714             SignalTableChanged();
715         }
716     }
717 }
718 
FillRouteTlv(Mle::RouteTlv & aRouteTlv,const Neighbor * aNeighbor) const719 void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighbor) const
720 {
721     uint8_t          routerIdSequence = mRouterIdSequence;
722     Mle::RouterIdSet routerIdSet;
723     uint8_t          routerIndex;
724 
725     mRouterIdMap.GetAsRouterIdSet(routerIdSet);
726 
727     if ((aNeighbor != nullptr) && Mle::IsActiveRouter(aNeighbor->GetRloc16()))
728     {
729         // Sending a Link Accept message that may require truncation
730         // of Route64 TLV.
731 
732         uint8_t routerCount = mRouters.GetLength();
733 
734         if (routerCount > kMaxRoutersInRouteTlvForLinkAccept)
735         {
736             for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
737             {
738                 if (routerCount <= kMaxRoutersInRouteTlvForLinkAccept)
739                 {
740                     break;
741                 }
742 
743                 if ((routerId == Mle::RouterIdFromRloc16(Get<Mle::Mle>().GetRloc16())) ||
744                     (routerId == aNeighbor->GetRouterId()) || (routerId == Get<Mle::Mle>().GetLeaderId()))
745                 {
746                     // Route64 TLV must contain this device and the
747                     // neighboring router to ensure that at least this
748                     // link can be established.
749                     continue;
750                 }
751 
752                 if (routerIdSet.Contains(routerId))
753                 {
754                     routerIdSet.Remove(routerId);
755                     routerCount--;
756                 }
757             }
758 
759             // Ensure that the neighbor will process the current
760             // Route64 TLV in a subsequent message exchange
761             routerIdSequence -= kLinkAcceptSequenceRollback;
762         }
763     }
764 
765     aRouteTlv.SetRouterIdSequence(routerIdSequence);
766     aRouteTlv.SetRouterIdMask(routerIdSet);
767 
768     routerIndex = 0;
769 
770     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
771     {
772         uint16_t routerRloc16;
773 
774         if (!routerIdSet.Contains(routerId))
775         {
776             continue;
777         }
778 
779         routerRloc16 = Mle::Rloc16FromRouterId(routerId);
780 
781         if (routerRloc16 == Get<Mle::Mle>().GetRloc16())
782         {
783             aRouteTlv.SetRouteData(routerIndex, kLinkQuality0, kLinkQuality0, 1);
784         }
785         else
786         {
787             const Router *router = FindRouterById(routerId);
788             uint8_t       pathCost;
789 
790             OT_ASSERT(router != nullptr);
791 
792             pathCost = GetPathCost(routerRloc16);
793 
794             if (pathCost >= Mle::kMaxRouteCost)
795             {
796                 pathCost = 0;
797             }
798 
799             aRouteTlv.SetRouteData(routerIndex, router->GetLinkQualityIn(), router->GetLinkQualityOut(), pathCost);
800         }
801 
802         routerIndex++;
803     }
804 
805     aRouteTlv.SetRouteDataLength(routerIndex);
806 }
807 
HandleTimeTick(void)808 void RouterTable::HandleTimeTick(void)
809 {
810     mRouterIdMap.HandleTimeTick();
811 
812     VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
813 
814     // Update router id sequence
815     if (GetLeaderAge() >= kRouterIdSequencePeriod)
816     {
817         mRouterIdSequence++;
818         mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
819     }
820 
821 exit:
822     return;
823 }
824 
825 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
GetRouterIdRange(uint8_t & aMinRouterId,uint8_t & aMaxRouterId) const826 void RouterTable::GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const
827 {
828     aMinRouterId = mMinRouterId;
829     aMaxRouterId = mMaxRouterId;
830 }
831 
SetRouterIdRange(uint8_t aMinRouterId,uint8_t aMaxRouterId)832 Error RouterTable::SetRouterIdRange(uint8_t aMinRouterId, uint8_t aMaxRouterId)
833 {
834     Error error = kErrorNone;
835 
836     VerifyOrExit(aMinRouterId <= aMaxRouterId, error = kErrorInvalidArgs);
837     VerifyOrExit(aMaxRouterId <= Mle::kMaxRouterId, error = kErrorInvalidArgs);
838     mMinRouterId = aMinRouterId;
839     mMaxRouterId = aMaxRouterId;
840 
841 exit:
842     return error;
843 }
844 #endif
845 
GetAsRouterIdSet(Mle::RouterIdSet & aRouterIdSet) const846 void RouterTable::RouterIdMap::GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const
847 {
848     aRouterIdSet.Clear();
849 
850     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
851     {
852         if (IsAllocated(routerId))
853         {
854             aRouterIdSet.Add(routerId);
855         }
856     }
857 }
858 
HandleTimeTick(void)859 void RouterTable::RouterIdMap::HandleTimeTick(void)
860 {
861     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
862     {
863         // If Router ID is not allocated the `mIndexes` tracks the
864         // remaining reuse delay time in seconds.
865 
866         if (!IsAllocated(routerId) && (mIndexes[routerId] > 0))
867         {
868             mIndexes[routerId]--;
869         }
870     }
871 }
872 
SignalTableChanged(void)873 void RouterTable::SignalTableChanged(void) { mChangedTask.Post(); }
874 
HandleTableChanged(void)875 void RouterTable::HandleTableChanged(void)
876 {
877 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
878     LogRouteTable();
879 #endif
880 
881 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
882     Get<Utils::HistoryTracker>().RecordRouterTableChange();
883 #endif
884 
885     Get<Mle::MleRouter>().UpdateAdvertiseInterval();
886 }
887 
888 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
LogRouteTable(void) const889 void RouterTable::LogRouteTable(void) const
890 {
891     static constexpr uint16_t kStringSize = 128;
892 
893     LogInfo("Route table");
894 
895     for (const Router &router : mRouters)
896     {
897         String<kStringSize> string;
898 
899         string.Append("    %2d 0x%04x", router.GetRouterId(), router.GetRloc16());
900 
901         if (router.GetRloc16() == Get<Mle::Mle>().GetRloc16())
902         {
903             string.Append(" - me");
904         }
905         else if (Get<Mle::Mle>().IsChild() && (router.GetRloc16() == Get<Mle::Mle>().GetParent().GetRloc16()))
906         {
907             string.Append(" - parent");
908         }
909         else
910         {
911             if (router.IsStateValid())
912             {
913                 string.Append(" - nbr{lq[i/o]:%d/%d cost:%d}", router.GetLinkQualityIn(), router.GetLinkQualityOut(),
914                               GetLinkCost(router));
915             }
916 
917             if (router.GetNextHop() != Mle::kInvalidRouterId)
918             {
919                 string.Append(" - nexthop{%d cost:%d}", router.GetNextHop(), router.GetCost());
920             }
921         }
922 
923         if (router.GetRouterId() == Get<Mle::Mle>().GetLeaderId())
924         {
925             string.Append(" - leader");
926         }
927 
928         LogInfo("%s", string.AsCString());
929     }
930 }
931 #endif
932 
933 } // namespace ot
934 
935 #endif // OPENTHREAD_FTD
936