Skip to content

Commit 6f434ce

Browse files
authored
[posix] add netlink-based address monitoring to MdnsSocket (openthread#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 openthread#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.
1 parent a495a22 commit 6f434ce

3 files changed

Lines changed: 210 additions & 9 deletions

File tree

src/posix/platform/mdns_socket.cpp

Lines changed: 179 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@
4141
#include <sys/socket.h>
4242
#include <sys/types.h>
4343
#include <unistd.h>
44+
#ifdef __linux__
45+
#include <linux/rtnetlink.h>
46+
#endif
4447

4548
#include <openthread/platform/time.h>
4649

4750
#include "ip6_utils.hpp"
4851
#include "platform-posix.h"
52+
#include "utils.hpp"
4953
#include "common/code_utils.hpp"
5054

5155
extern "C" otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
@@ -100,6 +104,10 @@ void MdnsSocket::Init(void)
100104
mMulticastIp4Address.mFields.m8[3] = 251;
101105

102106
memset(&mTxQueue, 0, sizeof(mTxQueue));
107+
108+
#if OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK
109+
mNetlinkFd = -1;
110+
#endif
103111
}
104112

105113
void MdnsSocket::SetUp(void)
@@ -154,6 +162,8 @@ void MdnsSocket::Update(otSysMainloopContext &aContext)
154162

155163
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
156164
UpdateTimeout(aContext.mTimeout);
165+
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
166+
UpdateNetlink(aContext);
157167
#endif
158168

159169
exit:
@@ -186,6 +196,8 @@ void MdnsSocket::Process(const otSysMainloopContext &aContext)
186196

187197
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
188198
ProcessTimeout();
199+
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
200+
ProcessNetlink(aContext);
189201
#endif
190202

191203
exit:
@@ -508,13 +520,13 @@ void MdnsSocket::ReceiveMessage(MsgType aMsgType)
508520
//---------------------------------------------------------------------------------------------------------------------
509521
// Monitoring address on infra netif
510522

511-
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
512-
513523
void MdnsSocket::ReportInfraIfAddresses(void)
514524
{
515525
struct ifaddrs *ifAddrs = nullptr;
516526

527+
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
517528
mNextReportTime = otPlatTimeGet() + kAddrMonitorPeriod * OT_US_PER_MS;
529+
#endif
518530

519531
if (getifaddrs(&ifAddrs) < 0)
520532
{
@@ -558,6 +570,12 @@ void MdnsSocket::ReportInfraIfAddresses(void)
558570
}
559571
}
560572

