blob: bf11573a2e8fd8b6739595fb5ce4dfaaf997cc28 [file] [log] [blame]
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ROUTER_TABLE_HPP_
#define ROUTER_TABLE_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_FTD
#include "common/array.hpp"
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/iterator_utils.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "common/serial_number.hpp"
#include "common/tasklet.hpp"
#include "mac/mac_types.hpp"
#include "thread/mle_tlvs.hpp"
#include "thread/mle_types.hpp"
#include "thread/router.hpp"
#include "thread/thread_tlvs.hpp"
namespace ot {
class RouterTable : public InstanceLocator, private NonCopyable
{
friend class NeighborTable;
public:
/**
* Constructor.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit RouterTable(Instance &aInstance);
/**
* Clears the router table.
*
*/
void Clear(void);
/**
* Removes all neighbor links to routers.
*
*/
void ClearNeighbors(void);
/**
* Allocates a router with a random Router ID.
*
* @returns A pointer to the allocated router or `nullptr` if a Router ID is not available.
*
*/
Router *Allocate(void);
/**
* Allocates a router with a specified Router ID.
*
* @param[in] aRouterId The Router ID to try to allocate.
*
* @returns A pointer to the allocated router or `nullptr` if the ID @p aRouterId could not be allocated.
*
*/
Router *Allocate(uint8_t aRouterId);
/**
* Releases a Router ID.
*
* @param[in] aRouterId The Router ID.
*
* @retval kErrorNone Successfully released the Router ID @p aRouterId.
* @retval kErrorInvalidState The device is not currently operating as a leader.
* @retval kErrorNotFound The Router ID @p aRouterId is not currently allocated.
*
*/
Error Release(uint8_t aRouterId);
/**
* Removes a router link.
*
* @param[in] aRouter A reference to the router.
*
*/
void RemoveRouterLink(Router &aRouter);
/**
* Returns the number of active routers in the Thread network.
*
* @returns The number of active routers in the Thread network.
*
*/
uint8_t GetActiveRouterCount(void) const { return mRouters.GetLength(); }
/**
* Returns the leader in the Thread network.
*
* @returns A pointer to the Leader in the Thread network.
*
*/
Router *GetLeader(void) { return AsNonConst(AsConst(this)->GetLeader()); }
/**
* Returns the leader in the Thread network.
*
* @returns A pointer to the Leader in the Thread network.
*
*/
const Router *GetLeader(void) const;
/**
* Returns the leader's age in seconds, i.e., seconds since the last Router ID Sequence update.
*
* @returns The leader's age.
*
*/
uint32_t GetLeaderAge(void) const;
/**
* Returns the link cost for a neighboring router.
*
* @param[in] aRouter A router.
*
* @returns The link cost to @p aRouter.
*
*/
uint8_t GetLinkCost(const Router &aRouter) const;
/**
* Returns the link cost to the given Router.
*
* @param[in] aRouterId The Router ID.
*
* @returns The link cost to the Router.
*
*/
uint8_t GetLinkCost(uint8_t aRouterId) const;
/**
* Returns the minimum mesh path cost to the given RLOC16
*
* @param[in] aDestRloc16 The RLOC16 of destination
*
* @returns The minimum mesh path cost to @p aDestRloc16 (via direct link or forwarding).
*
*/
uint8_t GetPathCost(uint16_t aDestRloc16) const;
/**
* Returns the mesh path cost to leader.
*
* @returns The path cost to leader.
*
*/
uint8_t GetPathCostToLeader(void) const;
/**
* Determines the next hop towards an RLOC16 destination.
*
* @param[in] aDestRloc16 The RLOC16 of the destination.
*
* @returns A RLOC16 of the next hop if a route is known, `Mle::kInvalidRloc16` otherwise.
*
*/
uint16_t GetNextHop(uint16_t aDestRloc16) const;
/**
* Determines the next hop and the path cost towards an RLOC16 destination.
*
* @param[in] aDestRloc16 The RLOC16 of the destination.
* @param[out] aNextHopRloc16 A reference to return the RLOC16 of next hop if known, or `Mle::kInvalidRloc16`.
* @param[out] aPathCost A reference to return the path cost.
*
*/
void GetNextHopAndPathCost(uint16_t aDestRloc16, uint16_t &aNextHopRloc16, uint8_t &aPathCost) const;
/**
* Finds the router for a given Router ID.
*
* @param[in] aRouterId The Router ID to search for.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
Router *FindRouterById(uint8_t aRouterId) { return AsNonConst(AsConst(this)->FindRouterById(aRouterId)); }
/**
* Finds the router for a given Router ID.
*
* @param[in] aRouterId The Router ID to search for.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
const Router *FindRouterById(uint8_t aRouterId) const;
/**
* Finds the router for a given RLOC16.
*
* @param[in] aRloc16 The RLOC16 to search for.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
Router *FindRouterByRloc16(uint16_t aRloc16) { return AsNonConst(AsConst(this)->FindRouterByRloc16(aRloc16)); }
/**
* Finds the router for a given RLOC16.
*
* @param[in] aRloc16 The RLOC16 to search for.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
const Router *FindRouterByRloc16(uint16_t aRloc16) const;
/**
* Finds the router that is the next hop of a given router.
*
* @param[in] aRouter The router to find next hop of.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
Router *FindNextHopOf(const Router &aRouter) { return AsNonConst(AsConst(this)->FindNextHopOf(aRouter)); }
/**
* Finds the router that is the next hop of a given router.
*
* @param[in] aRouter The router to find next hop of.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
const Router *FindNextHopOf(const Router &aRouter) const;
/**
* Find the router for a given MAC Extended Address.
*
* @param[in] aExtAddress A reference to the MAC Extended Address.
*
* @returns A pointer to the router or `nullptr` if the router could not be found.
*
*/
Router *FindRouter(const Mac::ExtAddress &aExtAddress);
/**
* Indicates whether the router table contains a given `Neighbor` instance.
*
* @param[in] aNeighbor A reference to a `Neighbor`.
*
* @retval TRUE if @p aNeighbor is a `Router` in the router table.
* @retval FALSE if @p aNeighbor is not a `Router` in the router table
* (i.e. it can be the parent or parent candidate, or a `Child` of the child table).
*
*/
bool Contains(const Neighbor &aNeighbor) const
{
return mRouters.IsInArrayBuffer(&static_cast<const Router &>(aNeighbor));
}
/**
* Retains diagnostic information for a given router.
*
* @param[in] aRouterId The router ID or RLOC16 for a given router.
* @param[out] aRouterInfo The router information.
*
* @retval kErrorNone Successfully retrieved the router info for given id.
* @retval kErrorInvalidArgs @p aRouterId is not a valid value for a router.
* @retval kErrorNotFound No router entry with the given id.
*
*/
Error GetRouterInfo(uint16_t aRouterId, Router::Info &aRouterInfo);
/**
* Returns the Router ID Sequence.
*
* @returns The Router ID Sequence.
*
*/
uint8_t GetRouterIdSequence(void) const { return mRouterIdSequence; }
/**
* Returns the local time when the Router ID Sequence was last updated.
*
* @returns The local time when the Router ID Sequence was last updated.
*
*/
TimeMilli GetRouterIdSequenceLastUpdated(void) const { return mRouterIdSequenceLastUpdated; }
/**
* Determines whether the Router ID Sequence in a received Route TLV is more recent than the current
* Router ID Sequence being used by `RouterTable`.
*
* @param[in] aRouteTlv The Route TLV to compare.
*
* @retval TRUE The Router ID Sequence in @p aRouteTlv is more recent.
* @retval FALSE The Router ID Sequence in @p aRouteTlv is not more recent.
*
*/
bool IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const;
/**
* Gets the number of router neighbors with `GetLinkQualityIn()` better than or equal to a given threshold.
*
* @param[in] aLinkQuality Link quality threshold.
*
* @returns Number of router neighbors with link quality of @o aLinkQuality or better.
*
*/
uint8_t GetNeighborCount(LinkQuality aLinkQuality) const;
/**
* Indicates whether or not a Router ID is allocated.
*
* @param[in] aRouterId The Router ID.
*
* @retval TRUE if @p aRouterId is allocated.
* @retval FALSE if @p aRouterId is not allocated.
*
*/
bool IsAllocated(uint8_t aRouterId) const { return mRouterIdMap.IsAllocated(aRouterId); }
/**
* Updates the Router ID allocation set.
*
* @param[in] aRouterIdSequence The Router ID Sequence.
* @param[in] aRouterIdSet The Router ID Set.
*
*/
void UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet);
/**
* Updates the routes based on a received `RouteTlv` from a neighboring router.
*
* @param[in] aRouteTlv The received `RouteTlv`
* @param[in] aNeighborId The router ID of neighboring router from which @p aRouteTlv is received.
*
*/
void UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId);
/**
* Updates the routes on an FED based on a received `RouteTlv` from the parent.
*
* MUST be called when device is an FED child and @p aRouteTlv is received from its current parent.
*
* @param[in] aRouteTlv The received `RouteTlv` from parent.
* @param[in] aParentId The Router ID of parent.
*
*/
void UpdateRoutesOnFed(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId);
/**
* Gets the allocated Router ID set.
*
* @param[out] aRouterIdSet A reference to output the allocated Router ID set.
*
*/
void GetRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const { return mRouterIdMap.GetAsRouterIdSet(aRouterIdSet); }
/**
* Fills a Route TLV.
*
* When @p aNeighbor is not `nullptr`, we limit the number of router entries to `kMaxRoutersInRouteTlvForLinkAccept`
* when populating `aRouteTlv`, so that the TLV can be appended in a Link Accept message. In this case, we ensure
* to include router entries associated with @p aNeighbor, leader, and this device itself.
*
* @param[out] aRouteTlv A Route TLV to be filled.
* @param[in] aNeighbor A pointer to the receiver (in case TLV is for a Link Accept message).
*
*/
void FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighbor = nullptr) const;
/**
* Updates the router table and must be called with a one second period.
*
*/
void HandleTimeTick(void);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* Gets the range of Router IDs.
*
* All the Router IDs in the range `[aMinRouterId, aMaxRouterId]` are allowed. This is intended for testing only.
*
* @param[out] aMinRouterId Reference to return the minimum Router ID.
* @param[out] aMaxRouterId Reference to return the maximum Router ID.
*
*/
void GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const;
/**
* Sets the range of Router IDs.
*
* All the Router IDs in the range `[aMinRouterId, aMaxRouterId]` are allowed. This is intended for testing only.
*
* @param[in] aMinRouterId The minimum Router ID.
* @param[in] aMaxRouterId The maximum Router ID.
*
* @retval kErrorNone Successfully set the Router ID range.
* @retval kErrorInvalidArgs The given range is not valid.
*
*/
Error SetRouterIdRange(uint8_t aMinRouterId, uint8_t aMaxRouterId);
#endif
// The following methods are intended to support range-based `for`
// loop iteration over the router and should not be used
// directly.
Router *begin(void) { return mRouters.begin(); }
Router *end(void) { return mRouters.end(); }
const Router *begin(void) const { return mRouters.begin(); }
const Router *end(void) const { return mRouters.end(); }
private:
static constexpr uint32_t kRouterIdSequencePeriod = 10; // in sec
static constexpr uint8_t kLinkAcceptSequenceRollback = 64;
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
static constexpr uint8_t kMaxRoutersInRouteTlvForLinkAccept = 3;
#else
static constexpr uint8_t kMaxRoutersInRouteTlvForLinkAccept = 20;
#endif
Router *AddRouter(uint8_t aRouterId);
void RemoveRouter(Router &aRouter);
Router *FindNeighbor(uint16_t aRloc16);
Router *FindNeighbor(const Mac::ExtAddress &aExtAddress);
Router *FindNeighbor(const Mac::Address &aMacAddress);
const Router *FindRouter(const Router::AddressMatcher &aMatcher) const;
Router *FindRouter(const Router::AddressMatcher &aMatcher)
{
return AsNonConst(AsConst(this)->FindRouter(aMatcher));
}
void SignalTableChanged(void);
void HandleTableChanged(void);
void LogRouteTable(void) const;
class RouterIdMap
{
public:
// The `RouterIdMap` tracks which Router IDs are allocated.
// For allocated IDs, tracks the index of the `Router` entry
// in `mRouters` array. For unallocated IDs, tracks the
// remaining reuse delay time (in seconds).
RouterIdMap(void) { Clear(); }
void Clear(void) { memset(mIndexes, 0, sizeof(mIndexes)); }
bool IsAllocated(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kAllocatedFlag); }
uint8_t GetIndex(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kIndexMask); }
void SetIndex(uint8_t aRouterId, uint8_t aIndex) { mIndexes[aRouterId] = kAllocatedFlag | aIndex; }
bool CanAllocate(uint8_t aRouterId) const { return (mIndexes[aRouterId] == 0); }
void Release(uint8_t aRouterId) { mIndexes[aRouterId] = kReuseDelay; }
void GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const;
void HandleTimeTick(void);
private:
// The high bit in `mIndexes[aRouterId]` indicates whether or
// not the router ID is allocated. The lower 7 bits give either
// the index in `mRouter` array or remaining reuse delay time.
static constexpr uint8_t kReuseDelay = 100; // in sec
static constexpr uint8_t kAllocatedFlag = 1 << 7;
static constexpr uint8_t kIndexMask = 0x7f;
static_assert(kReuseDelay <= kIndexMask, "kReuseDelay does not fit in 7 bits");
uint8_t mIndexes[Mle::kMaxRouterId + 1];
};
using ChangedTask = TaskletIn<RouterTable, &RouterTable::HandleTableChanged>;
Array<Router, Mle::kMaxRouters> mRouters;
ChangedTask mChangedTask;
RouterIdMap mRouterIdMap;
TimeMilli mRouterIdSequenceLastUpdated;
uint8_t mRouterIdSequence;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
uint8_t mMinRouterId;
uint8_t mMaxRouterId;
#endif
};
} // namespace ot
#endif // OPENTHREAD_FTD
#endif // ROUTER_TABLE_HPP_