[mlr] configure MLR.req response status (#5350)

This commit is contained in:
Simon Lin
2020-08-27 14:13:07 -07:00
committed by GitHub
parent 53e18618ae
commit c3845e72ff
9 changed files with 148 additions and 3 deletions
+12
View File
@@ -193,6 +193,18 @@ void otBackboneRouterConfigNextDuaRegistrationResponse(otInstance *
const otIp6InterfaceIdentifier *aMlIid,
uint8_t aStatus);
/**
* This method configures response status for next Multicast Listener Registration.
*
* Note: available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
* Only used for test and certification.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aStatus The status to respond.
*
*/
void otBackboneRouterConfigNextMulticastListenerRegistrationResponse(otInstance *aInstance, uint8_t aStatus);
/**
* Represents the Multicast Listener events.
*
+20
View File
@@ -185,6 +185,26 @@ Done
Done
```
### bbr mgmt mlr response \<status\>
Configure the response status for the next MLR.req.
Only for testing/reference device.
Known status values:
- 0: ST_MLR_SUCCESS
- 2: ST_MLR_INVALID
- 3: ST_MLR_NO_PERSISTENT
- 4: ST_MLR_NO_RESOURCES
- 5: ST_MLR_BBR_NOT_PRIMARY
- 6: ST_MLR_GENERAL_FAILURE
```bash
> bbr mgmt mlr response 2
Done
```
### bbr state
Show local Backbone state ([`Disabled`,`Primary`, `Secondary`]) for Thread 1.2 FTD.
+13
View File
@@ -605,6 +605,19 @@ otError Interpreter::ProcessBackboneRouterMgmtMlr(uint8_t aArgsLength, char **aA
error = otBackboneRouterMulticastListenerAdd(mInstance, &address, timeout);
}
}
else if (!strcmp(aArgs[0], "response"))
{
unsigned long value;
VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = ParseUnsignedLong(aArgs[1], value));
otBackboneRouterConfigNextMulticastListenerRegistrationResponse(mInstance, static_cast<uint8_t>(value));
}
else
{
error = OT_ERROR_INVALID_COMMAND;
}
exit:
return error;
+10
View File
@@ -131,6 +131,16 @@ void otBackboneRouterConfigNextDuaRegistrationResponse(otInstance *
static_cast<const Ip6::InterfaceIdentifier *>(aMlIid), aStatus);
}
void otBackboneRouterConfigNextMulticastListenerRegistrationResponse(otInstance *aInstance, uint8_t aStatus)
{
Instance &instance = *static_cast<Instance *>(aInstance);
OT_ASSERT(aStatus <= ThreadStatusTlv::kMlrStatusMax);
instance.Get<BackboneRouter::Manager>().ConfigNextMulticastListenerRegistrationResponse(
static_cast<ThreadStatusTlv::MlrStatus>(aStatus));
}
void otBackboneRouterMulticastListenerClear(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
+17 -1
View File
@@ -57,7 +57,9 @@ Manager::Manager(Instance &aInstance)
, mTimer(aInstance, Manager::HandleTimer, this)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mDuaResponseStatus(ThreadStatusTlv::kDuaSuccess)
, mMlrResponseStatus(ThreadStatusTlv::kMlrSuccess)
, mDuaResponseIsSpecified(false)
, mMlrResponseIsSpecified(false)
#endif
{
}
@@ -106,9 +108,17 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Message &aMessage,
VerifyOrExit(aMessage.IsConfirmable() && aMessage.GetCode() == OT_COAP_CODE_POST, error = OT_ERROR_PARSE);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
// Required by Test Specification 5.10.22 DUA-TC-26, only for certification purpose
if (mMlrResponseIsSpecified)
{
mMlrResponseIsSpecified = false;
ExitNow(status = mMlrResponseStatus);
}
#endif
VerifyOrExit(isPrimary, status = ThreadStatusTlv::kMlrBbrNotPrimary);
// TODO: (MLR) send configured MLR response for Reference Device
// TODO: (MLR) handle Commissioner Session TLV
// TODO: (MLR) handle Timeout TLV
@@ -292,6 +302,12 @@ void Manager::ConfigNextDuaRegistrationResponse(const Ip6::InterfaceIdentifier *
mDuaResponseStatus = static_cast<ThreadStatusTlv::DuaStatus>(aStatus);
}
void Manager::ConfigNextMulticastListenerRegistrationResponse(ThreadStatusTlv::MlrStatus aStatus)
{
mMlrResponseIsSpecified = true;
mMlrResponseStatus = aStatus;
}
#endif
} // namespace BackboneRouter
+14
View File
@@ -80,6 +80,18 @@ public:
*
*/
void ConfigNextDuaRegistrationResponse(const Ip6::InterfaceIdentifier *aMlIid, uint8_t aStatus);
/**
* This method configures response status for next Multicast Listener Registration.
*
* Note: available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
* Only used for test and certification.
*
* @param[in] aStatus The status to respond.
*
*/
void ConfigNextMulticastListenerRegistrationResponse(ThreadStatusTlv::MlrStatus aStatus);
#endif
/**
@@ -135,7 +147,9 @@ private:
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
Ip6::InterfaceIdentifier mDuaResponseTargetMlIid;
ThreadStatusTlv::DuaStatus mDuaResponseStatus;
ThreadStatusTlv::MlrStatus mMlrResponseStatus;
bool mDuaResponseIsSpecified : 1;
bool mMlrResponseIsSpecified : 1;
#endif
};
+1
View File
@@ -134,6 +134,7 @@ public:
kMlrNoResources = 4, ///< BBR resource shortage.
kMlrBbrNotPrimary = 5, ///< BBR is not Primary at this moment.
kMlrGeneralFailure = 6, ///< Reason(s) for failure are not further specified.
kMlrStatusMax = 6, ///< Max MLR status.
};
/**
+7 -2
View File
@@ -40,7 +40,7 @@ import time
import unittest
import binascii
from typing import Union
from typing import Union, Dict
class Node:
@@ -530,7 +530,7 @@ class Node:
self.send_command(cmd)
self._expect('Done')
def multicast_listener_list(self):
def multicast_listener_list(self) -> Dict[ipaddress.IPv6Address, int]:
cmd = 'bbr mgmt mlr listener'
self.send_command(cmd)
@@ -559,6 +559,11 @@ class Node:
self.send_command(cmd)
self._expect(r"(Done|Error .*)")
def set_next_mlr_response(self, status: int):
cmd = 'bbr mgmt mlr response {}'.format(status)
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)
@@ -285,6 +285,60 @@ class TestMulticastListenerRegistration(thread_cert.TestCase):
self._bootstrap()
self.__test_multicast_listeners_table_api()
def testMlrConfigResponse(self):
self._bootstrap()
self.__test_mlr_config_response()
def __test_mlr_config_response(self):
bbr = self.nodes[BBR_1]
router = self.nodes[ROUTER_1_2]
self.flush_all()
# Configure next response to 0
bbr.set_next_mlr_response(0)
router.add_ipmaddr("ff04::1")
self.simulator.go(WAIT_REDUNDANCE)
self.__check_send_mlr_req(ROUTER_1_2, ["ff04::1"],
should_send=True,
expect_mlr_rsp=True,
expect_mlr_rsp_status=0)
self.assertNotIn(ipaddress.IPv6Address("ff04::1"), bbr.multicast_listener_list())
router.del_ipmaddr("ff04::1")
self.simulator.go(WAIT_REDUNDANCE)
self.flush_all()
# Configure next response to 2
bbr.set_next_mlr_response(2)
router.add_ipmaddr("ff04::2")
self.simulator.go(WAIT_REDUNDANCE)
self.__check_send_mlr_req(ROUTER_1_2, ["ff04::2"],
should_send=True,
expect_mlr_rsp=True,
expect_mlr_rsp_status=2)
router.del_ipmaddr("ff04::2")
self.simulator.go(WAIT_REDUNDANCE)
self.flush_all()
# Configure next response to 4
bbr.set_next_mlr_response(4)
router.add_ipmaddr("ff04::4")
self.simulator.go(WAIT_REDUNDANCE)
self.__check_send_mlr_req(ROUTER_1_2, ["ff04::4"],
should_send=True,
expect_mlr_rsp=True,
expect_mlr_rsp_status=4)
# The MA should be eventually registered after reregistration
self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE)
self.assertIn(ipaddress.IPv6Address("ff04::4"), bbr.multicast_listener_list())
router.del_ipmaddr("ff04::4")
self.simulator.go(WAIT_REDUNDANCE)
self.flush_all()
def __test_multicast_listeners_table_api(self):
self.assertTrue(self.nodes[BBR_1].multicast_listener_list() == {})