[srp-client] add auto host address mode (#7655)

This commit adds a "auto host address mode" in SRP client. When
enabled, host IPv6 addresses are automatically set by SRP client
using all the unicast addresses on Thread netif excluding the
link-local and mesh-local addresses. If there is no valid address,
then Mesh Local EID address is added. The SRP client will
automatically re-register when/if addresses on Thread netif are
updated (e.g., new addresses are added or existing addresses are
removed).

This commit updates CLI to add support for new SRP client APIs related
to the new feature. It also adds `test_srp_auto_host_address` test to
cover the behavior of this feature.
This commit is contained in:
Abtin Keshavarzian
2022-06-02 15:32:08 -07:00
committed by GitHub
parent e83ecab395
commit 24d633d99d
11 changed files with 500 additions and 35 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (217)
#define OPENTHREAD_API_VERSION (218)
/**
* @addtogroup api-instance
+26 -1
View File
@@ -75,8 +75,9 @@ typedef enum
typedef struct otSrpClientHostInfo
{
const char * mName; ///< Host name (label) string (NULL if not yet set).
const otIp6Address * mAddresses; ///< Pointer to an array of host IPv6 addresses (NULL if not yet set).
const otIp6Address * mAddresses; ///< Array of host IPv6 addresses (NULL if not set or auto address is enabled).
uint8_t mNumAddresses; ///< Number of IPv6 addresses in `mAddresses` array.
bool mAutoAddress; ///< Indicates whether auto address mode is enabled or not.
otSrpClientItemState mState; ///< Host info state.
} otSrpClientHostInfo;
@@ -428,6 +429,27 @@ const otSrpClientHostInfo *otSrpClientGetHostInfo(otInstance *aInstance);
*/
otError otSrpClientSetHostName(otInstance *aInstance, const char *aName);
/**
* This function enables auto host address mode.
*
* When enabled host IPv6 addresses are automatically set by SRP client using all the unicast addresses on Thread netif
* excluding all link-local and mesh-local addresses. If there is no valid address, then Mesh Local EID address is
* added. The SRP client will automatically re-register when/if addresses on Thread netif are updated (new addresses
* are added or existing addresses are removed).
*
* The auto host address mode can be enabled before start or during operation of SRP client except when the host info
* is being removed (client is busy handling a remove request from an call to `otSrpClientRemoveHostAndServices()` and
* host info still being in either `STATE_TO_REMOVE` or `STATE_REMOVING` states).
*
* After auto host address mode is enabled, it can be disabled by a call to `otSrpClientSetHostAddresses()` which
* then explicitly sets the host addresses.
*
* @retval OT_ERROR_NONE Successfully enabled auto host address mode.
* @retval OT_ERROR_INVALID_STATE Host is being removed and therefore cannot enable auto host address mode.
*
*/
otError otSrpClientEnableAutoHostAddress(otInstance *aInstance);
/**
* This function sets/updates the list of host IPv6 address.
*
@@ -442,6 +464,9 @@ otError otSrpClientSetHostName(otInstance *aInstance, const char *aName);
* After a successful call to this function, `otSrpClientCallback` will be called to report the status of the address
* registration with SRP server.
*
* Calling this function disables auto host address mode if it was previously enabled from a successful call to
* `otSrpClientEnableAutoHostAddress()`.
*
* @param[in] aInstance A pointer to the OpenThread instance.
* @param[in] aIp6Addresses A pointer to the an array containing the host IPv6 addresses.
* @param[in] aNumAddresses The number of addresses in the @p aIp6Addresses array.
+26 -3
View File
@@ -139,6 +139,14 @@ name:"dev4312", state:Registered, addrs:[fd00:0:0:0:0:0:0:1234, fd00:0:0:0:0:0:0
Done
```
When auto host address mode is enabled.
```bash
srp client host
name:"dev1234", state:Registered, addrs:auto
Done
```
### host name
Usage: `srp client host name [name]`
@@ -160,9 +168,17 @@ Done
### host address
Usage : `srp client host address [<address> ...]`
Usage : `srp client host address [auto | <address> ...]`
Get the list of host addresses.
Indicate auto address mode is enabled.
```bash
> srp client host address
auto
Done
```
Get the list of host addresses (when auto host address is not enabled).
```bash
> srp client host address
@@ -171,7 +187,14 @@ fd00:0:0:0:0:0:0:beef
Done
```
Set the list of host addresses (can be set while client is running to update the host addresses)
Enable auto host address mode. When enabled client will automatically use all Thread netif unicast addresses excluding all link-local and mesh-local addresses. If there is no valid address, then Mesh Local EID address is added. SRP client will automatically re-register if/when addresses on Thread netif get changed (e.g., new address is added or existing address is removed).
```bash
> srp client host address auto
Done
```
Explicitly set the list of host addresses (can be set while client is running to update the host addresses), also disabled auto host address mode.
```bash
> srp client host address fd00::cafe
+29 -9
View File
@@ -160,10 +160,21 @@ template <> otError SrpClient::Process<Cmd("host")>(Arg aArgs[])
{
const otSrpClientHostInfo *hostInfo = otSrpClientGetHostInfo(GetInstancePtr());
for (uint8_t index = 0; index < hostInfo->mNumAddresses; index++)
if (hostInfo->mAutoAddress)
{
OutputIp6AddressLine(hostInfo->mAddresses[index]);
OutputLine("auto");
}
else
{
for (uint8_t index = 0; index < hostInfo->mNumAddresses; index++)
{
OutputIp6AddressLine(hostInfo->mAddresses[index]);
}
}
}
else if (aArgs[1] == "auto")
{
error = otSrpClientEnableAutoHostAddress(GetInstancePtr());
}
else
{
@@ -447,19 +458,28 @@ void SrpClient::OutputHostInfo(uint8_t aIndentSize, const otSrpClientHostInfo &a
OutputFormat("(null)");
}
OutputFormat(", state:%s, addrs:[", otSrpClientItemStateToString(aHostInfo.mState));
OutputFormat(", state:%s, addrs:", otSrpClientItemStateToString(aHostInfo.mState));
for (uint8_t index = 0; index < aHostInfo.mNumAddresses; index++)
if (aHostInfo.mAutoAddress)
{
if (index > 0)
OutputLine("auto");
}
else
{
OutputFormat("[");
for (uint8_t index = 0; index < aHostInfo.mNumAddresses; index++)
{
OutputFormat(", ");
if (index > 0)
{
OutputFormat(", ");
}
OutputIp6Address(aHostInfo.mAddresses[index]);
}
OutputIp6Address(aHostInfo.mAddresses[index]);
OutputLine("]");
}
OutputLine("]");
}
void SrpClient::OutputServiceList(uint8_t aIndentSize, const otSrpClientService *aServices)
+5
View File
@@ -124,6 +124,11 @@ otError otSrpClientSetHostName(otInstance *aInstance, const char *aName)
return AsCoreType(aInstance).Get<Srp::Client>().SetHostName(aName);
}
otError otSrpClientEnableAutoHostAddress(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Srp::Client>().EnableAutoHostAddress();
}
otError otSrpClientSetHostAddresses(otInstance *aInstance, const otIp6Address *aIp6Addresses, uint8_t aNumAddresses)
{
return AsCoreType(aInstance).Get<Srp::Client>().SetHostAddresses(AsCoreTypePtr(aIp6Addresses), aNumAddresses);
+104 -16
View File
@@ -76,10 +76,20 @@ void Client::HostInfo::SetState(ItemState aState)
}
}
void Client::HostInfo::EnableAutoAddress(void)
{
mAddresses = nullptr;
mNumAddresses = 0;
mAutoAddress = true;
LogInfo("HostInfo enabled auto address", GetNumAddresses());
}
void Client::HostInfo::SetAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses)
{
mAddresses = aAddresses;
mNumAddresses = aNumAddresses;
mAutoAddress = false;
LogInfo("HostInfo set %d addrs", GetNumAddresses());
@@ -239,6 +249,7 @@ Client::Client(Instance &aInstance)
, mState(kStateStopped)
, mTxFailureRetryCount(0)
, mShouldRemoveKeyLease(false)
, mAutoHostAddressAddedMeshLocal(false)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mServiceKeyRecordEnabled(false)
#endif
@@ -415,6 +426,22 @@ void Client::HandleNotifierEvents(Events aEvents)
ProcessAutoStart();
}
#endif
if (mHostInfo.IsAutoAddressEnabled())
{
Events::Flags eventFlags = (kEventIp6AddressAdded | kEventIp6AddressRemoved);
if (mAutoHostAddressAddedMeshLocal)
{
eventFlags |= kEventThreadMeshLocalAddrChanged;
}
if (aEvents.ContainsAny(eventFlags))
{
IgnoreError(UpdateHostInfoStateOnAddressChange());
UpdateState();
}
}
}
void Client::HandleRoleChanged(void)
@@ -466,11 +493,37 @@ exit:
return error;
}
Error Client::EnableAutoHostAddress(void)
{
Error error = kErrorNone;
VerifyOrExit(!mHostInfo.IsAutoAddressEnabled());
SuccessOrExit(error = UpdateHostInfoStateOnAddressChange());
mHostInfo.EnableAutoAddress();
UpdateState();
exit:
return error;
}
Error Client::SetHostAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses)
{
Error error = kErrorNone;
VerifyOrExit((aAddresses != nullptr) && (aNumAddresses > 0), error = kErrorInvalidArgs);
SuccessOrExit(error = UpdateHostInfoStateOnAddressChange());
mHostInfo.SetAddresses(aAddresses, aNumAddresses);
UpdateState();
exit:
return error;
}
Error Client::UpdateHostInfoStateOnAddressChange(void)
{
Error error = kErrorNone;
VerifyOrExit((mHostInfo.GetState() != kToRemove) && (mHostInfo.GetState() != kRemoving),
error = kErrorInvalidState);
@@ -484,9 +537,6 @@ Error Client::SetHostAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddre
mHostInfo.SetState(kToRefresh);
}
mHostInfo.SetAddresses(aAddresses, aNumAddresses);
UpdateState();
exit:
return error;
}
@@ -1008,10 +1058,9 @@ exit:
return error;
}
Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const
Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo)
{
Error error = kErrorNone;
Dns::ResourceRecord rr;
Error error = kErrorNone;
//----------------------------------
// Host Description Instruction
@@ -1024,16 +1073,37 @@ Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) c
// AAAA RRs
rr.Init(Dns::ResourceRecord::kTypeAaaa);
rr.SetTtl(GetTtl());
rr.SetLength(sizeof(Ip6::Address));
for (uint8_t index = 0; index < mHostInfo.GetNumAddresses(); index++)
if (mHostInfo.IsAutoAddressEnabled())
{
SuccessOrExit(error = AppendHostName(aMessage, aInfo));
SuccessOrExit(error = aMessage.Append(rr));
SuccessOrExit(error = aMessage.Append(mHostInfo.GetAddress(index)));
aInfo.mRecordCount++;
// Append all addresses on Thread netif excluding link-local and
// mesh-local addresses. If no address is appended, we include
// the mesh local address.
mAutoHostAddressAddedMeshLocal = true;
for (const Ip6::Netif::UnicastAddress &unicastAddress : Get<ThreadNetif>().GetUnicastAddresses())
{
if (unicastAddress.GetAddress().IsLinkLocal() ||
Get<Mle::Mle>().IsMeshLocalAddress(unicastAddress.GetAddress()))
{
continue;
}
SuccessOrExit(error = AppendAaaaRecord(unicastAddress.GetAddress(), aMessage, aInfo));
mAutoHostAddressAddedMeshLocal = false;
}
if (mAutoHostAddressAddedMeshLocal)
{
SuccessOrExit(error = AppendAaaaRecord(Get<Mle::Mle>().GetMeshLocal64(), aMessage, aInfo));
}
}
else
{
for (uint8_t index = 0; index < mHostInfo.GetNumAddresses(); index++)
{
SuccessOrExit(error = AppendAaaaRecord(mHostInfo.GetAddress(index), aMessage, aInfo));
}
}
// KEY RR
@@ -1045,6 +1115,24 @@ exit:
return error;
}
Error Client::AppendAaaaRecord(const Ip6::Address &aAddress, Message &aMessage, Info &aInfo) const
{
Error error;
Dns::ResourceRecord rr;
rr.Init(Dns::ResourceRecord::kTypeAaaa);
rr.SetTtl(GetTtl());
rr.SetLength(sizeof(Ip6::Address));
SuccessOrExit(error = AppendHostName(aMessage, aInfo));
SuccessOrExit(error = aMessage.Append(rr));
SuccessOrExit(error = aMessage.Append(aAddress));
aInfo.mRecordCount++;
exit:
return error;
}
Error Client::AppendKeyRecord(Message &aMessage, Info &aInfo) const
{
Error error;
@@ -1519,7 +1607,7 @@ void Client::UpdateState(void)
// host address, otherwise no need to send SRP update message.
// The exception is when removing host info where we allow
// for empty service list.
VerifyOrExit(!mServices.IsEmpty() && (mHostInfo.GetNumAddresses() > 0));
VerifyOrExit(!mServices.IsEmpty() && (mHostInfo.IsAutoAddressEnabled() || (mHostInfo.GetNumAddresses() > 0)));
// Fall through
+42 -5
View File
@@ -103,7 +103,7 @@ public:
* This type represents an SRP client host info.
*
*/
class HostInfo : public otSrpClientHostInfo, public Clearable<HostInfo>
class HostInfo : public otSrpClientHostInfo, private Clearable<HostInfo>
{
friend class Client;
@@ -128,6 +128,15 @@ public:
*/
const char *GetName(void) const { return mName; }
/**
* This method indicates whether or not the host auto address mode is enabled.
*
* @retval TRUE If the auto address mode is enabled.
* @retval FALSE If the auto address mode is disabled.
*
*/
bool IsAutoAddressEnabled(void) const { return mAutoAddress; }
/**
* This method gets the number of host IPv6 addresses.
*
@@ -158,6 +167,7 @@ public:
void SetName(const char *aName) { mName = aName; }
void SetState(ItemState aState);
void SetAddresses(const Ip6::Address *aAddresses, uint8_t aNumAddresses);
void EnableAutoAddress(void);
};
/**
@@ -489,16 +499,16 @@ public:
const HostInfo &GetHostInfo(void) const { return mHostInfo; }
/**
* This function sets the host name label.
* This method sets the host name label.
*
* After a successful call to this function, `Callback` will be called to report the status of host info
* After a successful call to this method, `Callback` will be called to report the status of host info
* registration with SRP server.
*
* The host name can be set before client is started or after start but before host info is registered with server
* (host info should be in either `kToAdd` or `kRemoved`).
*
* @param[in] aName A pointer to host name label string (MUST NOT be NULL). Pointer the string buffer MUST
* persist and remain valid and constant after return from this function.
* persist and remain valid and constant after return from this method.
*
* @retval kErrorNone The host name label was set successfully.
* @retval kErrorInvalidArgs The @p aName is NULL.
@@ -507,6 +517,27 @@ public:
*/
Error SetHostName(const char *aName);
/**
* This method enables auto host address mode.
*
* When enabled host IPv6 addresses are automatically set by SRP client using all the unicast addresses on Thread
* netif excluding the link-local and mesh-local addresses. If there is no valid address, then Mesh Local EID
* address is added. The SRP client will automatically re-register when/if addresses on Thread netif are updated
* (new addresses are added or existing addresses are removed).
*
* The auto host address mode can be enabled before start or during operation of SRP client except when the host
* info is being removed (client is busy handling a remove request from an call to `RemoveHostAndServices()` and
* host info still being in either `kStateToRemove` or `kStateRemoving` states).
*
* After auto host address mode is enabled, it can be disabled by a call to `SetHostAddresses()` which then
* explicitly sets the host addresses.
*
* @retval kErrorNone Successfully enabled auto host address mode.
* @retval kErrorInvalidState Host is being removed and therefore cannot enable auto host address mode.
*
*/
Error EnableAutoHostAddress(void);
/**
* This method sets/updates the list of host IPv6 address.
*
@@ -518,6 +549,9 @@ public:
* After a successful call to this method, `Callback` will be called to report the status of the address
* registration with SRP server.
*
* Calling this method disables auto host address mode if it was previously enabled from a successful call to
* `EnableAutoHostAddress()`.
*
* @param[in] aAddresses A pointer to the an array containing the host IPv6 addresses.
* @param[in] aNumAddresses The number of addresses in the @p aAddresses array.
*
@@ -884,6 +918,7 @@ private:
void Pause(void);
void HandleNotifierEvents(Events aEvents);
void HandleRoleChanged(void);
Error UpdateHostInfoStateOnAddressChange(void);
void UpdateServiceStateToRemove(Service &aService);
State GetState(void) const { return mState; }
void SetState(State aState);
@@ -895,10 +930,11 @@ private:
Error PrepareUpdateMessage(Message &aMessage);
Error ReadOrGenerateKey(Crypto::Ecdsa::P256::KeyPair &aKeyPair);
Error AppendServiceInstructions(Service &aService, Message &aMessage, Info &aInfo);
Error AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const;
Error AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo);
Error AppendKeyRecord(Message &aMessage, Info &aInfo) const;
Error AppendDeleteAllRrsets(Message &aMessage) const;
Error AppendHostName(Message &aMessage, Info &aInfo, bool aDoNotCompress = false) const;
Error AppendAaaaRecord(const Ip6::Address &aAddress, Message &aMessage, Info &aInfo) const;
Error AppendUpdateLeaseOptRecord(Message &aMessage) const;
Error AppendSignature(Message &aMessage, Info &aInfo);
void UpdateRecordLengthInMessage(Dns::ResourceRecord &aRecord, uint16_t aOffset, Message &aMessage) const;
@@ -938,6 +974,7 @@ private:
State mState;
uint8_t mTxFailureRetryCount : 4;
bool mShouldRemoveKeyLease : 1;
bool mAutoHostAddressAddedMeshLocal : 1;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
bool mServiceKeyRecordEnabled : 1;
#endif
+2
View File
@@ -188,6 +188,7 @@ EXTRA_DIST = \
test_router_upgrade.py \
test_service.py \
test_set_mliid.py \
test_srp_auto_host_address.py \
test_srp_auto_start_mode.py \
test_srp_client_remove_host.py \
test_srp_client_save_server_info.py \
@@ -264,6 +265,7 @@ check_SCRIPTS = \
test_router_reattach.py \
test_router_upgrade.py \
test_service.py \
test_srp_auto_host_address.py \
test_srp_auto_start_mode.py \
test_srp_client_remove_host.py \
test_srp_client_save_server_info.py \
+4
View File
@@ -1146,6 +1146,10 @@ class NodeImpl:
self.send_command(f'srp client host clear')
self._expect_done()
def srp_client_enable_auto_host_address(self):
self.send_command(f'srp client host address auto')
self._expect_done()
def srp_client_set_host_address(self, *addrs: str):
self.send_command(f'srp client host address {" ".join(addrs)}')
self._expect_done()
+258
View File
@@ -0,0 +1,258 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022, 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 config
import thread_cert
# Test description:
# This test verifies SRP client auto host address mode.
#
# Topology:
# SRP client (leader)
# |
# |
# SRP server (router)
#
CLIENT = 1
SERVER = 2
class SrpAutoHostAddress(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
CLIENT: {
'name': 'SRP_CLIENT',
'mode': 'rdn',
},
SERVER: {
'name': 'SRP_SERVER',
'mode': 'rdn',
},
}
def test(self):
client = self.nodes[CLIENT]
server = self.nodes[SERVER]
#-------------------------------------------------------------------
# Form the network.
client.srp_server_set_enabled(False)
client.start()
self.simulator.go(15)
self.assertEqual(client.get_state(), 'leader')
server.start()
self.simulator.go(5)
self.assertEqual(server.get_state(), 'router')
#-------------------------------------------------------------------
# Enable SRP server
server.srp_server_set_enabled(True)
self.simulator.go(5)
#-------------------------------------------------------------------
# Enable auto start mode on SRP client
self.assertEqual(client.srp_client_get_state(), 'Disabled')
client.srp_client_enable_auto_start_mode()
self.assertEqual(client.srp_client_get_auto_start_mode(), 'Enabled')
self.simulator.go(2)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
#-------------------------------------------------------------------
# Set host name and enable auto host address on client
client.srp_client_set_host_name('host')
client.srp_client_enable_auto_host_address()
#-------------------------------------------------------------------
# Register a service on client
client.srp_client_add_service('test_srv', '_test._udo', 12345, 0, 0)
self.simulator.go(2)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Add an address and check the SRP client re-registered and updated
# server with new address.
client.add_ipaddr('fd00:1:2:3:4:5:6:7')
self.simulator.go(5)
client_addresses = [addr.strip() for addr in client.get_addrs()]
self.assertIn('fd00:1:2:3:4:5:6:7', client_addresses)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Remove the address and check the SRP client re-registered and updated
# server.
client.del_ipaddr('fd00:1:2:3:4:5:6:7')
self.simulator.go(5)
client_addresses = [addr.strip() for addr in client.get_addrs()]
self.assertNotIn('fd00:1:2:3:4:5:6:7', client_addresses)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Add an SLAAC on-mesh prefix (which will trigger an address to be
# added) and check that the SRP client re-registered and updated
# server with the new address.
client.add_prefix('fd00:abba:cafe:bee::/64', 'paos')
client.register_netdata()
self.simulator.go(5)
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:abba:cafe:bee:')]
self.assertEqual(len(slaac_addr), 1)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Add another SLAAC on-mesh prefix and check that the SRP client
# re-registered and updated server with all address.
client.add_prefix('fd00:9:8:7::/64', 'paos')
client.register_netdata()
self.simulator.go(5)
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:9:8:7:')]
self.assertEqual(len(slaac_addr), 1)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Remove the on-mesh prefix (which will trigger an address to be
# removed) and check that the SRP client re-registered and updated
# server with the remaining address.
client.remove_prefix('fd00:abba:cafe:bee::/64')
client.register_netdata()
self.simulator.go(5)
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:abba:cafe:bee:')]
self.assertEqual(len(slaac_addr), 0)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Remove the next on-mesh prefix. Check that SRP client re-registered
# now with only ML-EID.
client.remove_prefix('fd00:9:8:7::/64')
client.register_netdata()
self.simulator.go(5)
slaac_addr = [addr.strip() for addr in client.get_addrs() if addr.strip().startswith('fd00:9:8:7:')]
self.assertEqual(len(slaac_addr), 0)
self.check_registered_addresses(client, server)
#-------------------------------------------------------------------
# Explicitly set the host addresses (which disables the auto host
# address mode) and check that only the new addresses are registered.
client.srp_client_set_host_address('fd00:f:e:d:c:b:a:9')
self.simulator.go(5)
self.assertEqual(client.srp_client_get_host_state(), 'Registered')
server_hosts = server.srp_server_get_hosts()
self.assertEqual(len(server_hosts), 1)
server_host = server_hosts[0]
self.assertEqual(server_host['deleted'], 'false')
self.assertEqual(server_host['fullname'], 'host.default.service.arpa.')
host_addresses = [addr.strip() for addr in server_host['addresses']]
self.assertEqual(len(host_addresses), 1)
self.assertEqual(host_addresses[0], 'fd00:f:e:d:c:b:a:9')
#-------------------------------------------------------------------
# Re-enable auto host address mode and check that addresses are
# updated and registered properly.
client.srp_client_enable_auto_host_address()
self.simulator.go(5)
self.check_registered_addresses(client, server)
def check_registered_addresses(self, client, server):
# Ensure client has registered successfully.
self.assertEqual(client.srp_client_get_host_state(), 'Registered')
# Check the host info on server.
server_hosts = server.srp_server_get_hosts()
self.assertEqual(len(server_hosts), 1)
server_host = server_hosts[0]
self.assertEqual(server_host['deleted'], 'false')
self.assertEqual(server_host['fullname'], 'host.default.service.arpa.')
# Check the host addresses on server to match client.
host_addresses = [addr.strip() for addr in server_host['addresses']]
client_addresses = [addr.strip() for addr in client.get_addrs()]
# All registered addresses must be in client list of addresses.
for addr in host_addresses:
self.assertIn(addr, client_addresses)
# All addresses on client excluding link-local and mesh-local
# addresses must be seen on server side. But if there was
# no address, then mesh-local address should be the only
# one registered.
client_mleid = client.get_mleid()
checked_address = False
for addr in client_addresses:
if not self.is_address_link_local(addr) and not self.is_address_locator(addr) and addr != client_mleid:
self.assertIn(addr, host_addresses)
checked_address = True
if not checked_address:
self.assertEqual(len(host_addresses), 1)
self.assertIn(client_mleid, host_addresses)
def is_address_locator(self, addr):
# Checks if an IPv6 address is a locator (IID should match `0:ff:fe00:xxxx`)
u32s = addr.split(':')
self.assertEqual(len(u32s), 8)
return ':'.join(u32s[4:]).startswith('0:ff:fe00:')
def is_address_link_local(self, addr):
# Checks if an IPv6 address is link-local
return addr.startswith('fe80:')
if __name__ == '__main__':
unittest.main()
+3
View File
@@ -329,6 +329,9 @@ class Node(object):
def srp_client_clear_host(self):
self._cli_no_output('srp client host clear')
def srp_client_enable_auto_host_address(self):
self._cli_no_output('srp client host address auto')
def srp_client_set_host_address(self, *addrs):
self._cli_no_output('srp client host address', *addrs)