Skip to content

Commit 40ebd8d

Browse files
authored
[router-table] append Route TLV directly to message (openthread#13042)
This commit updates the way Route TLV is constructed and appended to messages. Previously, a `RouteTlv` object with a large fixed-size `mRouteData` array was allocated on the stack, filled by `RouterTable`, and then appended to the message. To simplify the code and improve efficiently a new helper method `RouterTable::AppendRouteTlv()` is introduced which appends the TLV content directly in the `Message`. It uses `Tlv::StartTlv()` and `Tlv::EndTlv()` to encapsulate the `RouterIdMask` and the iteratively appended route data entries. A helper method `RouteTlv::AppendRouteDataEntry()` is added which handles encoding and adding a Route Data Entry, including the the bit-packing logic(the staggered 1.5-byte packing under `OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE`).
1 parent 8e0e65d commit 40ebd8d

6 files changed

Lines changed: 157 additions & 95 deletions

File tree

src/core/thread/mle.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3957,12 +3957,7 @@ Error Mle::TxMessage::AppendCompactRouteTlv(uint16_t aDestRloc16) { return Appen
39573957

39583958
Error Mle::TxMessage::AppendFullOrCompactRouteTlv(uint16_t aDestRloc16)
39593959
{
3960-
RouteTlv tlv;
3961-
3962-
tlv.Init();
3963-
Get<RouterTable>().FillRouteTlv(tlv, aDestRloc16);
3964-
3965-
return tlv.AppendTo(*this);
3960+
return Get<RouterTable>().AppendRouteTlv(*this, RouteTlv::kType, aDestRloc16);
39663961
}
39673962

39683963
Error Mle::TxMessage::AppendActiveDatasetTlv(void) { return AppendDatasetTlv(MeshCoP::Dataset::kActive); }

src/core/thread/mle_tlvs.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,75 @@ bool RouteTlv::IsValid(void) const
6565
return isValid;
6666
}
6767

68+
Error RouteTlv::AppendRouteDataEntry(Message &aMessage,
69+
LinkQuality aLqIn,
70+
LinkQuality aLqOut,
71+
uint8_t aRouteCost
72+
#if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
73+
,
74+
bool aIsEven
75+
#endif
76+
)
77+
{
78+
Error error;
79+
EntryType entry = 0;
80+
81+
if (aRouteCost >= kMaxRouteCost)
82+
{
83+
aRouteCost = 0;
84+
}
85+
86+
WriteBits<EntryType, kLinkQualityOutMask>(entry, aLqOut);
87+
WriteBits<EntryType, kLinkQualityInMask>(entry, aLqIn);
88+
WriteBits<EntryType, kRouteCostMask>(entry, aRouteCost);
89+
90+
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
91+
ExitNow(error = aMessage.Append<uint8_t>(entry));
92+
#else
93+
{
94+
// Under `OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE`, each route
95+
// data entry uses 1.5 bytes (12 bits). Two entries are packed
96+
// into 3 bytes.
97+
//
98+
// For the even (first) entry, we grow the message by 2 bytes
99+
// and write the 12 bits into the upper 12 bits of the new
100+
// 16-bit word at the end of the message.
101+
//
102+
// For the odd (second) entry, we grow the message by 1 byte. We
103+
// then read the last 16 bits (which overlap with the last byte
104+
// of the even entry), write the new 12-bit entry into the
105+
// lower 12 bits, and write the 16-bit word back. This
106+
// perfectly packs the two 12-bit entries into 3 bytes.
107+
108+
uint16_t offset;
109+
uint16_t data;
110+
111+
SuccessOrExit(error = aMessage.IncreaseLength(aIsEven ? sizeof(uint16_t) : sizeof(uint8_t)));
112+
113+
VerifyOrExit(aMessage.GetLength() >= sizeof(uint16_t), error = kErrorParse);
114+
offset = aMessage.GetLength() - sizeof(uint16_t);
115+
116+
if (aIsEven)
117+
{
118+
data = 0;
119+
WriteBits<uint16_t, kEvenEntryMask>(data, entry);
120+
}
121+
else
122+
{
123+
IgnoreError(aMessage.Read<uint16_t>(offset, data));
124+
data = BigEndian::HostSwap16(data);
125+
126+
WriteBits<uint16_t, kOddEntryMask>(data, entry);
127+
}
128+
129+
aMessage.Write<uint16_t>(offset, BigEndian::HostSwap16(data));
130+
}
131+
#endif // OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
132+
133+
exit:
134+
return error;
135+
}
136+
68137
//---------------------------------------------------------------------------------------------------------------------
69138
// ConnectivityTlvValue
70139

src/core/thread/mle_tlvs.hpp

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -302,20 +302,6 @@ class RouteTlv : public Tlv, public TlvInfo<Tlv::kRoute>
302302
#endif
303303
}
304304

