mirror of
https://github.com/espressif/openthread.git
synced 2026-09-20 07:57:41 +00:00
[bbr] add backbone router service (#4430)
- Introduce BACKBONE_ROUTER option for Backbone Router function.
- Implement Backbone Router service registration.
- Add basic Backbone Router service.
- Primary Backbone Router restores its Dataset when reattached after
short reset, increases sequence number and re-register to Leader.
- Add configurable jitter for Backbone Router service registration.
- Add Backbone Router service test.
This commit is contained in:
@@ -43,11 +43,17 @@ import binascii
|
||||
|
||||
class Node:
|
||||
|
||||
def __init__(self, nodeid, is_mtd=False, simulator=None, version=None):
|
||||
def __init__(self,
|
||||
nodeid,
|
||||
is_mtd=False,
|
||||
simulator=None,
|
||||
version=None,
|
||||
is_bbr=False):
|
||||
self.nodeid = nodeid
|
||||
self.verbose = int(float(os.getenv('VERBOSE', 0)))
|
||||
self.node_type = os.getenv('NODE_TYPE', 'sim')
|
||||
self.env_version = os.getenv('THREAD_VERSION', '1.1')
|
||||
self.is_bbr = is_bbr
|
||||
self._initialized = False
|
||||
|
||||
if version is not None:
|
||||
@@ -76,24 +82,45 @@ class Node:
|
||||
|
||||
def __init_sim(self, nodeid, mode):
|
||||
""" Initialize a simulation node. """
|
||||
if 'OT_CLI_PATH' in os.environ:
|
||||
cmd = os.environ['OT_CLI_PATH']
|
||||
elif (self.version == '1.1' and self.version != self.env_version):
|
||||
|
||||
# Default command if no match below, will be overridden if below conditions are met.
|
||||
cmd = './ot-cli-%s' % (mode)
|
||||
|
||||
# If Thread version of node matches the testing environment version.
|
||||
if self.version == self.env_version:
|
||||
# Load Thread 1.2 BBR device when testing Thread 1.2 scenarios
|
||||
# which requires device with Backbone functionality.
|
||||
if self.version == '1.2' and self.is_bbr:
|
||||
if 'OT_CLI_PATH_1_2_BBR' in os.environ:
|
||||
cmd = os.environ['OT_CLI_PATH_1_2_BBR']
|
||||
elif 'top_builddir_1_2_bbr' in os.environ:
|
||||
srcdir = os.environ['top_builddir_1_2_bbr']
|
||||
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
|
||||
|
||||
# Load Thread device of the testing environment version (may be 1.1 or 1.2)
|
||||
else:
|
||||
if 'OT_CLI_PATH' in os.environ:
|
||||
cmd = os.environ['OT_CLI_PATH']
|
||||
elif 'top_builddir' in os.environ:
|
||||
srcdir = os.environ['top_builddir']
|
||||
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
|
||||
|
||||
if 'RADIO_DEVICE' in os.environ:
|
||||
cmd += ' -v %s' % os.environ['RADIO_DEVICE']
|
||||
os.environ['NODE_ID'] = str(nodeid)
|
||||
|
||||
# Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability
|
||||
elif self.version == '1.1':
|
||||
# Posix app
|
||||
if 'OT_CLI_PATH_1_1' in os.environ:
|
||||
cmd = os.environ['OT_CLI_PATH_1_1']
|
||||
elif ('top_builddir_1_1') in os.environ:
|
||||
elif 'top_builddir_1_1' in os.environ:
|
||||
srcdir = os.environ['top_builddir_1_1']
|
||||
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
|
||||
elif ('top_builddir') in os.environ:
|
||||
srcdir = os.environ['top_builddir']
|
||||
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
|
||||
else:
|
||||
cmd = '%s/ot-cli-%s' % (self.version, mode)
|
||||
|
||||
if 'RADIO_DEVICE' in os.environ:
|
||||
cmd += ' -v %s' % os.environ['RADIO_DEVICE']
|
||||
os.environ['NODE_ID'] = str(nodeid)
|
||||
if 'RADIO_DEVICE_1_1' in os.environ:
|
||||
cmd += ' -v %s' % os.environ['RADIO_DEVICE_1_1']
|
||||
os.environ['NODE_ID'] = str(nodeid)
|
||||
|
||||
cmd += ' %d' % nodeid
|
||||
print("%s" % cmd)
|
||||
@@ -112,43 +139,69 @@ class Node:
|
||||
|
||||
def __init_ncp_sim(self, nodeid, mode):
|
||||
""" Initialize an NCP simulation node. """
|
||||
if 'RADIO_DEVICE' in os.environ:
|
||||
args = ' %s' % os.environ['RADIO_DEVICE']
|
||||
os.environ['NODE_ID'] = str(nodeid)
|
||||
else:
|
||||
args = ''
|
||||
|
||||
if 'OT_NCP_PATH' in os.environ:
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
os.environ['OT_NCP_PATH'],
|
||||
args,
|
||||
)
|
||||
elif (self.version == '1.1' and self.version != self.env_version):
|
||||
# Default command if no match below, will be overridden if below conditions are met.
|
||||
cmd = 'spinel-cli.py -p ./ot-ncp-%s -n' % mode
|
||||
|
||||
# If Thread version of node matches the testing environment version.
|
||||
if self.version == self.env_version:
|
||||
if 'RADIO_DEVICE' in os.environ:
|
||||
args = ' %s' % os.environ['RADIO_DEVICE']
|
||||
os.environ['NODE_ID'] = str(nodeid)
|
||||
else:
|
||||
args = ''
|
||||
|
||||
# Load Thread 1.2 BBR device when testing Thread 1.2 scenarios
|
||||
# which requires device with Backbone functionality.
|
||||
if self.version == '1.2' and self.is_bbr:
|
||||
if 'OT_NCP_PATH_1_2_BBR' in os.environ:
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
os.environ['OT_NCP_PATH_1_2_BBR'],
|
||||
args,
|
||||
)
|
||||
elif 'top_builddir_1_2_bbr' in os.environ:
|
||||
srcdir = os.environ['top_builddir_1_2_bbr']
|
||||
cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode)
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
cmd,
|
||||
args,
|
||||
)
|
||||
|
||||
# Load Thread device of the testing environment version (may be 1.1 or 1.2).
|
||||
else:
|
||||
if 'OT_NCP_PATH' in os.environ:
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
os.environ['OT_NCP_PATH'],
|
||||
args,
|
||||
)
|
||||
elif 'top_builddir' in os.environ:
|
||||
srcdir = os.environ['top_builddir']
|
||||
cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode)
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
cmd,
|
||||
args,
|
||||
)
|
||||
|
||||
# Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability.
|
||||
elif self.version == '1.1':
|
||||
if 'RADIO_DEVICE_1_1' in os.environ:
|
||||
args = ' %s' % os.environ['RADIO_DEVICE_1_1']
|
||||
os.environ['NODE_ID'] = str(nodeid)
|
||||
else:
|
||||
args = ''
|
||||
|
||||
if 'OT_NCP_PATH_1_1' in os.environ:
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
os.environ['OT_NCP_PATH_1_1'],
|
||||
args,
|
||||
)
|
||||
elif ('top_builddir_1_1') in os.environ:
|
||||
elif 'top_builddir_1_1' in os.environ:
|
||||
srcdir = os.environ['top_builddir_1_1']
|
||||
cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode)
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
cmd,
|
||||
args,
|
||||
)
|
||||
elif ('top_builddir') in os.environ:
|
||||
srcdir = os.environ['top_builddir']
|
||||
cmd = '%s/examples/apps/ncp/ot-ncp-%s' % (srcdir, mode)
|
||||
cmd = 'spinel-cli.py -p "%s%s" -n' % (
|
||||
cmd,
|
||||
args,
|
||||
)
|
||||
else:
|
||||
cmd = 'spinel-cli.py -p "%s/ot-ncp-%s%s" -n' % (
|
||||
self.version,
|
||||
mode,
|
||||
args,
|
||||
)
|
||||
|
||||
cmd += ' %d' % nodeid
|
||||
print("%s" % cmd)
|
||||
@@ -388,6 +441,74 @@ class Node:
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def get_bbr_registration_jitter(self):
|
||||
self.send_command('bbr jitter')
|
||||
return int(self._expect_result(r'\d+'))
|
||||
|
||||
def set_bbr_registration_jitter(self, jitter):
|
||||
cmd = 'bbr jitter %d' % jitter
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def enable_backbone_router(self):
|
||||
cmd = 'bbr enable'
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def disable_backbone_router(self):
|
||||
cmd = 'bbr disable'
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def register_backbone_router(self):
|
||||
cmd = 'bbr register'
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def get_backbone_router_state(self):
|
||||
states = [r'Disabled', r'Primary', r'Secondary']
|
||||
self.send_command('bbr state')
|
||||
return self._expect_result(states)
|
||||
|
||||
def get_backbone_router(self):
|
||||
cmd = 'bbr config'
|
||||
self.send_command(cmd)
|
||||
self._expect(r'(.*)Done')
|
||||
g = self.pexpect.match.groups()
|
||||
output = g[0].decode("utf-8")
|
||||
lines = output.strip().split('\n')
|
||||
lines = [l.strip() for l in lines]
|
||||
ret = {}
|
||||
for l in lines:
|
||||
z = re.search(r'seqno:\s+([0-9]+)', l)
|
||||
if z:
|
||||
ret['seqno'] = int(z.groups()[0])
|
||||
|
||||
z = re.search(r'delay:\s+([0-9]+)', l)
|
||||
if z:
|
||||
ret['delay'] = int(z.groups()[0])
|
||||
|
||||
z = re.search(r'timeout:\s+([0-9]+)', l)
|
||||
if z:
|
||||
ret['timeout'] = int(z.groups()[0])
|
||||
|
||||
return ret
|
||||
|
||||
def set_backbone_router(self, seqno=None, reg_delay=None, mlr_timeout=None):
|
||||
cmd = 'bbr config'
|
||||
|
||||
if seqno is not None:
|
||||
cmd += ' seqno %d' % seqno
|
||||
|
||||
if reg_delay is not None:
|
||||
cmd += ' delay %d' % reg_delay
|
||||
|
||||
if mlr_timeout is not None:
|
||||
cmd += ' timeout %d' % mlr_timeout
|
||||
|
||||
self.send_command(cmd)
|
||||
self._expect('Done')
|
||||
|
||||
def set_link_quality(self, addr, lqi):
|
||||
cmd = 'macfilter rss add-lqi %s %s' % (addr, lqi)
|
||||
self.send_command(cmd)
|
||||
|
||||
@@ -35,6 +35,7 @@ from node import Node
|
||||
|
||||
DEFAULT_PARAMS = {
|
||||
'is_mtd': False,
|
||||
'is_bbr': False,
|
||||
'mode': 'rsdn',
|
||||
'panid': 0xface,
|
||||
'whitelist': None,
|
||||
@@ -73,6 +74,7 @@ class TestCase(unittest.TestCase):
|
||||
params['is_mtd'],
|
||||
simulator=self.simulator,
|
||||
version=params['version'],
|
||||
is_bbr=params['is_bbr'],
|
||||
)
|
||||
self.nodes[i].set_panid(params['panid'])
|
||||
self.nodes[i].set_mode(params['mode'])
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# 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 unittest
|
||||
|
||||
import thread_cert
|
||||
|
||||
LEADER_1_1 = 1
|
||||
BBR_1 = 2
|
||||
BBR_2 = 3
|
||||
|
||||
WAIT_ATTACH = 5
|
||||
WAIT_REDUNDANCE = 3
|
||||
ROUTER_SELECTION_JITTER = 1
|
||||
BBR_REGISTRATION_JITTER = 5
|
||||
"""
|
||||
Topology
|
||||
|
||||
LEADER_1_1 --- BBR_1
|
||||
\ |
|
||||
\ |
|
||||
\ |
|
||||
BBR_2
|
||||
|
||||
1) Bring up Leader_1_1 and then BBR_1, BBR_1 becomes Primary Backbone Router.
|
||||
2) Reset BBR_1, if bring back soon, it could restore the Backbone Router Service
|
||||
from the network, after increasing sequence number, it will reregister its
|
||||
Backbone Router Service to the Leader and become Primary.
|
||||
3) Reset BBR_1, if bring back after it is released in the network, BBR_1 will
|
||||
choose a random sequence number, register its Backbone Router Service to
|
||||
Leader and become Primary.
|
||||
4) Configure BBR_2 with highest sequence number and explicitly trigger SRV_DATA.ntf.
|
||||
BBR_2 would become Primary and BBR_1 would change to Secondary with sequence
|
||||
number increased by 1.
|
||||
5) Stop BBR_2, BBR_1 would become Primary after detecting there is no available
|
||||
Backbone Router Service in Thread Network.
|
||||
6) Bring back BBR_2, and it would become Secondary.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class TestBackboneRouterService(thread_cert.TestCase):
|
||||
topology = {
|
||||
LEADER_1_1: {
|
||||
'version': '1.1',
|
||||
'whitelist': [BBR_1, BBR_2],
|
||||
},
|
||||
BBR_1: {
|
||||
'version': '1.2',
|
||||
'whitelist': [LEADER_1_1, BBR_2],
|
||||
'is_bbr': True
|
||||
},
|
||||
BBR_2: {
|
||||
'version': '1.2',
|
||||
'whitelist': [LEADER_1_1, BBR_1],
|
||||
'is_bbr': True
|
||||
},
|
||||
}
|
||||
"""All nodes are created with default configurations"""
|
||||
|
||||
def test(self):
|
||||
|
||||
self.nodes[LEADER_1_1].start()
|
||||
WAIT_TIME = WAIT_ATTACH
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[LEADER_1_1].get_state(), 'leader')
|
||||
|
||||
# 1) First Backbone Router would become the Primary.
|
||||
self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER)
|
||||
self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER)
|
||||
self.nodes[BBR_1].set_backbone_router(seqno=1)
|
||||
self.nodes[BBR_1].start()
|
||||
WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_1].get_state(), 'router')
|
||||
self.nodes[BBR_1].enable_backbone_router()
|
||||
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(),
|
||||
'Primary')
|
||||
|
||||
# 2) Reset BBR_1 and bring it back soon.
|
||||
# Verify that it restores Primary State with sequence number
|
||||
# increased by 1.
|
||||
self.nodes[BBR_1].reset()
|
||||
self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER)
|
||||
self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER)
|
||||
self.nodes[BBR_1].enable_backbone_router()
|
||||
self.nodes[BBR_1].start()
|
||||
WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_1].get_state(), 'router')
|
||||
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(),
|
||||
'Primary')
|
||||
assert self.nodes[BBR_1].get_backbone_router()['seqno'] == 2
|
||||
|
||||
# 3) Reset BBR_1 and bring it back after its original router id is released
|
||||
# 200s (100s MaxNeighborAge + 90s InfiniteCost + 10s redundance)
|
||||
# Verify it becomes Primary again.
|
||||
# Note: To ensure test in next step, here Step 3) will repeat until
|
||||
# the random sequence number is not the highest value 255.
|
||||
while True:
|
||||
self.nodes[BBR_1].reset()
|
||||
WAIT_TIME = 200
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.nodes[BBR_1].set_router_selection_jitter(
|
||||
ROUTER_SELECTION_JITTER)
|
||||
self.nodes[BBR_1].set_bbr_registration_jitter(
|
||||
BBR_REGISTRATION_JITTER)
|
||||
self.nodes[BBR_1].enable_backbone_router()
|
||||
self.nodes[BBR_1].start()
|
||||
WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_1].get_state(), 'router')
|
||||
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(),
|
||||
'Primary')
|
||||
BBR_1_SEQNO = self.nodes[BBR_1].get_backbone_router()['seqno']
|
||||
if (BBR_1_SEQNO != 255):
|
||||
break
|
||||
|
||||
#4) Configure BBR_2 with highest sequence number (255) and
|
||||
# explicitly trigger SRV_DATA.ntf.
|
||||
# Verify BBR_2 would become Primary and BBR_1 would change to
|
||||
# Secondary with sequence number increased by 1.
|
||||
|
||||
# Bring up BBR_2, it becomes Router with backbone function disabled
|
||||
# by default.
|
||||
self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER)
|
||||
self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER)
|
||||
self.nodes[BBR_2].start()
|
||||
WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_2].get_state(), 'router')
|
||||
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(),
|
||||
'Disabled')
|
||||
|
||||
# Enable Backbone function, it will stay at Secondary state as
|
||||
# there is Primary Backbone Router already.
|
||||
self.nodes[BBR_2].enable_backbone_router()
|
||||
self.nodes[BBR_2].set_backbone_router(seqno=255)
|
||||
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(),
|
||||
'Secondary')
|
||||
# Check no SRV_DATA.ntf.
|
||||
messages = self.simulator.get_messages_sent_by(BBR_2)
|
||||
msg = messages.next_coap_message('0.02', '/a/sd', False)
|
||||
assert (
|
||||
msg is None
|
||||
), "Error: %d sent unexpected SRV_DATA.ntf when there is PBbr already"
|
||||
|
||||
# Flush relative message queue.
|
||||
self.flush_nodes([BBR_1])
|
||||
|
||||
# BBR_2 registers SRV_DATA.ntf explicitly.
|
||||
self.nodes[BBR_2].register_backbone_router()
|
||||
WAIT_TIME = WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(),
|
||||
'Primary')
|
||||
|
||||
# Verify BBR_1 becomes Secondary and sends SRV_DATA.ntf to deregister
|
||||
# its service.
|
||||
messages = self.simulator.get_messages_sent_by(BBR_1)
|
||||
messages.next_coap_message('0.02', '/a/sd', True)
|
||||
self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(),
|
||||
'Secondary')
|
||||
# Verify Sequence number increases when become Secondary from Primary.
|
||||
assert self.nodes[BBR_1].get_backbone_router()['seqno'] == (
|
||||
BBR_1_SEQNO + 1)
|
||||
|
||||
# 5) Stop BBR_2, BBR_1 becomes Primary after detecting there is no
|
||||
# available Backbone Router Service.
|
||||
self.nodes[BBR_2].reset()
|
||||
self.nodes[LEADER_1_1].release_router_id(
|
||||
self.nodes[BBR_2].get_router_id())
|
||||
# Wait for the dissemination of Network Data without backbone router service
|
||||
self.simulator.go(10)
|
||||
|
||||
# BBR_1 becomes Primary.
|
||||
self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(),
|
||||
'Primary')
|
||||
messages = self.simulator.get_messages_sent_by(BBR_1)
|
||||
messages.next_coap_message('0.02', '/a/sd', True)
|
||||
|
||||
# 6) Bring back BBR_2.
|
||||
# Verify that BBR_2 stays at Secondary.
|
||||
self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER)
|
||||
self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER)
|
||||
self.nodes[BBR_2].enable_backbone_router()
|
||||
self.nodes[BBR_2].interface_up()
|
||||
self.nodes[BBR_2].thread_start()
|
||||
WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_2].get_state(), 'router')
|
||||
WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(),
|
||||
'Secondary')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user