mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 10:47:46 +00:00
[posix] add netlink-based address monitoring to MdnsSocket (#11645)
This commit adds a netlink-based address monitoring strategy, `OT_POSIX_MDNS_ADDR_MONITOR_NETLINK`, to `Posix::MdnsSocket`. This is provided as an alternative to the periodic poll-based approach introduced in PR #11641. With this model, `MdnsSocket` reports the initial list of IPv4/IPv6 addresses on the infrastructure network interface. It then uses a `NETLINK_ROUTE` socket to listen for `RTM_NEWADDR` and `RTM_DELADDR` events, signaling any subsequent address changes to the mDNS module.
This commit is contained in:
@@ -41,11 +41,15 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/rtnetlink.h>
|
||||
#endif
|
||||
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "ip6_utils.hpp"
|
||||
#include "platform-posix.h"
|
||||
#include "utils.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
extern "C" otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
@@ -100,6 +104,10 @@ void MdnsSocket::Init(void)
|
||||
mMulticastIp4Address.mFields.m8[3] = 251;
|
||||
|
||||
memset(&mTxQueue, 0, sizeof(mTxQueue));
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK
|
||||
mNetlinkFd = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MdnsSocket::SetUp(void)
|
||||
@@ -154,6 +162,8 @@ void MdnsSocket::Update(otSysMainloopContext &aContext)
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
UpdateTimeout(aContext.mTimeout);
|
||||
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
UpdateNetlink(aContext);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
@@ -186,6 +196,8 @@ void MdnsSocket::Process(const otSysMainloopContext &aContext)
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
ProcessTimeout();
|
||||
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
ProcessNetlink(aContext);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
@@ -508,13 +520,13 @@ exit:
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Monitoring address on infra netif
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
|
||||
void MdnsSocket::ReportInfraIfAddresses(void)
|
||||
{
|
||||
struct ifaddrs *ifAddrs = nullptr;
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
mNextReportTime = otPlatTimeGet() + kAddrMonitorPeriod * OT_US_PER_MS;
|
||||
#endif
|
||||
|
||||
if (getifaddrs(&ifAddrs) < 0)
|
||||
{
|
||||
@@ -558,6 +570,12 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
|
||||
void MdnsSocket::StartAddressMonitoring(void) { ReportInfraIfAddresses(); }
|
||||
|
||||
void MdnsSocket::StopAddressMonitoring(void) {}
|
||||
|
||||
void MdnsSocket::UpdateTimeout(struct timeval &aTimeout)
|
||||
{
|
||||
uint64_t now = otPlatTimeGet();
|
||||
@@ -588,6 +606,165 @@ void MdnsSocket::ProcessTimeout(void)
|
||||
|
||||
#endif // (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
|
||||
void MdnsSocket::StartAddressMonitoring(void)
|
||||
{
|
||||
int rval;
|
||||
struct sockaddr_nl addr;
|
||||
|
||||
mNetlinkFd = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketBlock);
|
||||
VerifyOrDie(mNetlinkFd >= 0, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
|
||||
|
||||
rval = bind(mNetlinkFd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
|
||||
VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
ReportInfraIfAddresses();
|
||||
}
|
||||
|
||||
void MdnsSocket::StopAddressMonitoring(void)
|
||||
{
|
||||
if (mNetlinkFd >= 0)
|
||||
{
|
||||
close(mNetlinkFd);
|
||||
}
|
||||
|
||||
mNetlinkFd = -1;
|
||||
}
|
||||
|
||||
void MdnsSocket::UpdateNetlink(otSysMainloopContext &aContext) const
|
||||
{
|
||||
VerifyOrExit(mNetlinkFd >= 0);
|
||||
|
||||
FD_SET(mNetlinkFd, &aContext.mReadFdSet);
|
||||
|
||||
if (aContext.mMaxFd < mNetlinkFd)
|
||||
{
|
||||
aContext.mMaxFd = mNetlinkFd;
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MdnsSocket::ProcessNetlink(const otSysMainloopContext &aContext) const
|
||||
{
|
||||
static const size_t kBufSize = 8192;
|
||||
|
||||
union NetlinkMessage
|
||||
{
|
||||
struct nlmsghdr mHeader;
|
||||
uint8_t mBuffer[kBufSize];
|
||||
};
|
||||
|
||||
NetlinkMessage rcvMsg;
|
||||
ssize_t rval;
|
||||
size_t len;
|
||||
|
||||
VerifyOrExit(mNetlinkFd >= 0);
|
||||
|
||||
VerifyOrExit(FD_ISSET(mNetlinkFd, &aContext.mReadFdSet));
|
||||
|
||||
rval = recv(mNetlinkFd, rcvMsg.mBuffer, sizeof(rcvMsg.mBuffer), 0);
|
||||
|
||||
if (rval < 0)
|
||||
{
|
||||
LogCrit("Failed to receive netlink message: %s", strerror(errno));
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(static_cast<size_t>(rval) <= sizeof(rcvMsg.mBuffer));
|
||||
|
||||
len = static_cast<size_t>(rval);
|
||||
|
||||
VerifyOrExit(len >= sizeof(nlmsghdr));
|
||||
|
||||
for (struct nlmsghdr *msg = &rcvMsg.mHeader; NLMSG_OK(msg, len); msg = NLMSG_NEXT(msg, len))
|
||||
{
|
||||
switch (msg->nlmsg_type)
|
||||
{
|
||||
case RTM_NEWADDR:
|
||||
case RTM_DELADDR:
|
||||
ProcessNetlinkAddrEvent(msg);
|
||||
break;
|
||||
case NLMSG_ERROR:
|
||||
LogWarn("netlink error:%d", reinterpret_cast<struct nlmsgerr *>(NLMSG_DATA(msg))->error);
|
||||
break;
|
||||
case NLMSG_DONE:
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MdnsSocket::ProcessNetlinkAddrEvent(void *aNetlinkMsg) const
|
||||
{
|
||||
struct nlmsghdr *msg = static_cast<struct nlmsghdr *>(aNetlinkMsg);
|
||||
struct ifaddrmsg *addrmsg = reinterpret_cast<struct ifaddrmsg *>(NLMSG_DATA(msg));
|
||||
bool added = (msg->nlmsg_type == RTM_NEWADDR);
|
||||
size_t len;
|
||||
struct rtattr *rta;
|
||||
otIp6Address ip6Addr;
|
||||
otIp4Address ip4Addr;
|
||||
|
||||
VerifyOrExit(addrmsg->ifa_index == mInfraIfIndex);
|
||||
|
||||
switch (addrmsg->ifa_family)
|
||||
{
|
||||
case AF_INET6:
|
||||
case AF_INET:
|
||||
break;
|
||||
default:
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
len = IFA_PAYLOAD(msg);
|
||||
|
||||
for (rta = reinterpret_cast<struct rtattr *>(IFA_RTA(addrmsg)); RTA_OK(rta, len); rta = RTA_NEXT(rta, len))
|
||||
{
|
||||
switch (rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
if (addrmsg->ifa_family == AF_INET6)
|
||||
{
|
||||
if (RTA_PAYLOAD(rta) < sizeof(otIp6Address))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ReadIp6AddressFrom(RTA_DATA(rta), ip6Addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RTA_PAYLOAD(rta) < sizeof(otIp4Address))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(&ip4Addr, RTA_DATA(rta), sizeof(otIp4Address));
|
||||
otIp4ToIp4MappedIp6Address(&ip4Addr, &ip6Addr);
|
||||
}
|
||||
|
||||
otPlatMdnsHandleHostAddressEvent(mInstance, &ip6Addr, added, mInfraIfIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Socket helpers
|
||||
|
||||
|
||||
@@ -43,15 +43,29 @@
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* Use `getifaddrs()` to enumerate addresses periodically and report to the OpenThread mDNS module.
|
||||
*
|
||||
* The polling interval is configured by `OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR_PERIOD`.
|
||||
*/
|
||||
#define OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC 1
|
||||
|
||||
/**
|
||||
* Use NetLink to monitor IPv4 and IPv6 address changes and report to the OpenThread mDNS module.
|
||||
*/
|
||||
#define OT_POSIX_MDNS_ADDR_MONITOR_NETLINK 2
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
#error "The `OT_POSIX_MDNS_ADDR_MONITOR_NETLINK` is not supported yet"
|
||||
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR != OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR != OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC) && \
|
||||
(OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR != OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
#error "The `OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR` is not valid. MUST be one of `OT_POSIX_MDNS_ADDR_MONITOR_*`"
|
||||
#endif
|
||||
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
#ifndef __linux__
|
||||
#error "The `OT_POSIX_MDNS_ADDR_MONITOR_NETLINK` requires linux platform"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Implements platform mDNS socket APIs.
|
||||
*/
|
||||
@@ -140,13 +154,16 @@ private:
|
||||
void ClearTxQueue(void);
|
||||
void SendQueuedMessages(MsgType aMsgType);
|
||||
void ReceiveMessage(MsgType aMsgType);
|
||||
|
||||
void StartAddressMonitoring(void);
|
||||
void StopAddressMonitoring(void);
|
||||
void ReportInfraIfAddresses(void);
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
void StartAddressMonitoring(void) { ReportInfraIfAddresses(); }
|
||||
void StopAddressMonitoring(void) {}
|
||||
void ReportInfraIfAddresses(void);
|
||||
void UpdateTimeout(struct timeval &aTimeout);
|
||||
void ProcessTimeout(void);
|
||||
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
void UpdateNetlink(otSysMainloopContext &aContext) const;
|
||||
void ProcessNetlink(const otSysMainloopContext &aContext) const;
|
||||
void ProcessNetlinkAddrEvent(void *aNetlinkMsg) const;
|
||||
#endif
|
||||
|
||||
otError OpenIp4Socket(uint32_t aInfraIfIndex);
|
||||
@@ -184,6 +201,9 @@ private:
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
|
||||
uint64_t mNextReportTime;
|
||||
#endif
|
||||
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
|
||||
int mNetlinkFd;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
|
||||
@@ -464,8 +464,12 @@
|
||||
* `posix/platform/mdns_socket.h`.
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR
|
||||
#ifdef __linux__
|
||||
#define OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR OT_POSIX_MDNS_ADDR_MONITOR_NETLINK
|
||||
#else
|
||||
#define OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR_PERIOD
|
||||
|
||||
Reference in New Issue
Block a user