diff options
Diffstat (limited to 'yardstick/network_services')
3 files changed, 433 insertions, 79 deletions
diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py index cc627ef78..e0b7aa000 100644 --- a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -14,6 +14,8 @@ import ipaddress import logging +import re +import collections import IxNetwork @@ -62,6 +64,13 @@ SUPPORTED_TOS_FIELDS = [ 'reliability' ] +IP_PRIORITY_PATTERN = r'[^\w+]*.+(Raw priority|' \ + 'Precedence|' \ + 'Default PHB|' \ + 'Class selector PHB|' \ + 'Assured forwarding selector PHB|' \ + 'Expedited forwarding PHB)' + class Vlan(object): def __init__(self, @@ -99,6 +108,18 @@ class IxNextgen(object): # pragma: no cover "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)', } + FLOWS_STATS_NAME_MAP = { + "Tx_Port": 'Tx Port', + "VLAN-ID": 'VLAN:VLAN-ID', + "IP_Priority": re.compile(IP_PRIORITY_PATTERN), + "Flow_Group": 'Flow Group', + "Tx_Frames": 'Tx Frames', + "Rx_Frames": 'Rx Frames', + "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)', + "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)', + "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)' + } + PPPOX_CLIENT_PER_PORT_NAME_MAP = { 'subs_port': 'Port', 'Sessions_Up': 'Sessions Up', @@ -111,6 +132,18 @@ class IxNextgen(object): # pragma: no cover FLOW_STATISTICS = '::ixNet::OBJ-/statistics/view:"Flow Statistics"' PPPOX_CLIENT_PER_PORT = '::ixNet::OBJ-/statistics/view:"PPPoX Client Per Port"' + PPPOE_SCENARIO_STATS = { + 'port_statistics': PORT_STATISTICS, + 'flow_statistic': FLOW_STATISTICS, + 'pppox_client_per_port': PPPOX_CLIENT_PER_PORT + } + + PPPOE_SCENARIO_STATS_MAP = { + 'port_statistics': PORT_STATS_NAME_MAP, + 'flow_statistic': FLOWS_STATS_NAME_MAP, + 'pppox_client_per_port': PPPOX_CLIENT_PER_PORT_NAME_MAP + } + @staticmethod def get_config(tg_cfg): card = [] @@ -731,6 +764,19 @@ class IxNextgen(object): # pragma: no cover 'getColumnValues', view_obj, data_ixia) for data_yardstick, data_ixia in name_map.items()} + def _get_view_page_stats(self, view_obj): + """Get full view page stats + + :param view_obj: view object, e.g. + '::ixNet::OBJ-/statistics/view:"Port Statistics"' + :return: (list) List of dicts. Each dict represents view page row + """ + view = view_obj + '/page' + column_headers = self.ixnet.getAttribute(view, '-columnCaptions') + view_rows = self.ixnet.getAttribute(view, '-rowValues') + view_page = [dict(zip(column_headers, row[0])) for row in view_rows] + return view_page + def _set_egress_flow_tracking(self, encapsulation, offset): """Set egress flow tracking options @@ -753,7 +799,7 @@ class IxNextgen(object): # pragma: no cover self.ixnet.setAttribute(enc_obj, '-offset', offset) self.ixnet.commit() - def _set_flow_tracking(self, track_by): + def set_flow_tracking(self, track_by): """Set flow tracking options :param track_by: list of tracking fields @@ -780,24 +826,39 @@ class IxNextgen(object): # pragma: no cover return stats def get_pppoe_scenario_statistics(self): - """Retrieve port, flow and PPPoE subscribers statistics - - "Port Statistics" parameters are stored in self.PORT_STATS_NAME_MAP. - "Flow Statistics" parameters are stored in self.LATENCY_NAME_MAP. - "PPPoX Client Per Port" parameters are stored in - self.PPPOE_CLIENT_PER_PORT_NAME_MAP - - :return: dictionary with the statistics; the keys of this dictionary - are PORT_STATS_NAME_MAP, LATENCY_NAME_MAP and - PPPOE_CLIENT_PER_PORT_NAME_MAP keys. - """ - stats = self._build_stats_map(self.PORT_STATISTICS, - self.PORT_STATS_NAME_MAP) - stats.update(self._build_stats_map(self.FLOW_STATISTICS, - self.LATENCY_NAME_MAP)) - stats.update(self._build_stats_map(self.PPPOX_CLIENT_PER_PORT, - self.PPPOX_CLIENT_PER_PORT_NAME_MAP)) - return stats + """Retrieve port, flow and PPPoE subscribers statistics""" + stats = collections.defaultdict(list) + result = collections.defaultdict(list) + for stat, view in self.PPPOE_SCENARIO_STATS.items(): + # Get view total pages number + total_pages = self.ixnet.getAttribute( + view + '/page', '-totalPages') + # Collect stats from all view pages + for page in range(1, int(total_pages) + 1): + current_page = int(self.ixnet.getAttribute( + view + '/page', '-currentPage')) + if page != int(current_page): + self.ixnet.setAttribute(view + '/page', '-currentPage', + str(page)) + self.ixnet.commit() + page_data = self._get_view_page_stats(view) + stats[stat].extend(page_data) + # Filter collected views stats + for stat in stats: + for view_row in stats[stat]: + filtered_row = {} + for key, value in self.PPPOE_SCENARIO_STATS_MAP[stat].items(): + if isinstance(value, str): + filtered_row.update({key: view_row[value]}) + # Handle keys which values are represented by regex + else: + for k in view_row.keys(): + if value.match(k): + value = value.match(k).group() + filtered_row.update({key: view_row[value]}) + break + result[stat].append(filtered_row) + return result def start_protocols(self): self.ixnet.execute('startAllProtocols') diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 7df590fb3..89bb3ef7a 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -146,12 +146,16 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): return result - def _ixia_traffic_generate(self, traffic, ixia_obj): + def _ixia_traffic_generate(self, traffic, ixia_obj, traffic_gen): ixia_obj.update_frame(traffic, self.config.duration) ixia_obj.update_ip_packet(traffic) ixia_obj.update_l4(traffic) + self._update_traffic_tracking_options(traffic_gen) ixia_obj.start_traffic() + def _update_traffic_tracking_options(self, traffic_gen): + traffic_gen.update_tracking_options() + def update_traffic_profile(self, traffic_generator): def port_generator(): for vld_id, intfs in sorted(traffic_generator.networks.items()): @@ -183,11 +187,12 @@ class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): self.rate = self._get_next_rate() traffic = self._get_ixia_traffic_profile(self.full_profile, mac) - self._ixia_traffic_generate(traffic, ixia_obj) + self._ixia_traffic_generate(traffic, ixia_obj, traffic_generator) return first_run + # pylint: disable=unused-argument def get_drop_percentage(self, samples, tol_min, tolerance, precision, - resolution, first_run=False): + resolution, first_run=False, tc_rfc2544_opts=None): completed = False drop_percent = 100.0 num_ifaces = len(samples) @@ -275,12 +280,131 @@ class IXIARFC2544PppoeScenarioProfile(IXIARFC2544Profile): self.full_profile.update({downlink: self.params[downlink]}) def update_traffic_profile(self, traffic_generator): + + networks = collections.OrderedDict() + + # Sort network interfaces pairs + for i in range(len(traffic_generator.networks)): + uplink = '_'.join([self.UPLINK, str(i)]) + downlink = '_'.join([self.DOWNLINK, str(i)]) + if uplink in traffic_generator.networks: + networks[uplink] = traffic_generator.networks[uplink] + if downlink in traffic_generator.networks: + networks[downlink] = traffic_generator.networks[downlink] + def port_generator(): - for vld_id, intfs in sorted(traffic_generator.networks.items()): - if not vld_id.startswith((self.UPLINK, self.DOWNLINK)): - continue + for intfs in networks.values(): for intf in intfs: yield traffic_generator.vnfd_helper.port_num(intf) self._get_flow_groups_params() self.ports = [port for port in port_generator()] + + def _get_prio_flows_drop_percentage(self, stats): + drop_percent = 100 + for prio_id in stats: + prio_flow = stats[prio_id] + sum_packet_drop = abs(prio_flow['out_packets'] - prio_flow['in_packets']) + try: + drop_percent = round( + (sum_packet_drop / float(prio_flow['out_packets'])) * 100, + self.DROP_PERCENT_ROUND) + except ZeroDivisionError: + LOG.info('No traffic is flowing') + prio_flow['DropPercentage'] = drop_percent + return stats + + def _get_summary_pppoe_subs_counters(self, samples): + result = {} + keys = ['sessions_up', + 'sessions_down', + 'sessions_not_started', + 'sessions_total'] + for key in keys: + result[key] = \ + sum([samples[port][key] for port in samples + if key in samples[port]]) + return result + + def get_drop_percentage(self, samples, tol_min, tolerance, precision, + resolution, first_run=False, tc_rfc2544_opts=None): + completed = False + sum_drop_percent = 100 + num_ifaces = len(samples) + duration = self.config.duration + priority_stats = samples.pop('priority_stats') + priority_stats = self._get_prio_flows_drop_percentage(priority_stats) + summary_subs_stats = self._get_summary_pppoe_subs_counters(samples) + in_packets_sum = sum( + [samples[iface]['in_packets'] for iface in samples]) + out_packets_sum = sum( + [samples[iface]['out_packets'] for iface in samples]) + rx_throughput = round(float(in_packets_sum) / duration, 3) + tx_throughput = round(float(out_packets_sum) / duration, 3) + sum_packet_drop = abs(out_packets_sum - in_packets_sum) + + try: + sum_drop_percent = round( + (sum_packet_drop / float(out_packets_sum)) * 100, + self.DROP_PERCENT_ROUND) + except ZeroDivisionError: + LOG.info('No traffic is flowing') + + latency_ns_avg = float( + sum([samples[iface]['Store-Forward_Avg_latency_ns'] + for iface in samples])) / num_ifaces + latency_ns_min = float( + sum([samples[iface]['Store-Forward_Min_latency_ns'] + for iface in samples])) / num_ifaces + latency_ns_max = float( + sum([samples[iface]['Store-Forward_Max_latency_ns'] + for iface in samples])) / num_ifaces + + samples['TxThroughput'] = tx_throughput + samples['RxThroughput'] = rx_throughput + samples['DropPercentage'] = sum_drop_percent + samples['latency_ns_avg'] = latency_ns_avg + samples['latency_ns_min'] = latency_ns_min + samples['latency_ns_max'] = latency_ns_max + samples['priority'] = priority_stats + samples.update(summary_subs_stats) + + if tc_rfc2544_opts: + priority = tc_rfc2544_opts.get('priority') + if priority: + drop_percent = samples['priority'][priority]['DropPercentage'] + else: + drop_percent = sum_drop_percent + else: + drop_percent = sum_drop_percent + + if first_run: + completed = True if drop_percent <= tolerance else False + if (first_run and + self.rate_unit == tp_base.TrafficProfileConfig.RATE_FPS): + self.rate = float(out_packets_sum) / duration / num_ifaces + + if drop_percent > tolerance: + self.max_rate = self.rate + elif drop_percent < tol_min: + self.min_rate = self.rate + else: + completed = True + + next_rate = self._get_next_rate() + if abs(next_rate - self.rate) < resolution: + LOG.debug("rate=%s, next_rate=%s, resolution=%s", self.rate, + next_rate, resolution) + # stop test if the difference between the rate transmission + # in two iterations is smaller than the value of the resolution + completed = True + + LOG.debug("tolerance=%s, tolerance_precision=%s drop_percent=%s " + "completed=%s", tolerance, precision, drop_percent, + completed) + + samples['Status'] = self.STATUS_FAIL + if round(drop_percent, precision) <= tolerance: + samples['Status'] = self.STATUS_SUCCESS + + return completed, samples diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py index 2c3140f8c..f8eec4f4c 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py @@ -15,6 +15,7 @@ import ipaddress import logging import six +import collections import os import time @@ -34,7 +35,7 @@ LOG = logging.getLogger(__name__) WAIT_AFTER_CFG_LOAD = 10 WAIT_FOR_TRAFFIC = 30 -WAIT_PROTOCOLS_STARTED = 360 +WAIT_PROTOCOLS_STARTED = 420 class IxiaBasicScenario(object): @@ -66,6 +67,47 @@ class IxiaBasicScenario(object): self.client.create_traffic_model(self._uplink_vports, self._downlink_vports) + def _get_stats(self): + return self.client.get_statistics() + + def generate_samples(self, resource_helper, ports, duration): + stats = self._get_stats() + + samples = {} + # this is not DPDK port num, but this is whatever number we gave + # when we selected ports and programmed the profile + for port_num in ports: + try: + # reverse lookup port name from port_num so the stats dict is descriptive + intf = resource_helper.vnfd_helper.find_interface_by_port(port_num) + port_name = intf['name'] + avg_latency = stats['Store-Forward_Avg_latency_ns'][port_num] + min_latency = stats['Store-Forward_Min_latency_ns'][port_num] + max_latency = stats['Store-Forward_Max_latency_ns'][port_num] + samples[port_name] = { + 'rx_throughput_kps': float(stats['Rx_Rate_Kbps'][port_num]), + 'tx_throughput_kps': float(stats['Tx_Rate_Kbps'][port_num]), + 'rx_throughput_mbps': float(stats['Rx_Rate_Mbps'][port_num]), + 'tx_throughput_mbps': float(stats['Tx_Rate_Mbps'][port_num]), + 'in_packets': int(stats['Valid_Frames_Rx'][port_num]), + 'out_packets': int(stats['Frames_Tx'][port_num]), + 'RxThroughput': float(stats['Valid_Frames_Rx'][port_num]) / duration, + 'TxThroughput': float(stats['Frames_Tx'][port_num]) / duration, + 'Store-Forward_Avg_latency_ns': utils.safe_cast(avg_latency, int, 0), + 'Store-Forward_Min_latency_ns': utils.safe_cast(min_latency, int, 0), + 'Store-Forward_Max_latency_ns': utils.safe_cast(max_latency, int, 0) + } + except IndexError: + pass + + return samples + + def update_tracking_options(self): + pass + + def get_tc_rfc2544_options(self): + pass + class IxiaL3Scenario(IxiaBasicScenario): """Ixia scenario for L3 flow between static ip's""" @@ -172,8 +214,12 @@ class IxiaPppoeClientScenario(object): traffic_profile.full_profile) endpoints_obj_pairs = \ self._get_endpoints_src_dst_obj_pairs(endpoints_id_pairs) - uplink_endpoints = endpoints_obj_pairs[::2] - downlink_endpoints = endpoints_obj_pairs[1::2] + if endpoints_obj_pairs: + uplink_endpoints = endpoints_obj_pairs[::2] + downlink_endpoints = endpoints_obj_pairs[1::2] + else: + uplink_endpoints = self._access_topologies + downlink_endpoints = self._core_topologies self.client.create_ipv4_traffic_model(uplink_endpoints, downlink_endpoints) @@ -266,18 +312,14 @@ class IxiaPppoeClientScenario(object): device groups pairs between which flow groups will be created: 1. In case uplink/downlink flows in traffic profile doesn't have - specified 'port' key, flows will be created between each device - group on access port and device group on corresponding core port. + specified 'port' key, flows will be created between topologies + on corresponding access and core port. E.g.: - Device groups created on access port xe0: dg1, dg2, dg3 - Device groups created on core port xe1: dg4 + Access topology on xe0: topology1 + Core topology on xe1: topology2 Flows will be created between: - dg1 -> dg4 - dg4 -> dg1 - dg2 -> dg4 - dg4 -> dg2 - dg3 -> dg4 - dg4 -> dg3 + topology1 -> topology2 + topology2 -> topology1 2. In case uplink/downlink flows in traffic profile have specified 'port' key, flows will be created between device groups on this @@ -338,13 +380,6 @@ class IxiaPppoeClientScenario(object): [endpoint_obj_pairs.extend([up, down]) for up, down in zip(uplink_dev_groups, downlink_dev_groups)] - if not endpoint_obj_pairs: - for up, down in zip(uplink_ports, downlink_ports): - uplink_dev_groups = port_to_dev_group_mapping[up] - downlink_dev_groups = \ - port_to_dev_group_mapping[down] * len(uplink_dev_groups) - [endpoint_obj_pairs.extend(list(i)) - for i in zip(uplink_dev_groups, downlink_dev_groups)] return endpoint_obj_pairs def _fill_ixia_config(self): @@ -438,6 +473,168 @@ class IxiaPppoeClientScenario(object): bgp_type=ipv4["bgp"].get("bgp_type")) self.protocols.append(bgp_peer_obj) + def update_tracking_options(self): + priority_map = { + 'raw': 'ipv4Raw0', + 'tos': {'precedence': 'ipv4Precedence0'}, + 'dscp': {'defaultPHB': 'ipv4DefaultPhb0', + 'selectorPHB': 'ipv4ClassSelectorPhb0', + 'assuredPHB': 'ipv4AssuredForwardingPhb0', + 'expeditedPHB': 'ipv4ExpeditedForwardingPhb0'} + } + + prio_trackby_key = 'ipv4Precedence0' + + try: + priority = list(self._ixia_cfg['priority'])[0] + if priority == 'raw': + prio_trackby_key = priority_map[priority] + elif priority in ['tos', 'dscp']: + priority_type = list(self._ixia_cfg['priority'][priority])[0] + prio_trackby_key = priority_map[priority][priority_type] + except KeyError: + pass + + tracking_options = ['flowGroup0', 'vlanVlanId0', prio_trackby_key] + self.client.set_flow_tracking(tracking_options) + + def get_tc_rfc2544_options(self): + return self._ixia_cfg.get('rfc2544') + + def _get_stats(self): + return self.client.get_pppoe_scenario_statistics() + + @staticmethod + def get_flow_id_data(stats, flow_id, key): + result = [float(flow.get(key)) for flow in stats if flow['id'] == flow_id] + return sum(result) / len(result) + + def get_priority_flows_stats(self, samples, duration): + results = {} + priorities = set([flow['IP_Priority'] for flow in samples]) + for priority in priorities: + tx_frames = sum( + [int(flow['Tx_Frames']) for flow in samples + if flow['IP_Priority'] == priority]) + rx_frames = sum( + [int(flow['Rx_Frames']) for flow in samples + if flow['IP_Priority'] == priority]) + prio_flows_num = len([flow for flow in samples + if flow['IP_Priority'] == priority]) + avg_latency_ns = sum( + [int(flow['Store-Forward_Avg_latency_ns']) for flow in samples + if flow['IP_Priority'] == priority]) / prio_flows_num + min_latency_ns = sum( + [int(flow['Store-Forward_Min_latency_ns']) for flow in samples + if flow['IP_Priority'] == priority]) / prio_flows_num + max_latency_ns = sum( + [int(flow['Store-Forward_Max_latency_ns']) for flow in samples + if flow['IP_Priority'] == priority]) / prio_flows_num + tx_throughput = float(tx_frames) / duration + rx_throughput = float(rx_frames) / duration + results[priority] = { + 'in_packets': rx_frames, + 'out_packets': tx_frames, + 'RxThroughput': round(rx_throughput, 3), + 'TxThroughput': round(tx_throughput, 3), + 'avg_latency_ns': utils.safe_cast(avg_latency_ns, int, 0), + 'min_latency_ns': utils.safe_cast(min_latency_ns, int, 0), + 'max_latency_ns': utils.safe_cast(max_latency_ns, int, 0) + } + return results + + def generate_samples(self, resource_helper, ports, duration): + + stats = self._get_stats() + samples = {} + ports_stats = stats['port_statistics'] + flows_stats = stats['flow_statistic'] + pppoe_subs_per_port = stats['pppox_client_per_port'] + + # Get sorted list of ixia ports names + ixia_port_names = sorted([data['port_name'] for data in ports_stats]) + + # Set 'port_id' key for ports stats items + for item in ports_stats: + port_id = item.pop('port_name').split('-')[-1].strip() + item['port_id'] = int(port_id) + + # Set 'id' key for flows stats items + for item in flows_stats: + flow_id = item.pop('Flow_Group').split('-')[1].strip() + item['id'] = int(flow_id) + + # Set 'port_id' key for pppoe subs per port stats + for item in pppoe_subs_per_port: + port_id = item.pop('subs_port').split('-')[-1].strip() + item['port_id'] = int(port_id) + + # Map traffic flows to ports + port_flow_map = collections.defaultdict(set) + for item in flows_stats: + tx_port = item.pop('Tx_Port') + tx_port_index = ixia_port_names.index(tx_port) + port_flow_map[tx_port_index].update([item['id']]) + + # Sort ports stats + ports_stats = sorted(ports_stats, key=lambda k: k['port_id']) + + # Get priority flows stats + prio_flows_stats = self.get_priority_flows_stats(flows_stats, duration) + samples['priority_stats'] = prio_flows_stats + + # this is not DPDK port num, but this is whatever number we gave + # when we selected ports and programmed the profile + for port_num in ports: + try: + # reverse lookup port name from port_num so the stats dict is descriptive + intf = resource_helper.vnfd_helper.find_interface_by_port(port_num) + port_name = intf['name'] + port_id = ports_stats[port_num]['port_id'] + port_subs_stats = \ + [port_data for port_data in pppoe_subs_per_port + if port_data.get('port_id') == port_id] + + avg_latency = \ + sum([float(self.get_flow_id_data( + flows_stats, flow, 'Store-Forward_Avg_latency_ns')) + for flow in port_flow_map[port_num]]) / len(port_flow_map[port_num]) + min_latency = \ + sum([float(self.get_flow_id_data( + flows_stats, flow, 'Store-Forward_Min_latency_ns')) + for flow in port_flow_map[port_num]]) / len(port_flow_map[port_num]) + max_latency = \ + sum([float(self.get_flow_id_data( + flows_stats, flow, 'Store-Forward_Max_latency_ns')) + for flow in port_flow_map[port_num]]) / len(port_flow_map[port_num]) + + samples[port_name] = { + 'rx_throughput_kps': float(ports_stats[port_num]['Rx_Rate_Kbps']), + 'tx_throughput_kps': float(ports_stats[port_num]['Tx_Rate_Kbps']), + 'rx_throughput_mbps': float(ports_stats[port_num]['Rx_Rate_Mbps']), + 'tx_throughput_mbps': float(ports_stats[port_num]['Tx_Rate_Mbps']), + 'in_packets': int(ports_stats[port_num]['Valid_Frames_Rx']), + 'out_packets': int(ports_stats[port_num]['Frames_Tx']), + 'RxThroughput': float(ports_stats[port_num]['Valid_Frames_Rx']) / duration, + 'TxThroughput': float(ports_stats[port_num]['Frames_Tx']) / duration, + 'Store-Forward_Avg_latency_ns': utils.safe_cast(avg_latency, int, 0), + 'Store-Forward_Min_latency_ns': utils.safe_cast(min_latency, int, 0), + 'Store-Forward_Max_latency_ns': utils.safe_cast(max_latency, int, 0) + } + + if port_subs_stats: + samples[port_name].update( + {'sessions_up': int(port_subs_stats[0]['Sessions_Up']), + 'sessions_down': int(port_subs_stats[0]['Sessions_Down']), + 'sessions_not_started': int(port_subs_stats[0]['Sessions_Not_Started']), + 'sessions_total': int(port_subs_stats[0]['Sessions_Total'])} + ) + + except IndexError: + pass + + return samples + class IxiaRfc2544Helper(Rfc2544ResourceHelper): @@ -474,9 +671,6 @@ class IxiaResourceHelper(ClientResourceHelper): def _connect(self, client=None): self.client.connect(self.vnfd_helper) - def get_stats(self, *args, **kwargs): - return self.client.get_statistics() - def setup(self): super(IxiaResourceHelper, self).setup() self._init_ix_scenario() @@ -486,36 +680,7 @@ class IxiaResourceHelper(ClientResourceHelper): self._terminated.value = 1 def generate_samples(self, ports, duration): - stats = self.get_stats() - - samples = {} - # this is not DPDK port num, but this is whatever number we gave - # when we selected ports and programmed the profile - for port_num in ports: - try: - # reverse lookup port name from port_num so the stats dict is descriptive - intf = self.vnfd_helper.find_interface_by_port(port_num) - port_name = intf['name'] - avg_latency = stats['Store-Forward_Avg_latency_ns'][port_num] - min_latency = stats['Store-Forward_Min_latency_ns'][port_num] - max_latency = stats['Store-Forward_Max_latency_ns'][port_num] - samples[port_name] = { - 'rx_throughput_kps': float(stats['Rx_Rate_Kbps'][port_num]), - 'tx_throughput_kps': float(stats['Tx_Rate_Kbps'][port_num]), - 'rx_throughput_mbps': float(stats['Rx_Rate_Mbps'][port_num]), - 'tx_throughput_mbps': float(stats['Tx_Rate_Mbps'][port_num]), - 'in_packets': int(stats['Valid_Frames_Rx'][port_num]), - 'out_packets': int(stats['Frames_Tx'][port_num]), - 'RxThroughput': float(stats['Valid_Frames_Rx'][port_num]) / duration, - 'TxThroughput': float(stats['Frames_Tx'][port_num]) / duration, - 'Store-Forward_Avg_latency_ns': utils.safe_cast(avg_latency, int, 0), - 'Store-Forward_Min_latency_ns': utils.safe_cast(min_latency, int, 0), - 'Store-Forward_Max_latency_ns': utils.safe_cast(max_latency, int, 0) - } - except IndexError: - pass - - return samples + return self._ix_scenario.generate_samples(self, ports, duration) def _init_ix_scenario(self): ixia_config = self.scenario_helper.scenario_cfg.get('ixia_config', 'IxiaBasic') @@ -536,6 +701,9 @@ class IxiaResourceHelper(ClientResourceHelper): self._ix_scenario.apply_config() self._ix_scenario.create_traffic_model(traffic_profile) + def update_tracking_options(self): + self._ix_scenario.update_tracking_options() + def run_traffic(self, traffic_profile): if self._terminated.value: return @@ -570,12 +738,13 @@ class IxiaResourceHelper(ClientResourceHelper): # pylint: disable=unnecessary-lambda utils.wait_until_true(lambda: self.client.is_traffic_stopped(), timeout=traffic_profile.config.duration * 2) + rfc2544_opts = self._ix_scenario.get_tc_rfc2544_options() samples = self.generate_samples(traffic_profile.ports, traffic_profile.config.duration) completed, samples = traffic_profile.get_drop_percentage( samples, min_tol, max_tol, precision, resolution, - first_run=first_run) + first_run=first_run, tc_rfc2544_opts=rfc2544_opts) self._queue.put(samples) if completed: |