573+
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
574+
575+
void MdnsSocket::StartAddressMonitoring(void) { ReportInfraIfAddresses(); }
576+
577+
void MdnsSocket::StopAddressMonitoring(void) {}
578+
561579
void MdnsSocket::UpdateTimeout(struct timeval &aTimeout)
562580
{
563581
uint64_t now = otPlatTimeGet();
@@ -588,6 +606,165 @@ void MdnsSocket::ProcessTimeout(void)
588606

589607
#endif // (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
590608

609+
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
610+
611+
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
612+
613+
void MdnsSocket::StartAddressMonitoring(void)
614+
{
615+
int rval;
616+
struct sockaddr_nl addr;
617+
618+
mNetlinkFd = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketBlock);
619+
VerifyOrDie(mNetlinkFd >= 0, OT_EXIT_ERROR_ERRNO);
620+
621+
memset(&addr, 0, sizeof(addr));
622+
addr.nl_family = AF_NETLINK;
623+
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
624+
625+
rval = bind(mNetlinkFd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
626+
VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO);
627+
628+
ReportInfraIfAddresses();
629+
}
630+
631+
void MdnsSocket::StopAddressMonitoring(void)
632+
{
633+
if (mNetlinkFd >= 0)
634+
{
635+
close(mNetlinkFd);
636+
}
637+
638+
mNetlinkFd = -1;
639+
}
640+
641+
void MdnsSocket::UpdateNetlink(otSysMainloopContext &aContext) const
642+
{
643+
VerifyOrExit(mNetlinkFd >= 0);
644+
645+
FD_SET(mNetlinkFd, &aContext.mReadFdSet);
646+
647+
if (aContext.mMaxFd < mNetlinkFd)
648+
{
649+
aContext.mMaxFd = mNetlinkFd;
650+
}
651+
652+
exit:
653+
return;
654+
}
655+
656+
void MdnsSocket::ProcessNetlink(const otSysMainloopContext &aContext) const
657+
{
658+
static const size_t kBufSize = 8192;
659+
660+
union NetlinkMessage
661+
{
662+
struct nlmsghdr mHeader;
663+
uint8_t mBuffer[kBufSize];
664+
};
665+
666+
NetlinkMessage rcvMsg;
667+
ssize_t rval;
668+
size_t len;
669+
670+
VerifyOrExit(mNetlinkFd >= 0);
671+
672+
VerifyOrExit(FD_ISSET(mNetlinkFd, &aContext.mReadFdSet));
673+
674+
rval = recv(mNetlinkFd, rcvMsg.mBuffer, sizeof(rcvMsg.mBuffer), 0);
675+
676+
if (rval < 0)
677+
{
678+
LogCrit("Failed to receive netlink message: %s", strerror(errno));
679+
ExitNow();
680+
}
681+
682+
VerifyOrExit(static_cast<size_t>(rval) <= sizeof(rcvMsg.mBuffer));
683+
684+
len = static_cast<size_t>(rval);
685+
686+
VerifyOrExit(len >= sizeof(nlmsghdr));
687+
688+
for (struct nlmsghdr *msg = &rcvMsg.mHeader; NLMSG_OK(msg, len); msg = NLMSG_NEXT(msg, len))
689+
{
690+
switch (msg->nlmsg_type)
691+
{
692+
case RTM_NEWADDR:
693+
case RTM_DELADDR:
694+
ProcessNetlinkAddrEvent(msg);
695+
break;
696+
case NLMSG_ERROR:
697+
LogWarn("netlink error:%d", reinterpret_cast<struct nlmsgerr *>(NLMSG_DATA(msg))->error);
698+
break;
699+
case NLMSG_DONE:
700+
ExitNow();
701+
}
702+
}
703+
704+
exit:
705+
return;
706+
}
707+
708+
void MdnsSocket::ProcessNetlinkAddrEvent(void *aNetlinkMsg) const
709+
{
710+
struct nlmsghdr *msg = static_cast<struct nlmsghdr *>(aNetlinkMsg);
711+
struct ifaddrmsg *addrmsg = reinterpret_cast<struct ifaddrmsg *>(NLMSG_DATA(msg));
712+
bool added = (msg->nlmsg_type == RTM_NEWADDR);
713+
size_t len;
714+
struct rtattr *rta;
715+
otIp6Address ip6Addr;
716+
otIp4Address ip4Addr;
717+
718+
VerifyOrExit(addrmsg->ifa_index == mInfraIfIndex);
719+
720+
switch (addrmsg->ifa_family)
721+
{
722+
case AF_INET6:
723+
case AF_INET:
724+
break;
725+
default:
726+
ExitNow();
727+
}
728+
729+
len = IFA_PAYLOAD(msg);
730+
731+
for (rta = reinterpret_cast<struct rtattr *>(IFA_RTA(addrmsg)); RTA_OK(rta, len); rta = RTA_NEXT(rta, len))
732+
{
733+
switch (rta->rta_type)
734+
{
735+
case IFA_ADDRESS:
736+
case IFA_LOCAL:
737+
if (addrmsg->ifa_family == AF_INET6)
738+
{
739+
if (RTA_PAYLOAD(rta) < sizeof(otIp6Address))
740+
{
741+
continue;
742+
}
743+
744+
ReadIp6AddressFrom(RTA_DATA(rta), ip6Addr);
745+
}
746+
else
747+
{
748+
if (RTA_PAYLOAD(rta) < sizeof(otIp4Address))
749+
{
750+
continue;
751+
}
752+
753+
memcpy(&ip4Addr, RTA_DATA(rta), sizeof(otIp4Address));
754+
otIp4ToIp4MappedIp6Address(&ip4Addr, &ip6Addr);
755+
}
756+
757+
otPlatMdnsHandleHostAddressEvent(mInstance, &ip6Addr, added, mInfraIfIndex);
758+
break;
759+
}
760+
}
761+
762+
exit:
763+
return;
764+
}
765+
766+
#endif // (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
767+
591768
//---------------------------------------------------------------------------------------------------------------------
592769
// Socket helpers
593770

