From 0c5a4348a31e0e8d76dd1fcf378cb2c0a2867f59 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 15 Oct 2015 09:57:35 +0300 Subject: updated yaml utils and stream object --- .../trex_control_plane/common/trex_streams.py | 190 +++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 scripts/automation/trex_control_plane/common/trex_streams.py (limited to 'scripts/automation/trex_control_plane/common/trex_streams.py') diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py new file mode 100644 index 00000000..3b0e7376 --- /dev/null +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -0,0 +1,190 @@ +#!/router/bin/python + +import external_packages +from client_utils.packet_builder import CTRexPktBuilder +from collections import OrderedDict + + +class CStreamList(object): + + def __init__(self): + self.streams_list = OrderedDict() + self._stream_id = 0 + # self._stream_by_name = {} + + def append_stream(self, name, stream_obj): + assert isinstance(stream_obj, CStream) + if name in self.streams_list: + raise NameError("A stream with this name already exists on this list.") + self.streams_list[name]=stream_obj + return + + def remove_stream(self, name): + return self.streams_list.pop(name) + + def export_to_yaml(self, file_path): + pass + + def load_yaml(self, file_path): + # clear all existing streams linked to this object + self.streams_list.clear() + # self._stream_id = 0 + # load from YAML file the streams one by one + try: + with open(file_path, 'r') as f: + loaded_streams = yaml.load(f) + + # assume at this point that YAML file is according to rules and correct + + + except yaml.YAMLError as e: + print "Error in YAML configuration file:", e + print "Aborting YAML loading, no changes made to stream list" + return + + + pass + + + + +class CStream(object): + """docstring for CStream""" + DEFAULTS = {"rx_stats": CRxStats, + "mode": CTxMode, + "isg": 5.0, + "next_stream": -1, + "self_start": True, + "enabled": True} + + def __init__(self, **kwargs): + super(CStream, self).__init__() + for k, v in kwargs.items(): + setattr(self, k, v) + # set default values to unset attributes, according to DEFAULTS dict + set_keys = set(kwargs.keys()) + keys_to_set = [x + for x in self.DEFAULTS + if x not in set_keys] + for key in keys_to_set: + default = self.DEFAULTS.get(key) + if type(default) == type: + setattr(self, key, default()) + else: + setattr(self, key, default) + + @property + def packet(self): + return self._packet + + @packet.setter + def packet(self, packet_obj): + assert isinstance(packet_obj, CTRexPktBuilder) + self._packet = packet_obj + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, bool_value): + self._enabled = bool(bool_value) + + @property + def self_start(self): + return self._self_start + + @self_start.setter + def self_start(self, bool_value): + self._self_start = bool(bool_value) + + @property + def next_stream(self): + return self._next_stream + + @next_stream.setter + def next_stream(self, value): + self._next_stream = int(value) + + def dump(self): + pass + return {"enabled": self.enabled, + "self_start": self.self_start, + "isg": self.isg, + "next_stream": self.next_stream, + "packet": self.packet.dump_pkt(), + "mode": self.mode.dump(), + "vm": self.packet.get_vm_data(), + "rx_stats": self.rx_stats.dump()} + +class CRxStats(object): + + def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): + self._rx_dict = {"enabled": enabled, + "seq_enabled": seq_enabled, + "latency_enabled": latency_enabled} + + @property + def enabled(self): + return self._rx_dict.get("enabled") + + @enabled.setter + def enabled(self, bool_value): + self._rx_dict['enabled'] = bool(bool_value) + + @property + def seq_enabled(self): + return self._rx_dict.get("seq_enabled") + + @seq_enabled.setter + def seq_enabled(self, bool_value): + self._rx_dict['seq_enabled'] = bool(bool_value) + + @property + def latency_enabled(self): + return self._rx_dict.get("latency_enabled") + + @latency_enabled.setter + def latency_enabled(self, bool_value): + self._rx_dict['latency_enabled'] = bool(bool_value) + + def dump(self): + return {k: v + for k, v in self._rx_dict.items() + if v + } + + +class CTxMode(object): + """docstring for CTxMode""" + def __init__(self, tx_mode, pps): + super(CTxMode, self).__init__() + if tx_mode not in ["continuous", "single_burst", "multi_burst"]: + raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode)) + self._tx_mode = tx_mode + self._fields = {'pps': float(pps)} + if tx_mode == "single_burst": + self._fields['total_pkts'] = 0 + elif tx_mode == "multi_burst": + self._fields['pkts_per_burst'] = 0 + self._fields['ibg'] = 0.0 + self._fields['count'] = 0 + else: + pass + + def set_tx_mode_attr(self, attr, val): + if attr in self._fields: + self._fields[attr] = type(self._fields.get(attr))(val) + else: + raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')". + format(attr, self._tx_mode)) + + def dump(self): + dump = {"type": self._tx_mode} + dump.update({k: v + for k, v in self._fields.items() + }) + return dump + +if __name__ == "__main__": + pass -- cgit From 4a8d34c7548e85e97426bc1d85c670003b1f5870 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sun, 18 Oct 2015 10:24:53 +0300 Subject: more yaml utils, better streams handling --- .../trex_control_plane/common/trex_streams.py | 230 +++++++++++++-------- 1 file changed, 145 insertions(+), 85 deletions(-) (limited to 'scripts/automation/trex_control_plane/common/trex_streams.py') diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index 3b0e7376..e6aa66f2 100644 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -3,12 +3,15 @@ import external_packages from client_utils.packet_builder import CTRexPktBuilder from collections import OrderedDict +from client_utils.yaml_utils import * +import dpkt class CStreamList(object): def __init__(self): self.streams_list = OrderedDict() + self.yaml_loader = CTRexYAMLLoader("rpc_exceptions.yaml") self._stream_id = 0 # self._stream_by_name = {} @@ -22,101 +25,50 @@ class CStreamList(object): def remove_stream(self, name): return self.streams_list.pop(name) + def rearrange_streams(self, streams_names_list, new_streams_dict={}): + tmp_list = OrderedDict() + for stream in streams_names_list: + if stream in self.streams_list: + tmp_list[stream] = self.streams_list.get(stream) + elif stream in new_streams_dict: + new_stream_obj = new_streams_dict.get(stream) + assert isinstance(new_stream_obj, CStream) + tmp_list[stream] = new_stream_obj + else: + raise NameError("Given stream named '{0}' cannot be found in existing stream list or and wasn't" + "provided with the new_stream_dict parameter.".format(stream)) + self.streams_list = tmp_list + def export_to_yaml(self, file_path): - pass + raise NotImplementedError("export_to_yaml method is not implemented, yet") - def load_yaml(self, file_path): + def load_yaml(self, file_path, multiplier_dict={}): # clear all existing streams linked to this object self.streams_list.clear() - # self._stream_id = 0 - # load from YAML file the streams one by one - try: - with open(file_path, 'r') as f: - loaded_streams = yaml.load(f) + streams_data = load_yaml_to_obj(file_path) + assert isinstance(streams_data, list) + raw_streams = {} + for stream in streams_data: + stream_name = stream.get("name") + raw_stream = stream.get("stream") + if not stream_name or not raw_stream: + raise ValueError("Provided stream is not according to convention." + "Each stream must be provided as two keys: 'name' and 'stream'. " + "Provided item was:\n {stream}".format(stream)) + new_stream_data = self.yaml_loader.validate_yaml(raw_stream, + "stream", + multiplier= multiplier_dict.get(stream_name, 1)) + new_stream_obj = CStream() + new_stream_obj.load_data(**new_stream_data) + self.append_stream(stream_name, new_stream_obj) - # assume at this point that YAML file is according to rules and correct - except yaml.YAMLError as e: - print "Error in YAML configuration file:", e - print "Aborting YAML loading, no changes made to stream list" - return + # start validating and reassembling clients input pass - - - -class CStream(object): - """docstring for CStream""" - DEFAULTS = {"rx_stats": CRxStats, - "mode": CTxMode, - "isg": 5.0, - "next_stream": -1, - "self_start": True, - "enabled": True} - - def __init__(self, **kwargs): - super(CStream, self).__init__() - for k, v in kwargs.items(): - setattr(self, k, v) - # set default values to unset attributes, according to DEFAULTS dict - set_keys = set(kwargs.keys()) - keys_to_set = [x - for x in self.DEFAULTS - if x not in set_keys] - for key in keys_to_set: - default = self.DEFAULTS.get(key) - if type(default) == type: - setattr(self, key, default()) - else: - setattr(self, key, default) - - @property - def packet(self): - return self._packet - - @packet.setter - def packet(self, packet_obj): - assert isinstance(packet_obj, CTRexPktBuilder) - self._packet = packet_obj - - @property - def enabled(self): - return self._enabled - - @enabled.setter - def enabled(self, bool_value): - self._enabled = bool(bool_value) - - @property - def self_start(self): - return self._self_start - - @self_start.setter - def self_start(self, bool_value): - self._self_start = bool(bool_value) - - @property - def next_stream(self): - return self._next_stream - - @next_stream.setter - def next_stream(self, value): - self._next_stream = int(value) - - def dump(self): - pass - return {"enabled": self.enabled, - "self_start": self.self_start, - "isg": self.isg, - "next_stream": self.next_stream, - "packet": self.packet.dump_pkt(), - "mode": self.mode.dump(), - "vm": self.packet.get_vm_data(), - "rx_stats": self.rx_stats.dump()} - class CRxStats(object): def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): @@ -154,7 +106,6 @@ class CRxStats(object): if v } - class CTxMode(object): """docstring for CTxMode""" def __init__(self, tx_mode, pps): @@ -186,5 +137,114 @@ class CTxMode(object): }) return dump +class CStream(object): + """docstring for CStream""" + DEFAULTS = {"rx_stats": CRxStats, + "mode": CTxMode, + "isg": 5.0, + "next_stream": -1, + "self_start": True, + "enabled": True} + + FIELDS = ["enabled", "self_start", "next_stream", "isg", "mode", "rx_stats", "packet", "vm"] + + def __init__(self): + super(CStream, self).__init__() + for field in CStream.FIELDS: + setattr(self, field, None) + + def load_data(self, **kwargs): + for k, v in kwargs.items(): + if k == "rx_stats": + if isinstance(v, dict): + setattr(self, k, CRxStats(**v)) + elif isinstance(v, CRxStats): + setattr(self, k, v) + elif k == "mode": + if isinstance(v, dict): + setattr(self, k, CTxMode(v)) + elif isinstance(v, CTxMode): + setattr(self, k, v) + else: + setattr(self, k, v) + + + + # def __init__(self, enabled, self_start, next_stream, isg, mode, rx_stats, packet, vm): + # super(CStream, self).__init__() + # for k, v in kwargs.items(): + # if k == "rx_stats": + # if isinstance(v, dict): + # setattr(self, k, CRxStats(v)) + # elif isinstance(v, CRxStats): + # setattr(self, k, v) + # elif k == "mode": + # if isinstance(v, dict): + # setattr(self, k, CTxMode(v)) + # elif isinstance(v, CTxMode): + # setattr(self, k, v) + # else: + # setattr(self, k, v) + # # set default values to unset attributes, according to DEFAULTS dict + # set_keys = set(kwargs.keys()) + # keys_to_set = [x + # for x in self.DEFAULTS + # if x not in set_keys] + # for key in keys_to_set: + # default = self.DEFAULTS.get(key) + # if type(default) == type: + # setattr(self, key, default()) + # else: + # setattr(self, key, default) + + # @property + # def packet(self): + # return self._packet + # + # @packet.setter + # def packet(self, packet_obj): + # assert isinstance(packet_obj, CTRexPktBuilder) + # self._packet = packet_obj + # + # @property + # def enabled(self): + # return self._enabled + # + # @enabled.setter + # def enabled(self, bool_value): + # self._enabled = bool(bool_value) + # + # @property + # def self_start(self): + # return self._self_start + # + # @self_start.setter + # def self_start(self, bool_value): + # self._self_start = bool(bool_value) + # + # @property + # def next_stream(self): + # return self._next_stream + # + # @next_stream.setter + # def next_stream(self, value): + # self._next_stream = int(value) + + def dump(self): + pass + return {"enabled": self.enabled, + "self_start": self.self_start, + "isg": self.isg, + "next_stream": self.next_stream, + "packet": self.packet.dump_pkt(), + "mode": self.mode.dump(), + "vm": self.packet.get_vm_data(), + "rx_stats": self.rx_stats.dump()} + + + + + + if __name__ == "__main__": pass -- cgit From 80bd7895112cba0b3cbb6d56995def6ffbdccf33 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sun, 18 Oct 2015 16:12:26 +0300 Subject: Progress in trex_streams and in yaml_utils. Next, start working on StreamList object --- .../trex_control_plane/common/trex_streams.py | 274 +++++++++------------ 1 file changed, 123 insertions(+), 151 deletions(-) mode change 100644 => 100755 scripts/automation/trex_control_plane/common/trex_streams.py (limited to 'scripts/automation/trex_control_plane/common/trex_streams.py') diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py old mode 100644 new mode 100755 index e6aa66f2..e366001d --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -5,13 +5,14 @@ from client_utils.packet_builder import CTRexPktBuilder from collections import OrderedDict from client_utils.yaml_utils import * import dpkt +import struct class CStreamList(object): def __init__(self): - self.streams_list = OrderedDict() - self.yaml_loader = CTRexYAMLLoader("rpc_exceptions.yaml") + self.streams_list = {OrderedDict()} + self.yaml_loader = CTRexYAMLLoader("rpc_defaults.yaml") self._stream_id = 0 # self._stream_by_name = {} @@ -62,184 +63,155 @@ class CStreamList(object): new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) - - - # start validating and reassembling clients input - + def compile_streams(self): + stream_ids = {} pass -class CRxStats(object): - - def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): - self._rx_dict = {"enabled": enabled, - "seq_enabled": seq_enabled, - "latency_enabled": latency_enabled} - - @property - def enabled(self): - return self._rx_dict.get("enabled") - @enabled.setter - def enabled(self, bool_value): - self._rx_dict['enabled'] = bool(bool_value) +class CRxStats(object): - @property - def seq_enabled(self): - return self._rx_dict.get("seq_enabled") + FIELDS = ["seq_enabled", "latency_enabled"] + def __init__(self, enabled=False, **kwargs): + self.enabled = bool(enabled) + for field in CRxStats.FIELDS: + setattr(self, field, kwargs.get(field, False)) - @seq_enabled.setter - def seq_enabled(self, bool_value): - self._rx_dict['seq_enabled'] = bool(bool_value) + def dump(self): + if self.enabled: + dump = {"enabled": True} + dump.update({k: getattr(self, k) + for k in CRxStats.FIELDS + if getattr(self, k) + }) + return dump + else: + return {"enabled": False} - @property - def latency_enabled(self): - return self._rx_dict.get("latency_enabled") - @latency_enabled.setter - def latency_enabled(self, bool_value): - self._rx_dict['latency_enabled'] = bool(bool_value) - - def dump(self): - return {k: v - for k, v in self._rx_dict.items() - if v - } class CTxMode(object): """docstring for CTxMode""" - def __init__(self, tx_mode, pps): - super(CTxMode, self).__init__() - if tx_mode not in ["continuous", "single_burst", "multi_burst"]: - raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode)) - self._tx_mode = tx_mode - self._fields = {'pps': float(pps)} - if tx_mode == "single_burst": - self._fields['total_pkts'] = 0 - elif tx_mode == "multi_burst": - self._fields['pkts_per_burst'] = 0 - self._fields['ibg'] = 0.0 - self._fields['count'] = 0 - else: - pass + GENERAL_FIELDS = ["type", "pps"] + FIELDS = {"continuous": [], + "single_burst": ["total_pkts"], + "multi_burst": ["pkts_per_burst", "ibg", "count"]} + + def __init__(self, type, pps=0, **kwargs): + self._MODES = CTxMode.FIELDS.keys() + self.type = type + self.pps = pps + for field in CTxMode.FIELDS.get(self.type): + setattr(self, field, kwargs.get(field, 0)) - def set_tx_mode_attr(self, attr, val): - if attr in self._fields: - self._fields[attr] = type(self._fields.get(attr))(val) - else: - raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')". - format(attr, self._tx_mode)) + @property + def type(self): + return self._type + + @type.setter + def type(self, type): + if type not in self._MODES: + raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(type)) + self._type = type + self._reset_fields() def dump(self): - dump = {"type": self._tx_mode} - dump.update({k: v - for k, v in self._fields.items() + dump = ({k: getattr(self, k) + for k in CTxMode.GENERAL_FIELDS + }) + dump.update({k: getattr(self, k) + for k in CTxMode.FIELDS.get(self.type) }) return dump + def _reset_fields(self): + for field in CTxMode.FIELDS.get(self.type): + setattr(self, field, 0) + + class CStream(object): """docstring for CStream""" - DEFAULTS = {"rx_stats": CRxStats, - "mode": CTxMode, - "isg": 5.0, - "next_stream": -1, - "self_start": True, - "enabled": True} FIELDS = ["enabled", "self_start", "next_stream", "isg", "mode", "rx_stats", "packet", "vm"] def __init__(self): - super(CStream, self).__init__() + self.is_loaded = False for field in CStream.FIELDS: setattr(self, field, None) def load_data(self, **kwargs): - for k, v in kwargs.items(): - if k == "rx_stats": - if isinstance(v, dict): - setattr(self, k, CRxStats(**v)) - elif isinstance(v, CRxStats): - setattr(self, k, v) - elif k == "mode": - if isinstance(v, dict): - setattr(self, k, CTxMode(v)) - elif isinstance(v, CTxMode): - setattr(self, k, v) - else: - setattr(self, k, v) - - - - # def __init__(self, enabled, self_start, next_stream, isg, mode, rx_stats, packet, vm): - # super(CStream, self).__init__() - # for k, v in kwargs.items(): - # if k == "rx_stats": - # if isinstance(v, dict): - # setattr(self, k, CRxStats(v)) - # elif isinstance(v, CRxStats): - # setattr(self, k, v) - # elif k == "mode": - # if isinstance(v, dict): - # setattr(self, k, CTxMode(v)) - # elif isinstance(v, CTxMode): - # setattr(self, k, v) - # else: - # setattr(self, k, v) - # # set default values to unset attributes, according to DEFAULTS dict - # set_keys = set(kwargs.keys()) - # keys_to_set = [x - # for x in self.DEFAULTS - # if x not in set_keys] - # for key in keys_to_set: - # default = self.DEFAULTS.get(key) - # if type(default) == type: - # setattr(self, key, default()) - # else: - # setattr(self, key, default) - - # @property - # def packet(self): - # return self._packet - # - # @packet.setter - # def packet(self, packet_obj): - # assert isinstance(packet_obj, CTRexPktBuilder) - # self._packet = packet_obj - # - # @property - # def enabled(self): - # return self._enabled - # - # @enabled.setter - # def enabled(self, bool_value): - # self._enabled = bool(bool_value) - # - # @property - # def self_start(self): - # return self._self_start - # - # @self_start.setter - # def self_start(self, bool_value): - # self._self_start = bool(bool_value) - # - # @property - # def next_stream(self): - # return self._next_stream - # - # @next_stream.setter - # def next_stream(self, value): - # self._next_stream = int(value) + try: + for k in CStream.FIELDS: + if k == "rx_stats": + rx_stats_data = kwargs[k] + if isinstance(rx_stats_data, dict): + setattr(self, k, CRxStats(**rx_stats_data)) + elif isinstance(rx_stats_data, CRxStats): + setattr(self, k, rx_stats_data) + elif k == "mode": + tx_mode = kwargs[k] + if isinstance(tx_mode, dict): + setattr(self, k, CTxMode(**tx_mode)) + elif isinstance(tx_mode, CTxMode): + setattr(self, k, tx_mode) + elif k == "packet": + if isinstance(kwargs[k], CTRexPktBuilder): + if "vm" not in kwargs: + self.load_packet_obj(kwargs[k]) + else: + raise ValueError("When providing packet object with a CTRexPktBuilder, vm parameter " + "should not be supplied") + else: + binary = kwargs[k]["binary"] + if isinstance(binary, list): + setattr(self, k, kwargs[k]) + elif isinstance(binary, str) and binary.endswith(".pcap"): + self.load_packet_from_pcap(binary, kwargs[k]["meta"]) + else: + raise ValueError("Packet binary attribute has been loaded with unsupported value." + "Supported values are reference to pcap file with SINGLE packet, " + "or a list of unsigned-byte integers") + else: + setattr(self, k, kwargs[k]) + self.is_loaded = True + except KeyError as e: + cause = e.args[0] + raise KeyError("The attribute '{0}' is missing as a field of the CStream object.\n" + "Loaded data must contain all of the following fields: {1}".format(cause, CStream.FIELDS)) + + def load_packet_obj(self, packet_obj): + assert isinstance(packet_obj, CTRexPktBuilder) + self.packet = packet_obj.dump_pkt() + self.vm = packet_obj.get_vm_data() + + def load_packet_from_pcap(self, pcap_path, metadata=''): + with open(pcap_path, 'r') as f: + pcap = dpkt.pcap.Reader(f) + first_packet = True + for _, buf in pcap: + # this is an iterator, can't evaluate the number of files in advance + if first_packet: + self.packet = {"binary": [struct.unpack('B', buf[i:i+1])[0] # represent data as list of 0-255 ints + for i in range(0, len(buf))], + "meta": metadata} # meta data continues without a change. + first_packet = False + else: + raise ValueError("Provided pcap file contains more than single packet.") + # arrive here ONLY if pcap contained SINGLE packet + return + def dump(self): - pass - return {"enabled": self.enabled, - "self_start": self.self_start, - "isg": self.isg, - "next_stream": self.next_stream, - "packet": self.packet.dump_pkt(), - "mode": self.mode.dump(), - "vm": self.packet.get_vm_data(), - "rx_stats": self.rx_stats.dump()} + if self.is_loaded: + dump = {} + for key in CStream.FIELDS: + try: + dump[key] = getattr(self, key).dump() # use dump() method of compound object, such TxMode + except AttributeError: + dump[key] = getattr(self, key) + return dump + else: + raise RuntimeError("CStream object isn't loaded with data. Use 'load_data' method.") -- cgit From d09df99769f67819c64a7a025dbdcd39811c7b44 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Tue, 20 Oct 2015 03:17:08 +0300 Subject: Major progress in console, yaml utils, and trex_streams basically done, minor changes remianing BIG ISSUE LEFT: rewire console to work with trexstateless client module --- .../trex_control_plane/common/trex_streams.py | 85 ++++++++++++++-------- 1 file changed, 56 insertions(+), 29 deletions(-) (limited to 'scripts/automation/trex_control_plane/common/trex_streams.py') diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index e366001d..674a6bcc 100755 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -2,19 +2,21 @@ import external_packages from client_utils.packet_builder import CTRexPktBuilder -from collections import OrderedDict +from collections import OrderedDict, namedtuple from client_utils.yaml_utils import * import dpkt import struct +import copy +import os +StreamPack = namedtuple('StreamPack', ['stream_id', 'stream']) class CStreamList(object): def __init__(self): - self.streams_list = {OrderedDict()} - self.yaml_loader = CTRexYAMLLoader("rpc_defaults.yaml") - self._stream_id = 0 - # self._stream_by_name = {} + self.streams_list = {} + self.yaml_loader = CTRexYAMLLoader(os.path.join(os.path.dirname(os.path.realpath(__file__)), + "rpc_defaults.yaml")) def append_stream(self, name, stream_obj): assert isinstance(stream_obj, CStream) @@ -24,21 +26,19 @@ class CStreamList(object): return def remove_stream(self, name): - return self.streams_list.pop(name) - - def rearrange_streams(self, streams_names_list, new_streams_dict={}): - tmp_list = OrderedDict() - for stream in streams_names_list: - if stream in self.streams_list: - tmp_list[stream] = self.streams_list.get(stream) - elif stream in new_streams_dict: - new_stream_obj = new_streams_dict.get(stream) - assert isinstance(new_stream_obj, CStream) - tmp_list[stream] = new_stream_obj - else: - raise NameError("Given stream named '{0}' cannot be found in existing stream list or and wasn't" - "provided with the new_stream_dict parameter.".format(stream)) - self.streams_list = tmp_list + popped = self.streams_list.pop(name) + if popped: + for stream_name, stream in self.streams_list.items(): + if stream.next_stream_id == name: + stream.next_stream_id = -1 + try: + rx_stats_stream = getattr(stream.rx_stats, "stream_id") + if rx_stats_stream == name: + # if a referenced stream of rx_stats object deleted, revert to rx stats of current stream + setattr(stream.rx_stats, "stream_id", stream_name) + except AttributeError as e: + continue # + return popped def export_to_yaml(self, file_path): raise NotImplementedError("export_to_yaml method is not implemented, yet") @@ -48,7 +48,6 @@ class CStreamList(object): self.streams_list.clear() streams_data = load_yaml_to_obj(file_path) assert isinstance(streams_data, list) - raw_streams = {} for stream in streams_data: stream_name = stream.get("name") raw_stream = stream.get("stream") @@ -62,16 +61,41 @@ class CStreamList(object): new_stream_obj = CStream() new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) + return streams_data def compile_streams(self): + # first, assign an id to each stream stream_ids = {} - - pass + for idx, stream_name in enumerate(self.streams_list): + stream_ids[stream_name] = idx + # next, iterate over the streams and transform them from working with names to ids. + # with that build a new dict with old stream_name as the key, and StreamPack as the stored value + compiled_streams = {} + for stream_name, stream in self.streams_list.items(): + tmp_stream = CStreamList._compile_single_stream(stream_name, stream, stream_ids) + compiled_streams[stream_name] = StreamPack(stream_ids.get(stream_name), + tmp_stream) + return compiled_streams + + @staticmethod + def _compile_single_stream(stream_name, stream, id_dict): + # copy the old stream to temporary one, no change to class attributes + tmp_stream = copy.copy(stream) + next_stream_id = id_dict.get(getattr(tmp_stream, "next_stream_id"), -1) + try: + rx_stats_stream_id = id_dict.get(getattr(tmp_stream.rx_stats, "stream_id"), + id_dict.get(stream_name)) + except AttributeError as e: + rx_stats_stream_id = id_dict.get(stream_name) + # assign resolved values to stream object + tmp_stream.next_stream_id = next_stream_id + tmp_stream.rx_stats.stream_id = rx_stats_stream_id + return tmp_stream class CRxStats(object): - FIELDS = ["seq_enabled", "latency_enabled"] + FIELDS = ["seq_enabled", "latency_enabled", "stream_id"] def __init__(self, enabled=False, **kwargs): self.enabled = bool(enabled) for field in CRxStats.FIELDS: @@ -82,7 +106,7 @@ class CRxStats(object): dump = {"enabled": True} dump.update({k: getattr(self, k) for k in CRxStats.FIELDS - if getattr(self, k) + if getattr(self, k) or k == "stream_id" }) return dump else: @@ -132,10 +156,12 @@ class CTxMode(object): class CStream(object): """docstring for CStream""" - FIELDS = ["enabled", "self_start", "next_stream", "isg", "mode", "rx_stats", "packet", "vm"] + FIELDS = ["enabled", "self_start", "next_stream_id", "isg", "mode", "rx_stats", "packet", "vm"] + # COMPILE_FIELDS = ["enabled", "self_start", "next_stream_id", "isg", "mode", "rx_stats", "packet", "vm"] def __init__(self): self.is_loaded = False + self._is_compiled = False for field in CStream.FIELDS: setattr(self, field, None) @@ -201,7 +227,8 @@ class CStream(object): return - def dump(self): + def dump(self, compilation=False): + # fields = CStream.COMPILE_FIELDS if compilation else CStream.FIELDS if self.is_loaded: dump = {} for key in CStream.FIELDS: @@ -213,8 +240,8 @@ class CStream(object): else: raise RuntimeError("CStream object isn't loaded with data. Use 'load_data' method.") - - + def dump_compiled(self): + return self.dump(compilation=True) -- cgit From 5abe21ffb26a15c2a63e90b5628d704e8211b599 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Tue, 20 Oct 2015 09:12:33 +0300 Subject: + Added traffic options at stl directory + updated console to support multiplier on loading + fixed minor issues at yaml_utils and trex_streams objects + console not stable, YET --- scripts/automation/trex_control_plane/common/trex_streams.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'scripts/automation/trex_control_plane/common/trex_streams.py') diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index 1aeb46b0..783f2769 100755 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -43,7 +43,7 @@ class CStreamList(object): def export_to_yaml(self, file_path): raise NotImplementedError("export_to_yaml method is not implemented, yet") - def load_yaml(self, file_path, multiplier_dict={}): + def load_yaml(self, file_path, multiplier=1): # clear all existing streams linked to this object self.streams_list.clear() streams_data = load_yaml_to_obj(file_path) @@ -57,11 +57,11 @@ class CStreamList(object): "Provided item was:\n {stream}".format(stream)) new_stream_data = self.yaml_loader.validate_yaml(raw_stream, "stream", - multiplier= multiplier_dict.get(stream_name, 1)) + multiplier= multiplier) new_stream_obj = CStream() new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) - return streams_data + return new_stream_data def compile_streams(self): # first, assign an id to each stream -- cgit