Source code for wlan_exp.ltg

# -*- 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
[docs]class ScheduleUniformRandom(Schedule): """LTG Schedule that will generate a payload a uniformly random time between min_interval and max_interval microseconds. Args: 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) """ # Must match _ltg_sched_uniform_rand_params_otw typedef struct_fields = [ ('min_interval', 'I', 'uint32', 'Minimum interval between packet creation, in microseconds'), ('max_interval', 'I', 'uint32', 'Maximum interval between packet creation, in microseconds'), ('duration', 'Q', 'uint64', 'Duration for traffic flow, in microseconds'), ] def __init__(self, min_interval, max_interval, duration=None): super(ScheduleUniformRandom, self).__init__(field_defs=self.struct_fields) self.ltg_type = LTG_PYLD_TYPE_UNIFORM_RAND # Convert intervals from float seconds to integer usec self['min_interval'] = int(float(min_interval) * 10**6) self['max_interval'] = int(float(max_interval) * 10**6) if duration is None: # Default duration runs forever self['duration'] = 0 else: 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 scheduler in usec """ # Apply the scheduler resolution to all interval fields for f in ['min_interval', 'max_interval']: temp_interval = (self[f] // resolution) * resolution if (temp_interval != self[f]): if (False): msg = "WARNING: Cannot schedule LTG with {0} = {1} usec\n".format(f, self[f]) msg += " Minimum LTG resolution is {0} usec.\n".format(resolution) msg += " Adjusting {0} to {1} usec".format(f, temp_interval) print(msg) self[f] = temp_interval
#----------------------------------------------------------------------------- # 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 PayloadUniformRandom(Payload): """LTG payload that will generate a payload with uniformly random size between min_length and max_length bytes. Args: dest_addr (int): Destination MAC address min_length (int): Minimum length of the LTG payload (in bytes) max_length (int): Maximum length of the LTG payload (in bytes) """ # Must match ltg_pyld_uniform_rand typedef struct_fields = [ ('type', 'I', 'uint32', 'LTG Payload spec type'), ('dest_addr', '6s', '6uint8', 'MAC address for destination of LTG flow'), ('min_length', 'H', 'uint16', 'Minimum LTG payload length, in bytes'), ('max_length', 'H', 'uint16', 'Maximum LTG payload length, in bytes'), ] def __init__(self, dest_addr, min_length, max_length): super(PayloadUniformRandom, self).__init__(field_defs=self.struct_fields) self['type'] = LTG_PYLD_TYPE_UNIFORM_RAND self['dest_addr'] = util.mac_addr_to_byte_str(dest_addr) self['min_length'] = self.validate_length(min_length) self['max_length'] = self.validate_length(max_length)
[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