src/posix/platform/mdns_socket.hpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,29 @@
4343
namespace ot {
4444
namespace Posix {
4545

46+
/**
47+
* Use `getifaddrs()` to enumerate addresses periodically and report to the OpenThread mDNS module.
48+
*
49+
* The polling interval is configured by `OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR_PERIOD`.
50+
*/
4651
#define OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC 1
52+
53+
/**
54+
* Use NetLink to monitor IPv4 and IPv6 address changes and report to the OpenThread mDNS module.
55+
*/
4756
#define OT_POSIX_MDNS_ADDR_MONITOR_NETLINK 2
4857

49-
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
50-
#error "The `OT_POSIX_MDNS_ADDR_MONITOR_NETLINK` is not supported yet"
51-
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR != OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
58+
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR != OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC) && \
59+
(OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR != OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
5260
#error "The `OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR` is not valid. MUST be one of `OT_POSIX_MDNS_ADDR_MONITOR_*`"
5361
#endif
5462

63+
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
64+
#ifndef __linux__
65+
#error "The `OT_POSIX_MDNS_ADDR_MONITOR_NETLINK` requires linux platform"
66+
#endif
67+
#endif
68+
5569
/**
5670
* Implements platform mDNS socket APIs.
5771
*/
@@ -140,13 +154,16 @@ class MdnsSocket : public Mainloop::Source, public Logger<MdnsSocket>, private N
140154
void ClearTxQueue(void);
141155
void SendQueuedMessages(MsgType aMsgType);
142156
void ReceiveMessage(MsgType aMsgType);
143-
157+
void StartAddressMonitoring(void);
158+
void StopAddressMonitoring(void);
159+
void ReportInfraIfAddresses(void);
144160
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
145-
void StartAddressMonitoring(void) { ReportInfraIfAddresses(); }
146-
void StopAddressMonitoring(void) {}
147-
void ReportInfraIfAddresses(void);
148161
void UpdateTimeout(struct timeval &aTimeout);
149162
void ProcessTimeout(void);
163+
#elif (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
164+
void UpdateNetlink(otSysMainloopContext &aContext) const;
165+
void ProcessNetlink(const otSysMainloopContext &aContext) const;
166+
void ProcessNetlinkAddrEvent(void *aNetlinkMsg) const;
150167
#endif
151168

152169
otError OpenIp4Socket(uint32_t aInfraIfIndex);
@@ -184,6 +201,9 @@ class MdnsSocket : public Mainloop::Source, public Logger<MdnsSocket>, private N
184201
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC)
185202
uint64_t mNextReportTime;
186203
#endif
204+
#if (OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR == OT_POSIX_MDNS_ADDR_MONITOR_NETLINK)
205+
int mNetlinkFd;
206+
#endif
187207
};
188208

189209
} // namespace Posix

src/posix/platform/openthread-posix-config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,12 @@
464464
* `posix/platform/mdns_socket.h`.
465465
*/
466466
#ifndef OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR
467+
#ifdef __linux__
468+
#define OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR OT_POSIX_MDNS_ADDR_MONITOR_NETLINK
469+
#else
467470
#define OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR OT_POSIX_MDNS_ADDR_MONITOR_PERIODIC
468471
#endif
472+
#endif
469473

470474
/**
471475
* @def OPENTHREAD_POSIX_CONFIG_MDNS_ADDR_MONITOR_PERIOD

0 commit comments

Comments
 (0)