[posix] drain TREL UDP packets per mainloop iteration (#13324)

This commit updates `ReceivePacket()` in the POSIX TREL platform
implementation (`trel.cpp`) to drain all available UDP datagrams
in a loop whenever the TREL socket (`sSocket`) is readable.

Previously, `ReceivePacket()` called `recvfrom()` exactly once per
`platformTrelProcess()` iteration. When multiple TREL packets (such as
an `AddressNotify` immediately followed by MLE or UDP traffic) arrived
in rapid succession, only the first datagram was read, leaving the
remaining packets buffered in the kernel until subsequent mainloop
cycles.

If an interleaved packet on another interface (such as `NcpSpinel` on
15.4) was processed before the next mainloop iteration, the neighbor's
`mLastRxFragmentTag` advanced, causing the delayed TREL datagram
(`AddressNotify`) to be dropped as `kErrorDuplicated` due to
`!neighbor->IsLastRxFragmentTagAfter(tag)`.

By looping over `recvfrom()` until `EAGAIN` or `EWOULDBLOCK` is returned
(`sSocket` is non-blocking), all queued TREL packets are read and
processed immediately in receipt order. A loop budget
(`kMaxRxPacketsPerIteration = 64`) is included to prevent mainloop
starvation during high-rate UDP floods. Additionally, a typo in the
buffer overflow check (`sizeof(sRxPacketLength)` vs
`sizeof(sRxPacketBuffer)`) is corrected.
This commit is contained in:
Jonathan Hui
2026-07-10 06:51:15 -07:00
committed by GitHub
parent 6526606739
commit a4881b949c
+37 -24
View File
@@ -276,37 +276,50 @@ exit:
static void ReceivePacket(int aSocket, otInstance *aInstance)
{
struct sockaddr_in6 sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
ssize_t ret;
const uint16_t kMaxRxPacketsPerIteration = 64;
memset(&sockAddr, 0, sizeof(sockAddr));
ret = recvfrom(aSocket, (char *)sRxPacketBuffer, sizeof(sRxPacketBuffer), 0, (struct sockaddr *)&sockAddr,
&sockAddrLen);
VerifyOrDie(ret >= 0, OT_EXIT_ERROR_ERRNO);
sRxPacketLength = (uint16_t)(ret);
if (sRxPacketLength > sizeof(sRxPacketBuffer))
for (uint16_t i = 0; i < kMaxRxPacketsPerIteration;)
{
sRxPacketLength = sizeof(sRxPacketLength);
}
struct sockaddr_in6 sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
ssize_t ret;
LogDebg("ReceivePacket() - received from [%s]:%d, id:%d, pkt:%s", Ip6AddrToString(&sockAddr.sin6_addr),
ntohs(sockAddr.sin6_port), sockAddr.sin6_scope_id, BufferToString(sRxPacketBuffer, sRxPacketLength));
memset(&sockAddr, 0, sizeof(sockAddr));
if (sEnabled)
{
otSockAddr senderAddr;
ret = recvfrom(aSocket, (char *)sRxPacketBuffer, sizeof(sRxPacketBuffer), 0, (struct sockaddr *)&sockAddr,
&sockAddrLen);
if (ret < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
break;
}
if (errno == EINTR)
{
continue;
}
VerifyOrDie(false, OT_EXIT_ERROR_ERRNO);
}
++sCounters.mRxPackets;
sCounters.mRxBytes += sRxPacketLength;
sRxPacketLength = (uint16_t)(ret);
memcpy(&senderAddr.mAddress, &sockAddr.sin6_addr, sizeof(otIp6Address));
senderAddr.mPort = ntohs(sockAddr.sin6_port);
LogDebg("ReceivePacket() - received from [%s]:%d, id:%d, pkt:%s", Ip6AddrToString(&sockAddr.sin6_addr),
ntohs(sockAddr.sin6_port), sockAddr.sin6_scope_id, BufferToString(sRxPacketBuffer, sRxPacketLength));
otPlatTrelHandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength, &senderAddr);
if (sEnabled)
{
otSockAddr senderAddr;
++sCounters.mRxPackets;
sCounters.mRxBytes += sRxPacketLength;
memcpy(&senderAddr.mAddress, &sockAddr.sin6_addr, sizeof(otIp6Address));
senderAddr.mPort = ntohs(sockAddr.sin6_port);
otPlatTrelHandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength, &senderAddr);
}
i++;
}
}