mirror of
https://github.com/espressif/openthread.git
synced 2026-09-02 15:20:07 +00:00
[srp-client] enhance selection of TX jitter based on trigger reason (#10357)
This commit improves the `Srp::Client` mechanism for applying random
jitter delays before sending update messages to the server. It now
supports different jitter ranges based on specific triggers. Since
trigger events are often network-wide, potentially causing
simultaneous SRP re-registration from many nodes, longer jitter
intervals are used to distribute the resulting SRP update
transmissions and avoid congestion.
The following triggers are covered:
- Server switch: Client switching to a new server while already
connected to a discovered server. This occurs when a new server
entry appears in Network Data which is preferred over the current
selection.
- Server restart: Client was previously connected to a server that
disappeared from Network Data. Later, the same or a new server is
discovered in Network Data.
- SLAAC address add or remove: This is generally triggered by updates
to SLAAC prefixes in Network Data (e.g., OMR prefix changes).
- First registration after attach:
- If the device is attaching to an established Thread mesh
(e.g., after a reboot or initial pairing), the Network Data it
receives should already include a server entry, leading to a
quick server selection after attach. If server selection occurs
within a short window, a shorter TX jitter is used, allowing the
device to register quickly and become discoverable.
- If server discovery takes longer, a longer TX jitter is used. This
situation can indicate a server/BR starting up or a network-wide
restart of many nodes (e.g., due to a power outage).
This commit introduces `TxJitter` class to manage the requested TX
jitter based on a trigger reason. It tracks the time of the event
that triggered a longer jitter request. If the update message is sent
immediately after the trigger event, the requested maximum jitter is
applied. However, if the update message is sent later, the maximum
jitter is adjusted proportionally to the time elapsed since the
trigger event. If the elapsed time exceeds the requested maximum
jitter interval, the default short jitter is applied to avoid
unnecessary registration delay.
This commit is contained in:
@@ -678,4 +678,13 @@
|
||||
"OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE. Pass the macro to source code under"\
|
||||
"src/lib/spinel."
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY
|
||||
#error "OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY was removed."
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MAX_DELAY
|
||||
#error "OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MAX_DELAY was removed."
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_CONFIG_CHECK_H_
|
||||
|
||||
@@ -225,38 +225,6 @@
|
||||
#define OPENTHREAD_CONFIG_SRP_CLIENT_EARLY_LEASE_RENEW_FACTOR_DENOMINATOR 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY
|
||||
*
|
||||
* Specifies the minimum value (in msec) for the short random delay wait time before sending an update message.
|
||||
*
|
||||
* The random delay is chosen uniformly from the min up to max value `OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MAX_DELAY`.
|
||||
*
|
||||
* When there is a change (e.g., a new service is added/removed) that requires an update, the SRP client will wait for
|
||||
* a short delay before preparing and sending an SRP update message to server. This allows user to provide more change
|
||||
* that are then all sent in same update message. The delay is only applied on the first change that triggers an
|
||||
* update message transmission. Subsequent changes (API calls) while waiting for the tx to start will not reset the
|
||||
* delay timer.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY
|
||||
#define OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY 10
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY
|
||||
*
|
||||
* Specifies the maximum value (in msec) for the short random delay wait time before sending an update message.
|
||||
*
|
||||
* The random delay is chosen uniformly from the min `OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY` up to max value.
|
||||
*
|
||||
* See `OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY` for more details.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MAX_DELAY
|
||||
#define OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MAX_DELAY 700
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SRP_CLIENT_MIN_RETRY_WAIT_INTERVAL
|
||||
*
|
||||
|
||||
@@ -415,6 +415,10 @@ void Netif::SignalUnicastAddressChange(AddressEvent aEvent, const UnicastAddress
|
||||
|
||||
Get<Notifier>().Signal(event);
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
|
||||
Get<Srp::Client>().HandleUnicastAddressEvent(aEvent, aAddress);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
Get<Utils::HistoryTracker>().RecordAddressEvent(aEvent, aAddress);
|
||||
#endif
|
||||
|
||||
+234
-21
@@ -175,6 +175,96 @@ bool Client::Service::Matches(const Service &aOther) const
|
||||
return (strcmp(GetName(), aOther.GetName()) == 0) && (strcmp(GetInstanceName(), aOther.GetInstanceName()) == 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Client::TxJitter
|
||||
|
||||
const uint32_t Client::TxJitter::kMaxJitters[] = {
|
||||
Client::kMaxTxJitterOnDeviceReboot, // (0) kOnDeviceReboot
|
||||
Client::kMaxTxJitterOnServerStart, // (1) kOnServerStart
|
||||
Client::kMaxTxJitterOnServerRestart, // (2) kOnServerRestart
|
||||
Client::kMaxTxJitterOnServerSwitch, // (3) kOnServerSwitch
|
||||
Client::kMaxTxJitterOnSlaacAddrAdd, // (4) kOnSlaacAddrAdd
|
||||
Client::kMaxTxJitterOnSlaacAddrRemove, // (5) kOnSlaacAddrRemove
|
||||
};
|
||||
|
||||
void Client::TxJitter::Request(Reason aReason)
|
||||
{
|
||||
static_assert(0 == kOnDeviceReboot, "kOnDeviceReboot value is incorrect");
|
||||
static_assert(1 == kOnServerStart, "kOnServerStart value is incorrect");
|
||||
static_assert(2 == kOnServerRestart, "kOnServerRestart value is incorrect");
|
||||
static_assert(3 == kOnServerSwitch, "kOnServerSwitch value is incorrect");
|
||||
static_assert(4 == kOnSlaacAddrAdd, "kOnSlaacAddrAdd value is incorrect");
|
||||
static_assert(5 == kOnSlaacAddrRemove, "kOnSlaacAddrRemove value is incorrect");
|
||||
|
||||
uint32_t maxJitter = kMaxJitters[aReason];
|
||||
|
||||
LogInfo("Requesting max tx jitter %lu (%s)", ToUlong(maxJitter), ReasonToString(aReason));
|
||||
|
||||
if (mRequestedMax != 0)
|
||||
{
|
||||
// If we have a previous request, adjust the `mRequestedMax`
|
||||
// based on the time elapsed since that request was made.
|
||||
|
||||
uint32_t duration = TimerMilli::GetNow() - mRequestTime;
|
||||
|
||||
mRequestedMax = (mRequestedMax > duration) ? mRequestedMax - duration : 0;
|
||||
}
|
||||
|
||||
mRequestedMax = Max(mRequestedMax, maxJitter);
|
||||
mRequestTime = TimerMilli::GetNow();
|
||||
}
|
||||
|
||||
uint32_t Client::TxJitter::DetermineDelay(void)
|
||||
{
|
||||
uint32_t delay;
|
||||
uint32_t maxJitter = kMaxTxJitterDefault;
|
||||
|
||||
if (mRequestedMax != 0)
|
||||
{
|
||||
uint32_t duration = TimerMilli::GetNow() - mRequestTime;
|
||||
|
||||
if (duration >= mRequestedMax)
|
||||
{
|
||||
LogInfo("Requested max tx jitter %lu already expired", ToUlong(mRequestedMax));
|
||||
}
|
||||
else
|
||||
{
|
||||
maxJitter = Max(mRequestedMax - duration, kMaxTxJitterDefault);
|
||||
LogInfo("Applying remaining max jitter %lu", ToUlong(maxJitter));
|
||||
}
|
||||
|
||||
mRequestedMax = 0;
|
||||
}
|
||||
|
||||
delay = Random::NonCrypto::GetUint32InRange(kMinTxJitter, maxJitter);
|
||||
LogInfo("Use random tx jitter %lu from [%lu, %lu]", ToUlong(delay), ToUlong(kMinTxJitter), ToUlong(maxJitter));
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
const char *Client::TxJitter::ReasonToString(Reason aReason)
|
||||
{
|
||||
static const char *const kReasonStrings[] = {
|
||||
"OnDeviceReboot", // (0) kOnDeviceReboot
|
||||
"OnServerStart", // (1) kOnServerStart
|
||||
"OnServerRestart", // (2) kOnServerRestart
|
||||
"OnServerSwitch", // (3) kOnServerSwitch
|
||||
"OnSlaacAddrAdd", // (4) kOnSlaacAddrAdd
|
||||
"OnSlaacAddrRemove", // (5) kOnSlaacAddrRemove
|
||||
};
|
||||
|
||||
static_assert(0 == kOnDeviceReboot, "kOnDeviceReboot value is incorrect");
|
||||
static_assert(1 == kOnServerStart, "kOnServerStart value is incorrect");
|
||||
static_assert(2 == kOnServerRestart, "kOnServerRestart value is incorrect");
|
||||
static_assert(3 == kOnServerSwitch, "kOnServerSwitch value is incorrect");
|
||||
static_assert(4 == kOnSlaacAddrAdd, "kOnSlaacAddrAdd value is incorrect");
|
||||
static_assert(5 == kOnSlaacAddrRemove, "kOnSlaacAddrRemove value is incorrect");
|
||||
|
||||
return kReasonStrings[aReason];
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Client::AutoStart
|
||||
|
||||
@@ -183,7 +273,7 @@ bool Client::Service::Matches(const Service &aOther) const
|
||||
Client::AutoStart::AutoStart(void)
|
||||
{
|
||||
Clear();
|
||||
mState = kDefaultMode ? kSelectedNone : kDisabled;
|
||||
mState = kDefaultMode ? kFirstTimeSelecting : kDisabled;
|
||||
}
|
||||
|
||||
bool Client::AutoStart::HasSelectedServer(void) const
|
||||
@@ -193,7 +283,8 @@ bool Client::AutoStart::HasSelectedServer(void) const
|
||||
switch (mState)
|
||||
{
|
||||
case kDisabled:
|
||||
case kSelectedNone:
|
||||
case kFirstTimeSelecting:
|
||||
case kReselecting:
|
||||
break;
|
||||
|
||||
case kSelectedUnicastPreferred:
|
||||
@@ -224,18 +315,20 @@ void Client::AutoStart::InvokeCallback(const Ip6::SockAddr *aServerSockAddr) con
|
||||
const char *Client::AutoStart::StateToString(State aState)
|
||||
{
|
||||
static const char *const kStateStrings[] = {
|
||||
"Disabled", // (0) kDisabled
|
||||
"Idle", // (1) kSelectedNone
|
||||
"Unicast-prf", // (2) kSelectedUnicastPreferred
|
||||
"Anycast", // (3) kSelectedAnycast
|
||||
"Unicast", // (4) kSelectedUnicast
|
||||
"Disabled", // (0) kDisabled
|
||||
"1stTimeSelect", // (1) kFirstTimeSelecting
|
||||
"Reselect", // (2) kReselecting
|
||||
"Unicast-prf", // (3) kSelectedUnicastPreferred
|
||||
"Anycast", // (4) kSelectedAnycast
|
||||
"Unicast", // (5) kSelectedUnicast
|
||||
};
|
||||
|
||||
static_assert(0 == kDisabled, "kDisabled value is incorrect");
|
||||
static_assert(1 == kSelectedNone, "kSelectedNone value is incorrect");
|
||||
static_assert(2 == kSelectedUnicastPreferred, "kSelectedUnicastPreferred value is incorrect");
|
||||
static_assert(3 == kSelectedAnycast, "kSelectedAnycast value is incorrect");
|
||||
static_assert(4 == kSelectedUnicast, "kSelectedUnicast value is incorrect");
|
||||
static_assert(1 == kFirstTimeSelecting, "kFirstTimeSelecting value is incorrect");
|
||||
static_assert(2 == kReselecting, "kReselecting value is incorrect");
|
||||
static_assert(3 == kSelectedUnicastPreferred, "kSelectedUnicastPreferred value is incorrect");
|
||||
static_assert(4 == kSelectedAnycast, "kSelectedAnycast value is incorrect");
|
||||
static_assert(5 == kSelectedUnicast, "kSelectedUnicast value is incorrect");
|
||||
|
||||
return kStateStrings[aState];
|
||||
}
|
||||
@@ -270,6 +363,9 @@ Client::Client(Instance &aInstance)
|
||||
, mSocket(aInstance, *this)
|
||||
, mDomainName(kDefaultDomainName)
|
||||
, mTimer(aInstance)
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
, mGuardTimer(aInstance)
|
||||
#endif
|
||||
{
|
||||
mHostInfo.Init();
|
||||
|
||||
@@ -444,6 +540,10 @@ void Client::HandleRoleChanged(void)
|
||||
{
|
||||
if (Get<Mle::Mle>().IsAttached())
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
ApplyAutoStartGuardOnAttach();
|
||||
#endif
|
||||
|
||||
VerifyOrExit(GetState() == kStatePaused);
|
||||
Resume();
|
||||
}
|
||||
@@ -524,6 +624,36 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Client::HandleUnicastAddressEvent(Ip6::Netif::AddressEvent aEvent, const Ip6::Netif::UnicastAddress &aAddress)
|
||||
{
|
||||
// This callback from `Netif` signals an impending addition or
|
||||
// removal of a unicast address, occurring before `Notifier`
|
||||
// events. If `AutoAddress` is enabled, we check whether the
|
||||
// address origin is SLAAC (e.g., an OMR address) and request a
|
||||
// longer `TxJitter`. This helps randomize the next SRP
|
||||
// update transmission time when triggered by an OMR prefix
|
||||
// change.
|
||||
|
||||
VerifyOrExit(IsRunning());
|
||||
VerifyOrExit(mHostInfo.IsAutoAddressEnabled());
|
||||
|
||||
VerifyOrExit(aAddress.GetOrigin() == Ip6::Netif::kOriginSlaac);
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
// The `mGuardTimer`, started by `ApplyAutoStartGuardOnAttach()`,
|
||||
// tracks a guard interval after the attach event. If an
|
||||
// address change occurs within this short window, we do not
|
||||
// apply a longer TX jitter, as this likely indicates a device
|
||||
// reboot.
|
||||
VerifyOrExit(!mGuardTimer.IsRunning());
|
||||
#endif
|
||||
|
||||
mTxJitter.Request((aEvent == Ip6::Netif::kAddressAdded) ? TxJitter::kOnSlaacAddrAdd : TxJitter::kOnSlaacAddrRemove);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool Client::ShouldUpdateHostAutoAddresses(void) const
|
||||
{
|
||||
bool shouldUpdate = false;
|
||||
@@ -736,7 +866,7 @@ void Client::SetState(State aState)
|
||||
break;
|
||||
|
||||
case kStateToUpdate:
|
||||
mTimer.Start(Random::NonCrypto::GetUint32InRange(kUpdateTxMinDelay, kUpdateTxMaxDelay));
|
||||
mTimer.Start(mTxJitter.DetermineDelay());
|
||||
break;
|
||||
|
||||
case kStateUpdating:
|
||||
@@ -778,7 +908,8 @@ bool Client::ChangeHostAndServiceStates(const ItemState *aNewStates, ServiceStat
|
||||
switch (mAutoStart.GetState())
|
||||
{
|
||||
case AutoStart::kDisabled:
|
||||
case AutoStart::kSelectedNone:
|
||||
case AutoStart::kFirstTimeSelecting:
|
||||
case AutoStart::kReselecting:
|
||||
break;
|
||||
|
||||
case AutoStart::kSelectedUnicastPreferred:
|
||||
@@ -2056,19 +2187,46 @@ void Client::EnableAutoStartMode(AutoStartCallback aCallback, void *aContext)
|
||||
|
||||
VerifyOrExit(mAutoStart.GetState() == AutoStart::kDisabled);
|
||||
|
||||
mAutoStart.SetState(AutoStart::kSelectedNone);
|
||||
mAutoStart.SetState(AutoStart::kFirstTimeSelecting);
|
||||
ApplyAutoStartGuardOnAttach();
|
||||
|
||||
ProcessAutoStart();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::ApplyAutoStartGuardOnAttach(void)
|
||||
{
|
||||
VerifyOrExit(Get<Mle::Mle>().IsAttached());
|
||||
VerifyOrExit(!IsRunning());
|
||||
VerifyOrExit(mAutoStart.GetState() == AutoStart::kFirstTimeSelecting);
|
||||
|
||||
// The `mGuardTimer` tracks a guard interval after the attach
|
||||
// event while `AutoStart` has yet to select a server for the
|
||||
// first time.
|
||||
//
|
||||
// This is used by `ProcessAutoStart()` to apply different TX
|
||||
// jitter values. If server selection occurs within this short
|
||||
// window, a shorter TX jitter is used. This typically represents
|
||||
// the device rebooting or being paired.
|
||||
//
|
||||
// The guard time is also checked when handling SLAAC address change
|
||||
// events, to decide whether or not to request longer TX jitter.
|
||||
|
||||
mGuardTimer.Start(kGuardTimeAfterAttachToUseShorterTxJitter);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::ProcessAutoStart(void)
|
||||
{
|
||||
Ip6::SockAddr serverSockAddr;
|
||||
DnsSrpAnycast::Info anycastInfo;
|
||||
DnsSrpUnicast::Info unicastInfo;
|
||||
bool shouldRestart = false;
|
||||
AutoStart::State oldAutoStartState = mAutoStart.GetState();
|
||||
bool shouldRestart = false;
|
||||
|
||||
// If auto start mode is enabled, we check the Network Data entries
|
||||
// to discover and select the preferred SRP server to register with.
|
||||
@@ -2083,7 +2241,7 @@ void Client::ProcessAutoStart(void)
|
||||
|
||||
if (IsRunning())
|
||||
{
|
||||
VerifyOrExit(mAutoStart.GetState() != AutoStart::kSelectedNone);
|
||||
VerifyOrExit(mAutoStart.HasSelectedServer());
|
||||
}
|
||||
|
||||
// There are three types of entries in Network Data:
|
||||
@@ -2131,15 +2289,69 @@ void Client::ProcessAutoStart(void)
|
||||
Stop(kRequesterAuto, kResetRetryInterval);
|
||||
}
|
||||
|
||||
if (!serverSockAddr.GetAddress().IsUnspecified())
|
||||
if (serverSockAddr.GetAddress().IsUnspecified())
|
||||
{
|
||||
IgnoreError(Start(serverSockAddr, kRequesterAuto));
|
||||
if (mAutoStart.HasSelectedServer())
|
||||
{
|
||||
mAutoStart.SetState(AutoStart::kReselecting);
|
||||
}
|
||||
|
||||
ExitNow();
|
||||
}
|
||||
else
|
||||
|
||||
// Before calling `Start()`, determine the trigger reason for
|
||||
// starting the client with the newly discovered server based on
|
||||
// `AutoStart` state transitions. This reason is then used to
|
||||
// select the appropriate TX jitter interval (randomizing the
|
||||
// initial SRP update transmission to the new server).
|
||||
|
||||
switch (oldAutoStartState)
|
||||
{
|
||||
mAutoStart.SetState(AutoStart::kSelectedNone);
|
||||
case AutoStart::kDisabled:
|
||||
break;
|
||||
|
||||
case AutoStart::kFirstTimeSelecting:
|
||||
|
||||
// If the device is attaching to an established Thread mesh
|
||||
// (e.g., after a reboot or pairing), the Network Data it
|
||||
// receives should already include a server entry, leading to
|
||||
// a quick server selection after attachment. The `mGuardTimer`,
|
||||
// started by `ApplyAutoStartGuardOnAttach()`, tracks a guard
|
||||
// interval after the attach event. If server selection
|
||||
// occurs within this short window, a shorter TX jitter is
|
||||
// used (`TxJitter::kOnDeviceReboot`), allowing the device to
|
||||
// register quickly and become discoverable.
|
||||
//
|
||||
// If server discovery takes longer, a longer TX jitter
|
||||
// is used (`TxJitter::kOnServerStart`). This situation
|
||||
// can indicate a server/BR starting up or a network-wide
|
||||
// restart of many nodes (e.g., due to a power outage).
|
||||
|
||||
if (mGuardTimer.IsRunning())
|
||||
{
|
||||
mTxJitter.Request(TxJitter::kOnDeviceReboot);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTxJitter.Request(TxJitter::kOnServerStart);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AutoStart::kReselecting:
|
||||
// Server is restarted (or possibly a new server started).
|
||||
mTxJitter.Request(TxJitter::kOnServerRestart);
|
||||
break;
|
||||
|
||||
case AutoStart::kSelectedUnicastPreferred:
|
||||
case AutoStart::kSelectedAnycast:
|
||||
case AutoStart::kSelectedUnicast:
|
||||
mTxJitter.Request(TxJitter::kOnServerSwitch);
|
||||
break;
|
||||
}
|
||||
|
||||
IgnoreError(Start(serverSockAddr, kRequesterAuto));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
@@ -2230,7 +2442,8 @@ void Client::SelectNextServer(bool aDisallowSwitchOnRegisteredHost)
|
||||
|
||||
case AutoStart::kSelectedAnycast:
|
||||
case AutoStart::kDisabled:
|
||||
case AutoStart::kSelectedNone:
|
||||
case AutoStart::kFirstTimeSelecting:
|
||||
case AutoStart::kReselecting:
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
|
||||
+70
-13
@@ -49,6 +49,7 @@
|
||||
#include "crypto/ecdsa.hpp"
|
||||
#include "net/dns_types.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "net/netif.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
#include "thread/network_data_service.hpp"
|
||||
|
||||
@@ -71,6 +72,7 @@ namespace Srp {
|
||||
class Client : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
friend class ot::Notifier;
|
||||
friend class ot::Ip6::Netif;
|
||||
|
||||
using DnsSrpUnicast = NetworkData::Service::DnsSrpUnicast;
|
||||
using DnsSrpAnycast = NetworkData::Service::DnsSrpAnycast;
|
||||
@@ -853,13 +855,28 @@ private:
|
||||
OPENTHREAD_CONFIG_SRP_CLIENT_EARLY_LEASE_RENEW_FACTOR_DENOMINATOR;
|
||||
|
||||
// -------------------------------
|
||||
// When there is a change (e.g., a new service is added/removed)
|
||||
// that requires an update, the SRP client will wait for a short
|
||||
// delay as specified by `kUpdateTxDelay` before sending an SRP
|
||||
// update to server. This allows the user to provide more change
|
||||
// that are then all sent in same update message.
|
||||
static constexpr uint32_t kUpdateTxMinDelay = OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MIN_DELAY; // in msec.
|
||||
static constexpr uint32_t kUpdateTxMaxDelay = OPENTHREAD_CONFIG_SRP_CLIENT_UPDATE_TX_MAX_DELAY; // in msec.
|
||||
// TX jitter constants
|
||||
//
|
||||
// When changes trigger a new SRP update message transmission a random
|
||||
// jitter delay is applied before sending the update message to server.
|
||||
// This can occur due to changes in client services or host info,
|
||||
// or `AutoStart` selecting a server for the first time or switching
|
||||
// to a new server thus requiring re-registration.
|
||||
//
|
||||
// The constants below specify jitter ranges applied based on
|
||||
// different trigger reasons. All values are in milliseconds.
|
||||
// Also see `TxJitter` class.
|
||||
|
||||
static constexpr uint32_t kMinTxJitter = 10;
|
||||
static constexpr uint32_t kMaxTxJitterDefault = 500;
|
||||
static constexpr uint32_t kMaxTxJitterOnDeviceReboot = 700;
|
||||
static constexpr uint32_t kMaxTxJitterOnServerStart = 10 * Time::kOneSecondInMsec;
|
||||
static constexpr uint32_t kMaxTxJitterOnServerRestart = 10 * Time::kOneSecondInMsec;
|
||||
static constexpr uint32_t kMaxTxJitterOnServerSwitch = 10 * Time::kOneSecondInMsec;
|
||||
static constexpr uint32_t kMaxTxJitterOnSlaacAddrAdd = 10 * Time::kOneSecondInMsec;
|
||||
static constexpr uint32_t kMaxTxJitterOnSlaacAddrRemove = 10 * Time::kOneSecondInMsec;
|
||||
|
||||
static constexpr uint32_t kGuardTimeAfterAttachToUseShorterTxJitter = 1000;
|
||||
|
||||
// -------------------------------
|
||||
// Retry related constants
|
||||
@@ -945,16 +962,47 @@ private:
|
||||
kForServicesAppendedInMessage,
|
||||
};
|
||||
|
||||
class TxJitter : public Clearable<TxJitter>
|
||||
{
|
||||
// Manages the random TX jitter to use when sending SRP update
|
||||
// messages.
|
||||
|
||||
public:
|
||||
enum Reason
|
||||
{
|
||||
kOnDeviceReboot,
|
||||
kOnServerStart,
|
||||
kOnServerRestart,
|
||||
kOnServerSwitch,
|
||||
kOnSlaacAddrAdd,
|
||||
kOnSlaacAddrRemove,
|
||||
};
|
||||
|
||||
TxJitter(void) { Clear(); }
|
||||
void Request(Reason aReason);
|
||||
uint32_t DetermineDelay(void);
|
||||
|
||||
private:
|
||||
static const uint32_t kMaxJitters[];
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
static const char *ReasonToString(Reason aReason);
|
||||
#endif
|
||||
|
||||
uint32_t mRequestedMax;
|
||||
TimeMilli mRequestTime;
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
class AutoStart : public Clearable<AutoStart>
|
||||
{
|
||||
public:
|
||||
enum State : uint8_t{
|
||||
kDisabled, // AutoStart is disabled.
|
||||
kSelectedNone, // AutoStart is enabled but not yet selected any servers.
|
||||
kSelectedUnicastPreferred, // AutoStart selected a preferred unicast entry (address in service data).
|
||||
kSelectedAnycast, // AutoStart selected an anycast entry with `mAnycastSeqNum`.
|
||||
kSelectedUnicast, // AutoStart selected a unicast entry (address in server data).
|
||||
kDisabled, // Disabled.
|
||||
kFirstTimeSelecting, // Trying to select a server for the first time since AutoStart was enabled.
|
||||
kReselecting, // Trying to select a server again (previously selected server was removed).
|
||||
kSelectedUnicastPreferred, // Has selected a preferred unicast entry (address in service data).
|
||||
kSelectedAnycast, // Has selected an anycast entry with `mAnycastSeqNum`.
|
||||
kSelectedUnicast, // Has selected a unicast entry (address in server data).
|
||||
};
|
||||
|
||||
AutoStart(void);
|
||||
@@ -1012,6 +1060,7 @@ private:
|
||||
void Pause(void);
|
||||
void HandleNotifierEvents(Events aEvents);
|
||||
void HandleRoleChanged(void);
|
||||
void HandleUnicastAddressEvent(Ip6::Netif::AddressEvent aEvent, const Ip6::Netif::UnicastAddress &aAddress);
|
||||
bool ShouldUpdateHostAutoAddresses(void) const;
|
||||
bool ShouldHostAutoAddressRegister(const Ip6::Netif::UnicastAddress &aUnicastAddress) const;
|
||||
Error UpdateHostInfoStateOnAddressChange(void);
|
||||
@@ -1056,8 +1105,10 @@ private:
|
||||
bool ShouldRenewEarly(const Service &aService) const;
|
||||
void HandleTimer(void);
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
void ApplyAutoStartGuardOnAttach(void);
|
||||
void ProcessAutoStart(void);
|
||||
Error SelectUnicastEntry(DnsSrpUnicast::Origin aOrigin, DnsSrpUnicast::Info &aInfo) const;
|
||||
void HandleGuardTimer(void) {}
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_SWITCH_SERVER_ON_FAILURE
|
||||
void SelectNextServer(bool aDisallowSwitchOnRegisteredHost);
|
||||
#endif
|
||||
@@ -1077,6 +1128,10 @@ private:
|
||||
using DelayTimer = TimerMilliIn<Client, &Client::HandleTimer>;
|
||||
using ClientSocket = Ip6::Udp::SocketIn<Client, &Client::HandleUdpReceive>;
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
using GuardTimer = TimerMilliIn<Client, &Client::HandleGuardTimer>;
|
||||
#endif
|
||||
|
||||
State mState;
|
||||
uint8_t mTxFailureRetryCount : 4;
|
||||
bool mShouldRemoveKeyLease : 1;
|
||||
@@ -1097,6 +1152,7 @@ private:
|
||||
uint32_t mKeyLease;
|
||||
uint32_t mDefaultLease;
|
||||
uint32_t mDefaultKeyLease;
|
||||
TxJitter mTxJitter;
|
||||
|
||||
ClientSocket mSocket;
|
||||
|
||||
@@ -1106,7 +1162,8 @@ private:
|
||||
LinkedList<Service> mServices;
|
||||
DelayTimer mTimer;
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
AutoStart mAutoStart;
|
||||
GuardTimer mGuardTimer;
|
||||
AutoStart mAutoStart;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class TestDnssdNameWithSpecialChars(thread_cert.TestCase):
|
||||
|
||||
server.srp_server_set_enabled(True)
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
# Register a single service with the instance name containing special chars
|
||||
client.srp_client_set_host_name('host1')
|
||||
|
||||
@@ -74,6 +74,7 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
client.start()
|
||||
self.simulator.go(15)
|
||||
self.assertEqual(client.get_state(), 'leader')
|
||||
client.srp_client_stop()
|
||||
|
||||
server.start()
|
||||
self.simulator.go(5)
|
||||
@@ -88,8 +89,9 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
#-------------------------------------------------------------------
|
||||
# Check auto start mode on SRP client
|
||||
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled')
|
||||
self.simulator.go(2)
|
||||
self.simulator.go(15)
|
||||
|
||||
self.assertEqual(client.srp_client_get_state(), 'Enabled')
|
||||
|
||||
@@ -135,7 +137,7 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
|
||||
client.add_prefix('fd00:abba:cafe:bee::/64', 'paos')
|
||||
client.register_netdata()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:abba:cafe:bee:')]
|
||||
self.assertEqual(len(slaac_addr), 1)
|
||||
@@ -147,7 +149,7 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
|
||||
client.add_prefix('fd00:9:8:7::/64', 'paos')
|
||||
client.register_netdata()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:9:8:7:')]
|
||||
self.assertEqual(len(slaac_addr), 1)
|
||||
@@ -160,7 +162,7 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
|
||||
client.add_prefix('fd00:a:b:c::/64', 'aos')
|
||||
client.register_netdata()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:a:b:c:')]
|
||||
self.assertEqual(len(slaac_addr), 1)
|
||||
@@ -173,7 +175,7 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
client.remove_prefix('fd00:abba:cafe:bee::/64')
|
||||
client.register_netdata()
|
||||
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
self.check_registered_addresses(client, server)
|
||||
|
||||
@@ -184,7 +186,7 @@ class SrpAutoHostAddress(thread_cert.TestCase):
|
||||
client.remove_prefix('fd00:9:8:7::/64')
|
||||
client.register_netdata()
|
||||
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
self.check_registered_addresses(client, server)
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class SrpRemoveHost(thread_cert.TestCase):
|
||||
|
||||
server.srp_server_set_enabled(True)
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
#-------------------------------------------------------------------------------------
|
||||
# Register a single service and verify that it worked.
|
||||
|
||||
@@ -48,7 +48,7 @@ SERVER1 = 2
|
||||
SERVER2 = 3
|
||||
SERVER3 = 4
|
||||
|
||||
WAIT_TIME = 5
|
||||
WAIT_TIME = 16
|
||||
MAX_ITER = 5
|
||||
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ class SrpRegisterSingleService(thread_cert.TestCase):
|
||||
|
||||
# Start the client again, the same service should be successfully registered.
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(2)
|
||||
self.simulator.go(15)
|
||||
|
||||
self.check_host_and_service(server, client)
|
||||
|
||||
@@ -132,7 +132,7 @@ class SrpRegisterSingleService(thread_cert.TestCase):
|
||||
|
||||
# Start the client again, the same service should be successfully registered.
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(2)
|
||||
self.simulator.go(15)
|
||||
|
||||
self.check_host_and_service(server, client)
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class SrpManyServicesMtuCheck(thread_cert.TestCase):
|
||||
|
||||
server.srp_server_set_enabled(True)
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
# Register 8 services with long name, 6 sub-types and long txt record.
|
||||
# The 8 services won't be fit in a single MTU (1280 bytes) UDP message
|
||||
|
||||
@@ -84,7 +84,7 @@ class SrpRegisterServicesDiffLease(thread_cert.TestCase):
|
||||
server.srp_server_set_enabled(True)
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
client.srp_client_set_host_name('host')
|
||||
client.srp_client_enable_auto_host_address()
|
||||
|
||||
@@ -147,7 +147,7 @@ class TestSrpServerAnycastMode(thread_cert.TestCase):
|
||||
# server and uses the proper address and port number.
|
||||
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
if addr_mode == 'anycast':
|
||||
server_alocs = server.get_ip6_address(config.ADDRESS_TYPE.ALOC)
|
||||
|
||||
@@ -109,7 +109,7 @@ class SrpServerRebootPort(thread_cert.TestCase):
|
||||
client.srp_client_set_host_name('my-host')
|
||||
client.srp_client_set_host_address('2001::1')
|
||||
client.srp_client_add_service('my-service', '_ipps._tcp', 12345, 0, 0, ['abc', 'def=', 'xyz=XYZ'])
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(16)
|
||||
self.check_host_and_service(server, client, '2001::1')
|
||||
|
||||
ports = [server.get_srp_server_port()]
|
||||
@@ -129,7 +129,7 @@ class SrpServerRebootPort(thread_cert.TestCase):
|
||||
# re-registered.
|
||||
#
|
||||
server.srp_server_set_enabled(True)
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(16)
|
||||
self.assertEqual(client.srp_client_get_state(), 'Enabled')
|
||||
self.assertEqual(client.srp_client_get_server_address(), server.get_mleid())
|
||||
self.assertNotEqual(old_port, server.get_srp_server_port())
|
||||
|
||||
@@ -80,7 +80,7 @@ class SrpSubType(thread_cert.TestCase):
|
||||
|
||||
server.srp_server_set_enabled(True)
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
self.simulator.go(5)
|
||||
self.simulator.go(15)
|
||||
|
||||
# Register a single service with 3 subtypes and verify that it worked.
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ class SrpTtl(thread_cert.TestCase):
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(client.get_state(), 'router')
|
||||
|
||||
self.simulator.go(15)
|
||||
self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled')
|
||||
|
||||
client.srp_client_set_host_name('my-host')
|
||||
|
||||
@@ -61,11 +61,12 @@ verify(client.get_state() == 'router')
|
||||
verify(server.srp_server_get_state() == 'disabled')
|
||||
verify(server.srp_server_get_addr_mode() == 'unicast')
|
||||
verify(client.srp_client_get_state() == 'Disabled')
|
||||
verify(client.srp_client_get_auto_start_mode() == 'Enabled')
|
||||
|
||||
# Start server and client and register single service
|
||||
server.srp_server_enable()
|
||||
|
||||
client.srp_client_enable_auto_start_mode()
|
||||
verify(client.srp_client_get_auto_start_mode() == 'Enabled')
|
||||
client.srp_client_set_host_name('host')
|
||||
client.srp_client_set_host_address('fd00::cafe')
|
||||
client.srp_client_add_service('ins', '_test._udp', 777, 2, 1)
|
||||
|
||||
@@ -147,6 +147,7 @@ verify(br2.srp_server_get_state() == 'disabled')
|
||||
# Register SRP services on all nodes
|
||||
|
||||
for node in nodes_non_br:
|
||||
node.srp_client_enable_auto_start_mode()
|
||||
verify(node.srp_client_get_auto_start_mode() == 'Enabled')
|
||||
node.srp_client_set_host_name('host' + str(node.index))
|
||||
node.srp_client_enable_auto_host_address()
|
||||
|
||||
@@ -147,6 +147,7 @@ verify(br2.srp_server_get_state() == 'disabled')
|
||||
# Register SRP services on all nodes
|
||||
|
||||
for node in nodes_non_br:
|
||||
node.srp_client_enable_auto_start_mode()
|
||||
verify(node.srp_client_get_auto_start_mode() == 'Enabled')
|
||||
node.srp_client_set_host_name('host' + str(node.index))
|
||||
node.srp_client_enable_auto_host_address()
|
||||
|
||||
@@ -175,6 +175,8 @@
|
||||
|
||||
#define OPENTHREAD_CONFIG_SRP_CLIENT_DOMAIN_NAME_API_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE 0
|
||||
|
||||
#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 1
|
||||
|
||||
#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 1
|
||||
|
||||
@@ -940,7 +940,7 @@ void TestSrpAdvProxy(void)
|
||||
|
||||
sProcessedClientCallback = false;
|
||||
|
||||
AdvanceTime(5 * 1000);
|
||||
AdvanceTime(15 * 1000);
|
||||
|
||||
// This time we should only see new host registration
|
||||
// since that's the only thing that changes
|
||||
|
||||
@@ -892,7 +892,7 @@ void TestUpdateLeaseShortVariant(void)
|
||||
srpClient->EnableAutoStartMode(nullptr, nullptr);
|
||||
VerifyOrQuit(srpClient->IsAutoStartModeEnabled());
|
||||
|
||||
AdvanceTime(2000);
|
||||
AdvanceTime(15 * 1000);
|
||||
VerifyOrQuit(srpClient->IsRunning());
|
||||
|
||||
SuccessOrQuit(srpClient->SetHostName(kHostName));
|
||||
|
||||
Reference in New Issue
Block a user