• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/instance.hpp"
35 #include "common/locator_getters.hpp"
36 #include "common/log.hpp"
37 #include "common/timer.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 
Iterator(Instance & aInstance)47 RouterTable::Iterator::Iterator(Instance &aInstance)
48     : InstanceLocator(aInstance)
49     , ItemPtrIterator(Get<RouterTable>().GetFirstEntry())
50 {
51 }
52 
Advance(void)53 void RouterTable::Iterator::Advance(void)
54 {
55     mItem = Get<RouterTable>().GetNextEntry(mItem);
56 }
57 
RouterTable(Instance & aInstance)58 RouterTable::RouterTable(Instance &aInstance)
59     : InstanceLocator(aInstance)
60     , mRouterIdSequenceLastUpdated(0)
61     , mRouterIdSequence(Random::NonCrypto::GetUint8())
62     , mActiveRouterCount(0)
63 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
64     , mMinRouterId(0)
65     , mMaxRouterId(Mle::kMaxRouterId)
66 #endif
67 {
68     for (Router &router : mRouters)
69     {
70         router.Init(aInstance);
71     }
72 
73     Clear();
74 }
75 
GetFirstEntry(void) const76 const Router *RouterTable::GetFirstEntry(void) const
77 {
78     const Router *router = &mRouters[0];
79     VerifyOrExit(router->GetRloc16() != 0xffff, router = nullptr);
80 
81 exit:
82     return router;
83 }
84 
GetNextEntry(const Router * aRouter) const85 const Router *RouterTable::GetNextEntry(const Router *aRouter) const
86 {
87     VerifyOrExit(aRouter != nullptr);
88     aRouter++;
89     VerifyOrExit(aRouter < &mRouters[Mle::kMaxRouters], aRouter = nullptr);
90     VerifyOrExit(aRouter->GetRloc16() != 0xffff, aRouter = nullptr);
91 
92 exit:
93     return aRouter;
94 }
95 
Clear(void)96 void RouterTable::Clear(void)
97 {
98     ClearNeighbors();
99     mAllocatedRouterIds.Clear();
100     memset(mRouterIdReuseDelay, 0, sizeof(mRouterIdReuseDelay));
101     UpdateAllocation();
102 }
103 
ClearNeighbors(void)104 void RouterTable::ClearNeighbors(void)
105 {
106     for (Router &router : mRouters)
107     {
108         if (router.IsStateValid())
109         {
110             Get<NeighborTable>().Signal(NeighborTable::kRouterRemoved, router);
111         }
112 
113         router.SetState(Neighbor::kStateInvalid);
114     }
115 }
116 
IsAllocated(uint8_t aRouterId) const117 bool RouterTable::IsAllocated(uint8_t aRouterId) const
118 {
119     return mAllocatedRouterIds.Contains(aRouterId);
120 }
121 
UpdateAllocation(void)122 void RouterTable::UpdateAllocation(void)
123 {
124     uint8_t indexMap[Mle::kMaxRouterId + 1];
125 
126     mActiveRouterCount = 0;
127 
128     // build index map
129     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
130     {
131         if (IsAllocated(routerId) && mActiveRouterCount < Mle::kMaxRouters)
132         {
133             indexMap[routerId] = mActiveRouterCount++;
134         }
135         else
136         {
137             indexMap[routerId] = Mle::kInvalidRouterId;
138         }
139     }
140 
141     // shift entries forward
142     for (int index = Mle::kMaxRouters - 2; index >= 0; index--)
143     {
144         uint8_t routerId = mRouters[index].GetRouterId();
145         uint8_t newIndex;
146 
147         if (routerId > Mle::kMaxRouterId || indexMap[routerId] == Mle::kInvalidRouterId)
148         {
149             continue;
150         }
151 
152         newIndex = indexMap[routerId];
153 
154         if (newIndex > index)
155         {
156             mRouters[newIndex] = mRouters[index];
157         }
158     }
159 
160     // shift entries backward
161     for (uint8_t index = 1; index < Mle::kMaxRouters; index++)
162     {
163         uint8_t routerId = mRouters[index].GetRouterId();
164         uint8_t newIndex;
165 
166         if (routerId > Mle::kMaxRouterId || indexMap[routerId] == Mle::kInvalidRouterId)
167         {
168             continue;
169         }
170 
171         newIndex = indexMap[routerId];
172 
173         if (newIndex < index)
174         {
175             mRouters[newIndex] = mRouters[index];
176         }
177     }
178 
179     // fix replaced entries
180     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
181     {
182         uint8_t index = indexMap[routerId];
183 
184         if (index != Mle::kInvalidRouterId)
185         {
186             Router &router = mRouters[index];
187 
188             if (router.GetRouterId() != routerId)
189             {
190                 router.Clear();
191                 router.SetRloc16(Mle::Mle::Rloc16FromRouterId(routerId));
192                 router.SetNextHop(Mle::kInvalidRouterId);
193             }
194         }
195     }
196 
197     // clear unused entries
198     for (uint8_t index = mActiveRouterCount; index < Mle::kMaxRouters; index++)
199     {
200         Router &router = mRouters[index];
201         router.Clear();
202         router.SetRloc16(0xffff);
203     }
204 }
205 
Allocate(void)206 Router *RouterTable::Allocate(void)
207 {
208     Router *rval         = nullptr;
209     uint8_t numAvailable = 0;
210     uint8_t freeBit;
211 
212     // count available router ids
213 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
214     for (uint8_t routerId = mMinRouterId; routerId <= mMaxRouterId; routerId++)
215 #else
216     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
217 #endif
218     {
219         if (!IsAllocated(routerId) && mRouterIdReuseDelay[routerId] == 0)
220         {
221             numAvailable++;
222         }
223     }
224 
225     VerifyOrExit(mActiveRouterCount < Mle::kMaxRouters && numAvailable > 0);
226 
227     // choose available router id at random
228     freeBit = Random::NonCrypto::GetUint8InRange(0, numAvailable);
229 
230     // allocate router
231 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
232     for (uint8_t routerId = mMinRouterId; routerId <= mMaxRouterId; routerId++)
233 #else
234     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
235 #endif
236     {
237         if (IsAllocated(routerId) || mRouterIdReuseDelay[routerId] > 0)
238         {
239             continue;
240         }
241 
242         if (freeBit == 0)
243         {
244             rval = Allocate(routerId);
245             OT_ASSERT(rval != nullptr);
246             ExitNow();
247         }
248 
249         freeBit--;
250     }
251 
252 exit:
253     return rval;
254 }
255 
Allocate(uint8_t aRouterId)256 Router *RouterTable::Allocate(uint8_t aRouterId)
257 {
258     Router *rval = nullptr;
259 
260     VerifyOrExit(aRouterId <= Mle::kMaxRouterId && mActiveRouterCount < Mle::kMaxRouters && !IsAllocated(aRouterId) &&
261                  mRouterIdReuseDelay[aRouterId] == 0);
262 
263     mAllocatedRouterIds.Add(aRouterId);
264     UpdateAllocation();
265 
266     rval = GetRouter(aRouterId);
267     rval->SetLastHeard(TimerMilli::GetNow());
268 
269     mRouterIdSequence++;
270     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
271     Get<Mle::MleRouter>().ResetAdvertiseInterval();
272 
273     LogNote("Allocate router id %d", aRouterId);
274 
275 exit:
276     return rval;
277 }
278 
Release(uint8_t aRouterId)279 Error RouterTable::Release(uint8_t aRouterId)
280 {
281     Error    error  = kErrorNone;
282     uint16_t rloc16 = Mle::Mle::Rloc16FromRouterId(aRouterId);
283     Router * router;
284 
285     OT_ASSERT(aRouterId <= Mle::kMaxRouterId);
286 
287     VerifyOrExit(Get<Mle::MleRouter>().IsLeader(), error = kErrorInvalidState);
288     VerifyOrExit(IsAllocated(aRouterId), error = kErrorNotFound);
289 
290     router = GetNeighbor(rloc16);
291 
292     if (router != nullptr)
293     {
294         Get<NeighborTable>().Signal(NeighborTable::kRouterRemoved, *router);
295     }
296 
297     mAllocatedRouterIds.Remove(aRouterId);
298     UpdateAllocation();
299 
300     mRouterIdReuseDelay[aRouterId] = Mle::kRouterIdReuseDelay;
301 
302     for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
303     {
304         if (router->GetNextHop() == rloc16)
305         {
306             router->SetNextHop(Mle::kInvalidRouterId);
307             router->SetCost(0);
308         }
309     }
310 
311     mRouterIdSequence++;
312     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
313 
314     Get<AddressResolver>().Remove(aRouterId);
315     Get<NetworkData::Leader>().RemoveBorderRouter(rloc16, NetworkData::Leader::kMatchModeRouterId);
316     Get<Mle::MleRouter>().ResetAdvertiseInterval();
317 
318     LogNote("Release router id %d", aRouterId);
319 
320 exit:
321     return error;
322 }
323 
RemoveRouterLink(Router & aRouter)324 void RouterTable::RemoveRouterLink(Router &aRouter)
325 {
326     if (aRouter.GetLinkQualityOut() != 0)
327     {
328         aRouter.SetLinkQualityOut(kLinkQuality0);
329         aRouter.SetLastHeard(TimerMilli::GetNow());
330     }
331 
332     for (Router *cur = GetFirstEntry(); cur != nullptr; cur = GetNextEntry(cur))
333     {
334         if (cur->GetNextHop() == aRouter.GetRouterId())
335         {
336             cur->SetNextHop(Mle::kInvalidRouterId);
337             cur->SetCost(0);
338 
339             if (GetLinkCost(*cur) >= Mle::kMaxRouteCost)
340             {
341                 Get<Mle::MleRouter>().ResetAdvertiseInterval();
342             }
343         }
344     }
345 
346     if (aRouter.GetNextHop() == Mle::kInvalidRouterId)
347     {
348         Get<Mle::MleRouter>().ResetAdvertiseInterval();
349 
350         // Clear all EID-to-RLOC entries associated with the router.
351         Get<AddressResolver>().Remove(aRouter.GetRouterId());
352     }
353 }
354 
GetActiveLinkCount(void) const355 uint8_t RouterTable::GetActiveLinkCount(void) const
356 {
357     uint8_t activeLinks = 0;
358 
359     for (const Router *router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
360     {
361         if (router->IsStateValid())
362         {
363             activeLinks++;
364         }
365     }
366 
367     return activeLinks;
368 }
369 
FindRouter(const Router::AddressMatcher & aMatcher) const370 const Router *RouterTable::FindRouter(const Router::AddressMatcher &aMatcher) const
371 {
372     const Router *router;
373 
374     for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
375     {
376         if (router->Matches(aMatcher))
377         {
378             break;
379         }
380     }
381 
382     return router;
383 }
384 
GetNeighbor(uint16_t aRloc16)385 Router *RouterTable::GetNeighbor(uint16_t aRloc16)
386 {
387     Router *router = nullptr;
388 
389     VerifyOrExit(aRloc16 != Get<Mle::MleRouter>().GetRloc16());
390     router = FindRouter(Router::AddressMatcher(aRloc16, Router::kInStateValid));
391 
392 exit:
393     return router;
394 }
395 
GetNeighbor(const Mac::ExtAddress & aExtAddress)396 Router *RouterTable::GetNeighbor(const Mac::ExtAddress &aExtAddress)
397 {
398     return FindRouter(Router::AddressMatcher(aExtAddress, Router::kInStateValid));
399 }
400 
GetNeighbor(const Mac::Address & aMacAddress)401 Router *RouterTable::GetNeighbor(const Mac::Address &aMacAddress)
402 {
403     return FindRouter(Router::AddressMatcher(aMacAddress, Router::kInStateValid));
404 }
405 
GetRouter(uint8_t aRouterId) const406 const Router *RouterTable::GetRouter(uint8_t aRouterId) const
407 {
408     const Router *router = nullptr;
409     uint16_t      rloc16;
410 
411     // Skip if invalid router id is passed.
412     VerifyOrExit(aRouterId < Mle::kInvalidRouterId);
413 
414     rloc16 = Mle::Mle::Rloc16FromRouterId(aRouterId);
415     router = FindRouter(Router::AddressMatcher(rloc16, Router::kInStateAny));
416 
417 exit:
418     return router;
419 }
420 
GetRouter(const Mac::ExtAddress & aExtAddress)421 Router *RouterTable::GetRouter(const Mac::ExtAddress &aExtAddress)
422 {
423     return FindRouter(Router::AddressMatcher(aExtAddress, Router::kInStateAny));
424 }
425 
GetRouterInfo(uint16_t aRouterId,Router::Info & aRouterInfo)426 Error RouterTable::GetRouterInfo(uint16_t aRouterId, Router::Info &aRouterInfo)
427 {
428     Error   error = kErrorNone;
429     Router *router;
430     uint8_t routerId;
431 
432     if (aRouterId <= Mle::kMaxRouterId)
433     {
434         routerId = static_cast<uint8_t>(aRouterId);
435     }
436     else
437     {
438         VerifyOrExit(Mle::Mle::IsActiveRouter(aRouterId), error = kErrorInvalidArgs);
439         routerId = Mle::Mle::RouterIdFromRloc16(aRouterId);
440         VerifyOrExit(routerId <= Mle::kMaxRouterId, error = kErrorInvalidArgs);
441     }
442 
443     router = GetRouter(routerId);
444     VerifyOrExit(router != nullptr, error = kErrorNotFound);
445 
446     aRouterInfo.SetFrom(*router);
447 
448 exit:
449     return error;
450 }
451 
GetLeader(void)452 Router *RouterTable::GetLeader(void)
453 {
454     return GetRouter(Get<Mle::MleRouter>().GetLeaderId());
455 }
456 
GetLeaderAge(void) const457 uint32_t RouterTable::GetLeaderAge(void) const
458 {
459     return (mActiveRouterCount > 0) ? Time::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated) : 0xffffffff;
460 }
461 
GetNeighborCount(void) const462 uint8_t RouterTable::GetNeighborCount(void) const
463 {
464     uint8_t count = 0;
465 
466     for (const Router *router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
467     {
468         if (router->IsStateValid())
469         {
470             count++;
471         }
472     }
473 
474     return count;
475 }
476 
GetLinkCost(Router & aRouter)477 uint8_t RouterTable::GetLinkCost(Router &aRouter)
478 {
479     uint8_t rval = Mle::kMaxRouteCost;
480 
481     VerifyOrExit(aRouter.GetRloc16() != Get<Mle::MleRouter>().GetRloc16() && aRouter.IsStateValid());
482 
483     rval = aRouter.GetLinkInfo().GetLinkQuality();
484 
485     if (rval > aRouter.GetLinkQualityOut())
486     {
487         rval = aRouter.GetLinkQualityOut();
488     }
489 
490     rval = Mle::MleRouter::LinkQualityToCost(rval);
491 
492 exit:
493     return rval;
494 }
495 
UpdateRouterIdSet(uint8_t aRouterIdSequence,const Mle::RouterIdSet & aRouterIdSet)496 void RouterTable::UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet)
497 {
498     mRouterIdSequence            = aRouterIdSequence;
499     mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
500 
501     VerifyOrExit(mAllocatedRouterIds != aRouterIdSet);
502 
503     for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
504     {
505         // If was allocated but removed in new Router Id Set
506         if (IsAllocated(routerId) && !aRouterIdSet.Contains(routerId))
507         {
508             Router *router = GetRouter(routerId);
509 
510             OT_ASSERT(router != nullptr);
511             router->SetNextHop(Mle::kInvalidRouterId);
512             RemoveRouterLink(*router);
513 
514             mAllocatedRouterIds.Remove(routerId);
515         }
516     }
517 
518     mAllocatedRouterIds = aRouterIdSet;
519     UpdateAllocation();
520     Get<Mle::MleRouter>().ResetAdvertiseInterval();
521 
522 exit:
523     return;
524 }
525 
HandleTimeTick(void)526 void RouterTable::HandleTimeTick(void)
527 {
528     Mle::MleRouter &mle = Get<Mle::MleRouter>();
529 
530     if (mle.IsLeader())
531     {
532         // update router id sequence
533         if (GetLeaderAge() >= Mle::kRouterIdSequencePeriod)
534         {
535             mRouterIdSequence++;
536             mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
537         }
538 
539         for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
540         {
541             if (mRouterIdReuseDelay[routerId] > 0)
542             {
543                 mRouterIdReuseDelay[routerId]--;
544             }
545         }
546     }
547 }
548 
549 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
GetRouterIdRange(uint8_t & aMinRouterId,uint8_t & aMaxRouterId) const550 void RouterTable::GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const
551 {
552     aMinRouterId = mMinRouterId;
553     aMaxRouterId = mMaxRouterId;
554 }
555 
SetRouterIdRange(uint8_t aMinRouterId,uint8_t aMaxRouterId)556 Error RouterTable::SetRouterIdRange(uint8_t aMinRouterId, uint8_t aMaxRouterId)
557 {
558     Error error = kErrorNone;
559 
560     VerifyOrExit(aMinRouterId <= aMaxRouterId, error = kErrorInvalidArgs);
561     VerifyOrExit(aMaxRouterId <= Mle::kMaxRouterId, error = kErrorInvalidArgs);
562     mMinRouterId = aMinRouterId;
563     mMaxRouterId = aMaxRouterId;
564 
565 exit:
566     return error;
567 }
568 #endif
569 
570 } // namespace ot
571 
572 #endif // OPENTHREAD_FTD
573