mirror of
https://github.com/espressif/openthread.git
synced 2026-07-28 14:47:46 +00:00
[simulation] implement otPlatInfraIf APIs in simulation platform (#9895)
This commit implements a subset of `otPlatInfraIf` platform APIs in simulation platforms using the `utilsSocket` to emulate communication between BRs. This can be used for testing. This commit also adds one (simple) example test case with two BRs attached to two different network on same infra-if.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The OpenThread Authors.
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,15 +28,154 @@
|
||||
|
||||
#include "platform-simulation.h"
|
||||
|
||||
#include <openthread/icmp6.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/logging.h>
|
||||
#include <openthread/platform/infra_if.h>
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
#include "simul_utils.h"
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && !OPENTHREAD_RADIO
|
||||
|
||||
#define DEBUG_LOG 0
|
||||
|
||||
#if DEBUG_LOG
|
||||
#define LOG(...) otLogNotePlat("[infra-if] "__VA_ARGS__)
|
||||
#else
|
||||
#define LOG(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define INFRA_IF_SIM_PORT 9800
|
||||
#define INFRA_IF_MAX_PACKET_SIZE 1800
|
||||
#define INFRA_IF_MAX_PENDING_TX 64
|
||||
#define INFRA_IF_NEIGHBOR_ADVERT_SIZE 24
|
||||
|
||||
typedef struct Message
|
||||
{
|
||||
uint32_t mIfIndex;
|
||||
otIp6Address mSrc;
|
||||
otIp6Address mDst;
|
||||
uint16_t mDataLength;
|
||||
uint8_t mData[INFRA_IF_MAX_PACKET_SIZE];
|
||||
} Message;
|
||||
|
||||
static bool sInitialized = false;
|
||||
static otIp6Address sIp6Address;
|
||||
static otIp6Address sLinkLocalAllNodes;
|
||||
static otIp6Address sLinkLocalAllRouters;
|
||||
static utilsSocket sSocket;
|
||||
static uint16_t sPortOffset = 0;
|
||||
static uint8_t sNumPendingTx = 0;
|
||||
static Message sPendingTx[INFRA_IF_MAX_PENDING_TX];
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
static bool addressesMatch(const otIp6Address *aFirstAddr, const otIp6Address *aSecondAddr)
|
||||
{
|
||||
return memcmp(aFirstAddr, aSecondAddr, sizeof(otIp6Address)) == 0;
|
||||
}
|
||||
|
||||
static uint16_t getMessageSize(const Message *aMessage)
|
||||
{
|
||||
return (uint16_t)(&aMessage->mData[aMessage->mDataLength] - (const uint8_t *)aMessage);
|
||||
}
|
||||
|
||||
static void sendPendingTxMessages(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < sNumPendingTx; i++)
|
||||
{
|
||||
utilsSendOverSocket(&sSocket, &sPendingTx[i], getMessageSize(&sPendingTx[i]));
|
||||
}
|
||||
|
||||
sNumPendingTx = 0;
|
||||
}
|
||||
|
||||
static void sendNeighborAdvert(const Message *aNsMessage)
|
||||
{
|
||||
Message *message;
|
||||
uint8_t index;
|
||||
|
||||
assert(sNumPendingTx < INFRA_IF_MAX_PENDING_TX);
|
||||
|
||||
message = &sPendingTx[sNumPendingTx++];
|
||||
|
||||
message->mIfIndex = aNsMessage->mIfIndex;
|
||||
message->mSrc = sIp6Address;
|
||||
message->mDst = aNsMessage->mSrc;
|
||||
|
||||
// Neighbor Advertisement Message (RFC 4861)
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type | Code | Checksum |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |R|S|O| Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// + Target Address +
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
index = 0;
|
||||
memset(message->mData, 0, INFRA_IF_NEIGHBOR_ADVERT_SIZE);
|
||||
|
||||
message->mData[index++] = OT_ICMP6_TYPE_NEIGHBOR_ADVERT; // Type.
|
||||
index += 3; // Code is zero. Checksum (uint16) as zero.
|
||||
message->mData[index++] = 0xd0; // Flags, set R and S bits.
|
||||
index += 3; // Skip over the reserved bytes.
|
||||
memcpy(&message->mData[index], &sIp6Address, sizeof(sIp6Address)); // Set the target address field.
|
||||
index += sizeof(sIp6Address);
|
||||
|
||||
assert(index == INFRA_IF_NEIGHBOR_ADVERT_SIZE);
|
||||
|
||||
message->mDataLength = INFRA_IF_NEIGHBOR_ADVERT_SIZE;
|
||||
}
|
||||
|
||||
static void processMessage(otInstance *aInstance, Message *aMessage, uint16_t aLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otEXPECT(aLength > 0);
|
||||
otEXPECT(getMessageSize(aMessage) == aLength);
|
||||
otEXPECT(aMessage->mDataLength > 0);
|
||||
|
||||
// Validate the dest address.
|
||||
otEXPECT(addressesMatch(&aMessage->mDst, &sIp6Address) || addressesMatch(&aMessage->mDst, &sLinkLocalAllNodes) ||
|
||||
addressesMatch(&aMessage->mDst, &sLinkLocalAllRouters));
|
||||
|
||||
if (aMessage->mData[0] == OT_ICMP6_TYPE_NEIGHBOR_SOLICIT)
|
||||
{
|
||||
LOG("Received NS, responding with NA");
|
||||
sendNeighborAdvert(aMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Received msg, len:%u", aMessage->mDataLength);
|
||||
otPlatInfraIfRecvIcmp6Nd(aInstance, aMessage->mIfIndex, &aMessage->mSrc, aMessage->mData,
|
||||
aMessage->mDataLength);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// otPlatInfraIf
|
||||
|
||||
bool otPlatInfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
OT_UNUSED_VARIABLE(aAddress);
|
||||
|
||||
return false;
|
||||
return addressesMatch(aAddress, &sIp6Address);
|
||||
}
|
||||
|
||||
otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
|
||||
@@ -44,12 +183,27 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
|
||||
const uint8_t *aBuffer,
|
||||
uint16_t aBufferLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
OT_UNUSED_VARIABLE(aDestAddress);
|
||||
OT_UNUSED_VARIABLE(aBuffer);
|
||||
OT_UNUSED_VARIABLE(aBufferLength);
|
||||
otError error = OT_ERROR_FAILED;
|
||||
Message *message;
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
otEXPECT(sInitialized);
|
||||
otEXPECT(sNumPendingTx < INFRA_IF_MAX_PENDING_TX);
|
||||
|
||||
message = &sPendingTx[sNumPendingTx++];
|
||||
|
||||
message->mIfIndex = aInfraIfIndex;
|
||||
message->mSrc = sIp6Address;
|
||||
message->mDst = *aDestAddress;
|
||||
|
||||
assert(aBufferLength <= INFRA_IF_MAX_PACKET_SIZE);
|
||||
message->mDataLength = aBufferLength;
|
||||
memcpy(message->mData, aBuffer, aBufferLength);
|
||||
error = OT_ERROR_NONE;
|
||||
|
||||
LOG("otPlatInfraIfSendIcmp6Nd() msg-len:%u", aBufferLength);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
|
||||
@@ -58,4 +212,127 @@ otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// platformInfraIf
|
||||
|
||||
void platformInfraIfInit(void)
|
||||
{
|
||||
char *str;
|
||||
|
||||
otEXPECT(!sInitialized);
|
||||
|
||||
sInitialized = true;
|
||||
|
||||
memset(&sIp6Address, 0, sizeof(sIp6Address));
|
||||
sIp6Address.mFields.m8[0] = 0xfe;
|
||||
sIp6Address.mFields.m8[1] = 0x80;
|
||||
sIp6Address.mFields.m8[15] = (uint8_t)(gNodeId & 0xff);
|
||||
|
||||
// "ff02::01"
|
||||
memset(&sLinkLocalAllNodes, 0, sizeof(sLinkLocalAllNodes));
|
||||
sLinkLocalAllNodes.mFields.m8[0] = 0xff;
|
||||
sLinkLocalAllNodes.mFields.m8[1] = 0x02;
|
||||
sLinkLocalAllNodes.mFields.m8[15] = 0x01;
|
||||
|
||||
// "ff02::02"
|
||||
memset(&sLinkLocalAllRouters, 0, sizeof(sLinkLocalAllRouters));
|
||||
sLinkLocalAllRouters.mFields.m8[0] = 0xff;
|
||||
sLinkLocalAllRouters.mFields.m8[1] = 0x02;
|
||||
sLinkLocalAllRouters.mFields.m8[15] = 0x02;
|
||||
|
||||
str = getenv("PORT_OFFSET");
|
||||
|
||||
if (str != NULL)
|
||||
{
|
||||
char *endptr;
|
||||
|
||||
sPortOffset = (uint16_t)strtol(str, &endptr, 0);
|
||||
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
fprintf(stderr, "\r\nInvalid PORT_OFFSET: %s\r\n", str);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sPortOffset *= (MAX_NETWORK_SIZE + 1);
|
||||
}
|
||||
|
||||
utilsInitSocket(&sSocket, INFRA_IF_SIM_PORT + sPortOffset);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void platformInfraIfDeinit(void)
|
||||
{
|
||||
otEXPECT(sInitialized);
|
||||
sInitialized = false;
|
||||
utilsDeinitSocket(&sSocket);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void platformInfraIfUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd)
|
||||
{
|
||||
otEXPECT(sInitialized);
|
||||
|
||||
utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
|
||||
|
||||
if (sNumPendingTx > 0)
|
||||
{
|
||||
utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void platformInfraIfProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otEXPECT(sInitialized);
|
||||
|
||||
if ((sNumPendingTx > 0) && utilsCanSocketSend(&sSocket, aWriteFdSet))
|
||||
{
|
||||
sendPendingTxMessages();
|
||||
}
|
||||
|
||||
if (utilsCanSocketReceive(&sSocket, aReadFdSet))
|
||||
{
|
||||
Message message;
|
||||
uint16_t len;
|
||||
|
||||
message.mDataLength = 0;
|
||||
|
||||
len = utilsReceiveFromSocket(&sSocket, &message, sizeof(message), NULL);
|
||||
processMessage(aInstance, &message, len);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Provide weak implementation (used for RCP builds).
|
||||
// `OPENTHREAD_RADIO` is not available in simulation platform
|
||||
|
||||
OT_TOOL_WEAK void otPlatInfraIfRecvIcmp6Nd(otInstance *aInstance,
|
||||
uint32_t aInfraIfIndex,
|
||||
const otIp6Address *aSrcAddress,
|
||||
const uint8_t *aBuffer,
|
||||
uint16_t aBufferLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
OT_UNUSED_VARIABLE(aSrcAddress);
|
||||
OT_UNUSED_VARIABLE(aBuffer);
|
||||
OT_UNUSED_VARIABLE(aBufferLength);
|
||||
|
||||
fprintf(stderr, "\n\r Weak otPlatInfraIfRecvIcmp6Nd is being used\n\r");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
@@ -305,4 +305,40 @@ void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
/**
|
||||
* Initializes the platform infra-if module.
|
||||
*
|
||||
*/
|
||||
void platformInfraIfInit(void);
|
||||
|
||||
/**
|
||||
* Shuts down the platform infra-if module.
|
||||
*
|
||||
*/
|
||||
void platformInfraIfDeinit(void);
|
||||
|
||||
/**
|
||||
* Updates the file descriptor sets with file descriptors used by the infra-if module
|
||||
*
|
||||
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
|
||||
* @param[in,out] aMaxFd A pointer to the max file descriptor.
|
||||
*
|
||||
*/
|
||||
void platformInfraIfUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd);
|
||||
|
||||
/**
|
||||
* Performs infra-if module processing.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in] aWriteFdSet A pointer to the write file descriptors.
|
||||
*
|
||||
*/
|
||||
void platformInfraIfProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet);
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
#endif // PLATFORM_SIMULATION_H_
|
||||
|
||||
@@ -188,6 +188,9 @@ void otSysInit(int aArgCount, char *aArgVector[])
|
||||
platformRadioInit();
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelInit(speedUpFactor);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
platformInfraIfInit();
|
||||
#endif
|
||||
platformRandomInit();
|
||||
}
|
||||
@@ -199,6 +202,9 @@ void otSysDeinit(void)
|
||||
platformRadioDeinit();
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelDeinit();
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
// platformInfrIfDeinit();
|
||||
#endif
|
||||
platformLoggingDeinit();
|
||||
}
|
||||
@@ -222,6 +228,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
platformInfraIfUpdateFdSet(&read_fds, &write_fds, &max_fd);
|
||||
#endif
|
||||
|
||||
if (otTaskletsArePending(aInstance))
|
||||
{
|
||||
@@ -246,6 +255,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelProcess(aInstance, &read_fds, &write_fds);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
platformInfraIfProcess(aInstance, &read_fds, &write_fds);
|
||||
#endif
|
||||
|
||||
if (gTerminate)
|
||||
{
|
||||
|
||||
@@ -760,6 +760,18 @@ class Node(object):
|
||||
def br_get_state(self):
|
||||
return self._cli_single_output('br state')
|
||||
|
||||
def br_get_favored_omrprefix(self):
|
||||
return self._cli_single_output('br omrprefix favored')
|
||||
|
||||
def br_get_local_omrprefix(self):
|
||||
return self._cli_single_output('br omrprefix local')
|
||||
|
||||
def br_get_favored_onlinkprefix(self):
|
||||
return self._cli_single_output('br onlinkprefix favored')
|
||||
|
||||
def br_get_local_onlinkprefix(self):
|
||||
return self._cli_single_output('br onlinkprefix local')
|
||||
|
||||
def br_get_routeprf(self):
|
||||
return self._cli_single_output('br routeprf')
|
||||
|
||||
@@ -769,6 +781,9 @@ class Node(object):
|
||||
def br_clear_routeprf(self):
|
||||
self._cli_no_output('br routeprf clear')
|
||||
|
||||
def br_get_routers(self):
|
||||
return self.cli('br routers')
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
# Helper methods
|
||||
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2024, 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.
|
||||
|
||||
from cli import verify
|
||||
from cli import verify_within
|
||||
import cli
|
||||
import time
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description:
|
||||
#
|
||||
# Two BRs on two different Thread networks.
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print('-' * 120)
|
||||
print('Starting \'{}\''.format(test_name))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `cli.Nodes` instances
|
||||
|
||||
speedup = 60
|
||||
cli.Node.set_time_speedup_factor(speedup)
|
||||
|
||||
br1 = cli.Node()
|
||||
br2 = cli.Node()
|
||||
|
||||
WAIT_TIME = 5
|
||||
IF_INDEX = 1
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
# Start first BR with its own Thread network
|
||||
|
||||
br1.form('net1')
|
||||
verify(br1.get_state() == 'leader')
|
||||
|
||||
br1.br_init(IF_INDEX, 1)
|
||||
br1.br_enable()
|
||||
|
||||
time.sleep(1)
|
||||
verify(br1.br_get_state() == 'running')
|
||||
|
||||
br1_local_omr = br1.br_get_local_omrprefix()
|
||||
br1_favored_omr = br1.br_get_favored_omrprefix().split()[0]
|
||||
verify(br1_local_omr == br1_favored_omr)
|
||||
|
||||
br1_local_onlink = br1.br_get_local_onlinkprefix()
|
||||
br1_favored_onlink = br1.br_get_favored_onlinkprefix().split()[0]
|
||||
verify(br1_local_onlink == br1_favored_onlink)
|
||||
|
||||
# Start second BR with its own Thread network.
|
||||
|
||||
br2.form('net2')
|
||||
verify(br2.get_state() == 'leader')
|
||||
|
||||
br2.br_init(IF_INDEX, 1)
|
||||
br2.br_enable()
|
||||
|
||||
time.sleep(1)
|
||||
verify(br2.br_get_state() == 'running')
|
||||
|
||||
br2_local_omr = br2.br_get_local_omrprefix()
|
||||
br2_favored_omr = br2.br_get_favored_omrprefix().split()[0]
|
||||
verify(br2_local_omr == br2_favored_omr)
|
||||
|
||||
br2_local_onlink = br2.br_get_local_onlinkprefix()
|
||||
br2_favored_onlink = br2.br_get_favored_onlinkprefix().split()[0]
|
||||
verify(br2_local_onlink != br2_favored_onlink)
|
||||
|
||||
# BR2 should see and favor the on-link prefix already advertised by BR1.
|
||||
|
||||
verify(br1_favored_onlink == br2_favored_onlink)
|
||||
|
||||
br1_routers = br1.br_get_routers()
|
||||
br2_routers = br2.br_get_routers()
|
||||
|
||||
verify(len(br1_routers) > 0)
|
||||
verify(len(br2_routers) > 0)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
cli.Node.finalize_all_nodes()
|
||||
|
||||
print('\'{}\' passed.'.format(test_name))
|
||||
@@ -194,6 +194,7 @@ if [ "$TORANJ_CLI" = 1 ]; then
|
||||
run cli/test-027-slaac-address.py
|
||||
run cli/test-028-border-agent-ephemeral-key.py
|
||||
run cli/test-400-srp-client-server.py
|
||||
run cli/test-500-two-brs-two-networks.py
|
||||
run cli/test-601-channel-manager-channel-change.py
|
||||
# Skip the "channel-select" test on a TREL only radio link, since it
|
||||
# requires energy scan which is not supported in this case.
|
||||
|
||||
Reference in New Issue
Block a user