[mdns] alternate platform API for signaling local address changes (#11394)

This commit introduces an alternate mechanism for the platform layer
to signal local host address changes to the OpenThread mDNS module.

The existing approach, where the platform invokes
`otPlatMdnsHandleHostAddressEvent()` for each added or removed
address, remains supported.

The new approach allows the platform to call the newly added
`otPlatMdnsHandleHostAddressRemoveAll()` callback once, immediately
followed by invoking `otPlatMdnsHandleHostAddressEvent` for every
currently assigned IPv4 and IPv6 address on the interface.

These two approaches offer flexibility for platforms with varying
capabilities accommodating different operating systems and network
stacks. Some network stacks may provide mechanisms to identify the
added or removed addresses, while others may only provide the new
list upon a change.

The `test_mdns` unit test is updated to validate this newly added
mechanism.
This commit is contained in:
Abtin Keshavarzian
2025-04-16 08:17:45 -06:00
committed by GitHub
parent d9d5b2e2c6
commit 247b353e16
5 changed files with 175 additions and 6 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (494)
#define OPENTHREAD_API_VERSION (495)
/**
* @addtogroup api-instance
+21 -4
View File
@@ -161,18 +161,25 @@ extern void otPlatMdnsHandleReceive(otInstance *aInstance,
/**
* Callback to notify OpenThread mDNS module of host address changes.
*
* When `otPlatMdnsSetListeningEnabled()` enables mDNS listening on an @p aInfraIfIndex, the platform MUST monitor and
* When `otPlatMdnsSetListeningEnabled()` enables mDNS listening on an `aInfraIfIndex`, the platform MUST monitor and
* report ALL IPv4 and IPv6 addresses assigned to this network interface.
*
* When mDNS is enabled:
* - The platform MUST retrieve ALL currently assigned IPv4 and IPv6 addresses on the specified interface.
* - For each retrieved address, the platform MUST call `otPlatMdnsHandleHostAddressEvent()`.
* - For each retrieved address, the platform MUST call `otPlatMdnsHandleHostAddressEvent()` to add the address.
* - The IPv4 addresses are represented using IPv4-mapped IPv6 format.
*
* Ongoing monitoring (while enabled):
* - The platform MUST continuously monitor the specified interface for address changes.
* - If any addresses are added or removed, the platform MUST call this callback for each affected address, indicating
* the change (addition or removal using @p aAdded).
* - When the address list changes, the platform MUST notify the OpenThread stack of the change using one of the
* following methods:
* A. Call this callback for each affected address, indicating the change (addition or removal using @p aAdded).
* B. Alternatively, call the `otPlatMdnsHandleHostAddressRemoveAll()` callback once, immediately followed by
* invoking this callback for every currently assigned IPv4 and IPv6 address on the interface adding them
* (@p aAdded set to `TRUE`), providing the completed updated address list.
* - These two approaches offer flexibility for platforms with varying capabilities, such as different operating
* systems and network stacks. Some network stacks may provide mechanisms to identify the added or removed
* addresses, while others may only provide the new list upon a change.
*
* When mDNS is disabled:
* - The platform MUST cease monitoring for address changes on the interface.
@@ -199,6 +206,16 @@ extern void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
bool aAdded,
uint32_t aInfraIfIndex);
/**
* Callback to notify OpenThread mDNS module to remove all previously added host IPv4 and IPv6 addresses.
*
* See documentation of `otPlatMdnsHandleHostAddressEvent()` for how this callback MUST be used.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aInfraIfIndex The interface index.
*/
extern void otPlatMdnsHandleHostAddressRemoveAll(otInstance *aInstance, uint32_t aInfraIfIndex);
/**
* @}
*/
+31
View File
@@ -63,6 +63,11 @@ extern "C" void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
AsCoreType(aInstance).Get<Core>().HandleHostAddressEvent(AsCoreType(aAddress), aAdded, aInfraIfIndex);
}
extern "C" void otPlatMdnsHandleHostAddressRemoveAll(otInstance *aInstance, uint32_t aInfraIfIndex)
{
AsCoreType(aInstance).Get<Core>().HandleHostAddressRemoveAll(aInfraIfIndex);
}
//----------------------------------------------------------------------------------------------------------------------
// Core
@@ -284,6 +289,8 @@ void Core::HandleHostAddressEvent(const Ip6::Address &aAddress, bool aAdded, uin
mLocalHost.HandleAddressEvent(aAddress, aAdded, aInfraIfIndex);
}
void Core::HandleHostAddressRemoveAll(uint32_t aInfraIfIndex) { mLocalHost.HandleAddressRemoveAll(aInfraIfIndex); }
void Core::HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress)
{
OwnedPtr<Message> messagePtr(&aMessage);
@@ -1593,6 +1600,30 @@ exit:
return;
}
void Core::LocalHost::HandleAddressRemoveAll(uint32_t aInfraIfIndex)
{
VerifyOrExit(Get<Core>().mIsEnabled);
VerifyOrExit(aInfraIfIndex == Get<Core>().mInfraIfIndex);
mAddrEvents.Clear();
mEventTimer.Stop();
LogInfo("Host address event: remove all");
for (const Ip6::Address &address : mIp4Addresses)
{
HandleAddressEvent(address, /* aAdded */ false, aInfraIfIndex);
}
for (const Ip6::Address &address : mIp6Addresses)
{
HandleAddressEvent(address, /* aAdded */ false, aInfraIfIndex);
}
exit:
return;
}
void Core::LocalHost::HandleEventTimer(void)
{
// Process all saved `AddrEvents` and update IPv4 and IPv6
+6
View File
@@ -82,6 +82,8 @@ extern "C" void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
bool aAdded,
uint32_t aInfraIfIndex);
extern "C" void otPlatMdnsHandleHostAddressRemoveAll(otInstance *aInstance, uint32_t aInfraIfIndex);
/**
* Implements Multicast DNS (mDNS) core.
*/
@@ -99,6 +101,8 @@ class Core : public InstanceLocator, private NonCopyable
bool aAdded,
uint32_t aInfraIfIndex);
friend void otPlatMdnsHandleHostAddressRemoveAll(otInstance *aInstance, uint32_t aInfraIfIndex);
public:
/**
* Initializes a `Core` instance.
@@ -1144,6 +1148,7 @@ private:
const AddressArray &GetIp4Addresses(void) const { return mIp4Addresses; }
const AddressArray &GetIp6Addresses(void) const { return mIp6Addresses; }
void HandleAddressEvent(const Ip6::Address &aAddress, bool aAdded, uint32_t aInfraIfIndex);
void HandleAddressRemoveAll(uint32_t aInfraIfIndex);
void HandleEventTimer(void);
void ClearAddresses(void);
@@ -2204,6 +2209,7 @@ private:
void AfterInstanceInit(void);
void HandleHostAddressEvent(const Ip6::Address &aAddress, bool aAdded, uint32_t aInfraIfIndex);
void HandleHostAddressRemoveAll(uint32_t aInfraIfIndex);
void InvokeConflictCallback(const char *aName, const char *aServiceType);
void HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress);
void AddPassiveSrvTxtCache(const char *aServiceInstance, const char *aServiceType);
+116 -1
View File
@@ -2321,7 +2321,7 @@ void TestLocalHost(void)
localHost.mIp6Addrs.Remove(ip6Address);
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
// Add and then remove the same address quickly
// Add then remove the same address quickly
// It should not be included in the announcements.
SuccessOrQuit(ip6Address.FromString("fd00:cafe::333"));
@@ -2387,6 +2387,121 @@ void TestLocalHost(void)
sDnsMessages.Clear();
}
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Signal removal of all host addresses and add them all back");
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
{
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
}
for (Ip4::Address &ip4Addr : localHost.mIp4Addrs)
{
ip6Address.SetToIp4Mapped(ip4Addr);
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
}
Log("Validate that there are no announcements");
sDnsMessages.Clear();
AdvanceTime(10 * 1000);
VerifyOrQuit(sDnsMessages.IsEmpty());
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Signal removal of all addr, add them all back with one extra IPv6 and one extra IPv4 addr");
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
SuccessOrQuit(ip6Address.FromString("fd00:cafe::5555"));
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
{
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
}
SuccessOrQuit(ip4Address.FromString("200.0.64.13"));
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
for (Ip4::Address &ip4Addr : localHost.mIp4Addrs)
{
ip6Address.SetToIp4Mapped(ip4Addr);
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
}
Log("Validate the announcements");
sDnsMessages.Clear();
AdvanceTime(5);
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
{
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
VerifyOrQuit(!sDnsMessages.IsEmpty());
dnsMsg = sDnsMessages.GetHead();
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 8, /* Auth */ 0, /* Addnl */ 1);
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
sDnsMessages.Clear();
}
AdvanceTime(10 * 1000);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Signal removal of all addresses and add some back");
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
{
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
}
Log("Before previous events are processed, signal removal of all addresses again");
Log("And add them all back without the recently added extra IPv6 and IPv4 addresses");
AdvanceTime(1);
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
otPlatMdnsHandleHostAddressRemoveAll(sInstance, kInfraIfIndex);
localHost.mIp6Addrs.PopBack();
localHost.mIp4Addrs.PopBack();
for (Ip6::Address &ip6Addr : localHost.mIp6Addrs)
{
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Addr, /* aAdded */ true, kInfraIfIndex);
}
for (Ip4::Address &ip4Addr : localHost.mIp4Addrs)
{
ip6Address.SetToIp4Mapped(ip4Addr);
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
}
Log("Validate the announcements");
sDnsMessages.Clear();
AdvanceTime(5);
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
{
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
VerifyOrQuit(!sDnsMessages.IsEmpty());
dnsMsg = sDnsMessages.GetHead();
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 6, /* Auth */ 0, /* Addnl */ 1);
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
sDnsMessages.Clear();
}
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Signal all host IPv4 addresses are removed, validate goodbye announcements");