[posix-trel] retry adding interface address if failed (#7047)

This commit enhances TREL UDP6 to retry adding the link-local
interface address until it's successful.
This commit is contained in:
Simon Lin
2021-09-30 09:22:45 -07:00
committed by GitHub
parent 72c2f630c9
commit 5e76bd50fa
+185 -9
View File
@@ -92,6 +92,13 @@ static int sSocket = -1;
static uint16_t sUdpPort = 0;
static otIp6Address sInterfaceAddress;
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
constexpr static uint64_t kAddInterfaceAddressTimeoutSecs = 10;
static int sNetlinkSocket = -1;
uint64_t sAddInterfaceAddressRetryTime = 0;
#endif
#if OPENTHREAD_CONFIG_LOG_PLATFORM
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_CRIT)
static const char *Ip6AddrToString(const void *aAddress)
@@ -144,7 +151,6 @@ exit:
static void UpdateUnicastAddress(const otIp6Address *aUnicastAddress, bool aToAdd)
{
int netlinkSocket;
int ret;
struct rtattr *rta;
@@ -155,9 +161,6 @@ static void UpdateUnicastAddress(const otIp6Address *aUnicastAddress, bool aToAd
char buf[64];
} request;
netlinkSocket = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock);
VerifyOrDie(netlinkSocket >= 0, OT_EXIT_ERROR_ERRNO);
memset(&request, 0, sizeof(request));
request.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
@@ -180,16 +183,15 @@ static void UpdateUnicastAddress(const otIp6Address *aUnicastAddress, bool aToAd
request.nh.nlmsg_len = NLMSG_ALIGN(request.nh.nlmsg_len) + rta->rta_len;
ret = send(netlinkSocket, &request, request.nh.nlmsg_len, 0);
ret = send(sNetlinkSocket, &request, request.nh.nlmsg_len, 0);
VerifyOrDie(ret != -1, OT_EXIT_ERROR_ERRNO);
close(netlinkSocket);
}
static void AddUnicastAddress(const otIp6Address *aUnicastAddress)
{
otLogDebgPlat("[trel] AddUnicastAddress(%s)", Ip6AddrToString(aUnicastAddress));
UpdateUnicastAddress(aUnicastAddress, /* aToAdd */ true);
sAddInterfaceAddressRetryTime = otPlatTimeGet() + kAddInterfaceAddressTimeoutSecs * US_PER_S;
}
static void RemoveUnicastAddress(const otIp6Address *aUnicastAddress)
@@ -198,6 +200,100 @@ static void RemoveUnicastAddress(const otIp6Address *aUnicastAddress)
UpdateUnicastAddress(aUnicastAddress, /* aToAdd */ false);
}
static void HandleAddInterfaceAddressTimeout(void)
{
otLogWarnPlat("[trel] Failed to add TREL interface address after %d seconds. Trying to add again.",
kAddInterfaceAddressTimeoutSecs);
RemoveUnicastAddress(&sInterfaceAddress);
AddUnicastAddress(&sInterfaceAddress);
sAddInterfaceAddressRetryTime = otPlatTimeGet() + kAddInterfaceAddressTimeoutSecs * US_PER_S;
}
static void ProcessNetifAddrEvent(struct nlmsghdr *aNetlinkMessage)
{
struct ifaddrmsg *ifaddr = reinterpret_cast<struct ifaddrmsg *>(NLMSG_DATA(aNetlinkMessage));
size_t rtaLength;
VerifyOrExit(ifaddr->ifa_index == static_cast<unsigned int>(sInterfaceIndex) && ifaddr->ifa_family == AF_INET6);
rtaLength = IFA_PAYLOAD(aNetlinkMessage);
for (struct rtattr *rta = reinterpret_cast<struct rtattr *>(IFA_RTA(ifaddr)); RTA_OK(rta, rtaLength);
rta = RTA_NEXT(rta, rtaLength))
{
if (rta->rta_type != IFA_ADDRESS)
{
continue;
}
if (memcmp(&sInterfaceAddress, RTA_DATA(rta), sizeof(sInterfaceAddress)) != 0)
{
continue;
}
if (aNetlinkMessage->nlmsg_type == RTM_NEWADDR)
{
otLogInfoPlat("[trel] Interface address added successfully.");
sAddInterfaceAddressRetryTime = 0;
}
else if (aNetlinkMessage->nlmsg_type == RTM_DELADDR)
{
if (sAddInterfaceAddressRetryTime == 0)
{
otLogWarnPlat("[trel] Interface address removed unexpectedly.");
sAddInterfaceAddressRetryTime = otPlatTimeGet() + kAddInterfaceAddressTimeoutSecs * US_PER_S;
}
}
}
exit:
return;
}
static void ReceiveNetlinkMessage(void)
{
const size_t kMaxNetLinkBufSize = 8192;
ssize_t len;
union
{
nlmsghdr mHeader;
uint8_t mBuffer[kMaxNetLinkBufSize];
} msgBuffer;
len = recv(sNetlinkSocket, msgBuffer.mBuffer, sizeof(msgBuffer.mBuffer), 0);
if (len < 0)
{
otLogCritPlat("failed to receive netlink message: %s", strerror(errno));
ExitNow();
}
for (struct nlmsghdr *header = &msgBuffer.mHeader; NLMSG_OK(header, static_cast<size_t>(len));
header = NLMSG_NEXT(header, len))
{
switch (header->nlmsg_type)
{
case RTM_NEWADDR:
case RTM_DELADDR:
ProcessNetifAddrEvent(header);
break;
case NLMSG_ERROR:
{
struct nlmsgerr *errMsg = reinterpret_cast<struct nlmsgerr *>(NLMSG_DATA(header));
if (errMsg->error != 0)
{
otLogWarnPlat("netlink NLMSG_ERROR response: seq=%u, error=%d", header->nlmsg_seq, errMsg->error);
}
}
default:
break;
}
}
exit:
return;
}
#else // OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
static void AddUnicastAddress(const otIp6Address *aUnicastAddress)
@@ -512,6 +608,23 @@ void otPlatTrelUdp6Init(otInstance *aInstance, const otIp6Address *aUnicastAddre
DieNow(OT_EXIT_ERROR_ERRNO);
}
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
{
struct sockaddr_nl addr;
sNetlinkSocket = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock);
VerifyOrDie(sNetlinkSocket >= 0, OT_EXIT_ERROR_ERRNO);
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV6_IFADDR;
VerifyOrDie(bind(sNetlinkSocket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) == 0,
OT_EXIT_ERROR_ERRNO);
}
#endif
RemoveUnicastAddress(aUnicastAddress);
AddUnicastAddress(aUnicastAddress);
sMulticastSocket = socket(AF_INET6, SOCK_DGRAM, 0);
@@ -695,6 +808,14 @@ void platformTrelDeinit(void)
RemoveUnicastAddress(&sInterfaceAddress);
}
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
if (sNetlinkSocket != -1)
{
close(sNetlinkSocket);
sNetlinkSocket = -1;
}
#endif
sInitialized = false;
sEnabled = false;
@@ -705,13 +826,17 @@ exit:
void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd, struct timeval *aTimeout)
{
OT_UNUSED_VARIABLE(aTimeout);
assert((aReadFdSet != NULL) && (aWriteFdSet != NULL) && (aMaxFd != NULL) && (aTimeout != NULL));
VerifyOrExit((sSocket >= 0) && (sMulticastSocket >= 0));
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
VerifyOrExit(sNetlinkSocket >= 0);
#endif
FD_SET(sMulticastSocket, aReadFdSet);
FD_SET(sSocket, aReadFdSet);
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
FD_SET(sNetlinkSocket, aReadFdSet);
#endif
if (sTxPacketQueueTail != NULL)
{
@@ -728,6 +853,35 @@ void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxF
*aMaxFd = sSocket;
}
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
if (*aMaxFd < sNetlinkSocket)
{
*aMaxFd = sNetlinkSocket;
}
if (sAddInterfaceAddressRetryTime > 0)
{
uint64_t now = otPlatTimeGet();
if (sAddInterfaceAddressRetryTime > now)
{
uint64_t remain = sAddInterfaceAddressRetryTime - now;
if (remain <
(static_cast<uint64_t>(aTimeout->tv_sec) * US_PER_S + static_cast<uint64_t>(aTimeout->tv_usec)))
{
aTimeout->tv_sec = static_cast<time_t>(remain / US_PER_S);
aTimeout->tv_usec = static_cast<suseconds_t>(remain % US_PER_S);
}
}
else
{
aTimeout->tv_sec = 0;
aTimeout->tv_usec = 0;
}
}
#endif
exit:
return;
}
@@ -735,6 +889,9 @@ exit:
void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
{
VerifyOrExit((sSocket >= 0) && (sMulticastSocket >= 0));
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
VerifyOrExit(sNetlinkSocket >= 0);
#endif
if (FD_ISSET(sSocket, aWriteFdSet))
{
@@ -751,6 +908,25 @@ void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
ReceivePacket(sMulticastSocket, aInstance);
}
#if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
if (FD_ISSET(sNetlinkSocket, aReadFdSet))
{
ReceiveNetlinkMessage();
}
if (sAddInterfaceAddressRetryTime > 0)
{
uint64_t now = otPlatTimeGet();
if (sAddInterfaceAddressRetryTime <= now)
{
sAddInterfaceAddressRetryTime = 0;
HandleAddInterfaceAddressTimeout();
}
}
#endif
exit:
return;
}