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 unittest
30
31import config
32import thread_cert
33
34# Test description:
35#   This test verifies TREL connectivity.
36#
37# Topology:
38#    ----------------(eth)--------------------------
39#                 |                  |
40#       FED1 --- BR1 (Leader) ----- BR2 --- ROUTER2
41#                /\
42#               /  \
43#             MED1 SED1
44#
45from config import PACKET_VERIFICATION_TREL
46from pktverify.packet_filter import PacketFilter
47from pktverify.packet_verifier import PacketVerifier
48
49BR1 = 1
50FED1 = 2
51MED1 = 3
52SED1 = 4
53BR2 = 5
54ROUTER2 = 6
55
56
57class TestTrelConnectivity(thread_cert.TestCase):
58    USE_MESSAGE_FACTORY = False
59    PACKET_VERIFICATION = PACKET_VERIFICATION_TREL
60
61    TOPOLOGY = {
62        BR1: {
63            'name': 'BR1',
64            'allowlist': [BR2, FED1, MED1, SED1],
65            'is_otbr': True,
66            'version': '1.2',
67        },
68        FED1: {
69            'name': 'ROUTER1',
70            'allowlist': [BR1],
71            'version': '1.2',
72            'router_eligible': False,
73        },
74        MED1: {
75            'name': 'MED1',
76            'allowlist': [BR1],
77            'version': '1.2',
78            'mode': 'rn',
79        },
80        SED1: {
81            'name': 'SED1',
82            'allowlist': [BR1],
83            'version': '1.2',
84            'mode': 'n',
85        },
86        BR2: {
87            'name': 'BR2',
88            'allowlist': [BR1, ROUTER2],
89            'is_otbr': True,
90            'version': '1.2',
91        },
92        ROUTER2: {
93            'name': 'ROUTER2',
94            'allowlist': [BR2],
95            'version': '1.2',
96        },
97    }
98
99    def test(self):
100        br1 = self.nodes[BR1]
101        fed1 = self.nodes[FED1]
102        med1 = self.nodes[MED1]
103        sed1 = self.nodes[SED1]
104        br2 = self.nodes[BR2]
105        router2 = self.nodes[ROUTER2]
106
107        if br1.is_trel_enabled() is None:
108            self.skipTest("TREL is not supported")
109
110        if br1.is_trel_enabled() == False:
111            br1.enable_trel()
112
113        if br2.is_trel_enabled() == False:
114            br2.enable_trel()
115
116        br1.start()
117        self.wait_node_state(br1, 'leader', 10)
118
119        fed1.start()
120        self.wait_node_state(fed1, 'child', 10)
121
122        med1.start()
123        self.wait_node_state(med1, 'child', 10)
124
125        sed1.start()
126        self.wait_node_state(sed1, 'child', 10)
127
128        br2.start()
129        self.wait_node_state(br2, 'router', 10)
130
131        router2.start()
132        self.wait_node_state(router2, 'router', 10)
133
134        # Allow the network to stabilize
135        self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY)
136
137        self.collect_ipaddrs()
138        self.collect_rloc16s()
139
140        router2_mleid = router2.get_mleid()
141        self.assertTrue(br1.ping(router2_mleid))
142        self.assertTrue(fed1.ping(router2_mleid))
143        self.assertTrue(med1.ping(router2_mleid))
144        self.assertTrue(sed1.ping(router2_mleid))
145
146        counters = br1.get_trel_counters()
147        print('br1 trel counters', counters)
148        self.assertTrue(counters['Inbound']['packets'] > 0)
149        self.assertTrue(counters['Inbound']['bytes'] > 0)
150        self.assertTrue(counters['Outbound']['packets'] > 0)
151        self.assertTrue(counters['Outbound']['bytes'] > 0)
152        self.assertTrue(counters['Outbound']['failures'] >= 0)
153
154        br1.reset_trel_counters()
155        counters = br1.get_trel_counters()
156        print('br1 trel counters after reset', counters)
157        self.assertTrue(counters['Inbound']['packets'] == 0)
158        self.assertTrue(counters['Inbound']['bytes'] == 0)
159        self.assertTrue(counters['Outbound']['packets'] == 0)
160        self.assertTrue(counters['Outbound']['bytes'] == 0)
161        self.assertTrue(counters['Outbound']['failures'] == 0)
162
163    def verify(self, pv: PacketVerifier):
164        pkts: PacketFilter = pv.pkts
165        BR1_RLOC16 = pv.vars['BR1_RLOC16']
166        BR2_RLOC16 = pv.vars['BR2_RLOC16']
167
168        print('BR1_RLOC16:', hex(BR1_RLOC16))
169        print('BR2_RLOC16:', hex(BR2_RLOC16))
170
171        # Make sure BR1 and BR2 always use TREL for transmitting ping request and reply
172        pkts.filter_wpan_src16_dst16(BR1_RLOC16, BR2_RLOC16).filter_ping_request().must_not_next()
173        pkts.filter_wpan_src16_dst16(BR1_RLOC16, BR2_RLOC16).filter_ping_reply().must_not_next()
174
175        pkts.filter_wpan_src16_dst16(BR2_RLOC16, BR1_RLOC16).filter_ping_request().must_not_next()
176        pkts.filter_wpan_src16_dst16(BR2_RLOC16, BR1_RLOC16).filter_ping_reply().must_not_next()
177
178
179if __name__ == '__main__':
180    unittest.main()
181