mirror of
https://github.com/espressif/openthread.git
synced 2026-09-11 11:40:06 +00:00
[virtual-time-simulator] optimize ACK radio events (#5559)
This commit optimizes Virtual Time Simulator by only sending ACK to nodes that are expecting it.
This commit is contained in:
@@ -184,6 +184,7 @@ EXTRA_DIST = \
|
|||||||
pktverify/test_info.py \
|
pktverify/test_info.py \
|
||||||
pktverify/utils.py \
|
pktverify/utils.py \
|
||||||
pktverify/verify_result.py \
|
pktverify/verify_result.py \
|
||||||
|
wpan.py \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
check_PROGRAMS = \
|
check_PROGRAMS = \
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import config
|
|||||||
import mesh_cop
|
import mesh_cop
|
||||||
import message
|
import message
|
||||||
import pcap
|
import pcap
|
||||||
|
import wpan
|
||||||
|
|
||||||
|
|
||||||
def dbg_print(*args):
|
def dbg_print(*args):
|
||||||
@@ -162,6 +163,8 @@ class VirtualTime(BaseSimulator):
|
|||||||
self.current_time = 0
|
self.current_time = 0
|
||||||
self.current_event = None
|
self.current_event = None
|
||||||
self.awake_devices = set()
|
self.awake_devices = set()
|
||||||
|
self._nodes_by_ack_seq = {}
|
||||||
|
self._node_ack_seq = {}
|
||||||
|
|
||||||
self._pcap = pcap.PcapCodec(os.getenv('TEST_NAME', 'current'))
|
self._pcap = pcap.PcapCodec(os.getenv('TEST_NAME', 'current'))
|
||||||
# the addr for spinel-cli sending OT_SIM_EVENT_POSTCMD
|
# the addr for spinel-cli sending OT_SIM_EVENT_POSTCMD
|
||||||
@@ -325,7 +328,15 @@ class VirtualTime(BaseSimulator):
|
|||||||
elif type == self.OT_SIM_EVENT_RADIO_RECEIVED:
|
elif type == self.OT_SIM_EVENT_RADIO_RECEIVED:
|
||||||
assert self._is_radio(addr)
|
assert self._is_radio(addr)
|
||||||
# add radio receive events event queue
|
# add radio receive events event queue
|
||||||
for device in self.devices:
|
frame_info = wpan.dissect(data)
|
||||||
|
|
||||||
|
recv_devices = None
|
||||||
|
if frame_info.frame_type == wpan.FrameType.ACK:
|
||||||
|
recv_devices = self._nodes_by_ack_seq.get(frame_info.seq_no)
|
||||||
|
|
||||||
|
recv_devices = recv_devices or self.devices.keys()
|
||||||
|
|
||||||
|
for device in recv_devices:
|
||||||
if device != addr and self._is_radio(device):
|
if device != addr and self._is_radio(device):
|
||||||
event = (
|
event = (
|
||||||
event_time,
|
event_time,
|
||||||
@@ -354,6 +365,9 @@ class VirtualTime(BaseSimulator):
|
|||||||
self.event_sequence += 1
|
self.event_sequence += 1
|
||||||
bisect.insort(self.event_queue, event)
|
bisect.insort(self.event_queue, event)
|
||||||
|
|
||||||
|
if frame_info.frame_type != wpan.FrameType.ACK and not frame_info.is_broadcast:
|
||||||
|
self._on_ack_seq_change(addr, frame_info.seq_no)
|
||||||
|
|
||||||
self.awake_devices.add(addr)
|
self.awake_devices.add(addr)
|
||||||
|
|
||||||
elif type == self.OT_SIM_EVENT_RADIO_SPINEL_WRITE:
|
elif type == self.OT_SIM_EVENT_RADIO_SPINEL_WRITE:
|
||||||
@@ -400,6 +414,14 @@ class VirtualTime(BaseSimulator):
|
|||||||
if self.current_nodeid == nodeid:
|
if self.current_nodeid == nodeid:
|
||||||
self.current_nodeid = None
|
self.current_nodeid = None
|
||||||
|
|
||||||
|
def _on_ack_seq_change(self, device: tuple, seq_no: int):
|
||||||
|
old_seq = self._node_ack_seq.pop(device, None)
|
||||||
|
if old_seq is not None:
|
||||||
|
self._nodes_by_ack_seq[old_seq].remove(device)
|
||||||
|
|
||||||
|
self._node_ack_seq[device] = seq_no
|
||||||
|
self._nodes_by_ack_seq.setdefault(seq_no, set()).add(device)
|
||||||
|
|
||||||
def _send_message(self, message, addr):
|
def _send_message(self, message, addr):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020, 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 struct
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
FCF_FRAME_BEACON = 0 << 0
|
||||||
|
FCF_FRAME_DATA = 1 << 0
|
||||||
|
FCF_FRAME_ACK = 2 << 0
|
||||||
|
FCF_FRAME_MAC_CMD = 3 << 0
|
||||||
|
FCF_FRAME_TYPE_MASK = 7 << 0
|
||||||
|
FCF_SECURITY_ENABLED = 1 << 3
|
||||||
|
FCF_FRAME_PENDING = 1 << 4
|
||||||
|
FCF_ACK_REQUEST = 1 << 5
|
||||||
|
FCF_PANID_COMPRESSION = 1 << 6
|
||||||
|
FCF_IE_PRESENT = 1 << 9
|
||||||
|
FCF_DST_ADDR_NONE = 0 << 10
|
||||||
|
FCF_DST_ADDR_SHORT = 2 << 10
|
||||||
|
FCF_DST_ADDR_EXT = 3 << 10
|
||||||
|
FCF_DST_ADDR_MASK = 3 << 10
|
||||||
|
FCF_FRAME_VERSION_2006 = 1 << 12
|
||||||
|
FCF_FRAME_VERSION_2015 = 2 << 12
|
||||||
|
FCF_FRAME_VERSION_MASK = 3 << 12
|
||||||
|
FCF_SRC_ADDR_NONE = 0 << 14
|
||||||
|
FCF_SRC_ADDR_SHORT = 2 << 14
|
||||||
|
FCF_SRC_ADDR_EXT = 3 << 14
|
||||||
|
FCD_SRC_ADDR_MASK = 3 << 14
|
||||||
|
|
||||||
|
|
||||||
|
class DstAddrMode(Enum):
|
||||||
|
NONE = 0
|
||||||
|
RESERVED = 1
|
||||||
|
SHORT = 2
|
||||||
|
EXTENDED = 3
|
||||||
|
|
||||||
|
|
||||||
|
class FrameType(Enum):
|
||||||
|
BEACON = 0
|
||||||
|
DATA = 1
|
||||||
|
ACK = 2
|
||||||
|
COMMAND = 3
|
||||||
|
|
||||||
|
|
||||||
|
class WpanFrameInfo(namedtuple('WpanFrameInfo', ['fcf', 'seq_no', 'dst_extaddr', 'dst_short'])):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def frame_type(self) -> FrameType:
|
||||||
|
return FrameType(self.fcf & 0x7)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dst_addr_mode(self) -> DstAddrMode:
|
||||||
|
return DstAddrMode((self.fcf & 0x0c00) >> 10)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_broadcast(self) -> bool:
|
||||||
|
return self.dst_addr_mode == DstAddrMode.SHORT and self.dst_short == 0xffff
|
||||||
|
|
||||||
|
|
||||||
|
def _is_version_2015(fcf: int) -> bool:
|
||||||
|
return (fcf & FCF_FRAME_VERSION_MASK) == FCF_FRAME_VERSION_2015
|
||||||
|
|
||||||
|
|
||||||
|
def _is_dst_addr_present(fcf: int) -> bool:
|
||||||
|
dst_addr_mode = DstAddrMode((fcf & 0x0c00) >> 10)
|
||||||
|
return dst_addr_mode != DstAddrMode.NONE
|
||||||
|
|
||||||
|
|
||||||
|
_DST_PAN_ID_NOT_PRESENT_SET = {
|
||||||
|
FCF_DST_ADDR_NONE | FCF_SRC_ADDR_NONE,
|
||||||
|
FCF_DST_ADDR_EXT | FCF_SRC_ADDR_NONE | FCF_PANID_COMPRESSION,
|
||||||
|
FCF_DST_ADDR_SHORT | FCF_SRC_ADDR_NONE | FCF_PANID_COMPRESSION,
|
||||||
|
FCF_DST_ADDR_NONE | FCF_SRC_ADDR_EXT,
|
||||||
|
FCF_DST_ADDR_NONE | FCF_SRC_ADDR_SHORT,
|
||||||
|
FCF_DST_ADDR_NONE | FCF_SRC_ADDR_EXT | FCF_PANID_COMPRESSION,
|
||||||
|
FCF_DST_ADDR_NONE | FCF_SRC_ADDR_SHORT | FCF_PANID_COMPRESSION,
|
||||||
|
FCF_DST_ADDR_EXT | FCF_SRC_ADDR_EXT | FCF_PANID_COMPRESSION,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _is_dst_pan_id_present(fcf: int) -> bool:
|
||||||
|
if _is_version_2015(fcf):
|
||||||
|
v = fcf & (FCF_DST_ADDR_MASK | FCD_SRC_ADDR_MASK | FCF_PANID_COMPRESSION)
|
||||||
|
present = v not in _DST_PAN_ID_NOT_PRESENT_SET
|
||||||
|
else:
|
||||||
|
present = _is_dst_addr_present(fcf)
|
||||||
|
|
||||||
|
return present
|
||||||
|
|
||||||
|
|
||||||
|
def dissect(frame: bytes) -> WpanFrameInfo:
|
||||||
|
fcf = struct.unpack("<H", frame[1:3])[0]
|
||||||
|
|
||||||
|
seq_no = frame[3]
|
||||||
|
|
||||||
|
dst_addr_mode = (fcf & 0x0c00) >> 10
|
||||||
|
|
||||||
|
dst_extaddr, dst_short = None, None
|
||||||
|
|
||||||
|
if dst_addr_mode in [DstAddrMode.SHORT.value, DstAddrMode.EXTENDED.value]:
|
||||||
|
offset = 4
|
||||||
|
|
||||||
|
if _is_dst_pan_id_present(fcf):
|
||||||
|
offset += 2
|
||||||
|
|
||||||
|
if dst_addr_mode == DstAddrMode.SHORT.value:
|
||||||
|
dst_short = struct.unpack('<H', frame[offset:offset + 2])[0]
|
||||||
|
else:
|
||||||
|
dst_extaddr = '%016x' % struct.unpack('<Q', frame[offset:offset + 8])[0]
|
||||||
|
|
||||||
|
return WpanFrameInfo(fcf=fcf, seq_no=seq_no, dst_extaddr=dst_extaddr, dst_short=dst_short)
|
||||||
Reference in New Issue
Block a user