305-
/**
306-
* Sets the Route Data entry count.
307-
*
308-
* @param[in] aCount The number of Route Data entries in the Route TLV.
309-
*/
310-
void SetRouteDataEntryCount(uint8_t aCount)
311-
{
312-
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
313-
SetLength(sizeof(mRouterIdMask) + aCount);
314-
#else
315-
SetLength(sizeof(mRouterIdMask) + aCount + (aCount + 1) / 2);
316-
#endif
317-
}
318-
319305
/**
320306
* Returns the Route Cost value for a given Router index.
321307
*
@@ -364,32 +350,42 @@ class RouteTlv : public Tlv, public TlvInfo<Tlv::kRoute>
364350
#endif
365351
}
366352

353+
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
367354
/**
368-
* Sets the Route Data (Link Quality In/Out and Route Cost) for a given Router index.
355+
* Appends a Route Data entry (Link Quality In/Out and Route Cost) to a message.
369356
*
370-
* @param[in] aRouterIndex The Router index.
371-
* @param[in] aLinkQualityIn The Link Quality In value.
372-
* @param[in] aLinkQualityOut The Link Quality Out value.
357+
* @param[in] aMessage The message to append to.
358+
* @param[in] aLqIn The Link Quality In value.
359+
* @param[in] aLqOut The Link Quality Out value.
373360
* @param[in] aRouteCost The Route Cost value.
361+
*
362+
* @retval kErrorNone Successfully appended the data.
363+
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
374364
*/
375-
void SetRouteData(uint8_t aRouterIndex, LinkQuality aLinkQualityIn, LinkQuality aLinkQualityOut, uint8_t aRouteCost)
376-
{
377-
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
378-
mRouteData[aRouterIndex] = 0;
379-
380-
WriteBits<uint8_t, kLinkQualityInMask>(mRouteData[aRouterIndex], aLinkQualityIn);
381-
WriteBits<uint8_t, kLinkQualityOutMask>(mRouteData[aRouterIndex], aLinkQualityOut);
382-
WriteBits<uint8_t, kRouteCostMask>(mRouteData[aRouterIndex], aRouteCost);
365+
static Error AppendRouteDataEntry(Message &aMessage, LinkQuality aLqIn, LinkQuality aLqOut, uint8_t aRouteCost);
383366
#else
384-
uint16_t data = 0;
385-
386-
WriteBits<uint16_t, kLinkQualityOutMask>(data, aLinkQualityOut);
387-
WriteBits<uint16_t, kLinkQualityInMask>(data, aLinkQualityIn);
388-
WriteBits<uint16_t, kRouteCostMask>(data, aRouteCost);
389-
390-
WriteEntry(aRouterIndex, data);
367+
/**
368+
* Appends a Route Data entry (Link Quality In/Out and Route Cost) to a message.
369+
*
370+
* Under `OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE`, each route data entry uses 1.5 bytes (12 bits). Two entries
371+
* are packed into 3 bytes. @p aIsEven is used to indicate whether this is an even (first) or an odd (second) entry.
372+
*
373+
* @param[in] aMessage The message to append to.
374+
* @param[in] aLqIn The Link Quality In value.
375+
* @param[in] aLqOut The Link Quality Out value.
376+
* @param[in] aRouteCost The Route Cost value.
377+
* @param[in] aIsEven Indicates whether this is an even (first) entry.
378+
*
379+
* @retval kErrorNone Successfully appended the data.
380+
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
381+
* @retval kErrorParse Message length is invalid for parsing route data.
382+
*/
383+
static Error AppendRouteDataEntry(Message &aMessage,
384+
LinkQuality aLqIn,
385+
LinkQuality aLqOut,
386+
uint8_t aRouteCost,
387+
bool aIsEven);
391388
#endif
392-
}
393389

394390
private:
395391
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
@@ -398,6 +394,8 @@ class RouteTlv : public Tlv, public TlvInfo<Tlv::kRoute>
398394
// | LQOut | LQIn | Route Cost |
399395
// +---+---+---+---+---+---+---+---+
400396

