[netdata] adding NetworkData::Publisher (#6768)

This commit implements a new feature "Network Data Publisher" which
provides mechanisms to limit the number of similar entries (service
and/or prefix) in the Thread Network Data by monitoring the Network
Data and managing if or when to add or remove entries. This feature is
enabled using `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE` config, or
`NETDATA_PUBLISHER` in autoconf, or `OT_NETDATA_PUBLISHER` cmake
option.

This commit adds support for publishing DNS/SRP anycast/unicast
service, on-mesh prefix, and external route prefix entries.

When there is a request to publish an entry, the `Publisher` monitors
the Network Data and counts the number of similar entries. If there
are fewer entries than a desired target number, the entry is added
after a short random delay.

If there are too many similar entries, `Publisher` starts the process
of removing its own entry (again after some random wait time). When
removing entries, certain entries are preferred over others (e.g., an
entry from a router over one from an end-device or if they are from
the same type of node, the one with smaller RLOC16). If `Publisher`
determines that its own entry is a preferred one, it adds an extra
wait time before removing its entry. This gives higher chance for a
non-preferred entry from another device to be removed before removing
a preferred entry which helps towards quicker convergence of the
process to the desired number of entries.

On-mesh prefix and external route entries have a "preference" field.
When publishing such an entry, a matching entry in the network data is
counted only if its preference is same or higher than the entry's
preference. This ensures that a device with a higher preference entry
publishes its entry even when there are many lower preference similar
entries in the network data (potentially causing a lower preference
entry to be removed).

This commit also adds `test_netdata_publisher.py` to verify the
behavior of the `Publisher`.
This commit is contained in:
Abtin Keshavarzian
2021-08-10 22:32:33 -07:00
committed by GitHub
parent 71bc37bbc3
commit 2e625bfe39
50 changed files with 3072 additions and 146 deletions
+2
View File
@@ -190,6 +190,7 @@ LOCAL_SRC_FILES := \
src/core/api/message_api.cpp \
src/core/api/multi_radio_api.cpp \
src/core/api/netdata_api.cpp \
src/core/api/netdata_publisher_api.cpp \
src/core/api/netdiag_api.cpp \
src/core/api/network_time_api.cpp \
src/core/api/ping_sender_api.cpp \
@@ -322,6 +323,7 @@ LOCAL_SRC_FILES := \
src/core/thread/network_data_leader_ftd.cpp \
src/core/thread/network_data_local.cpp \
src/core/thread/network_data_notifier.cpp \
src/core/thread/network_data_publisher.cpp \
src/core/thread/network_data_service.cpp \
src/core/thread/network_data_tlvs.cpp \
src/core/thread/network_data_types.cpp \
+5
View File
@@ -269,6 +269,11 @@ if(OT_NEIGHBOR_DISCOVERY_AGENT)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT_ENABLE=1")
endif()
option(OT_NETDATA_PUBLISHER "enable Thread Network Data publisher")
if(OT_NETDATA_PUBLISHER)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE=1")
endif()
option(OT_PING_SENDER "enable ping sender support" ${OT_APP_CLI})
if(OT_PING_SENDER)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_PING_SENDER_ENABLE=1")
+1
View File
@@ -60,6 +60,7 @@ LINK_RAW ?= 1
MAC_FILTER ?= 1
MTD_NETDIAG ?= 1
NEIGHBOR_DISCOVERY_AGENT ?= 1
NETDATA_PUBLISHER ?= 1
PING_SENDER ?= 1
REFERENCE_DEVICE ?= 1
SERVICE ?= 1
+1
View File
@@ -48,6 +48,7 @@ This page lists the available common switches with description. Unless stated ot
| MLR | OT_MLR | Enables Multicast Listener Registration feature for Thread 1.2. |
| MTD_NETDIAG | OT_MTD_NETDIAG | Enables the TMF network diagnostics on MTDs. |
| MULTIPLE_INSTANCE | OT_MULTIPLE_INSTANCE | Enables multiple OpenThread instances. |
| NETDATA_PUBLISHER | OT_NETDATA_PUBLISHER | Enables support for Thread Network Data publisher. |
| PING_SENDER | OT_PING_SENDER | Enables support for ping sender. |
| OTNS | OT_OTNS | Enables support for [OpenThread Network Simulator](https://github.com/openthread/ot-ns). Enable this switch if you are building OpenThread for OpenThread Network Simulator. |
| PLATFORM_UDP | OT_PLATFORM_UDP | Enables platform UDP support. |
+5
View File
@@ -70,6 +70,7 @@ MLR ?= 0
MTD_NETDIAG ?= 0
MULTIPLE_INSTANCE ?= 0
NEIGHBOR_DISCOVERY_AGENT ?= 0
NETDATA_PUBLISHER ?= 0
OTNS ?= 0
PING_SENDER ?= 1
PLATFORM_UDP ?= 0
@@ -265,6 +266,10 @@ ifeq ($(NEIGHBOR_DISCOVERY_AGENT),1)
COMMONCFLAGS += -DOPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT_ENABLE=1
endif
ifeq ($(NETDATA_PUBLISHER),1)
COMMONCFLAGS += -DOPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE=1
endif
ifeq ($(PING_SENDER),1)
COMMONCFLAGS += -DOPENTHREAD_CONFIG_PING_SENDER_ENABLE=1
endif
+1
View File
@@ -71,6 +71,7 @@ openthread_headers = \
openthread/multi_radio.h \
openthread/ncp.h \
openthread/netdata.h \
openthread/netdata_publisher.h \
openthread/netdiag.h \
openthread/network_time.h \
openthread/ping_sender.h \
+1
View File
@@ -92,6 +92,7 @@ source_set("openthread") {
"multi_radio.h",
"ncp.h",
"netdata.h",
"netdata_publisher.h",
"netdiag.h",
"network_time.h",
"ping_sender.h",
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (146)
#define OPENTHREAD_API_VERSION (147)
/**
* @addtogroup api-instance
+283
View File
@@ -0,0 +1,283 @@
/*
* Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief
* This file defines the OpenThread Network Data Publisher API.
*/
#ifndef OPENTHREAD_NETDATA_PUBLISHER_H_
#define OPENTHREAD_NETDATA_PUBLISHER_H_
#include <openthread/netdata.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-thread-general
*
* @{
*
* The Network Data Publisher provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix
* or external route) entries in the Thread Network Data by monitoring the Network Data and managing if or when to add
* or remove entries.
*
* All the functions in this module require `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE` to be enabled.
*
*/
/**
* This enumeration represents the events reported from the Publisher callbacks.
*
*/
typedef enum otNetDataPublisherEvent
{
OT_NETDATA_PUBLISHER_EVENT_ENTRY_ADDED = 0, ///< Published entry is added to the Thread Network Data.
OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED = 1, ///< Published entry is removed from the Thread Network Data.
} otNetDataPublisherEvent;
/**
* This function pointer type defines the callback used to notify when a "DNS/SRP Service" entry is added to or removed
* from the Thread Network Data.
*
* On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there are
* too many similar entries already present in the Network Data) or through an explicit call to unpublish the entry
* (i.e., a call to `otNetDataUnpublishDnsSrpService()`).
*
* @param[in] aEvent Indicates the event (whether the entry was added or removed).
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*otNetDataDnsSrpServicePublisherCallback)(otNetDataPublisherEvent aEvent, void *aContext);
/**
* This function pointer type defines the callback used to notify when a prefix (on-mesh or external route) entry is
* added to or removed from the Thread Network Data.
*
* On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there are
* too many similar entries already present in the Network Data) or through an explicit call to unpublish the entry.
*
* @param[in] aEvent Indicates the event (whether the entry was added or removed).
* @param[in] aPrefix A pointer to the prefix entry.
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*otNetDataPrefixPublisherCallback)(otNetDataPublisherEvent aEvent,
const otIp6Prefix * aPrefix,
void * aContext);
/**
* This function requests "DNS/SRP Service Anycast Address" to be published in the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` to be enabled.
*
* A call to this function will remove and replace any previous "DNS/SRP Service" entry that was being published (from
* earlier call to any of `otNetDataPublishDnsSrpService{Type}()` functions).
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aSequenceNUmber The sequence number of DNS/SRP Anycast Service.
*
*/
void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequenceNUmber);
/**
* This function requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` to be enabled.
*
* A call to this function will remove and replace any previous "DNS/SRP Service" entry that was being published (from
* earlier call to any of `otNetDataPublishDnsSrpService{Type}()` functions).
*
* This function publishes the "DNS/SRP Service Unicast Address" by including the address and port info in the Service
* TLV data.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aAddress The DNS/SRP server address to publish (MUST NOT be NULL).
* @param[in] aPort The SRP server port number to publish.
*
*/
void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, const otIp6Address *aAddress, uint16_t aPort);
/**
* This function requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` to be enabled.
*
* A call to this function will remove and replace any previous "DNS/SRP Service" entry that was being published (from
* earlier call to any of `otNetDataPublishDnsSrpService{Type}()` functions).
*
* Unlike `otNetDataPublishDnsSrpServiceUnicast()` which requires the published address to be given and includes the
* info in the Service TLV data, this function uses the device's mesh-local EID and includes the info in the Server TLV
* data.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPort The SRP server port number to publish.
*
*/
void otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(otInstance *aInstance, uint16_t aPort);
/**
* This function indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE The published DNS/SRP Service entry is added to the Thread Network Data.
* @retval FLASE The entry is not added to Thread Network Data or there is no entry to publish.
*
*/
bool otNetDataIsDnsSrpServiceAdded(otInstance *aInstance);
/**
* This function sets a callback for notifying when a published "DNS/SRP Service" is actually added to or removed from
* the Thread Network Data.
*
* A subsequent call to this function replaces any previously set callback function.
*
* This function requires the feature `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCallback The callback function pointer (can be NULL if not needed).
* @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked).
*
*/
void otNetDataSetDnsSrpServicePublisherCallback(otInstance * aInstance,
otNetDataDnsSrpServicePublisherCallback aCallback,
void * aContext);
/**
* This function unpublishes any previously added "DNS/SRP (Anycast or Unicast) Service" entry from the Thread Network
* Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
*/
void otNetDataUnpublishDnsSrpService(otInstance *aInstance);
/**
* This function requests an on-mesh prefix to be published in the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` to be enabled.
*
* Only stable entries can be published (i.e.,`aConfig.mStable` MUST be TRUE).
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aConfig The on-mesh prefix config to publish (MUST NOT be NULL).
*
* @retval OT_ERROR_NONE The on-mesh prefix is published successfully.
* @retval OT_ERROR_INVALID_ARGS The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
* @retval OT_ERROR_ALREADY An entry with the same prefix is already in the published list.
* @retval OT_ERROR_NO_BUFS Could not allocate an entry for the new request. Publisher supports a limited number
* of entries (shared between on-mesh prefix and external route) determined by config
* `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
*
*
*/
otError otNetDataPublishOnMeshPrefix(otInstance *aInstance, const otBorderRouterConfig *aConfig);
/**
* This function requests an external route prefix to be published in the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` to be enabled.
*
* Only stable entries can be published (i.e.,`aConfig.mStable` MUST be TRUE).
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aConfig The external route config to publish (MUST NOT be NULL).
*
* @retval OT_ERROR_NONE The external route is published successfully.
* @retval OT_ERROR_INVALID_ARGS The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
* @retval OT_ERROR_ALREADY An entry with the same prefix is already in the published list.
* @retval OT_ERROR_NO_BUFS Could not allocate an entry for the new request. Publisher supports a limited number
* of entries (shared between on-mesh prefix and external route) determined by config
* `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
*/
otError otNetDataPublishExternalRoute(otInstance *aInstance, const otExternalRouteConfig *aConfig);
/**
* This function indicates whether or not currently a published prefix entry (on-mesh or external route) is added to
* the Thread Network Data.
*
* This function requires the feature `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPrefix A pointer to the prefix (MUST NOT be NULL).
*
* @retval TRUE The published prefix entry is added to the Thread Network Data.
* @retval FLASE The entry is not added to Thread Network Data or there is no entry to publish.
*
*/
bool otNetDataIsPrefixAdded(otInstance *aInstance, const otIp6Prefix *aPrefix);
/**
* This function sets a callback for notifying when a published prefix entry is actually added to or removed from
* the Thread Network Data.
*
* A subsequent call to this function replaces any previously set callback function.
*
* This function requires the feature `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCallback The callback function pointer (can be NULL if not needed).
* @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked).
*
*/
void otNetDataSetPrefixPublisherCallback(otInstance * aInstance,
otNetDataPrefixPublisherCallback aCallback,
void * aContext);
/**
* This function unpublishes a previously published prefix (on-mesh or external route).
*
* This function requires the feature `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPrefix The prefix to unpublish (MUST NOT be NULL).
*
* @retval OT_ERROR_NONE The prefix was unpublished successfully.
* @retval OT_ERROR_NOT_FOUND Could not find the prefix in the published list.
*
*/
otError otNetDataUnpublishPrefix(otInstance *aInstance, const otIp6Prefix *aPrefix);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif // OPENTHREAD_NETDATA_PUBLISHER_H_
+1
View File
@@ -69,6 +69,7 @@ do_scan_build()
"-DOPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE=1"
"-DOPENTHREAD_CONFIG_MPL_DYNAMIC_INTERVAL_ENABLE"
"-DOPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT=1"
"-DOPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE=1"
"-DOPENTHREAD_CONFIG_PING_SENDER_ENABLE=1"
"-DOPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE=1"
"-DOPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE=1"
+1
View File
@@ -136,6 +136,7 @@ size_nrf52840_version()
"-DOT_MAC_FILTER=ON"
"-DOT_MESSAGE_USE_HEAP=ON"
"-DOT_MTD_NETDIAG=ON"
"-DOT_NETDATA_PUBLISHER=ON"
"-DOT_PING_SENDER=ON"
"-DOT_SERVICE=ON"
"-DOT_SLAAC=ON"
+1
View File
@@ -89,6 +89,7 @@ readonly OT_POSIX_SIM_COMMON_OPTIONS=(
"-DOT_MAC_FILTER=ON"
"-DOT_MTD_NETDIAG=ON"
"-DOT_NEIGHBOR_DISCOVERY_AGENT=ON"
"-DOT_NETDATA_PUBLISHER=ON"
"-DOT_PING_SENDER=ON"
"-DOT_REFERENCE_DEVICE=ON"
"-DOT_SERVICE=ON"
+1
View File
@@ -108,6 +108,7 @@ readonly OT_CLANG_TIDY_BUILD_OPTS=(
'-DOT_LINK_METRICS_SUBJECT=ON'
'-DOT_MAC_FILTER=ON'
'-DOT_MTD_NETDIAG=ON'
'-DOT_NETDATA_PUBLISHER=ON'
'-DOT_PING_SENDER=ON'
'-DOT_REFERENCE_DEVICE=ON'
'-DOT_SERVICE=ON'
+11 -9
View File
@@ -55,17 +55,18 @@ build_simulation()
{
local version="$1"
local options=(
"-DOT_MESSAGE_USE_HEAP=ON"
"-DOT_THREAD_VERSION=${version}"
"-DBUILD_TESTING=ON"
"-DOT_REFERENCE_DEVICE=ON"
"-DOT_SRP_SERVER=ON"
"-DOT_SRP_CLIENT=ON"
"-DOT_SERVICE=ON"
"-DOT_ECDSA=ON"
"-DOT_PING_SENDER=ON"
"-DOT_DNSSD_SERVER=ON"
"-DOT_DNS_CLIENT=ON"
"-DOT_DNSSD_SERVER=ON"
"-DOT_ECDSA=ON"
"-DOT_MESSAGE_USE_HEAP=ON"
"-DOT_NETDATA_PUBLISHER=ON"
"-DOT_PING_SENDER=ON"
"-DOT_REFERENCE_DEVICE=ON"
"-DOT_SERVICE=ON"
"-DOT_SRP_CLIENT=ON"
"-DOT_SRP_SERVER=ON"
"-DOT_THREAD_VERSION=${version}"
)
if [[ ${FULL_LOGS} == 1 ]]; then
@@ -269,6 +270,7 @@ do_build_otbr_docker()
"-DOT_DNS_CLIENT=ON"
"-DOT_DUA=ON"
"-DOT_MLR=ON"
"-DOT_NETDATA_PUBLISHER=ON"
"-DOT_SLAAC=ON"
"-DOT_SRP_CLIENT=ON"
"-DOT_TREL=OFF"
+2 -1
View File
@@ -2168,11 +2168,12 @@ Get the external route list in the local Network Data.
Done
```
### route add \<prefix\> [s][prf]
### route add \<prefix\> [sn][prf]
Add a valid external route to the Network Data.
- s: Stable flag
- n: NAT64 flag
- prf: Default Router Preference, which may be: 'high', 'med', or 'low'.
```bash
+94
View File
@@ -142,9 +142,11 @@ After the device successfully attaches to a Thread network, the device will retr
## Command List
- [help](#help)
- [publish](#publish)
- [register](#register)
- [show](#show)
- [steeringdata](#steeringdata-check-eui64discerner)
- [unpublish](#unpublish)
## Command Details
@@ -157,9 +159,75 @@ Print netdata help menu.
```bash
> netdata help
help
publish
register
show
steeringdata
unpublish
Done
```
### publish
The Network Data Publisher provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix or external route) entries in the Thread Network Data by monitoring the Network Data and managing if or when to add or remove entries.
The Publisher requires `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE`.
### publish dnssrp
Publish DNS/SRP service entry.
This command requires `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE`.
The following formats are available: :
- `netdata publish dnssrp anycast <seq-num>` to publish "DNS/SRP Service Anycast Address" with a given sequence number.
- `netdata publish dnssrp unicast <address> <port>` to publish "DNS/SRP Service Unicast Address" with given address and port number info. The address/port info is included in Service TLV data.
- `netdata publish dnssrp unicast <port>` to publish "DNS/SRP Service Unicast Address" with given port number and the device's mesh-local EID for the address. The address and port info is included in Server TLV data.
A new call to `netdata publish dnssrp [anycast|unicast] [...]` command will remove and replace any previous "DNS/SRP Service" entry that was being published (from earlier `netdata publish dnssrp [...]` commands).
```bash
> netdata publish dnssrp anycast 1
Done
> netdata publish dnssrp unicast fd00::1234 51525
Done
> netdata publish dnssrp unicast 50152
Done
```
### publish prefix \<prefix\> [padcrosnD][prf]
Publish an on-mesh prefix entry.
- p: Preferred flag
- a: Stateless IPv6 Address Autoconfiguration flag
- d: DHCPv6 IPv6 Address Configuration flag
- c: DHCPv6 Other Configuration flag
- r: Default Route flag
- o: On Mesh flag
- s: Stable flag
- n: Nd Dns flag
- D: Domain Prefix flag (only available for Thread 1.2).
- prf: Preference, which may be 'high', 'med', or 'low'.
```bash
> netdata publish prefix fd00:1234:5678::/64 paos med
Done
```
### publish route \<prefix\> [sn][prf]
Publish an external route entry.
- s: Stable flag
- n: NAT64 flag
- prf: Preference, which may be: 'high', 'med', or 'low'.
```bash
> netdata publish route fd00:1234:5678::/64 s high
Done
```
@@ -212,3 +280,29 @@ Done
> netdata steeringdata check 0xdef/12
Error 23: NotFound
```
### unpublish
This command unpublishes a previously published Network Data entry.
This command requires `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE`.
### unpublish dnssrp
Unpublishes DNS/SRP Service entry (available when `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` is enabled):
- `netdata unpublish dnssrp` to unpublish "DNS/SRP Service" entry (anycast or unciast).
```bash
> netdata unpublish dnssrp
Done
```
### unpublish \<prefix\>
Unpublishes a previously published on-mesh prefix or external route entry.
```bash
> netdata unpublish fd00:1234:5678::/64
Done
```
+45 -27
View File
@@ -3302,29 +3302,28 @@ void Interpreter::HandleLinkPcapReceive(const otRadioFrame *aFrame, bool aIsTx)
}
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
otError Interpreter::ProcessPrefixAdd(Arg aArgs[])
otError Interpreter::ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig)
{
otError error = OT_ERROR_NONE;
otBorderRouterConfig config;
otError error = OT_ERROR_NONE;
memset(&config, 0, sizeof(otBorderRouterConfig));
memset(&aConfig, 0, sizeof(otBorderRouterConfig));
SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(config.mPrefix));
SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix));
aArgs++;
for (; !aArgs->IsEmpty(); aArgs++)
{
if (*aArgs == "high")
{
config.mPreference = OT_ROUTE_PREFERENCE_HIGH;
aConfig.mPreference = OT_ROUTE_PREFERENCE_HIGH;
}
else if (*aArgs == "med")
{
config.mPreference = OT_ROUTE_PREFERENCE_MED;
aConfig.mPreference = OT_ROUTE_PREFERENCE_MED;
}
else if (*aArgs == "low")
{
config.mPreference = OT_ROUTE_PREFERENCE_LOW;
aConfig.mPreference = OT_ROUTE_PREFERENCE_LOW;
}
else
{
@@ -3333,40 +3332,40 @@ otError Interpreter::ProcessPrefixAdd(Arg aArgs[])
switch (*arg)
{
case 'p':
config.mPreferred = true;
aConfig.mPreferred = true;
break;
case 'a':
config.mSlaac = true;
aConfig.mSlaac = true;
break;
case 'd':
config.mDhcp = true;
aConfig.mDhcp = true;
break;
case 'c':
config.mConfigure = true;
aConfig.mConfigure = true;
break;
case 'r':
config.mDefaultRoute = true;
aConfig.mDefaultRoute = true;
break;
case 'o':
config.mOnMesh = true;
aConfig.mOnMesh = true;
break;
case 's':
config.mStable = true;
aConfig.mStable = true;
break;
case 'n':
config.mNdDns = true;
aConfig.mNdDns = true;
break;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
case 'D':
config.mDp = true;
aConfig.mDp = true;
break;
#endif
default:
@@ -3376,6 +3375,16 @@ otError Interpreter::ProcessPrefixAdd(Arg aArgs[])
}
}
exit:
return error;
}
otError Interpreter::ProcessPrefixAdd(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otBorderRouterConfig config;
SuccessOrExit(error = ParsePrefix(aArgs, config));
error = otBorderRouterAddOnMeshPrefix(mInstance, &config);
exit:
@@ -3526,37 +3535,36 @@ otError Interpreter::ProcessRloc16(Arg aArgs[])
}
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
otError Interpreter::ProcessRouteAdd(Arg aArgs[])
otError Interpreter::ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig)
{
otError error = OT_ERROR_NONE;
otExternalRouteConfig config;
otError error = OT_ERROR_NONE;
memset(&config, 0, sizeof(otExternalRouteConfig));
memset(&aConfig, 0, sizeof(otExternalRouteConfig));
SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(config.mPrefix));
SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix));
aArgs++;
for (; !aArgs->IsEmpty(); aArgs++)
{
if (*aArgs == "s")
{
config.mStable = true;
aConfig.mStable = true;
}
else if (*aArgs == "n")
{
config.mNat64 = true;
aConfig.mNat64 = true;
}
else if (*aArgs == "high")
{
config.mPreference = OT_ROUTE_PREFERENCE_HIGH;
aConfig.mPreference = OT_ROUTE_PREFERENCE_HIGH;
}
else if (*aArgs == "med")
{
config.mPreference = OT_ROUTE_PREFERENCE_MED;
aConfig.mPreference = OT_ROUTE_PREFERENCE_MED;
}
else if (*aArgs == "low")
{
config.mPreference = OT_ROUTE_PREFERENCE_LOW;
aConfig.mPreference = OT_ROUTE_PREFERENCE_LOW;
}
else
{
@@ -3564,6 +3572,16 @@ otError Interpreter::ProcessRouteAdd(Arg aArgs[])
}
}
exit:
return error;
}
otError Interpreter::ProcessRouteAdd(Arg aArgs[])
{
otError error;
otExternalRouteConfig config;
SuccessOrExit(error = ParseRoute(aArgs, config));
error = otBorderRouterAddRoute(mInstance, &config);
exit:
+4
View File
@@ -412,6 +412,10 @@ private:
otError ParsePingInterval(const Arg &aArg, uint32_t &aInterval);
#endif
static otError ParseJoinerDiscerner(Arg &aArg, otJoinerDiscerner &aDiscerner);
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
static otError ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig);
static otError ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig);
#endif
otError ProcessUserCommands(Arg aArgs[]);
otError ProcessHelp(Arg aArgs[]);
+95
View File
@@ -34,6 +34,7 @@
#include "cli_network_data.hpp"
#include <openthread/border_router.h>
#include <openthread/netdata_publisher.h>
#include <openthread/server.h>
#include "cli/cli.hpp"
@@ -215,6 +216,100 @@ otError NetworkData::ProcessHelp(Arg aArgs[])
return OT_ERROR_NONE;
}
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
otError NetworkData::ProcessPublish(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
if (aArgs[0] == "dnssrp")
{
if (aArgs[1] == "anycast")
{
uint8_t sequenceNumber;
SuccessOrExit(error = aArgs[2].ParseAsUint8(sequenceNumber));
otNetDataPublishDnsSrpServiceAnycast(mInterpreter.mInstance, sequenceNumber);
ExitNow();
}
if (aArgs[1] == "unicast")
{
otIp6Address address;
uint16_t port;
if (aArgs[3].IsEmpty())
{
SuccessOrExit(error = aArgs[2].ParseAsUint16(port));
otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(mInterpreter.mInstance, port);
ExitNow();
}
SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address));
SuccessOrExit(error = aArgs[3].ParseAsUint16(port));
otNetDataPublishDnsSrpServiceUnicast(mInterpreter.mInstance, &address, port);
ExitNow();
}
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
if (aArgs[0] == "prefix")
{
otBorderRouterConfig config;
SuccessOrExit(error = Interpreter::ParsePrefix(aArgs + 1, config));
error = otNetDataPublishOnMeshPrefix(mInterpreter.mInstance, &config);
ExitNow();
}
if (aArgs[0] == "route")
{
otExternalRouteConfig config;
SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 1, config));
error = otNetDataPublishExternalRoute(mInterpreter.mInstance, &config);
ExitNow();
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
error = OT_ERROR_INVALID_ARGS;
exit:
return error;
}
otError NetworkData::ProcessUnpublish(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
if (aArgs[0] == "dnssrp")
{
otNetDataUnpublishDnsSrpService(mInterpreter.mInstance);
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
{
otIp6Prefix prefix;
if (aArgs[0].ParseAsIp6Prefix(prefix) == OT_ERROR_NONE)
{
error = otNetDataUnpublishPrefix(mInterpreter.mInstance, &prefix);
ExitNow();
}
}
#endif
error = OT_ERROR_INVALID_ARGS;
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
otError NetworkData::ProcessRegister(Arg aArgs[])
{
+11 -2
View File
@@ -103,6 +103,10 @@ private:
};
otError ProcessHelp(Arg aArgs[]);
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
otError ProcessPublish(Arg aArgs[]);
otError ProcessUnpublish(Arg aArgs[]);
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
otError ProcessRegister(Arg aArgs[]);
#endif
@@ -118,11 +122,16 @@ private:
static constexpr Command sCommands[] = {
{"help", &NetworkData::ProcessHelp},
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
{"publish", &NetworkData::ProcessPublish},
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
{"register", &NetworkData::ProcessRegister},
#endif
{"show", &NetworkData::ProcessShow},
{"steeringdata", &NetworkData::ProcessSteeringData},
{"show", &NetworkData::ProcessShow}, {"steeringdata", &NetworkData::ProcessSteeringData},
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
{"unpublish", &NetworkData::ProcessUnpublish},
#endif
};
static_assert(Utils::LookupTable::IsSorted(sCommands), "Command Table is not sorted");
+4
View File
@@ -327,6 +327,7 @@ openthread_core_files = [
"api/message_api.cpp",
"api/multi_radio_api.cpp",
"api/netdata_api.cpp",
"api/netdata_publisher_api.cpp",
"api/netdiag_api.cpp",
"api/network_time_api.cpp",
"api/ping_sender_api.cpp",
@@ -597,6 +598,8 @@ openthread_core_files = [
"thread/network_data_local.hpp",
"thread/network_data_notifier.cpp",
"thread/network_data_notifier.hpp",
"thread/network_data_publisher.cpp",
"thread/network_data_publisher.hpp",
"thread/network_data_service.cpp",
"thread/network_data_service.hpp",
"thread/network_data_tlvs.cpp",
@@ -714,6 +717,7 @@ source_set("libopenthread_core_config") {
"config/logging.h",
"config/mac.h",
"config/mle.h",
"config/netdata_publisher.h",
"config/openthread-core-config-check.h",
"config/openthread-core-default-config.h",
"config/parent_search.h",
+2
View File
@@ -63,6 +63,7 @@ set(COMMON_SOURCES
api/message_api.cpp
api/multi_radio_api.cpp
api/netdata_api.cpp
api/netdata_publisher_api.cpp
api/netdiag_api.cpp
api/network_time_api.cpp
api/ping_sender_api.cpp
@@ -195,6 +196,7 @@ set(COMMON_SOURCES
thread/network_data_leader_ftd.cpp
thread/network_data_local.cpp
thread/network_data_notifier.cpp
thread/network_data_publisher.cpp
thread/network_data_service.cpp
thread/network_data_tlvs.cpp
thread/network_data_types.cpp
+4
View File
@@ -140,6 +140,7 @@ SOURCES_COMMON = \
api/message_api.cpp \
api/multi_radio_api.cpp \
api/netdata_api.cpp \
api/netdata_publisher_api.cpp \
api/netdiag_api.cpp \
api/network_time_api.cpp \
api/ping_sender_api.cpp \
@@ -272,6 +273,7 @@ SOURCES_COMMON = \
thread/network_data_leader_ftd.cpp \
thread/network_data_local.cpp \
thread/network_data_notifier.cpp \
thread/network_data_publisher.cpp \
thread/network_data_service.cpp \
thread/network_data_tlvs.cpp \
thread/network_data_types.cpp \
@@ -435,6 +437,7 @@ HEADERS_COMMON = \
config/logging.h \
config/mac.h \
config/mle.h \
config/netdata_publisher.h \
config/openthread-core-config-check.h \
config/openthread-core-default-config.h \
config/parent_search.h \
@@ -538,6 +541,7 @@ HEADERS_COMMON = \
thread/network_data_leader_ftd.hpp \
thread/network_data_local.hpp \
thread/network_data_notifier.hpp \
thread/network_data_publisher.hpp \
thread/network_data_service.hpp \
thread/network_data_tlvs.hpp \
thread/network_data_types.hpp \
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread Network Data Publisher API.
*/
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#include <openthread/netdata_publisher.h>
#include "common/instance.hpp"
#include "common/locator_getters.hpp"
using namespace ot;
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequenceNumber)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(aSequenceNumber);
}
void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, const otIp6Address *aAddress, uint16_t aPort)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(*static_cast<const Ip6::Address *>(aAddress),
aPort);
}
void otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(otInstance *aInstance, uint16_t aPort)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(aPort);
}
bool otNetDataIsDnsSrpServiceAdded(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkData::Publisher>().IsDnsSrpServiceAdded();
}
void otNetDataSetDnsSrpServicePublisherCallback(otInstance * aInstance,
otNetDataDnsSrpServicePublisherCallback aCallback,
void * aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkData::Publisher>().SetDnsSrpServiceCallback(aCallback, aContext);
}
void otNetDataUnpublishDnsSrpService(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.Get<NetworkData::Publisher>().UnpublishDnsSrpService();
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
otError otNetDataPublishOnMeshPrefix(otInstance *aInstance, const otBorderRouterConfig *aConfig)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkData::Publisher>().PublishOnMeshPrefix(
*static_cast<const NetworkData::OnMeshPrefixConfig *>(aConfig));
}
otError otNetDataPublishExternalRoute(otInstance *aInstance, const otExternalRouteConfig *aConfig)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkData::Publisher>().PublishExternalRoute(
*static_cast<const NetworkData::ExternalRouteConfig *>(aConfig));
}
bool otNetDataIsPrefixAdded(otInstance *aInstance, const otIp6Prefix *aPrefix)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkData::Publisher>().IsPrefixAdded(*static_cast<const Ip6::Prefix *>(aPrefix));
}
void otNetDataSetPrefixPublisherCallback(otInstance * aInstance,
otNetDataPrefixPublisherCallback aCallback,
void * aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkData::Publisher>().SetPrefixCallback(aCallback, aContext);
}
otError otNetDataUnpublishPrefix(otInstance *aInstance, const otIp6Prefix *aPrefix)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<NetworkData::Publisher>().UnpublishPrefix(*static_cast<const Ip6::Prefix *>(aPrefix));
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
#endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
+3
View File
@@ -187,6 +187,8 @@ Error Local::AddService(bool aForce)
serverData.SetMlrTimeout(mMlrTimeout);
SuccessOrExit(error = Get<NetworkData::Service::Manager>().Add<NetworkData::Service::BackboneRouter>(serverData));
Get<NetworkData::Notifier>().HandleServerDataUpdated();
mIsServiceAdded = true;
exit:
@@ -199,6 +201,7 @@ void Local::RemoveService(void)
Error error;
SuccessOrExit(error = Get<NetworkData::Service::Manager>().Remove<NetworkData::Service::BackboneRouter>());
Get<NetworkData::Notifier>().HandleServerDataUpdated();
mIsServiceAdded = false;
exit:
+7
View File
@@ -640,6 +640,13 @@ template <> inline NetworkData::Notifier &Instance::Get(void)
}
#endif
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
template <> inline NetworkData::Publisher &Instance::Get(void)
{
return mThreadNetif.mNetworkDataPublisher;
}
#endif
template <> inline NetworkData::Service::Manager &Instance::Get(void)
{
return mThreadNetif.mNetworkDataServiceManager;
+6 -3
View File
@@ -183,12 +183,15 @@ void Notifier::EmitEvents(void)
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
Get<BorderRouter::RoutingManager>().HandleNotifierEvents(events);
#endif
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
Get<Srp::Server>().HandleNotifierEvents(events);
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
Get<Srp::Client>().HandleNotifierEvents(events);
#endif
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
// The `NetworkData::Publisher` is notified last (e.g., after SRP
// client) to allow other modules to request changes to what is
// being published (if needed).
Get<NetworkData::Publisher>().HandleNotifierEvents(events);
#endif
for (ExternalCallback &callback : mExternalCallbacks)
{
+155
View File
@@ -0,0 +1,155 @@
/*
* Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes compile-time configurations for Network Data Publisher.
*
*/
#ifndef CONFIG_NETDATA_PUBLISHER_H_
#define CONFIG_NETDATA_PUBLISHER_H_
#include "config/srp_server.h"
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
*
* Define to 1 to enable Network Data Publisher.
*
* Network Data Publisher provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix
* or external route) entries in the Thread Network Data by monitoring the Network Data and managing if or when to add
* or remove entries.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD
*
* Specifies the maximum value (in milliseconds) of the random delay used before adding an entry in the Thread Network
* Data.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD 3500
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE
*
* Specifies the maximum value (in milliseconds) of the random wait time used before removing an entry from the Thread
* Network Data.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE 15000
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED
*
* Specifies the extra wait time (in milliseconds) used when removing a preferred entry.
*
* When removing entries, certain entries are preferred over others. How the preference is determined depends on the
* entry type (e.g., (for DNS/SRP service entries associated with smaller RLOC16 or smaller IPv6 address are preferred).
* If the `Publisher` determines that its own entry is a preferred one, it adds the above extra wait time in addition
* to the random wait selected based on `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE` before removing
* its entry. This gives higher chance for a non-preferred entry from another device to be removed before removing a
* preferred entry which helps towards quicker convergence of the process to the desired number of entries.
*
* It is recommended that `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED` to be set to a
* value larger than `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE` to ensure that non-preferred entries
* are removed first.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED 16000
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES
*
* Specifies the desired number of "DNS/SRP Service Anycast Address" entries in the Thread Network Data.
*
* Publisher attempts to limit the number of such entries to this value.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES 8
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES
*
* Specifies the desired number of "DNS/SRP Service Anycast Address" entries in the Thread Network Data.
*
* Publisher attempts to limit the number of such entries to this value.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES 2
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES
*
* Specifies the desired number of matching On-mesh Prefix entries in the Thread Network Data.
*
* Publisher attempts to limit the number of matching entries to this value.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES 3
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES
*
* Specifies the desired number of matching External Route entries in the Thread Network Data.
*
* Publisher attempts to limit the number of matching entries to this value.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES 10
#endif
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES
*
* Specifies maximum number of prefix (on-mesh prefix or external route) entries supported by Publisher.
*
*/
#ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES 3
#endif
#endif // CONFIG_NETDATA_PUBLISHER_H_
+50 -58
View File
@@ -41,7 +41,6 @@
#include "common/new.hpp"
#include "common/random.hpp"
#include "net/dns_types.hpp"
#include "thread/network_data_service.hpp"
#include "thread/thread_netif.hpp"
namespace ot {
@@ -87,7 +86,8 @@ Server::Server(Instance &aInstance)
, mLeaseTimer(aInstance, HandleLeaseTimer)
, mOutstandingUpdatesTimer(aInstance, HandleOutstandingUpdatesTimer)
, mServiceUpdateId(Random::NonCrypto::GetUint32())
, mEnabled(false)
, mPort(kUdpPortMin)
, mState(kStateDisabled)
, mHasRegisteredAnyService(false)
{
IgnoreError(SetDomain(kDefaultDomain));
@@ -101,17 +101,27 @@ void Server::SetServiceHandler(otSrpServerServiceUpdateHandler aServiceHandler,
void Server::SetEnabled(bool aEnabled)
{
VerifyOrExit(mEnabled != aEnabled);
mEnabled = aEnabled;
if (!mEnabled)
if (aEnabled)
{
Stop();
VerifyOrExit(mState == kStateDisabled);
mState = kStateStopped;
// Select a port and then publish "DNS/SRP Unicast Address
// Service" in Thread Network Data using the device's
// mesh-local EID as the address. Then wait for callback
// `HandleNetDataPublisherEntryChange()` from to `Publisher` to
// start server operation when entry is published (i.e., added
// to the Network Data).
SelectPort();
Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(mPort);
}
else if (Get<Mle::MleRouter>().IsAttached())
else
{
Start();
VerifyOrExit(mState != kStateDisabled);
Get<NetworkData::Publisher>().UnpublishDnsSrpService();
Stop();
mState = kStateDisabled;
}
exit:
@@ -174,7 +184,7 @@ Error Server::SetDomain(const char *aDomain)
Error error = kErrorNone;
uint16_t length;
VerifyOrExit(!mEnabled, error = kErrorInvalidState);
VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
length = StringLength(aDomain, Dns::Name::kMaxNameSize);
VerifyOrExit((length > 0) && (length < Dns::Name::kMaxNameSize), error = kErrorInvalidArgs);
@@ -407,12 +417,9 @@ exit:
}
}
void Server::Start(void)
void Server::SelectPort(void)
{
Error error = kErrorNone;
uint16_t port = kUdpPortMin;
VerifyOrExit(!IsRunning());
mPort = kUdpPortMin;
#if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
{
@@ -420,35 +427,44 @@ void Server::Start(void)
if (Get<Settings>().Read(info) == kErrorNone)
{
port = info.GetPort() + 1;
if (port < kUdpPortMin || port > kUdpPortMax)
mPort = info.GetPort() + 1;
if (mPort < kUdpPortMin || mPort > kUdpPortMax)
{
port = kUdpPortMin;
mPort = kUdpPortMin;
}
}
}
#endif
SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
SuccessOrExit(error = mSocket.Bind(port, OT_NETIF_THREAD));
SuccessOrExit(error = PublishServerData());
otLogInfoSrp("[server] selected port %u", mPort);
}
otLogInfoSrp("[server] start listening on port %hu", mSocket.GetSockName().mPort);
void Server::Start(void)
{
Error error = kErrorNone;
VerifyOrExit(mState == kStateStopped);
mState = kStateRunning;
SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
SuccessOrExit(error = mSocket.Bind(mPort, OT_NETIF_THREAD));
otLogInfoSrp("[server] start listening on port %u", mPort);
exit:
if (error != kErrorNone)
{
otLogCritSrp("[server] failed to start: %s", ErrorToString(error));
// Cleanup any resources we may have allocated.
Stop();
}
}
void Server::Stop(void)
{
VerifyOrExit(IsRunning());
VerifyOrExit(mState == kStateRunning);
UnpublishServerData();
mState = kStateStopped;
while (!mHosts.IsEmpty())
{
@@ -465,7 +481,7 @@ void Server::Stop(void)
mLeaseTimer.Stop();
mOutstandingUpdatesTimer.Stop();
otLogInfoSrp("[server] stop listening on %hu", mSocket.GetSockName().mPort);
otLogInfoSrp("[server] stop listening on %u", mPort);
IgnoreError(mSocket.Close());
mHasRegisteredAnyService = false;
@@ -473,41 +489,17 @@ exit:
return;
}
void Server::HandleNotifierEvents(Events aEvents)
void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
{
VerifyOrExit(mEnabled);
VerifyOrExit(aEvents.Contains(kEventThreadRoleChanged));
if (Get<Mle::MleRouter>().IsAttached())
switch (aEvent)
{
case NetworkData::Publisher::kEventEntryAdded:
Start();
}
else
{
break;
case NetworkData::Publisher::kEventEntryRemoved:
Stop();
}
exit:
return;
}
Error Server::PublishServerData(void)
{
NetworkData::Service::DnsSrpUnicast::ServerData serverData(Get<Mle::Mle>().GetMeshLocal64(),
mSocket.GetSockName().GetPort());
OT_ASSERT(mSocket.IsBound());
return Get<NetworkData::Service::Manager>().Add<NetworkData::Service::DnsSrpUnicast>(serverData);
}
void Server::UnpublishServerData(void)
{
Error error = Get<NetworkData::Service::Manager>().Remove<NetworkData::Service::DnsSrpUnicast>();
if (error != kErrorNone)
{
otLogWarnSrp("[server] failed to unpublish SRP service: %s", ErrorToString(error));
break;
}
}
+20 -8
View File
@@ -42,6 +42,10 @@
#error "OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE is required for OPENTHREAD_CONFIG_SRP_SERVER_ENABLE"
#endif
#if !OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE is required for OPENTHREAD_CONFIG_SRP_SERVER_ENABLE"
#endif
#if !OPENTHREAD_CONFIG_ECDSA_ENABLE
#error "OPENTHREAD_CONFIG_ECDSA_ENABLE is required for OPENTHREAD_CONFIG_SRP_SERVER_ENABLE"
#endif
@@ -61,6 +65,7 @@
#include "net/ip6.hpp"
#include "net/ip6_address.hpp"
#include "net/udp6.hpp"
#include "thread/network_data_publisher.hpp"
namespace ot {
namespace Srp {
@@ -71,7 +76,7 @@ namespace Srp {
*/
class Server : public InstanceLocator, private NonCopyable
{
friend class ot::Notifier;
friend class NetworkData::Publisher;
friend class UpdateMetadata;
friend class Service;
friend class Host;
@@ -593,7 +598,7 @@ public:
* @returns A boolean that indicates whether the server is running.
*
*/
bool IsRunning(void) const { return mSocket.IsBound(); }
bool IsRunning(void) const { return (mState == kStateRunning); }
/**
* This method enables/disables the SRP server.
@@ -655,6 +660,13 @@ private:
static constexpr uint32_t kDefaultMaxKeyLease = 3600u * 24 * 14; // 14 days (in seconds).
static constexpr uint32_t kDefaultEventsHandlerTimeout = OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_UPDATE_TIMEOUT;
enum State : uint8_t
{
kStateDisabled,
kStateRunning,
kStateStopped,
};
// This class includes metadata for processing a SRP update (register, deregister)
// and sending DNS response to the client.
class UpdateMetadata : public InstanceLocator, public LinkedListEntry<UpdateMetadata>
@@ -688,11 +700,10 @@ private:
UpdateMetadata * mNext;
};
void Start(void);
void Stop(void);
void HandleNotifierEvents(Events aEvents);
Error PublishServerData(void);
void UnpublishServerData(void);
void Start(void);
void Stop(void);
void SelectPort(void);
void HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent);
ServiceUpdateId AllocateId(void) { return mServiceUpdateId++; }
@@ -778,7 +789,8 @@ private:
LinkedList<UpdateMetadata> mOutstandingUpdates;
ServiceUpdateId mServiceUpdateId;
bool mEnabled : 1;
uint16_t mPort;
State mState;
bool mHasRegisteredAnyService : 1;
};
+1
View File
@@ -78,6 +78,7 @@
#include "config/logging.h"
#include "config/mac.h"
#include "config/mle.h"
#include "config/netdata_publisher.h"
#include "config/parent_search.h"
#include "config/ping_sender.h"
#include "config/platform.h"
+1
View File
@@ -106,6 +106,7 @@ constexpr Iterator kIteratorInit = OT_NETWORK_DATA_ITERATOR_INIT; ///< Initializ
class NetworkData : public InstanceLocator
{
friend class Service::Manager;
friend class Publisher;
public:
static constexpr uint8_t kMaxSize = 254; ///< Maximum size of Thread Network Data in bytes.
File diff suppressed because it is too large Load Diff
+464
View File
@@ -0,0 +1,464 @@
/*
* Copyright (c) 2021, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definition of Network Data Publisher.
*/
#ifndef NETWORK_DATA_PUBLISHER_HPP_
#define NETWORK_DATA_PUBLISHER_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#if !OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE && !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
#error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE requires either OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE"\
"or OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE"
#endif
#include <openthread/netdata_publisher.h>
#include "common/clearable.hpp"
#include "common/equatable.hpp"
#include "common/error.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "common/notifier.hpp"
#include "common/string.hpp"
#include "common/timer.hpp"
#include "net/ip6_address.hpp"
#include "thread/network_data_types.hpp"
namespace ot {
namespace NetworkData {
/**
* This class implements the Network Data Publisher.
*
* It provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix or external route)
* entries in the Thread Network Data by monitoring the Network Data and managing if or when to add or remove entries.
*
*/
class Publisher : public InstanceLocator, private NonCopyable
{
friend class ot::Notifier;
public:
/**
* This enumeration represents the events reported from the Publisher callbacks.
*
*/
enum Event : uint8_t
{
kEventEntryAdded = OT_NETDATA_PUBLISHER_EVENT_ENTRY_ADDED, ///< Entry is added to Network Data.
kEventEntryRemoved = OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED, ///< Entry is removed from Network Data.
};
/**
* This constructor initializes `Publisher` object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit Publisher(Instance &aInstance);
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
/**
* This type represents the callback function pointer used to notify when a "DNS/SRP Service" entry is added to or
* removed from the Thread Network Data.
*
* On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there
* are too many similar entries already present in the Network Data) or through an explicit call to unpublish the
* entry (i.e., a call to `UnpublishDnsSrpService()`).
*
*/
typedef otNetDataDnsSrpServicePublisherCallback DnsSrpServiceCallback;
/**
* This method sets a callback for notifying when a published "DNS/SRP Service" is actually added to or removed
* from the Thread Network Data.
*
* A subsequent call to this method replaces any previously set callback function.
*
* @param[in] aCallback The callback function pointer (can be NULL if not needed).
* @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked).
*
*/
void SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback, void *aContext)
{
mDnsSrpServiceEntry.SetCallback(aCallback, aContext);
}
/**
* This method requests "DNS/SRP Service Anycast Address" to be published in the Thread Network Data.
*
* A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
* (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
*
* @param[in] aSequenceNumber The sequence number of DNS/SRP Anycast Service.
*
*/
void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber) { mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber); }
/**
* This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
*
* A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
* (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
*
* This method publishes the "DNS/SRP Service Unicast Address" by including the address and port info in the
* Service TLV data.
*
* @param[in] aAddress The DNS/SRP server address to publish.
* @param[in] aPort The SRP server port number to publish.
*
*/
void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort)
{
mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort);
}
/**
* This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data.
*
* A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published
* (from earlier call to any of `PublishDnsSrpService{Type}()` methods).
*
* Unlike the `PublishDnsSrpServiceUnicast(aAddress, aPort)` which requires the published address to be given and
* includes the info in the Service TLV data, this method uses the device's mesh-local EID and includes the info
* in the Server TLV data.
*
* @param[in] aPort The SRP server port number to publish.
*
*/
void PublishDnsSrpServiceUnicast(uint16_t aPort) { mDnsSrpServiceEntry.PublishUnicast(aPort); }
/**
* This method indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data.
*
* @retval TRUE The published DNS/SRP Service entry is added to the Thread Network Data.
* @retval FLASE The entry is not added to Thread Network Data or there is no entry to publish.
*
*/
bool IsDnsSrpServiceAdded(void) const { return mDnsSrpServiceEntry.IsAdded(); }
/**
* This method unpublishes any previously added "DNS/SRP (Anycast or Unicast) Service" entry from the Thread
* Network Data.
*
*/
void UnpublishDnsSrpService(void) { mDnsSrpServiceEntry.Unpublish(); }
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
/**
* This type represents the callback function pointer used to notify when a prefix (on-mesh or external route)
* entry is added to or removed from the Thread Network Data.
*
* On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there
* are too many similar entries already present in the Network Data) or through an explicit call to unpublish the
* entry.
*
*/
typedef otNetDataPrefixPublisherCallback PrefixCallback;
/**
* This method sets a callback for notifying when a published prefix entry is actually added to or removed from
* the Thread Network Data.
*
* A subsequent call to this method replaces any previously set callback function.
*
* @param[in] aCallback The callback function pointer (can be NULL if not needed).
* @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked).
*
*/
void SetPrefixCallback(PrefixCallback aCallback, void *aContext);
/**
* This method requests an on-mesh prefix to be published in the Thread Network Data.
*
* Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`).
*
* @param[in] aConfig The on-mesh prefix config to publish.
*
* @retval kErrorNone The on-mesh prefix is published successfully.
* @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
* @retval kErrorAlready An entry with the same prefix is already in the published list.
* @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number
* of entries (shared between on-mesh prefix and external route) determined by config
* `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
*
*
*/
Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig);
/**
* This method requests an external route prefix to be published in the Thread Network Data.
*
* Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`).
*
* @param[in] aConfig The external route config to publish.
*
* @retval kErrorNone The external route is published successfully.
* @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable).
* @retval kErrorAlready An entry with the same prefix is already in the published list.
* @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number
* of entries (shared between on-mesh prefix and external route) determined by config
* `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`.
*
*
*/
Error PublishExternalRoute(const ExternalRouteConfig &aConfig);
/**
* This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to
* the Thread Network Data.
*
* @param[in] aPrefix The prefix to check.
*
* @retval TRUE The published prefix entry is added to the Thread Network Data.
* @retval FLASE The entry is not added to Thread Network Data or there is no matching entry to publish.
*
*/
bool IsPrefixAdded(const Ip6::Prefix &aPrefix) const;
/**
* This method unpublishes a previously published prefix (on-mesh or external route).
*
* @param[in] aPrefix The prefix to unpublish.
*
* @retval kErrorNone The prefix was unpublished successfully.
* @retval kErrorNotFound Could not find the prefix in the published list.
*
*/
Error UnpublishPrefix(const Ip6::Prefix &aPrefix);
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
private:
class Entry : public InstanceLocatorInit
{
protected:
enum State : uint8_t
{
kNoEntry, // Entry is unused (there is no entry).
kToAdd, // Entry is ready to be added, monitoring network data to decide if/when to add it.
kAdding, // Entry is being added in network data (random wait interval before add).
kAdded, // Entry is added in network data, monitoring to determine if/when to remove.
kRemoving, // Entry is being removed from network data (random wait interval before remove).
};
// All intervals are in milliseconds.
static constexpr uint32_t kMaxDelayToAdd = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD;
static constexpr uint32_t kMaxDelayToRemove = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE;
static constexpr uint32_t kExtraDelayToRemovePeferred =
OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED;
static constexpr uint16_t kInfoStringSize = 50;
typedef String<kInfoStringSize> InfoString;
Entry(void)
: mState(kNoEntry)
{
}
void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); }
State GetState(void) const { return mState; }
void SetState(State aState);
const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; }
bool IsPreferred(uint16_t aRloc16) const;
void UpdateState(uint8_t aNumEntries, uint8_t aNumPreferredEntries, uint8_t aDesiredNumEntries);
bool HandleTimer(void);
InfoString ToString(bool aIncludeState = true) const;
public:
bool IsAdded(void) const { return (mState == kAdded); }
private:
bool Add(void);
bool Remove(State aNextState);
void LogUpdateTime(void) const;
static const char *StateToString(State aState);
TimeMilli mUpdateTime;
State mState;
};
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
class DnsSrpServiceEntry : public Entry, private NonCopyable
{
friend class Entry;
public:
explicit DnsSrpServiceEntry(Instance &aInstance);
void SetCallback(DnsSrpServiceCallback aCallback, void *aContext);
void PublishAnycast(uint8_t aSequenceNumber);
void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort);
void PublishUnicast(uint16_t aPort);
void Unpublish(void);
bool HandleTimer(void) { return Entry::HandleTimer(); }
bool HandleNotifierEvents(Events aEvents);
private:
static constexpr uint8_t kDesiredNumAnycast =
OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES;
static constexpr uint8_t kDesiredNumUnicast =
OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES;
enum Type : uint8_t
{
kTypeAnycast,
kTypeUnicast,
kTypeUnicastMeshLocalEid,
};
class Info : public Clearable<Info>, public Equatable<Info>
{
public:
Info(void) { Clear(); }
Type GetType(void) const { return mType; }
uint8_t GetSequenceNumber(void) const { return static_cast<uint8_t>(mPortOrSeqNumber); }
uint16_t GetPort(void) const { return mPortOrSeqNumber; }
const Ip6::Address &GetAddress(void) const { return mAddress; }
void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; }
static Info InfoAnycast(uint8_t aSequenceNumber) { return Info(kTypeAnycast, aSequenceNumber); }
static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort)
{
return Info(aType, aPort, &aAddress);
}
private:
Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress = nullptr);
Ip6::Address mAddress;
uint16_t mPortOrSeqNumber;
Type mType;
};
Type GetType(void) const { return mInfo.GetType(); }
void Publish(const Info &aInfo);
bool Add(void);
bool Remove(State aNextState);
void Notify(Event aEvent) const;
void Process(void);
void CountAnycastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
void CountUnicastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
Info mInfo;
DnsSrpServiceCallback mCallback;
void * mCallbackContext;
};
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
// Max number of prefix (on-mesh or external route) entries.
static constexpr uint16_t kMaxPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES;
class PrefixEntry : public Entry, private NonCopyable
{
friend class Entry;
public:
void Init(Instance &aInstance) { Entry::Init(aInstance); }
bool IsInUse(void) const { return GetState() != kNoEntry; }
bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
void Publish(const OnMeshPrefixConfig &aConfig);
void Publish(const ExternalRouteConfig &aConfig);
void Unpublish(void);
bool HandleTimer(void) { return Entry::HandleTimer(); }
void HandleNotifierEvents(Events aEvents);
private:
static constexpr uint8_t kDesiredNumOnMeshPrefix =
OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES;
static constexpr uint8_t kDesiredNumExternalRoute =
OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES;
enum Type : uint8_t
{
kTypeOnMeshPrefix,
kTypeExternalRoute,
};
bool Add(void);
Error AddOnMeshPrefix(void);
Error AddExternalRoute(void);
bool Remove(State aNextState);
void Process(void);
void CountOnMeshPrefixEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
void CountExternalRouteEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const;
Type mType;
Ip6::Prefix mPrefix;
uint16_t mFlags;
};
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
bool IsADnsSrpServiceEntry(const Entry &aEntry) const { return (&aEntry == &mDnsSrpServiceEntry); }
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
Error AllocatePrefixEntry(const Ip6::Prefix &aPrefix, PrefixEntry *&aEntry);
PrefixEntry * FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix);
const PrefixEntry *FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix) const;
bool IsAPrefixEntry(const Entry &aEntry) const;
void NotifyPrefixEntryChange(Event aEvent, const Ip6::Prefix &aPrefix) const;
#endif
TimerMilli &GetTimer(void) { return mTimer; }
void HandleNotifierEvents(Events aEvents);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
DnsSrpServiceEntry mDnsSrpServiceEntry;
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
PrefixEntry mPrefixEntries[kMaxPrefixEntries];
PrefixCallback mPrefixCallback;
void * mPrefixCallbackContext;
#endif
TimerMilli mTimer;
};
} // namespace NetworkData
} // namespace ot
#endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#endif // NETWORK_DATA_PUBLISHER_HPP_
+5 -18
View File
@@ -59,28 +59,15 @@ Error Manager::AddService(const void *aServiceData,
const void *aServerData,
uint8_t aServerDataLength)
{
Error error;
SuccessOrExit(error = Get<Local>().AddService(
kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData), aServiceDataLength,
aServerStable, reinterpret_cast<const uint8_t *>(aServerData), aServerDataLength));
Get<Notifier>().HandleServerDataUpdated();
exit:
return error;
return Get<Local>().AddService(kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData),
aServiceDataLength, aServerStable, reinterpret_cast<const uint8_t *>(aServerData),
aServerDataLength);
}
Error Manager::RemoveService(const void *aServiceData, uint8_t aServiceDataLength)
{
Error error;
SuccessOrExit(error = Get<Local>().RemoveService(
kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData), aServiceDataLength));
Get<Notifier>().HandleServerDataUpdated();
exit:
return error;
return Get<Local>().RemoveService(kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData),
aServiceDataLength);
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
+2 -12
View File
@@ -421,9 +421,6 @@ public:
/**
* This method adds a Thread Service entry to the local Thread Network Data.
*
* When successfully added, this method also invokes `Notifier::HandleServerDataUpdated()` to register the changes
* in local Network Data with leader.
*
* This version of `Add<SeviceType>()` is intended for use with a `ServiceType` that has a constant service data
* format with a non-empty and potentially non-const server data format (provided as input parameter).
*
@@ -451,9 +448,6 @@ public:
/**
* This method adds a Thread Service entry to the local Thread Network Data.
*
* When successfully added, this method also invokes `Notifier::HandleServerDataUpdated()` to register the changes
* in local Network Data with leader.
*
* This version of `Add<SeviceType>()` is intended for use with a `ServiceType` that has a non-const service data
* format (provided as input parameter) with an empty server data.
*
@@ -479,9 +473,6 @@ public:
/**
* This method removes a Thread Service entry from the local Thread Network Data.
*
* When successfully removed, this method also invokes `Notifier::HandleServerDataUpdated()` to register the
* changes in local Network Data with leader.
*
* This version of `Remove<SeviceType>()` is intended for use with a `ServiceType` that has a constant service data
* format.
*
@@ -502,9 +493,6 @@ public:
/**
* This method removes a Thread Service entry from the local Thread Network Data.
*
* When successfully removed, this method also invokes `Notifier::HandleServerDataUpdated()` to register the
* changes in local Network Data with leader.
*
* This version of `Remove<SeviceType>()` is intended for use with a `ServiceType` that has a non-const service data
* format (provided as input parameter).
*
@@ -514,6 +502,8 @@ public:
*
* @tparam ServiceType The service type to be removed.
*
* @param[in] aServiceData The service data.
*
* @retval kErrorNone Successfully removed the Service entry.
* @retval kErrorNotFound Could not find the Service entry.
*
+50 -5
View File
@@ -391,7 +391,7 @@ public:
* @returns The preference value.
*
*/
int8_t GetPreference(void) const { return static_cast<int8_t>(mFlags) >> kPreferenceOffset; }
int8_t GetPreference(void) const { return PreferenceFromFlags(GetFlags()); }
/**
* This method gets the Flags value.
@@ -434,6 +434,30 @@ public:
*/
const HasRouteEntry *GetNext(void) const { return (this + 1); }
/**
* This static method returns an updated flags bitmask by removing the preference bits (sets them to zero) from a
* given flags bitmask.
*
* @param[in] aFlags The flags bitmask.
*
* @returns An updated version @p aFlags with preference bits cleared.
*
*/
static uint8_t FlagsWithoutPreference(uint8_t aFlags) { return (aFlags & ~kPreferenceMask); }
/**
* This static method gets the preference field from a flags bitmask.
*
* @param[in] aFlags The flags.
*
* @returns The preference field from the @p aFlags.
*
*/
static int8_t PreferenceFromFlags(uint8_t aFlags)
{
return static_cast<int8_t>(static_cast<int8_t>(aFlags) >> kPreferenceOffset);
}
private:
static constexpr uint8_t kPreferenceOffset = 6;
static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset;
@@ -890,10 +914,7 @@ public:
* @returns the Preference value.
*
*/
int8_t GetPreference(void) const
{
return static_cast<int8_t>(static_cast<int16_t>(HostSwap16(mFlags)) >> kPreferenceOffset);
}
int8_t GetPreference(void) const { return PreferenceFromFlags(GetFlags()); }
/**
* This method indicates whether or not the Preferred flag is set.
@@ -983,6 +1004,30 @@ public:
*/
const BorderRouterEntry *GetNext(void) const { return (this + 1); }
/**
* This static method returns an updated flags bitmask by removing the preference bits (sets them to zero) from a
* given flags bitmask.
*
* @param[in] aFlags The flags bitmask.
*
* @returns An updated version @p aFlags with preference bits cleared.
*
*/
static uint16_t FlagsWithoutPreference(uint16_t aFlags) { return (aFlags & ~kPreferenceMask); }
/**
* This static method gets the preference field from a flags bitmask.
*
* @param[in] aFlags The flags.
*
* @returns The preference field from the @p aFlags.
*
*/
static int8_t PreferenceFromFlags(uint16_t aFlags)
{
return static_cast<int8_t>(static_cast<int16_t>(aFlags) >> kPreferenceOffset);
}
private:
static constexpr uint8_t kPreferenceOffset = 14;
static constexpr uint16_t kPreferenceMask = 3 << kPreferenceOffset;
+3
View File
@@ -56,6 +56,7 @@ namespace NetworkData {
// Forward declarations
class NetworkData;
class Local;
class Publisher;
class PrefixTlv;
class BorderRouterTlv;
class BorderRouterEntry;
@@ -74,6 +75,7 @@ class OnMeshPrefixConfig : public otBorderRouterConfig,
{
friend class NetworkData;
friend class Local;
friend class Publisher;
public:
/**
@@ -125,6 +127,7 @@ class ExternalRouteConfig : public otExternalRouteConfig,
{
friend class NetworkData;
friend class Local;
friend class Publisher;
public:
/**
+3
View File
@@ -95,6 +95,9 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
, mNetworkDataLeader(aInstance)
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
, mNetworkDataNotifier(aInstance)
#endif
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
, mNetworkDataPublisher(aInstance)
#endif
, mNetworkDataServiceManager(aInstance)
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
+4
View File
@@ -97,6 +97,7 @@
#include "thread/mle_router.hpp"
#include "thread/network_data_local.hpp"
#include "thread/network_data_notifier.hpp"
#include "thread/network_data_publisher.hpp"
#include "thread/network_data_service.hpp"
#include "thread/network_diagnostic.hpp"
#include "thread/panid_query_server.hpp"
@@ -239,6 +240,9 @@ private:
NetworkData::Leader mNetworkDataLeader;
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
NetworkData::Notifier mNetworkDataNotifier;
#endif
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
NetworkData::Publisher mNetworkDataPublisher;
#endif
NetworkData::Service::Manager mNetworkDataServiceManager;
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
+1
View File
@@ -63,6 +63,7 @@ MAC_FILTER ?= 1
MAX_POWER_TABLE ?= 1
MTD_NETDIAG ?= 1
NEIGHBOR_DISCOVERY_AGENT ?= 1
NETDATA_PUBLISHER ?= 1
PING_SENDER ?= 1
READLINE ?= readline
REFERENCE_DEVICE ?= 1
+1
View File
@@ -61,6 +61,7 @@
-DOT_LOG_OUTPUT=APP \
-DOT_MAC_FILTER=ON \
-DOT_MTD_NETDIAG=ON \
-DOT_NETDATA_PUBLISHER=ON \
-DOT_PING_SENDER=ON \
-DOT_SERVICE=ON \
-DOT_SLAAC=ON \
+2
View File
@@ -168,6 +168,7 @@ EXTRA_DIST = \
test_lowpan.py \
test_mac802154.py \
test_mle.py \
test_netdata_publisher.py \
test_network_data.py \
test_network_layer.py \
test_on_mesh_prefix.py \
@@ -233,6 +234,7 @@ check_SCRIPTS = \
test_lowpan.py \
test_mac802154.py \
test_mle.py \
test_netdata_publisher.py \
test_network_data.py \
test_network_layer.py \
test_on_mesh_prefix.py \
@@ -157,7 +157,7 @@ class SingleHostAndService(thread_cert.TestCase):
#
server.srp_server_set_enabled(False)
self.simulator.go(2)
self.simulator.go(5)
self.assertEqual(len(server.srp_server_get_hosts()), 0)
self.assertEqual(len(server.srp_server_get_services()), 0)
+28
View File
@@ -1715,6 +1715,34 @@ class NodeImpl:
self.send_command('netdata register')
self._expect_done()
def netdata_publish_dnssrp_anycast(self, seqnum):
self.send_command(f'netdata publish dnssrp anycast {seqnum}')
self._expect_done()
def netdata_publish_dnssrp_unicast(self, address, port):
self.send_command(f'netdata publish dnssrp unicast {address} {port}')
self._expect_done()
def netdata_publish_dnssrp_unicast_mleid(self, port):
self.send_command(f'netdata publish dnssrp unicast {port}')
self._expect_done()
def netdata_unpublish_dnssrp(self):
self.send_command('netdata unpublish dnssrp')
self._expect_done()
def netdata_publish_prefix(self, prefix, flags='paosr', prf='med'):
self.send_command(f'netdata publish prefix {prefix} {flags} {prf}')
self._expect_done()
def netdata_publish_route(self, prefix, flags='s', prf='med'):
self.send_command(f'netdata publish route {prefix} {flags} {prf}')
self._expect_done()
def netdata_unpublish_prefix(self, prefix):
self.send_command(f'netdata unpublish {prefix}')
self._expect_done()
def send_network_diag_get(self, addr, tlv_types):
self.send_command('networkdiagnostic get %s %s' % (addr, ' '.join([str(t.value) for t in tlv_types])))
+452
View File
@@ -0,0 +1,452 @@
#!/usr/bin/env python3
#
# Copyright (c) 2021, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
import ipaddress
import unittest
import command
import thread_cert
# Test description:
# This test verifies network data publisher behavior with DNS/SRP service entries and on-mesh prefix and external
# route entries.
#
# Topology:
#
# 1 leader, 5 routers and 5 end-devices all connected.
#
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ROUTER3 = 4
ROUTER4 = 5
ROUTER5 = 6
END_DEV1 = 7
END_DEV2 = 8
END_DEV3 = 9
END_DEV4 = 10
END_DEV5 = 11
WAIT_TIME = 55
ON_MESH_PREFIX = 'fd00:1234::/64'
ON_MESH_FLAGS = 'paso'
EXTERNAL_ROUTE = 'fd00:abce::/64'
EXTERNAL_FLAGS = 's'
ANYCAST_SEQ_NUM = 4
DNSSRP_ADDRESS = 'fd00::cdef'
DNSSRP_PORT = 49152
# The desired number of entries (based on related config).
DESIRED_NUM_DNSSRP_ANYCAST = 8
DESIRED_NUM_DNSSRP_UNCIAST = 2
DESIRED_NUM_ON_MESH_PREFIX = 3
DESIRED_NUM_EXTERNAL_ROUTE = 10
THREAD_ENTERPRISE_NUMBER = 44970
ANYCAST_SERVICE_NUM = 0x5c
UNICAST_SERVICE_NUM = 0x5d
class NetDataPublisher(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
},
ROUTER1: {
'name': 'ROUTER1',
'mode': 'rdn',
},
ROUTER2: {
'name': 'ROUTER2',
'mode': 'rdn',
},
ROUTER3: {
'name': 'ROUTER3',
'mode': 'rdn',
},
ROUTER4: {
'name': 'ROUTER4',
'mode': 'rdn',
},
ROUTER5: {
'name': 'ROUTER5',
'mode': 'rdn',
},
END_DEV1: {
'name': 'END_DEV1',
'mode': 'rn',
},
END_DEV2: {
'name': 'END_DEV2',
'mode': 'rn',
},
END_DEV3: {
'name': 'END_DEV3',
'mode': 'rn',
},
END_DEV4: {
'name': 'END_DEV4',
'mode': 'rn',
},
END_DEV5: {
'name': 'END_DEV5',
'mode': 'rn',
},
}
def verify_anycast_service(self, service):
# Verify the data in a single anycast `service` from `get_services()`
# Example of `service`: ['44970', '5c04', '', 's', 'bc00']
self.assertEqual(int(service[0]), THREAD_ENTERPRISE_NUMBER)
# Check service data
service_data = bytes.fromhex(service[1])
self.assertTrue(len(service_data) >= 2)
self.assertEqual(service_data[0], ANYCAST_SERVICE_NUM)
self.assertEqual(service_data[1], int(ANYCAST_SEQ_NUM))
# Verify that it stable
self.assertEqual(service[3], 's')
def verify_anycast_services(self, services):
# Verify a list of anycast `services` from `get_services()`
for service in services:
self.verify_anycast_service(service)
def verify_unicast_service(self, service):
# Verify the data in a single unicast `service` from `get_services()`
# Example of `service`: ['44970', '5d', 'fd000db800000000c6b0e5ee81f940e8223d', 's', '7000']
self.assertEqual(int(service[0]), THREAD_ENTERPRISE_NUMBER)
# Check service data
service_data = bytes.fromhex(service[1])
self.assertTrue(len(service_data) >= 1)
self.assertEqual(service_data[0], UNICAST_SERVICE_NUM)
# Verify that it stable
self.assertEqual(service[3], 's')
def verify_unicast_services(self, services):
# Verify a list of unicast `services` from `get_services()`
for service in services:
self.verify_unicast_service(service)
def check_num_of_prefixes(self, prefixes, num_low, num_med, num_high):
# Check and validate the prefix entries in network data (from
# `prefixes`) based on number of published prefix entries at
# different preference levels given by `num_low`, `num_med`,
# `num_high`. Prefixes is a list of the format
# 'fd00:1234:0:0::/64 paos low a802'.
self.assertEqual(len(prefixes), min(num_high + num_med + num_low, DESIRED_NUM_ON_MESH_PREFIX))
prfs = [prefix.split(' ')[2] for prefix in prefixes]
self.assertEqual(prfs.count('high'), min(num_high, DESIRED_NUM_ON_MESH_PREFIX))
self.assertEqual(prfs.count('med'), min(num_med, max(0, DESIRED_NUM_ON_MESH_PREFIX - num_high)))
self.assertEqual(prfs.count('low'), min(num_low, max(0, DESIRED_NUM_ON_MESH_PREFIX - num_high - num_med)))
def check_num_of_routes(self, routes, num_low, num_med, num_high):
# Check and validate the prefix entries in network data (from
# `routes`) based on number of published prefix entries at
# different preference levels given by `num_low`, `num_med`,
# `num_high`. Prefixes is a list of the format
# 'fd00:abce:0:0::/64 s med 6c01'.
self.assertEqual(len(routes), min(num_high + num_med + num_low, DESIRED_NUM_EXTERNAL_ROUTE))
prfs = [route.split(' ')[2] for route in routes]
self.assertEqual(prfs.count('high'), min(num_high, DESIRED_NUM_EXTERNAL_ROUTE))
self.assertEqual(prfs.count('med'), min(num_med, max(0, DESIRED_NUM_EXTERNAL_ROUTE - num_high)))
self.assertEqual(prfs.count('low'), min(num_low, max(0, DESIRED_NUM_EXTERNAL_ROUTE - num_high - num_med)))
def test(self):
leader = self.nodes[LEADER]
router1 = self.nodes[ROUTER1]
router2 = self.nodes[ROUTER2]
router3 = self.nodes[ROUTER3]
router4 = self.nodes[ROUTER4]
router5 = self.nodes[ROUTER5]
end_dev1 = self.nodes[END_DEV1]
end_dev2 = self.nodes[END_DEV2]
end_dev3 = self.nodes[END_DEV3]
end_dev4 = self.nodes[END_DEV4]
end_dev5 = self.nodes[END_DEV5]
nodes = self.nodes.values()
routers = [router1, router2, router3, router4, router5]
end_devs = [end_dev1, end_dev2, end_dev3, end_dev4, end_dev5]
# Start the nodes
leader.start()
self.simulator.go(5)
self.assertEqual(leader.get_state(), 'leader')
for router in routers:
router.start()
self.simulator.go(5)
self.assertEqual(router.get_state(), 'router')
for end_dev in end_devs:
end_dev.start()
self.simulator.go(5)
self.assertEqual(end_dev.get_state(), 'child')
#---------------------------------------------------------------------------------
# DNS/SRP anycast entries
# Publish DNS/SRP anycast on leader and all routers (6 nodes).
leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
for node in routers:
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
self.simulator.go(WAIT_TIME)
# Check all entries are present in the network data
services = leader.get_services()
self.assertEqual(len(services), min(1 + len(routers), DESIRED_NUM_DNSSRP_ANYCAST))
self.verify_anycast_services(services)
# Publish same entry on all end-devices (5 nodes).
for node in end_devs:
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
print(node.name)
self.simulator.go(WAIT_TIME)
# Check number of entries in the network data is limited to
# the desired number (8 entries).
services = leader.get_services()
self.assertEqual(len(leader.get_services()), min(len(nodes), DESIRED_NUM_DNSSRP_ANYCAST))
self.verify_anycast_services(services)
# Unpublish the entry from nodes one by one starting from leader
# and check that number of entries is correct in each step.
num = len(nodes)
for node in nodes:
node.netdata_unpublish_dnssrp()
self.simulator.go(WAIT_TIME)
num -= 1
services = leader.get_services()
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
self.verify_anycast_services(services)
#---------------------------------------------------------------------------------
# DNS/SRP unicast entries
# Publish DNS/SRP unicast address on all routers, first using
# MLE-EID address, then change to use specific address. Verify
# that number of entries in network data is correct in each step
# and that entries are switched correctly.
num = 0
for node in routers:
node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT)
self.simulator.go(WAIT_TIME)
num += 1
services = leader.get_services()
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNCIAST))
self.verify_unicast_services(services)
for node in routers:
node.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT)
self.simulator.go(WAIT_TIME)
services = leader.get_services()
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNCIAST))
self.verify_unicast_services(services)
for node in routers:
node.netdata_unpublish_dnssrp()
self.simulator.go(WAIT_TIME)
num -= 1
services = leader.get_services()
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNCIAST))
self.verify_unicast_services(services)
#---------------------------------------------------------------------------------
# DNS/SRP entries: Verify publisher preference when removing
# entries.
#
# Publish DNS/SRP anycast on 8 nodes: leader, router1,
# router2, and all 5 end-devices. Afterwards, manually add
# the same service entry in Network Data on router3, router4,
# and router5 and at each step check that entry from one of
# the end-devices is removed (publisher prefers
# entries from routers over the ones from end-devices).
num = 0
test_routers = [leader, router1, router2]
for node in test_routers + end_devs:
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
self.simulator.go(WAIT_TIME)
num += 1
services = leader.get_services()
self.assertEqual(len(services), num)
self.verify_anycast_services(services)
self.assertEqual(num, DESIRED_NUM_DNSSRP_ANYCAST)
service_data = '%02x%02x' % (ANYCAST_SERVICE_NUM, int(ANYCAST_SEQ_NUM))
for node in [router3, router4, router5]:
node.add_service(str(THREAD_ENTERPRISE_NUMBER), service_data, '00')
node.register_netdata()
self.simulator.go(WAIT_TIME)
services = leader.get_services()
self.assertEqual(len(services), num)
self.verify_anycast_services(services)
service_rlocs = [int(service[4], 16) for service in services]
test_routers.append(node)
for router in test_routers:
self.assertIn(router.get_addr16(), service_rlocs)
#---------------------------------------------------------------------------------
# On-mesh prefix
# Publish the same on-mesh prefix on different nodes (low
# preference on end-devices, medium preference on routers, and
# high on leader) one by one and then unpublish them one by one.
# Verify that at each step the entries in the network data are
# correct. Particularly verify that that higher preference
# entries replace lower preference ones even when there are
# already desired number in network data.
num_low = 0
num_med = 0
num_high = 0
for node in end_devs:
node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'low')
self.simulator.go(WAIT_TIME)
num_low += 1
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
# Now add the entry as 'med' on routers and check that we see those in the list.
for node in routers:
node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
self.simulator.go(WAIT_TIME)
num_med += 1
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
leader.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'high')
self.simulator.go(WAIT_TIME)
num_high += 1
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
for node in routers:
node.netdata_unpublish_prefix(ON_MESH_PREFIX)
self.simulator.go(WAIT_TIME)
num_med -= 1
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
leader.netdata_unpublish_prefix(ON_MESH_PREFIX)
self.simulator.go(WAIT_TIME)
num_high -= 1
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
for node in end_devs:
node.netdata_unpublish_prefix(ON_MESH_PREFIX)
self.simulator.go(WAIT_TIME)
num_low -= 1
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Verify that when removing extra entries, non-preferred entries
# are removed first over preferred ones. Entries from routers are
# preferred over similar entries from end-devices.
# Publish prefix entry on `end_dev1` and verify that it is added.
end_dev1.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
self.simulator.go(WAIT_TIME)
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, 0, 1, 0)
# Publish same prefix on all routers (again as `med` preference).
# Verify that we reach the desired number of prefix entries in network
# data and that the entry from `end_dev1` is present in network data.
for node in routers:
node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
self.simulator.go(WAIT_TIME)
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, 0, 1 + len(routers), 0)
self.assertTrue(1 + len(routers) >= DESIRED_NUM_ON_MESH_PREFIX)
# `prefixes` is a list of format 'fd00:1234:0:0::/64 paos low a802'
rlocs = [int(prefix.split(' ')[3], 16) for prefix in prefixes]
self.assertTrue(rlocs.count(end_dev1.get_addr16()) == 1)
# Publish same prefix now with `high` preference on leader.
# Since it is `high` preference, it is added to network data
# which leads to total number of entries to go above the desired
# number temporarily and trigger other nodes to try to remove
# their entry. The entries from routers should be preferred over
# the one from `end_dev1` so that is the one we expect to be
# removed. We check that this is the case (i.e., the entry from
# `end_dev1` is no longer present in network data).
leader.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'high')
self.simulator.go(WAIT_TIME)
prefixes = leader.get_prefixes()
self.check_num_of_prefixes(prefixes, 0, 1 + len(routers), 1)
rlocs = [int(prefix.split(' ')[3], 16) for prefix in prefixes]
self.assertTrue(rlocs.count(end_dev1.get_addr16()) == 0)
#---------------------------------------------------------------------------------
# External route
num = 0
for node in nodes:
node.netdata_publish_route(EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'low')
self.simulator.go(WAIT_TIME)
num += 1
routes = leader.get_routes()
self.check_num_of_routes(routes, num, 0, 0)
leader.netdata_unpublish_prefix(EXTERNAL_ROUTE)
leader.netdata_publish_route(EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'high')
self.simulator.go(WAIT_TIME)
routes = leader.get_routes()
self.check_num_of_routes(routes, num - 1, 0, 1)
if __name__ == '__main__':
unittest.main()
@@ -128,7 +128,7 @@ class SrpAutoStartMode(thread_cert.TestCase):
#
server1.srp_server_set_enabled(True)
self.simulator.go(2)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertEqual(client.srp_client_get_server_address(), server2_address)
@@ -98,6 +98,7 @@ class SrpAutoStartMode(thread_cert.TestCase):
# Enable auto start mode on client and check that server1 is used.
server1.srp_server_set_enabled(True)
self.simulator.go(WAIT_TIME)
client.srp_client_set_host_name('host')
client.srp_client_set_host_address('2001::1')
@@ -79,6 +79,7 @@ class SrpSubType(thread_cert.TestCase):
server.srp_server_set_enabled(True)
client.srp_client_enable_auto_start_mode()
self.simulator.go(5)
# Register a single service with 3 subtypes and verify that it worked.
@@ -103,6 +103,14 @@
*/
#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
*
* Define to 1 to enable Network Data Publisher.
*
*/
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_LEGACY_ENABLE
*