[srp-client] adding auto-start feature (#6140)

This commit adds auto-start SRP client feature. Config option
`OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE` adds support for
this feature in SRP client allowing auto-start mode to be enabled or
disabled. When enabled, the SRP client will monitor the Thread Network
Data for SRP Server Service entries and automatically start and stop
the client when an SRP server is detected. If multiple SRP servers are
found, a random one will be selected. If the selected SRP server is no
longer detected (not longer present in the Thread Network Data), the
SRP client will be stopped and then it may switch to another SRP
server (if available).

This commit also adds support for the new feature in CLI and adds a
new test `test_srp_auto_start_mode.py` covering the behavior of this
feature.
This commit is contained in:
Abtin Keshavarzian
2021-02-19 10:00:19 -08:00
committed by GitHub
parent c261cf2dff
commit ef259cdd6b
13 changed files with 619 additions and 32 deletions
+2
View File
@@ -172,6 +172,7 @@ EXTRA_DIST = \
test_route_table.py \
test_router_reattach.py \
test_service.py \
test_srp_auto_start_mode.py \
test_srp_lease.py \
test_srp_name_conflicts.py \
test_srp_register_single_service.py \
@@ -225,6 +226,7 @@ check_SCRIPTS = \
test_route_table.py \
test_router_reattach.py \
test_service.py \
test_srp_auto_start_mode.py \
test_srp_lease.py \
test_srp_name_conflicts.py \
test_srp_register_single_service.py \
+28
View File
@@ -928,6 +928,34 @@ class NodeImpl:
self.send_command(f'srp client stop')
self._expect_done()
def srp_client_get_state(self):
cmd = 'srp client state'
self.send_command(cmd)
return self._expect_command_output(cmd)[0]
def srp_client_get_auto_start_mode(self):
cmd = 'srp client autostart'
self.send_command(cmd)
return self._expect_command_output(cmd)[0]
def srp_client_enable_auto_start_mode(self):
self.send_command(f'srp client autostart enable')
self._expect_done()
def srp_client_disable_auto_start_mode(self):
self.send_command(f'srp client autostart able')
self._expect_done()
def srp_client_get_server_address(self):
cmd = 'srp client server address'
self.send_command(cmd)
return self._expect_command_output(cmd)[0]
def srp_client_get_server_port(self):
cmd = 'srp client server port'
self.send_command(cmd)
return int(self._expect_command_output(cmd)[0])
def srp_client_get_host_state(self):
cmd = 'srp client host state'
self.send_command(cmd)
+151
View File
@@ -0,0 +1,151 @@
#!/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 SRP client auto-start functionality that SRP client can
# correctly discover and connect to SRP server.
#
# Topology:
#
# CLIENT (leader) -- SERVER1 (router)
# |
# |
# SERVER2 (router)
#
CLIENT = 1
SERVER1 = 2
SERVER2 = 3
class SrpAutoStartMode(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
CLIENT: {
'name': 'SRP_CLIENT',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'panid': 0xface
},
SERVER1: {
'name': 'SRP_SERVER1',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'panid': 0xface,
'router_selection_jitter': 1
},
SERVER2: {
'name': 'SRP_SERVER2',
'masterkey': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'panid': 0xface,
'router_selection_jitter': 1
},
}
def test(self):
client = self.nodes[CLIENT]
server1 = self.nodes[SERVER1]
server2 = self.nodes[SERVER2]
#
# 0. Start the server & client devices.
#
client.srp_server_set_enabled(False)
client.start()
self.simulator.go(5)
self.assertEqual(client.get_state(), 'leader')
server1.srp_server_set_enabled(True)
server2.srp_server_set_enabled(False)
server1.start()
server2.start()
self.simulator.go(5)
self.assertEqual(server1.get_state(), 'router')
self.assertEqual(server2.get_state(), 'router')
#
# 1. Enable auto start mode on client and check that server1 is used.
#
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')
self.assertEqual(client.srp_client_get_server_port(), client.get_srp_server_port())
#
# 2. Disable server1 and check client is stopped/disabled.
#
server1.srp_server_set_enabled(False)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Disabled')
#
# 3. Enable server2 and check client starts again.
#
server2.srp_server_set_enabled(True)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
prev_port = client.srp_client_get_server_port()
#
# 4. Enable both servers and check client stays with server2.
#
server1.srp_server_set_enabled(True)
self.simulator.go(2)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertEqual(client.srp_client_get_server_port(), prev_port)
#
# 5. Disable server2 and check client switches to server1.
#
server2.srp_server_set_enabled(False)
self.simulator.go(5)
self.assertEqual(client.srp_client_get_state(), 'Enabled')
self.assertNotEqual(client.srp_client_get_server_port(), prev_port)
if __name__ == '__main__':
unittest.main()