397+
typedef uint8_t EntryType;
398+
401399
static constexpr uint8_t kLinkQualityOutMask = 0x03 << 6;
402400
static constexpr uint8_t kLinkQualityInMask = 0x03 << 4;
403401
static constexpr uint8_t kRouteCostMask = 0x0f << 0;
@@ -409,6 +407,8 @@ class RouteTlv : public Tlv, public TlvInfo<Tlv::kRoute>
409407
// remaining 8 bits are for the route cost. The even and odd
410408
// entries are staggered.
411409

410+
typedef uint16_t EntryType;
411+
412412
static constexpr uint16_t kEvenEntryMask = 0xfff << 4;
413413
static constexpr uint16_t kOddEntryMask = 0xfff << 0;
414414

@@ -434,25 +434,6 @@ class RouteTlv : public Tlv, public TlvInfo<Tlv::kRoute>
434434

435435
return data;
436436
}
437-
438-
void WriteEntry(uint8_t aRouterIndex, uint16_t aData)
439-
{
440-
uint16_t offset = (aRouterIndex + aRouterIndex / 2);
441-
uint16_t existing;
442-
443-
existing = BigEndian::ReadUint16(&mRouteData[offset]);
444-
445-
if (aRouterIndex & 0x1)
446-
{
447-
WriteBits<uint16_t, kOddEntryMask>(existing, aData);
448-
}
449-
else
450-
{
451-
WriteBits<uint16_t, kEvenEntryMask>(existing, aData);
452-
}
453-
454-
BigEndian::WriteUint16(existing, &mRouteData[offset]);
455-
}
456437
#endif // OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
457438

458439
RouterIdMask mRouterIdMask;

src/core/thread/network_diagnostic.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -432,14 +432,8 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage)
432432
}
433433

434434
case Tlv::kRoute:
435-
{
436-
RouteTlv tlv;
437-
438-
tlv.Init();
439-
Get<RouterTable>().FillRouteTlv(tlv);
440-
SuccessOrExit(error = tlv.AppendTo(aMessage));
435+
SuccessOrExit(error = Get<RouterTable>().AppendRouteTlv(aMessage, Tlv::kRoute));
441436
break;
442-
}
443437

444438
case Tlv::kEnhancedRoute:
445439
error = AppendEnhancedRoute(aMessage);

src/core/thread/router_table.cpp

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -763,11 +763,19 @@ void RouterTable::GetRouterIdMask(Mle::RouterIdMask &aRouterIdMask) const
763763
}
764764
}
765765

766-
void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, uint16_t aDestRloc16) const
766+
Error RouterTable::AppendRouteTlv(Message &aMessage, uint8_t aTlvType, uint16_t aDestRloc16) const
767767
{
768-
uint8_t routerIndex;
768+
Error error;
769+
Tlv::Bookmark tlvBookmark;
770+
Mle::RouterIdMask routerIdMask;
771+
#if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
772+
bool isEven = true;
773+
#endif
774+
775+
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
776+
// Determine the Router ID mask to use.
769777

770-
GetRouterIdMask(aRouteTlv.GetRouterIdMask());
778+
GetRouterIdMask(routerIdMask);
771779

772780
if (aDestRloc16 != Mle::kInvalidRloc16)
773781
{
@@ -795,26 +803,35 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, uint16_t aDestRloc16) c
795803
continue;
796804
}
797805

798-
if (aRouteTlv.GetRouterIdMask().IsAllocated(routerId))
806+
if (routerIdMask.IsAllocated(routerId))
799807
{
800-
aRouteTlv.GetRouterIdMask().Remove(routerId);
808+
routerIdMask.Remove(routerId);
801809
routerCount--;
802810
}
803811
}
804812

805813
// Ensure that the neighbor will process the current
806814
// Route TLV in a subsequent message exchange
807-
aRouteTlv.GetRouterIdMask().SetSequence(GetRouterIdSequence() - kLinkAcceptSequenceRollback);
815+
routerIdMask.SetSequence(GetRouterIdSequence() - kLinkAcceptSequenceRollback);
808816
}
809817
}
810818

811-
routerIndex = 0;
819+
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
820+
// Append TLV: Router ID Mask followed by Route Data Entries per
821+
// allocated router in the mask
822+
823+
SuccessOrExit(error = Tlv::StartTlv(aMessage, aTlvType, tlvBookmark));
824+
825+
SuccessOrExit(error = aMessage.Append(routerIdMask));
812826

