From 8bddf61ae2d698362e40069827b6230065fcc906 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 18 Mar 2019 22:58:13 -0700 Subject: [PATCH] [toranj] add test to cover OT/NCP SLAAC module behavior (#3688) This commit updates and renames the existing `test-026-slaac-address` to indicate that it covers the behavior of `wpantund` related to SLAAC address management (in `test-026` we disable NCP SLAAC module). It adds a new test `test-030-slaac-address-ncp` to cover behavior of OpenThread/NCP SLAAC module: - Verify that adding prefix (with SLAAC flag) causes a corresponding SLAAC IPv6 address to be added. - Verify that removing the prefix would remove the SLAAC address. - Verify behavior when same prefix is added and removed on multiple nodes (with or without SLAAC flag). - Check behavior when an IPv6 address with the same prefix already exists. - Check behavior when the address with same prefix is removed (SLAAC module should add a SLAAC address upon removal of the address). - Verify that removal of prefix does not remove user-added addresses with same prefix. - Verify disabling SLAAC module removes any previously added SLAAC addresses, and re-enabling it adds them back (with same IID). - Check behavior when prefix is added while SLAAC module is disabled and then enabled later. --- tests/toranj/openthread-core-toranj-config.h | 7 + tests/toranj/start.sh | 3 +- ....py => test-026-slaac-address-wpantund.py} | 9 +- tests/toranj/test-030-slaac-address-ncp.py | 309 ++++++++++++++++++ tests/toranj/wpan.py | 1 + 5 files changed, 327 insertions(+), 2 deletions(-) rename tests/toranj/{test-026-slaac-address.py => test-026-slaac-address-wpantund.py} (96%) create mode 100644 tests/toranj/test-030-slaac-address-ncp.py diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index a99a9740b..01d85272e 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -288,6 +288,13 @@ */ #define OPENTHREAD_CONFIG_NCP_ENABLE_MCU_POWER_STATE_CONTROL 1 +/** + * @def OPENTHREAD_CONFIG_ENABLE_SLAAC + * + * Define as 1 to enable support for adding of auto-configured SLAAC addresses by OpenThread. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SLAAC 1 #if OPENTHREAD_RADIO /** diff --git a/tests/toranj/start.sh b/tests/toranj/start.sh index c447c2509..530fcd5ff 100755 --- a/tests/toranj/start.sh +++ b/tests/toranj/start.sh @@ -128,10 +128,11 @@ run test-022-multicast-ip6-address.py run test-023-multicast-traffic.py run test-024-partition-merge.py run test-025-network-data-timeout.py -run test-026-slaac-address.py +run test-026-slaac-address-wpantund.py run test-027-child-mode-change.py run test-028-router-leader-reset-recovery.py run test-029-data-poll-interval.py +run test-030-slaac-address-ncp.py run test-100-mcu-power-state.py run test-600-channel-manager-properties.py run test-601-channel-manager-channel-change.py diff --git a/tests/toranj/test-026-slaac-address.py b/tests/toranj/test-026-slaac-address-wpantund.py similarity index 96% rename from tests/toranj/test-026-slaac-address.py rename to tests/toranj/test-026-slaac-address-wpantund.py index 585cb7692..78241ee43 100644 --- a/tests/toranj/test-026-slaac-address.py +++ b/tests/toranj/test-026-slaac-address-wpantund.py @@ -33,7 +33,7 @@ from wpan import verify #----------------------------------------------------------------------------------------------------------------------- # Test description: SLAAC address # -# This test covers the addition/removal of SLAAC IPv6 address. +# This test covers the addition/removal of SLAAC IPv6 address by `wpantund`. # test_name = __file__[:-3] if __file__.endswith('.py') else __file__ @@ -125,6 +125,13 @@ c2.join_node(r2, node_type=wpan.JOIN_TYPE_END_DEVICE) #----------------------------------------------------------------------------------------------------------------------- # Test implementation +# This test covers the SLAAC address management by `wpantund`. So before starting the test we ensure that SLAAC module +# on NCP is disabled on all nodes + +for node in all_nodes: + node.set(wpan.WPAN_OT_SLAAC_ENABLED, 'false') + verify(node.get(wpan.WPAN_OT_SLAAC_ENABLED) == 'false') + WAIT_INTERVAL = 5 PREFIX = 'fd00:abba:beef:cafe::' diff --git a/tests/toranj/test-030-slaac-address-ncp.py b/tests/toranj/test-030-slaac-address-ncp.py new file mode 100644 index 000000000..78b9d9a50 --- /dev/null +++ b/tests/toranj/test-030-slaac-address-ncp.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019, 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 time +import wpan +from wpan import verify + +#----------------------------------------------------------------------------------------------------------------------- +# Test description: SLAAC address +# +# This test covers the behavior of SLAAC module in OpenThread (NCP): +# +# - Verify that adding prefix (with SLAAC flag) causes a corresponding SLAAC IPv6 address to be added. +# - Verify that removing the prefix, would remove the SLAAC address. +# - Verify behavior when same prefix is added/removed on multiple nodes (with or without SLAAC flag). +# - Check behavior when a user-added address with the same prefix already exists. +# - Check behavior when a user-added address with same prefix is removed (SLAAC module should add a SLAAC address). +# - Ensure removal of prefix does not remove user-added address with same prefix. +# - Ensure disabling SLAAC module removes previously added SLAAC addresses, and re-enabling it adds them back. +# - Check behavior when prefix is added while SLAAC module is disabled and then enabled later. + +test_name = __file__[:-3] if __file__.endswith('.py') else __file__ +print '-' * 120 +print 'Starting \'{}\''.format(test_name) + +#----------------------------------------------------------------------------------------------------------------------- +# Utility functions + +def verify_address(node_list, prefix): + """ + This function verifies that all nodes in the `node_list` contain an IPv6 address with the given `prefix`. + """ + for node in node_list: + all_addrs = wpan.parse_list(node.get(wpan.WPAN_IP6_ALL_ADDRESSES)) + verify(any([addr.startswith(prefix[:-1]) for addr in all_addrs])) + +def verify_no_address(node_list, prefix): + """ + This function verifies that none of nodes in the `node_list` contain an IPv6 address with the given `prefix`. + """ + for node in node_list: + all_addrs = wpan.parse_list(node.get(wpan.WPAN_IP6_ALL_ADDRESSES)) + verify(all([not addr.startswith(prefix[:-1]) for addr in all_addrs])) + +def verify_prefix(node_list, prefix, prefix_len=64, stable=True, priority='med', on_mesh=False, slaac=False, dhcp=False, + configure=False, default_route=False, preferred=False): + """ + This function verifies that the `prefix` is present on all nodes in the `node_list`. + """ + for node in node_list: + prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES)) + for p in prefixes: + if p.prefix == prefix: + if int(p.prefix_len) == prefix_len and \ + p.is_stable() == stable and \ + p.is_on_mesh() == on_mesh and \ + p.is_def_route() == default_route and \ + p.is_slaac() == slaac and \ + p.is_dhcp() == dhcp and \ + p.is_config() == configure and \ + p.is_preferred() == preferred and \ + p.priority == priority: + break + else: + raise wpan.VerifyError("Did not find prefix {} on node {}".format(prefix, node)) + +def verify_no_prefix(node_list, prefix): + """ + This function verifies that the `prefix` is NOT present on any node in the `node_list`. + """ + for node in node_list: + prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES)) + for p in prefixes: + verify(not p.prefix == prefix) + +#----------------------------------------------------------------------------------------------------------------------- +# Creating `wpan.Nodes` instances + +speedup = 4 +wpan.Node.set_time_speedup_factor(speedup) + +r1 = wpan.Node() +r2 = wpan.Node() +c2 = wpan.Node() + +all_nodes = [r1, r2, c2] + +#----------------------------------------------------------------------------------------------------------------------- +# Init all nodes + +wpan.Node.init_all_nodes() + +#----------------------------------------------------------------------------------------------------------------------- +# Build network topology + +r1.form('slaac-ncp') + +r1.whitelist_node(r2) +r2.whitelist_node(r1) + +r2.join_node(r1, node_type=wpan.JOIN_TYPE_ROUTER) + +c2.whitelist_node(r2) +r2.whitelist_node(c2) + +c2.join_node(r2, node_type=wpan.JOIN_TYPE_END_DEVICE) + +#----------------------------------------------------------------------------------------------------------------------- +# Test implementation + +# This test covers the SLAAC address management by NCP. So before starting the test we ensure that SLAAC module +# on NCP is enabled on all nodes, and disable it on wpantund. + +for node in all_nodes: + verify(node.get(wpan.WPAN_OT_SLAAC_ENABLED) == 'true') + node.set("Daemon:IPv6:AutoAddSLAACAddress", 'false') + verify(node.get("Daemon:IPv6:AutoAddSLAACAddress") == 'false') + +WAIT_INTERVAL = 5 + +PREFIX = 'fd00:1234::' + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Add prefix and check all nodes get the prefix and add a corresponding SLAAC address. + +r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) + +def check_prefix_and_slaac_address_are_added(): + verify_prefix(all_nodes, PREFIX, stable=True, on_mesh=True, slaac=True) + verify_address(all_nodes, PREFIX) + +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) + +# Save the assigned SLAAC addresses. +slaac_addrs = [node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Check recovery after reseting r1 and c1 (same SLAAC address to be added) + +r1.reset() +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Remove the prefix on r1 and verify that the address and prefix are removed on all nodes. + +r1.remove_prefix(PREFIX) + +def check_prefix_and_slaac_address_are_removed(): + verify_no_prefix(all_nodes, PREFIX) + verify_no_address(all_nodes, PREFIX) + +wpan.verify_within(check_prefix_and_slaac_address_are_removed, WAIT_INTERVAL) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Add the prefix on both r1 and r2, then remove from r1 and ensure SLAAC addresses are assigned on all nodes. + +# Add prefix on r2 +r2.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +# Add same prefix on r1 and verify prefix and addresses stay as before +r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +# Remove on r1, addresses and prefixes should stay as before (r2 still has the same prefix) +r1.remove_prefix(PREFIX) +time.sleep(0.5) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +# Remove the prefix on r2 and verify that the address and prefix are now removed on all nodes. +r2.remove_prefix(PREFIX) +wpan.verify_within(check_prefix_and_slaac_address_are_removed, WAIT_INTERVAL) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Add the prefix on r1 (without SLAAC flag) and r2 (with SLAAC flag) + +# Add prefix on r1 without SLAAC flag, and on r2 with SLAAC flag +r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=False) +r2.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +# Now remove the prefix on r2 and verify that SLAAC address is removed +r2.remove_prefix(PREFIX) + +def check_slaac_address_is_removed(): + verify_no_address(all_nodes, PREFIX) + +wpan.verify_within(check_slaac_address_is_removed, WAIT_INTERVAL) + +r1.remove_prefix(PREFIX) +wpan.verify_within(check_prefix_and_slaac_address_are_removed, WAIT_INTERVAL) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Check behavior when a user-added address with same prefix already exists. + +IP_ADDRESS = PREFIX + "1234" + +# Explicitly add an address with the prefix on r1 +r1.add_ip6_address_on_interface(IP_ADDRESS) + +# Afterwards, add the prefix on r2 (with SLAAC flag) +r2.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) + +# Verify that on r1 we do see the user-added address +r1_addrs = wpan.parse_list(r1.get(wpan.WPAN_IP6_ALL_ADDRESSES)) +verify(IP_ADDRESS in r1_addrs) + +# Also verify that adding the prefix did not add a SLAAC address for same prefix on r1 +r1_addrs.remove(IP_ADDRESS); +verify(all([not addr.startswith(PREFIX[:-1]) for addr in r1_addrs])) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Check behavior when a user-added address with same prefix is removed (SLAAC module should add a SLAAC address). + +r1.remove_ip6_address_on_interface(IP_ADDRESS) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +# Re-add the address +r1.add_ip6_address_on_interface(IP_ADDRESS) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Ensure removal of prefix does not remove user-added address with same prefix. + +r2.remove_prefix(PREFIX) + +def check_ip6_addresses(): + # Verify that SLAAC addresses are removed on r2 and c2 + verify_no_address([r2,c2], PREFIX) + # And that user-added address matching the prefix is not removed on r1 + r1_addrs = wpan.parse_list(r1.get(wpan.WPAN_IP6_ALL_ADDRESSES)) + verify(IP_ADDRESS in r1_addrs) + +wpan.verify_within(check_ip6_addresses, WAIT_INTERVAL) + +r1.remove_ip6_address_on_interface(IP_ADDRESS) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Ensure disabling SLAAC module removes previously added SLAAC addresses, and re-enabling it adds them back. + +r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +for node in all_nodes: + node.set(wpan.WPAN_OT_SLAAC_ENABLED, 'false') +wpan.verify_within(check_slaac_address_is_removed, WAIT_INTERVAL) + +# Re-enable SLAAC support on NCP and verify addresses are re-added back. +for node in all_nodes: + node.set(wpan.WPAN_OT_SLAAC_ENABLED, 'true') +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +r1.remove_prefix(PREFIX) +wpan.verify_within(check_prefix_and_slaac_address_are_removed, WAIT_INTERVAL) + +#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Check behavior when prefix is added while SLAAC is disabled and then enabled later. + +for node in all_nodes: + node.set(wpan.WPAN_OT_SLAAC_ENABLED, 'false') + +# Add prefix and verify that there is no address added +r1.add_prefix(PREFIX, stable=True, on_mesh=True, slaac=True) +wpan.verify_within(check_slaac_address_is_removed, WAIT_INTERVAL) + +for node in all_nodes: + node.set(wpan.WPAN_OT_SLAAC_ENABLED, 'true') +wpan.verify_within(check_prefix_and_slaac_address_are_added, WAIT_INTERVAL) +verify([node.find_ip6_address_with_prefix(PREFIX) for node in all_nodes] == slaac_addrs) + +#----------------------------------------------------------------------------------------------------------------------- +# Test finished + +wpan.Node.finalize_all_nodes() + +print '\'{}\' passed.'.format(test_name) diff --git a/tests/toranj/wpan.py b/tests/toranj/wpan.py index dba2ef702..0b9243631 100644 --- a/tests/toranj/wpan.py +++ b/tests/toranj/wpan.py @@ -106,6 +106,7 @@ WPAN_THREAD_ADDRESS_CACHE_TABLE = "Thread:AddressCacheTable" WPAN_THREAD_ADDRESS_CACHE_TABLE_ASVALMAP = "Thread:AddressCacheTable:AsValMap" WPAN_OT_LOG_LEVEL = "OpenThread:LogLevel" +WPAN_OT_SLAAC_ENABLED = "OpenThread:SLAAC:Enabled" WPAN_OT_STEERING_DATA_ADDRESS = "OpenThread:SteeringData:Address" WPAN_OT_STEERING_DATA_SET_WHEN_JOINABLE = "OpenThread:SteeringData:SetWhenJoinable" WPAN_OT_MSG_BUFFER_COUNTERS = "OpenThread:MsgBufferCounters"