# -*- coding: utf-8 -*-
"""
------------------------------------------------------------------------------
Mango 802.11 Reference Design Experiments Framework
- Local Traffic Generation (LTG)
------------------------------------------------------------------------------
License: Copyright 2019 Mango Communications, Inc. All rights reserved.
Use and distribution subject to terms in LICENSE.txt
------------------------------------------------------------------------------
This module provides definitions for Local Traffic Generation (LTG) on
wlan_exp nodes.
It is assumed that users will extend these classes to create their own
LTG flow configurations. When an LTG component is serialized, it follows
the following structure:
+------------+------------+---------------------------------+
| Word | Bits | Function |
+============+============+=================================+
| [0] | [31:16] | Type |
+------------+------------+---------------------------------+
| [0] | [15:0] | Length (number of 32 bit words) |
+------------+------------+---------------------------------+
| [1:length] | Parameters |
+------------+------------+---------------------------------+
When a LTG flow configuration is serialized, the schedule is serialized
first and then the payload.
"""
from wlan_exp.info import InfoStruct
import wlan_exp.util as util
__all__ = ['Schedule', 'SchedulePeriodic', 'ScheduleUniformRandom',
'Payload', 'PayloadFixed', 'PayloadUniformRandom', 'PayloadControlResponse',
'FlowConfig', 'FlowConfigCBR', 'FlowConfigCTS', 'FlowConfigRandomRandom']
# LTG Schedule IDs - must match corresponding values in wlan_mac_ltg.h
LTG_SCHED_TYPE_PERIODIC = 1
LTG_SCHED_TYPE_UNIFORM_RAND = 2
# LTG Payload IDs - must match corresponding values in wlan_mac_ltg.h
LTG_PYLD_TYPE_FIXED = 1
LTG_PYLD_TYPE_UNIFORM_RAND = 2
LTG_PYLD_TYPE_ALL_ASSOC_FIXED = 3
LTG_PYLD_TYPE_CTRL_RESP = 4
# LTG Payload Min/Max
#
# Currently, the minimum payload size is determined by the size of the LTG
# header in the payload (as of 0.96, the LTG header contains the LLC header,
# a 64-bit unique sequence number and a 32-bit LTG ID). Currently, the maximum
# payload size is 1500 bytes. This is a relatively arbitrary amount chosen
# because 1) in 0.96 the 802.11 phy cannot transmit more than 1600 bytes total
# per packet; 2) 1500 bytes is about the size of a standard Ethernet MTU. If
# sizes outside the range are requested, the functions will print a warning and
# adjust the value to the appropriate boundary.
#
LTG_PYLD_MIN = 20
LTG_PYLD_MAX = 1500
# LTG action constants - must match corresponding values in wlan_mac_ltg.h
LTG_REMOVE_ALL = 0xFFFFFFFF
LTG_START_ALL = 0xFFFFFFFF
LTG_STOP_ALL = 0xFFFFFFFF
#-----------------------------------------------------------------------------
# LTG Schedules
#-----------------------------------------------------------------------------
[docs]class Schedule(InfoStruct):
"""Base class for LTG Schedules."""
ltg_type = None
def __init__(self, field_defs):
super(Schedule, self).__init__(field_sets=None, field_defs=field_defs)
def enforce_min_resolution(self, resolution):
"""Updates time intervals in the schedule configuration for the minimum interval
implemented by the node. Interval/duration values will be rounded down
to the nearest multiple of the node's LTG polling interval.
Subclasses of the Schedule class must implement their own verson of this method.
Args: resolution (int): Resolution of the schedule
"""
raise NotImplementedError
[docs]class SchedulePeriodic(Schedule):
"""LTG Schedule that will generate a payload every 'interval' seconds, stopping
after 'duration' seconds. Both arguments are float seconds. These values are
converted to microseconds for the command message to the node.
Args:
interval (float): Interval between packets in float seconds; actual packet
creation interval will be quantized to the LTG polling interval in CPU
High (typically 64 usec) usec.
duration (float, optional): Duration of the traffic flow in float
seconds
"""
# Must match _ltg_sched_periodic_params_otw typedef
struct_fields = [
('interval', 'I', 'uint32', 'Interval between packet creation, in microseconds'),
('duration', 'Q', 'uint64', 'Duration for traffic flow, in microseconds'),
]
def __init__(self, interval, duration=None):
super(SchedulePeriodic, self).__init__(field_defs=self.struct_fields)
self.ltg_type = LTG_SCHED_TYPE_PERIODIC
# Convert argument from float seconds to integer microseconds
self['interval'] = int(float(interval) * 10**6)
if duration is None:
# LTG schedule runs forever by default
self['duration'] = 0
else:
# Convert argument from float seconds to integer microseconds
self['duration'] = int(float(duration) * 10**6)
def enforce_min_resolution(self, resolution):
"""Enforce the minimum resolution on the Schedule.
Args:
resolution (int): Resolution of the schedule
"""
temp_interval = (self['interval'] // resolution) * resolution
if (temp_interval != self['interval']):
# Set to True to print warning message when adjusting interval
if (False):
msg = "WARNING: Cannot schedule LTG with interval: {0} us\n".format(self['interval'])
msg += " Minimum LTG resolution is {0} us.\n".format(resolution)
msg += " Adjusting interval to {0} us".format(temp_interval)
print(msg)
self['interval'] = temp_interval
# End Class WlanExpLTGSchedPeriodic
#-----------------------------------------------------------------------------
# LTG Payloads
#-----------------------------------------------------------------------------
[docs]class Payload(InfoStruct):
"""Base class for LTG Payloads."""
ltg_type = None
def __init__(self, field_defs):
# InfoStruct constructor accepts either pre-defined fields in Info.py via 'field_sets'
# or caller-specified fields via 'field_defs'
super(Payload, self).__init__(field_sets=None, field_defs=field_defs)
def validate_length(self, length):
"""Contrains a requested length to the min/max supported LTG payload lengths
"""
msg = "WARNING: Adjusting LTG Payload length from {0} ".format(length)
if (length < LTG_PYLD_MIN):
msg += "to {0} (min).".format(LTG_PYLD_MIN)
print(msg)
return LTG_PYLD_MIN
if (length > LTG_PYLD_MAX):
msg += "to {0} (max).".format(LTG_PYLD_MAX)
print(msg)
return LTG_PYLD_MAX
return length
[docs]class PayloadFixed(Payload):
"""LTG payload that will generate a fixed payload of the given length.
Args:
dest_addr (int): Destination MAC address
length (int): Minimum length of the LTG payload (in bytes)
"""
# Must match ltg_pyld_fixed typedef
struct_fields = [
('type', 'I', 'uint32', 'LTG Payload spec type'),
('dest_addr', '6s', '6uint8', 'MAC address for destination of LTG flow'),
('length', 'H', 'uint16', 'Length of payload in bytes for LTG packets'),
]
def __init__(self, dest_addr, length):
super(PayloadFixed, self).__init__(field_defs=self.struct_fields)
self['type'] = LTG_PYLD_TYPE_FIXED
self['dest_addr'] = util.mac_addr_to_byte_str(dest_addr)
self['length'] = self.validate_length(length)
class PayloadControlResponse(Payload):
"""LTG payload that will generate an ACK or CTS.
Args:
dest_addr (int): Destination MAC address
subtype (int): 0 for CTS, 1 for ACK
duration (int): duration/ID value (ignored in ACK)
"""
# Must match ltg_pyld_ctrl_resp typedef
struct_fields = [
('type', 'I', 'uint32', 'LTG Payload spec type'),
('dest_addr', '6s', '6uint8', 'MAC address for destination of LTG flow'),
('subtype', 'H', 'uint16', 'Subtype, 0 for CTS, 1 for ACK'),
('duration', 'H', 'uint16', 'DURATION value for MAC header, ignored for ACKs'),
]
def __init__(self, dest_addr, subtype, duration):
super(PayloadControlResponse, self).__init__(field_defs=self.struct_fields)
self['type'] = LTG_PYLD_TYPE_CTRL_RESP
self['dest_addr'] = util.mac_addr_to_byte_str(dest_addr)
self['subtype'] = subtype
self['duration'] = duration
[docs]class PayloadAllAssocFixed(Payload):
"""LTG payload that will generate a fixed payload of the given length
to all associated deivces.
Args:
length (int): Length of the LTG payload (in bytes)
"""
# Must match ltg_pyld_all_assoc_fixed_t typedef
struct_fields = [
('type', 'I', 'uint32', 'LTG Payload spec type'),
('length', 'H', 'uint16', 'LTG payload length, in bytes'),
]
def __init__(self, length):
super(PayloadAllAssocFixed, self).__init__(field_defs=self.struct_fields)
self['type'] = LTG_PYLD_TYPE_ALL_ASSOC_FIXED
self['length'] = self.validate_length(length)
#-----------------------------------------------------------------------------
# LTG Flow Configurations
#-----------------------------------------------------------------------------
[docs]class FlowConfig(object):
"""Base class for LTG Flow Configurations."""
ltg_schedule = None
ltg_payload = None
def serialize(self):
"""Converts the FlowConfig object to a byte array suitable for inclusion
in a wlan_exp command payload
"""
# Concatenate and serialize the schedule and payload InfoStructs
r = self.ltg_schedule + self.ltg_payload
return r.serialize()
def enforce_min_resolution(self, resolution):
"""Enforce the minimum resolution on time intervals in the LTG Schedule.
Args:
resolution (int): Minimum time interval supported by hardware, in usec
"""
self.ltg_schedule.enforce_min_resolution(resolution)
[docs]class FlowConfigCBR(FlowConfig):
"""Class to implement a Constant Bit Rate LTG flow configuration to a given device.
Args:
dest_addr (int): Destination MAC address
payload_length (int): Length of the LTG payload (in bytes)
interval (float): Interval between packets (in float seconds);
actual packet creation interval will be quantized
to the interval of the fast timer in CPU High.
Currently this interval is 64 usec.
duration (float): Duration of the traffic flow (in float seconds)
"""
def __init__(self, dest_addr, payload_length, interval, duration=None):
self.ltg_schedule = SchedulePeriodic(interval, duration)
self.ltg_payload = PayloadFixed(dest_addr, payload_length)
# End Class FlowConfigCBR
class FlowConfigCTS(FlowConfig):
"""Class to implement a CTS flow configuration to a given device.
Args:
dest_addr (int): Destination MAC address
interval (float): Interval between packets (in float seconds);
actual packet creation interval will be quantized
to the interval of the fast timer in CPU High.
Currently this interval is 64 usec.
duration (float): Duration of the traffic flow (in float seconds)
duration_id (int): Value to be included in CTS Duration/ID field
"""
def __init__(self, dest_addr, interval, duration=None, duration_id=None):
self.ltg_schedule = SchedulePeriodic(interval, duration)
self.ltg_payload = PayloadControlResponse(dest_addr, 0, duration_id) #The 0 represents a CTS
# End Class FlowConfigCTS
class FlowConfigACK(FlowConfig):
"""Class to implement a ACK flow configuration to a given device.
Args:
dest_addr (int): Destination MAC address
interval (float): Interval between packets (in float seconds);
actual packet creation interval will be quantized
to the interval of the fast timer in CPU High.
Currently this interval is 64 usec.
duration (float): Duration of the traffic flow (in float seconds)
"""
def __init__(self, dest_addr, interval, duration=None):
self.ltg_schedule = SchedulePeriodic(interval, duration)
self.ltg_payload = PayloadControlResponse(dest_addr, 1, 0) #The 1 represents a CTS
# End Class FlowConfigCTS
[docs]class FlowConfigAllAssocCBR(FlowConfig):
"""Class to implement a Constant Bit Rate LTG flow configuration to all associated
devices.
Args:
payload_length (int): Length of the LTG payload (in bytes)
interval (float): Interval between packets (in float seconds);
actual packet creation interval will be quantized
to the interval of the fast timer in CPU High.
Currently this interval is 64 usec.
duration (float): Duration of the traffic flow (in float seconds)
"""
def __init__(self, payload_length, interval, duration=None):
self.ltg_schedule = SchedulePeriodic(interval, duration)
self.ltg_payload = PayloadAllAssocFixed(payload_length)
# End Class FlowConfigAllAssocCBR
[docs]class FlowConfigRandomRandom(FlowConfig):
"""Class to implement an LTG flow configuration with random period and random
sized payload to a given device.
Args:
dest_addr (int): Destination MAC address
min_payload_length (int): Minimum length of the LTG payload (in bytes)
max_payload_length (int): Maximum length of the LTG payload (in bytes)
min_interval (float): Minimum interval between packets (in float seconds);
actual packet creation interval will be quantized
to the interval of the fast timer in CPU High.
Currently this interval is 64 usec.
max_interval (float): Maximum interval between packets (in float seconds)
actual packet creation interval will be quantized
to the interval of the fast timer in CPU High.
Currently this interval is 64 usec.
duration (float, optional): Duration of the traffic flow (in float seconds)
"""
def __init__(self, dest_addr, min_payload_length, max_payload_length, min_interval, max_interval, duration=None):
self.ltg_schedule = ScheduleUniformRandom(min_interval, max_interval, duration)
self.ltg_payload = PayloadUniformRandom(dest_addr, min_payload_length, max_payload_length)
# End Class FlowConfigRandom