1#!/usr/bin/env python3 2# 3# Copyright (c) 2021, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29import logging 30import unittest 31 32import config 33import pktverify 34from pktverify import packet_verifier, packet_filter, consts 35import thread_cert 36 37# Test description: 38# This test verifies that the Border Router will use the same RA parameters 39# when there is already a running radvd service on the same host. 40# 41# Topology: 42# ----------------(eth)-------------------- 43# | | 44# BR (Leader) HOST 45# | 46# ROUTER 47# 48 49BR = 1 50ROUTER = 2 51HOST = 3 52 53ON_LINK_PREFIX = 'fd00::/64' 54 55 56class SingleBorderRouter(thread_cert.TestCase): 57 USE_MESSAGE_FACTORY = False 58 59 TOPOLOGY = { 60 BR: { 61 'name': 'BR', 62 'allowlist': [ROUTER], 63 'is_otbr': True, 64 'version': '1.2', 65 }, 66 ROUTER: { 67 'name': 'Router', 68 'allowlist': [BR], 69 'version': '1.2', 70 }, 71 HOST: { 72 'name': 'Host', 73 'is_host': True 74 }, 75 } 76 77 def test(self): 78 br = self.nodes[BR] 79 router = self.nodes[ROUTER] 80 host = self.nodes[HOST] 81 82 host.start(start_radvd=False) 83 self.simulator.go(5) 84 85 br.start_radvd_service(prefix=ON_LINK_PREFIX, slaac=True) 86 self.simulator.go(5) 87 88 br.start() 89 self.simulator.go(config.LEADER_STARTUP_DELAY) 90 self.assertEqual('leader', br.get_state()) 91 92 router.start() 93 self.simulator.go(config.ROUTER_STARTUP_DELAY) 94 self.assertEqual('router', router.get_state()) 95 96 self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY) 97 self.collect_ipaddrs() 98 99 logging.info("BR addrs: %r", br.get_addrs()) 100 logging.info("ROUTER addrs: %r", router.get_addrs()) 101 logging.info("HOST addrs: %r", host.get_addrs()) 102 103 self.assertEqual(len(br.get_netdata_omr_prefixes()), 1) 104 self.assertEqual(len(router.get_netdata_omr_prefixes()), 1) 105 self.assertEqual(len(br.get_netdata_non_nat64_routes()), 1) 106 self.assertEqual(len(router.get_netdata_non_nat64_routes()), 1) 107 108 self.assertEqual(len(br.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 109 self.assertEqual(len(router.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 110 111 # radvd doesn't deprecates the PIO so that the Border Router will not 112 # advertise its own on-link prefix immediately. 113 self.assertEqual(len(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)), 1) 114 115 self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) 116 self.assertTrue(host.ping(router.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True)) 117 118 # Stop the radvd service and wait for the Border Router 119 # to reset the RA parameters. 120 br.stop_radvd_service() 121 self.simulator.go(15) 122 123 self.assertEqual(len(br.get_netdata_omr_prefixes()), 1) 124 self.assertEqual(len(router.get_netdata_omr_prefixes()), 1) 125 self.assertEqual(len(br.get_netdata_non_nat64_routes()), 1) 126 self.assertEqual(len(router.get_netdata_non_nat64_routes()), 1) 127 128 self.assertEqual(len(br.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 129 self.assertEqual(len(router.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 130 self.assertEqual(len(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)), 1) 131 132 self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) 133 self.assertTrue(host.ping(router.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True)) 134 135 self.collect_ipaddrs() 136 self.collect_rloc16s() 137 self.collect_rlocs() 138 self.collect_extra_vars() 139 140 def verify(self, pv: pktverify.packet_verifier.PacketVerifier): 141 RA_OPT_TYPE_PIO = 3 142 RA_OPT_TYPE_RIO = 24 143 144 pkts = pv.pkts 145 vars = pv.vars 146 pv.summary.show() 147 logging.info(f'vars = {vars}') 148 149 # Ensure the topology is formed correctly 150 pv.verify_attached('Router', 'BR') 151 152 # verify that radvd sends RA messages with PIO. 153 radvd_ra = pkts.filter_eth_src(vars['BR_ETH']) \ 154 .filter_icmpv6_nd_ra() \ 155 .filter(lambda p: RA_OPT_TYPE_PIO in p.icmpv6.opt.type) \ 156 .must_next() 157 158 # Verify that the BR sends RA messages with the same parameters. 159 br_ra = pkts.filter_eth_src(vars['BR_ETH']) \ 160 .filter_icmpv6_nd_ra() \ 161 .filter(lambda p: RA_OPT_TYPE_RIO in p.icmpv6.opt.type) \ 162 .filter(lambda p: p.icmpv6.nd.ra.router_lifetime == radvd_ra.icmpv6.nd.ra.router_lifetime) \ 163 .filter(lambda p: p.icmpv6.nd.ra.retrans_timer == radvd_ra.icmpv6.nd.ra.retrans_timer) \ 164 .filter(lambda p: p.icmpv6.nd.ra.reachable_time == radvd_ra.icmpv6.nd.ra.reachable_time) \ 165 .must_next() 166 167 # Verify that radvd sends at lease one RA message with zero Router Lifetime 168 # when it is stopped. 169 pkts.filter_eth_src(vars['BR_ETH']) \ 170 .filter_icmpv6_nd_ra() \ 171 .filter(lambda p: RA_OPT_TYPE_PIO in p.icmpv6.opt.type) \ 172 .filter(lambda p: p.icmpv6.nd.ra.router_lifetime == 0) \ 173 .must_next() 174 175 # Verify that the BR forgets radvd's RA parameters. 176 pkts.filter_eth_src(vars['BR_ETH']) \ 177 .filter_icmpv6_nd_ra() \ 178 .filter(lambda p: RA_OPT_TYPE_RIO in p.icmpv6.opt.type) \ 179 .filter(lambda p: p.icmpv6.nd.ra.router_lifetime == 0) \ 180 .filter(lambda p: p.icmpv6.nd.ra.retrans_timer == 0) \ 181 .filter(lambda p: p.icmpv6.nd.ra.reachable_time == 0) \ 182 .must_next() 183 184 # TODO: verify that the BR forgets the radvd's RA parameters in 185 # a period after radvd is force killed. 186 187 188if __name__ == '__main__': 189 unittest.main() 190