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