From ee721fd3e8b77ccfe4252a107a9af8dc41ccc389 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Tue, 10 Apr 2018 08:39:16 +0100 Subject: Improve IXIA IxNetwork library and traffic profile (1) This patch introduces a new way to configure the TCL IxNetwork server. All the configuration is done using the TCL API, removing the need of using the pre-saved configuration file. "IxNextgen.assign_ports" creates and assigns the virtual ports for each physical port defined in the test case. "IxNextgen.create_traffic_item" creates one traffic item and two flow groups per pair of ports, in both directions. "IxNextgen.gt_statistics" retrieves only the required statistics to generate the samples blob in the traffic generator. JIRA: YARDSTICK-1116 Change-Id: I8f1c0c55e99c274b2ed8276ed9a385c502e16d93 Signed-off-by: Rodolfo Alonso Hernandez Signed-off-by: Emma Foley --- .../network_services/libs/ixia_libs/IxNet/IxNet.py | 201 +++++++++++++++------ 1 file changed, 143 insertions(+), 58 deletions(-) (limited to 'yardstick/network_services/libs/ixia_libs') diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py index c538ceeba..0cf2a4126 100644 --- a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py +++ b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py @@ -23,6 +23,11 @@ log = logging.getLogger(__name__) IP_VERSION_4 = 4 IP_VERSION_6 = 6 +PROTO_IPV4 = 'ipv4' +PROTO_IPV6 = 'ipv6' +PROTO_UDP = 'udp' +PROTO_TCP = 'tcp' +PROTO_VLAN = 'vlan' class TrafficStreamHelper(object): @@ -77,17 +82,6 @@ class FramesizeHelper(object): class IxNextgen(object): - STATS_NAME_MAP = { - "traffic_item": 'Traffic Item', - "Tx_Frames": 'Tx Frames', - "Rx_Frames": 'Rx Frames', - "Tx_Frame_Rate": 'Tx Frame Rate', - "Rx_Frame_Rate": 'Tx Frame Rate', - "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)', - } - PORT_STATS_NAME_MAP = { "stat_name": 'Stat Name', "Frames_Tx": 'Frames Tx.', @@ -117,11 +111,6 @@ class IxNextgen(object): MODE_SEEDS_DEFAULT = 'downlink', ['2048', '256'] - @staticmethod - def find_view_obj(view_name, views): - edited_view_name = '::ixNet::OBJ-/statistics/view:"{}"'.format(view_name) - return next((view for view in views if edited_view_name == view), '') - @staticmethod def get_config(tg_cfg): card = [] @@ -150,7 +139,6 @@ class IxNextgen(object): self.ixnet = ixnet self._objRefs = dict() self._cfg = None - self._logger = logging.getLogger(__name__) self._params = None self._bidir = None @@ -197,41 +185,137 @@ class IxNextgen(object): self.ixnet.commit() - def _connect(self, tg_cfg): + def connect(self, tg_cfg): self._cfg = self.get_config(tg_cfg) self.ixnet = IxNetwork.IxNet() machine = self._cfg['machine'] port = str(self._cfg['port']) version = str(self._cfg['version']) - result = self.ixnet.connect(machine, '-port', port, '-version', version) - return result + return self.ixnet.connect(machine, '-port', port, + '-version', version) - def clear_ixia_config(self): + def clear_config(self): + """Wipe out any possible configuration present in the client""" self.ixnet.execute('newConfig') - def load_ixia_profile(self, profile): - self.ixnet.execute('loadConfig', self.ixnet.readFrom(profile)) - - def ix_load_config(self, profile): - self.clear_ixia_config() - self.load_ixia_profile(profile) - - def ix_assign_ports(self): - vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport') - ports = [] - - chassis = self._cfg['chassis'] - ports = [(chassis, card, port) for card, port in + def assign_ports(self): + """Create and assign vports for each physical port defined in config + + This configuration is present in the IXIA profile file. E.g.: + name: trafficgen_1 + role: IxNet + interfaces: + xe0: + vpci: "2:15" # Card:port + driver: "none" + dpdk_port_num: 0 + local_ip: "152.16.100.20" + netmask: "255.255.0.0" + local_mac: "00:98:10:64:14:00" + xe1: + ... + """ + chassis_ip = self._cfg['chassis'] + ports = [(chassis_ip, card, port) for card, port in zip(self._cfg['cards'], self._cfg['ports'])] - vport_list = self.ixnet.getList("/", "vport") - self.ixnet.execute('assignPorts', ports, [], vport_list, True) + log.info('Create and assign vports: %s', ports) + for port in ports: + vport = self.ixnet.add(self.ixnet.getRoot(), 'vport') + self.ixnet.commit() + self.ixnet.execute('assignPorts', [port], [], [vport], True) + self.ixnet.commit() + if self.ixnet.getAttribute(vport, '-state') != 'up': + log.warning('Port %s is down', vport) + + def _create_traffic_item(self): + """Create the traffic item to hold the flow groups + + The traffic item tracking by "Traffic Item" is enabled to retrieve the + latency statistics. + """ + log.info('Create the traffic item "RFC2544"') + traffic_item = self.ixnet.add(self.ixnet.getRoot() + '/traffic', + 'trafficItem') + self.ixnet.setMultiAttribute(traffic_item, '-name', 'RFC2544', + '-trafficType', 'raw') self.ixnet.commit() - for vport in vports: - if self.ixnet.getAttribute(vport, '-state') != 'up': - log.error("Both thr ports are down...") + traffic_item_id = self.ixnet.remapIds(traffic_item)[0] + self.ixnet.setAttribute(traffic_item_id + '/tracking', + '-trackBy', 'trafficGroupId0') + self.ixnet.commit() + + def _create_flow_groups(self): + """Create the flow groups between the assigned ports""" + traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic', + 'trafficItem')[0] + log.info('Create the flow groups') + vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport') + uplink_ports = vports[::2] + downlink_ports = vports[1::2] + for up, down in zip(uplink_ports, downlink_ports): + log.info('FGs: %s <--> %s', up, down) + endpoint_set_1 = self.ixnet.add(traffic_item_id, 'endpointSet') + endpoint_set_2 = self.ixnet.add(traffic_item_id, 'endpointSet') + self.ixnet.setMultiAttribute( + endpoint_set_1, + '-sources', [up + ' /protocols'], + '-destinations', [down + '/protocols']) + self.ixnet.setMultiAttribute( + endpoint_set_2, + '-sources', [down + ' /protocols'], + '-destinations', [up + '/protocols']) + self.ixnet.commit() + + def _append_procotol_to_stack(self, protocol_name, previous_element): + """Append a new element in the packet definition stack""" + protocol = (self.ixnet.getRoot() + + '/traffic/protocolTemplate:"{}"'.format(protocol_name)) + self.ixnet.execute('append', previous_element, protocol) + + def _setup_config_elements(self): + """Setup the config elements + + The traffic item is configured to allow individual configurations per + config element. The default frame configuration is applied: + Ethernet II: added by default + IPv4: element to add + UDP: element to add + Payload: added by default + Ethernet II (Trailer): added by default + :return: + """ + traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic', + 'trafficItem')[0] + log.info('Split the frame rate distribution per config element') + config_elements = self.ixnet.getList(traffic_item_id, 'configElement') + for config_element in config_elements: + self.ixnet.setAttribute(config_element + '/frameRateDistribution', + '-portDistribution', 'splitRateEvenly') + self.ixnet.setAttribute(config_element + '/frameRateDistribution', + '-streamDistribution', 'splitRateEvenly') + self.ixnet.commit() + self._append_procotol_to_stack( + PROTO_UDP, config_element + '/stack:"ethernet-1"') + self._append_procotol_to_stack( + PROTO_IPV4, config_element + '/stack:"ethernet-1"') + + def create_traffic_model(self): + """Create a traffic item and the needed flow groups + + Each flow group inside the traffic item (only one is present) + represents the traffic between two ports: + (uplink) (downlink) + FlowGroup1: port1 -> port2 + FlowGroup2: port1 <- port2 + FlowGroup3: port3 -> port4 + FlowGroup4: port3 <- port4 + """ + self._create_traffic_item() + self._create_flow_groups() + self._setup_config_elements() def ix_update_frame(self, params): streams = ["configElement"] @@ -245,7 +329,7 @@ class IxNextgen(object): self.ixnet.setMultiAttribute(helper.transmissionControl, '-type', '{0}'.format(param.get('traffic_type', - 'continuous')), + 'fixedDuration')), '-duration', '{0}'.format(param.get('duration', "30"))) @@ -314,21 +398,22 @@ class IxNextgen(object): self.ixnet.execute('stop', '/traffic') def build_stats_map(self, view_obj, name_map): - return {kl: self.execute_get_column_values(view_obj, kr) for kl, kr in name_map.items()} - - def execute_get_column_values(self, view_obj, name): - return self.ixnet.execute('getColumnValues', view_obj, name) - - def ix_get_statistics(self): - views = self.ixnet.getList('/statistics', 'view') - stats = {} - view_obj = self.find_view_obj("Traffic Item Statistics", views) - stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP) - - view_obj = self.find_view_obj("Port Statistics", views) - ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP) - - view_obj = self.find_view_obj("Flow Statistics", views) - stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP) - - return stats, ports_stats + return {data_yardstick: self.ixnet.execute( + 'getColumnValues', view_obj, data_ixia) + for data_yardstick, data_ixia in name_map.items()} + + def get_statistics(self): + """Retrieve port and flow statistics + + "Port Statistics" parameters are stored in self.PORT_STATS_NAME_MAP. + "Flow Statistics" parameters are stored in self.LATENCY_NAME_MAP. + + :return: dictionary with the statistics; the keys of this dictionary + are PORT_STATS_NAME_MAP and LATENCY_NAME_MAP keys. + """ + port_statistics = '::ixNet::OBJ-/statistics/view:"Port Statistics"' + flow_statistics = '::ixNet::OBJ-/statistics/view:"Flow Statistics"' + stats = self.build_stats_map(port_statistics, self.PORT_STATS_NAME_MAP) + stats.update(self.build_stats_map(flow_statistics, + self.LATENCY_NAME_MAP)) + return stats -- cgit 1.2.3-korg