Skip to content

Commit

Permalink
[mesh-forwarder] add delay-aware queue management (#7568)
Browse files Browse the repository at this point in the history
This commit implements delay-aware queue management. When enabled the
device will monitor time-in-queue of messages in the direct tx queue
and if it is lager than specified thresholds it updates ECN flag
(if message indicates it is ECN-capable) and/or drop the message. This
mechanism is applied to IPv6 messages on the first device that sends
the message into Thread mesh and also on intermediate routers that are
forwarding the message (e.g., as a "mesh lowpan fragment" frame). On an
intermediate router when forwarding the fragments of a message, if any
fragment is dropped by the queue management policy, all subsequent
fragments will also be dropped.

In particular, this commit contains the following:

- Adds `DecompressEcn()` and `MarkCompressedEcn()` in `Lowpan` class
  to decompress or update the ECN field in a compressed IPHC header
  (unit test `test_lowpan` is also updated to test the new methods).
- Adds `UpdateEcnOrDrop()` which implements the main queue management
 logic. This method is used when preparing next direct tx message. It
 decides whether to keep the message as is, update ECN on it or drop
 it.
- Updates `EvictMessage()` to first apply the queue management rule
  to see if any message can be dropped before using the eviction
  logic based on message priority.
- Updates and reuses the `FragmentPriorityList` to track whether
  queue management dropped any of the fragments of same message so
  to also drop any subsequent ones.
- Updates `LogMessage()` to log when a message is dropped by
  queue-management or when ECN is marked on a message.
  • Loading branch information
abtink committed Jul 8, 2022
1 parent 8aca065 commit 2ce3d3b
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 11 deletions.
62 changes: 62 additions & 0 deletions src/core/config/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,68 @@
#define OPENTHREAD_CONFIG_NUM_FRAGMENT_PRIORITY_ENTRIES 8
#endif

/**
* @def OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
*
* Define to 1 to enable delay-aware queue management for the send queue.
*
* When enabled device will monitor time-in-queue of messages in the direct tx queue and if the wait time is lager than
* specified thresholds it may update ECN flag (if message indicates it is ECN-capable) or drop the message.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE \
(OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_3)
#endif

/**
* @OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL
*
* Specifies the time-in-queue threshold interval in milliseconds to mark ECN on a message if it is ECN-capable or
* drop the message if not ECN-capable.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL 500
#endif

/**
* @OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL
*
* Specifies the time-in-queue threshold interval in milliseconds to drop a message.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_DROP_MSG_INTERVAL 1000
#endif

/**
* OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME
*
* Specifies the max retain time in seconds of a mesh header fragmentation tag entry in the list.
*
* The entry in list is used to track whether an earlier fragment of same message was dropped by the router and if so
* the next fragments are also dropped. The entry is removed once last fragment is processed or after the retain time
* specified by this config parameter expires.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_RETAIN_TIME (4 * 60) // 4 minutes
#endif

/**
* OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE
*
* Specifies the number of mesh header fragmentation tag entries in the list for delay-aware queue management.
*
* The list is used to track whether an earlier fragment of same message was dropped by the router and if so the next
* fragments are also dropped.
*
*/
#ifndef OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE
#define OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_FRAG_TAG_ENTRY_LIST_SIZE 16
#endif

/**
* @def OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
*
Expand Down
1 change: 1 addition & 0 deletions src/core/thread/discover_scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage)
// the next scan channel. Also pause message tx on `MeshForwarder`
// while listening to receive Discovery Responses.
aMessage.SetDirectTransmission();
aMessage.SetTimestampToNow();
Get<MeshForwarder>().PauseMessageTransmissions();
mTimer.Start(kDefaultScanDuration);
break;
Expand Down
40 changes: 40 additions & 0 deletions src/core/thread/lowpan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,46 @@ int Lowpan::Decompress(Message & aMessage,
return (error == kErrorNone) ? static_cast<int>(compressedLength) : -1;
}

Ip6::Ecn Lowpan::DecompressEcn(const Message &aMessage, uint16_t aOffset) const
{
Ip6::Ecn ecn = Ip6::kEcnNotCapable;
uint16_t hcCtl;
uint8_t byte;

SuccessOrExit(aMessage.Read(aOffset, hcCtl));
hcCtl = HostSwap16(hcCtl);

VerifyOrExit((hcCtl & kHcDispatchMask) == kHcDispatch);
aOffset += sizeof(uint16_t);

if ((hcCtl & kHcTrafficFlowMask) == kHcTrafficFlow)
{
// ECN is elided and is zero (`kEcnNotCapable`).
ExitNow();
}

// When ECN is not elided, it is always included as the
// first two bits of the next byte.
SuccessOrExit(aMessage.Read(aOffset, byte));
ecn = static_cast<Ip6::Ecn>((byte & kEcnMask) >> kEcnOffset);

exit:
return ecn;
}

void Lowpan::MarkCompressedEcn(Message &aMessage, uint16_t aOffset)
{
uint8_t byte;

aOffset += sizeof(uint16_t);
IgnoreError(aMessage.Read(aOffset, byte));

byte &= ~kEcnMask;
byte |= static_cast<uint8_t>(Ip6::kEcnMarked << kEcnOffset);

aMessage.Write(aOffset, byte);
}

//---------------------------------------------------------------------------------------------------------------------
// MeshHeader

Expand Down
27 changes: 27 additions & 0 deletions src/core/thread/lowpan.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "mac/mac_types.hpp"
#include "net/ip6.hpp"
#include "net/ip6_address.hpp"
#include "net/ip6_types.hpp"

namespace ot {

Expand Down Expand Up @@ -308,6 +309,29 @@ class Lowpan : public InstanceLocator, private NonCopyable
*/
int DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, const uint8_t *aBuf, uint16_t aBufLength);

/**
* This method decompresses the IPv6 ECN field in a LOWPAN_IPHC header.
*
* @param[in] aMessage The message to read the IPHC header from.
* @param[in] aOffset The offset in @p aMessage to start of IPHC header.
*
* @returns The decompressed ECN field. If the IPHC header is not valid `kEcnNotCapable` is returned.
*
*/
Ip6::Ecn DecompressEcn(const Message &aMessage, uint16_t aOffset) const;

/**
* This method updates the compressed ECN field in a LOWPAN_IPHC header to `kEcnMarked`.
*
* This method MUST be used when the ECN field is not elided in the IPHC header. Note that the ECN is not elided
* when it is not zero (`kEcnNotCapable`).
*
* @param[in,out] aMessage The message containing the IPHC header and to update.
* @param[in] aOffset The offset in @p aMessage to start of IPHC header.
*
*/
void MarkCompressedEcn(Message &aMessage, uint16_t aOffset);

private:
static constexpr uint16_t kHcDispatch = 3 << 13;
static constexpr uint16_t kHcDispatchMask = 7 << 13;
Expand Down Expand Up @@ -336,6 +360,9 @@ class Lowpan : public InstanceLocator, private NonCopyable
static constexpr uint16_t kHcDstAddrMode3 = 3 << 0;
static constexpr uint16_t kHcDstAddrModeMask = 3 << 0;

static constexpr uint8_t kEcnOffset = 6;
static constexpr uint8_t kEcnMask = 3 << kEcnOffset;

static constexpr uint8_t kExtHdrDispatch = 0xe0;
static constexpr uint8_t kExtHdrDispatchMask = 0xf0;

Expand Down

0 comments on commit 2ce3d3b

Please sign in to comment.