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