813827
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
814828
{
815-
uint16_t routerRloc16;
829+
uint16_t routerRloc16;
830+
LinkQuality lqIn;
831+
LinkQuality lqOut;
832+
uint8_t routeCost;
816833

817-
if (!aRouteTlv.GetRouterIdMask().IsAllocated(routerId))
834+
if (!routerIdMask.IsAllocated(routerId))
818835
{
819836
continue;
820837
}
@@ -823,29 +840,31 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, uint16_t aDestRloc16) c
823840

824841
if (Get<Mle::Mle>().HasRloc16(routerRloc16))
825842
{
826-
aRouteTlv.SetRouteData(routerIndex, kLinkQuality0, kLinkQuality0, 1);
843+
lqIn = kLinkQuality0;
844+
lqOut = kLinkQuality0;
845+
routeCost = 1;
827846
}
828847
else
829848
{
830849
const Router *router = FindRouterById(routerId);
831-
uint8_t pathCost;
832850

833-
OT_ASSERT(router != nullptr);
834-
835-
pathCost = GetPathCost(routerRloc16);
836-
837-
if (pathCost >= Mle::kMaxRouteCost)
838-
{
839-
pathCost = 0;
840-
}
841-
842-
aRouteTlv.SetRouteData(routerIndex, router->GetLinkQualityIn(), router->GetLinkQualityOut(), pathCost);
851+
lqIn = router->GetLinkQualityIn();
852+
lqOut = router->GetLinkQualityOut();
853+
routeCost = GetPathCost(routerRloc16);
843854
}
844855

845-
routerIndex++;
856+
#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
857+
SuccessOrExit(error = Mle::RouteTlv::AppendRouteDataEntry(aMessage, lqIn, lqOut, routeCost));
858+
#else
859+
SuccessOrExit(error = Mle::RouteTlv::AppendRouteDataEntry(aMessage, lqIn, lqOut, routeCost, isEven));
860+
isEven = !isEven;
861+
#endif
846862
}
847863

848-
aRouteTlv.SetRouteDataEntryCount(routerIndex);
864+
error = Tlv::EndTlv(aMessage, tlvBookmark);
865+
866+
exit:
867+
return error;
849868
}
850869

851870
void RouterTable::HandleTimeTick(void)

src/core/thread/router_table.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,17 +371,21 @@ class RouterTable : public InstanceLocator, private NonCopyable
371371
void GetRouterIdMask(Mle::RouterIdMask &aRouterIdMask) const;
372372

373373
/**
374-
* Fills a Route TLV.
374+
* Appends a Route TLV to a given message.
375375
*
376376
* If @p aDestRloc16 is not `Mle::kInvalidRloc16`, a compact format is used for the Route TLV by limiting the
377377
* number of router entries to `kMaxRoutersInRouteTlvForLinkAccept`. This is used for Link Accept messages. In this
378-
* case, we ensure that entries for this device, the leader, and the @p aDestRloc16 (itself or its parent if it is
379-
* child) are included.
378+
* case, we ensure that entries for this device, the leader, and the destination router (itself or its parent if it
379+
* is a child) are always included.
380380
*
381-
* @param[out] aRouteTlv A Route TLV to be filled.
382-
* @param[in] aDestRloc16 The destination RLOC16 (used for compact format when not `Mle::kInvalidRloc16)`
381+
* @param[in,out] aMessage The message to append the Route TLV to.
382+
* @param[in] aTlvType The TLV type to use (e.g., `Tlv::kRoute`).
383+
* @param[in] aDestRloc16 The destination RLOC16. Used to determine whether to use the compact format.
384+
*
385+
* @retval kErrorNone Successfully appended the Route TLV.
386+
* @retval kErrorNoBufs Insufficient available buffers to append the TLV.
383387
*/
384-
void FillRouteTlv(Mle::RouteTlv &aRouteTlv, uint16_t aDestRloc16 = Mle::kInvalidRloc16) const;
388+
Error AppendRouteTlv(Message &aMessage, uint8_t aTlvType, uint16_t aDestRloc16 = Mle::kInvalidRloc16) const;
385389

386390
/**
387391
* Updates the router table and must be called with a one second period.

0 commit comments

Comments
 (0)