def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20, lossrate=0.0): """ Send traffic per RFC2544 BacktoBack test specifications. """ verbose = False framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE") if traffic and 'l2' in traffic: if 'framesize' in traffic['l2']: framesize = traffic['l2']['framesize'] stc_common_args = get_stc_common_settings() rfc2544_common_args = get_rfc2544_common_settings() rfc2544_custom_args = get_rfc2544_custom_settings(framesize, '') args = stc_common_args + rfc2544_common_args + rfc2544_custom_args if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True": args.append("--verbose") verbose = True self._logger.info("Arguments used to call test: %s", args) subprocess.check_call(args) filecs = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"), settings.getValue( "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") + ".csv") if verbose: self._logger.debug("file: %s", filecs) return self.get_rfc2544_results(filecs)
def send_cont_traffic(self, traffic=None, duration=30): """ Send Custom - Continuous Test traffic Reuse RFC2544 throughput test specifications along with 'custom' configuration """ verbose = False custom = "cont" framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE") if traffic and 'l2' in traffic: if 'framesize' in traffic['l2']: framesize = traffic['l2']['framesize'] stc_common_args = get_stc_common_settings() rfc2544_common_args = get_rfc2544_common_settings() rfc2544_custom_args = get_rfc2544_custom_settings(framesize, custom) args = stc_common_args + rfc2544_common_args + rfc2544_custom_args if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True": args.append("--verbose") verbose = True self._logger.debug("Arguments used to call test: %s", args) subprocess.check_call(args) filec = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"), settings.getValue( "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") + ".csv") if verbose: self._logger.info("file: %s", filec) return self.get_rfc2544_results(filec)
def connect(self): self._logger.info("MOONGEN: In MoonGen connect method...") moongen_host_ip_addr = settings.getValue('TRAFFICGEN_MOONGEN_HOST_IP_ADDR') moongen_base_dir = settings.getValue('TRAFFICGEN_MOONGEN_BASE_DIR') moongen_user = settings.getValue('TRAFFICGEN_MOONGEN_USER') if moongen_host_ip_addr: print(moongen_host_ip_addr) cmd_ping = "ping -c1 " + moongen_host_ip_addr else: raise RuntimeError('MOONGEN: MoonGen host not defined') ping = subprocess.Popen(cmd_ping, shell=True, stderr=subprocess.PIPE) output, error = ping.communicate() print(output) if error: raise RuntimeError('MOONGEN: Cannot ping MoonGen host at %s' % moongen_host_ip_addr) connect_moongen = "ssh " + moongen_user + "@" + moongen_host_ip_addr cmd_find_moongen = connect_moongen + " ls " + moongen_base_dir + "/examples/opnfv-vsperf.lua" find_moongen = subprocess.Popen(cmd_find_moongen, shell=True, stderr=subprocess.PIPE) output, error = find_moongen.communicate() if error: raise RuntimeError('MOONGEN: Cannot locate MoonGen program at %s within %s' \ % (moongen_host_ip_addr, moongen_base_dir)) self._logger.info("MOONGEN: MoonGen host successfully found...")
def __init__(self): """Loader ctor - initialization method. All data is read from configuration each time Loader instance is created. It is up to creator to maintain object life cycle if this behavior is unwanted. """ self._trafficgen_loader = LoaderServant( settings.getValue('TRAFFICGEN_DIR'), settings.getValue('TRAFFICGEN'), ITrafficGenerator) self._metrics_loader = LoaderServant( settings.getValue('COLLECTOR_DIR'), settings.getValue('COLLECTOR'), ICollector) self._vswitch_loader = LoaderServant( settings.getValue('VSWITCH_DIR'), settings.getValue('VSWITCH'), IVSwitch) self._vnf_loader = LoaderServant( settings.getValue('VNF_DIR'), settings.getValue('VNF'), IVnf) self._pktfwd_loader = LoaderServant( settings.getValue('PKTFWD_DIR'), settings.getValue('PKTFWD'), IPktFwd)
def __init__(self): """Moongen class constructor.""" self._logger.info("In moongen __init__ method") self._params = {} self._moongen_host_ip_addr = ( settings.getValue('TRAFFICGEN_MOONGEN_HOST_IP_ADDR')) self._moongen_base_dir = ( settings.getValue('TRAFFICGEN_MOONGEN_BASE_DIR')) self._moongen_user = settings.getValue('TRAFFICGEN_MOONGEN_USER') self._moongen_ports = settings.getValue('TRAFFICGEN_MOONGEN_PORTS')
def _setup_decap(self): """ Sets up the switch for overlay P2P decapsulation test """ self._logger.debug('Setup using ' + str(self._vswitch_class)) try: self._vswitch.start() bridge = settings.getValue('TUNNEL_INTEGRATION_BRIDGE') bridge_ext = settings.getValue('TUNNEL_EXTERNAL_BRIDGE') bridge_ext_ip = settings.getValue('TUNNEL_EXTERNAL_BRIDGE_IP') tgen_ip1 = settings.getValue('TRAFFICGEN_PORT1_IP') self._vswitch.add_switch(bridge) tasks.run_task(['sudo', 'ip', 'addr', 'add', settings.getValue('VTEP_IP1'), 'dev', bridge], self._logger, 'Assign ' + settings.getValue('VTEP_IP1') + ' to ' + bridge, False) tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', bridge, 'up'], self._logger, 'Bring up ' + bridge, False) tunnel_type = self._traffic['tunnel_type'] self._vswitch.add_switch(bridge_ext) self._vswitch.add_phy_port(bridge) (_, phy2_number) = self._vswitch.add_phy_port(bridge_ext) if tunnel_type == "vxlan": vxlan_vni = 'options:key=' + settings.getValue('VXLAN_VNI') (_, phy3_number) = self._vswitch.add_tunnel_port(bridge_ext, tgen_ip1, tunnel_type, params=[vxlan_vni]) else: (_, phy3_number) = self._vswitch.add_tunnel_port(bridge_ext, tgen_ip1, tunnel_type) tasks.run_task(['sudo', 'ip', 'addr', 'add', bridge_ext_ip, 'dev', bridge_ext], self._logger, 'Assign ' + bridge_ext_ip + ' to ' + bridge_ext) tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', bridge_ext, 'up'], self._logger, 'Set ' + bridge_ext + ' status to up') self._vswitch.set_tunnel_arp(tgen_ip1, settings.getValue('TRAFFICGEN_PORT1_MAC'), bridge) # Test is unidirectional for now self._vswitch.del_flow(bridge_ext) flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy3_number, phy2_number) self._vswitch.add_flow(bridge_ext, flow1) except: self._vswitch.stop() raise
def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20, lossrate=0.0): """Send traffic per RFC2544 back2back test specifications. See ITrafficGenerator for description """ self._duration = duration self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) self._setup_json_config(trials, lossrate, '2544_b2b') args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", "./tools/pkt_gen/xena", "-u", settings.getValue('TRAFFICGEN_XENA_USER')] self.mono_pipe = subprocess.Popen( args, stdout=sys.stdout) self.mono_pipe.communicate() root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot() return Xena._create_throughput_result(root)
def setup(self): """Sets up the switch for p2p. """ self._logger.debug('Setup using ' + str(self._vswitch_class)) try: self._vswitch.start() bridge = settings.getValue('VSWITCH_BRIDGE_NAME') self._vswitch.add_switch(bridge) (_, _) = self._vswitch.add_phy_port(bridge) (_, _) = self._vswitch.add_phy_port(bridge) self._vswitch.del_flow(bridge) # table#0 - flows designed to force 5 & 13 tuple matches go here flow = {'table':'0', 'priority':'1', 'actions': ['goto_table:1']} self._vswitch.add_flow(bridge, flow) # table#1 - flows to route packets between ports goes here. The # chosen port is communicated to subsequent tables by setting the # metadata value to the egress port number # configure flows according to the TC definition flow_template = _FLOW_TEMPLATE.copy() if self._traffic['flow_type'] == 'IP': flow_template.update({'dl_type':'0x0800', 'nw_src':self._traffic['l3']['srcip'], 'nw_dst':self._traffic['l3']['dstip']}) flow = flow_template.copy() flow.update({'table':'1', 'priority':'1', 'in_port':'1', 'actions': ['write_actions(output:2)', 'write_metadata:0x2', 'goto_table:2']}) self.process_flow_template(bridge, flow) flow = flow_template.copy() flow.update({'table':'1', 'priority':'1', 'in_port':'2', 'actions': ['write_actions(output:1)', 'write_metadata:0x1', 'goto_table:2']}) self.process_flow_template(bridge, flow) # Frame modification table. Frame modification flow rules are # isolated in this table so that they can be turned on or off # without affecting the routing or tuple-matching flow rules. flow = {'table':'2', 'priority':'1', 'actions': ['goto_table:3']} self._vswitch.add_flow(bridge, flow) # Egress table # (TODO) Billy O'Mahony - the drop action here actually required in # order to egress the packet. This is the subject of a thread on # ovs-discuss 2015-06-30. flow = {'table':'3', 'priority':'1', 'actions': ['drop']} self._vswitch.add_flow(bridge, flow) except: self._vswitch.stop() raise
def _create_moongen_cfg_file(traffic, duration=60, acceptable_loss_pct=1): moongen_host_ip_addr = settings.getValue('TRAFFICGEN_MOONGEN_HOST_IP_ADDR') moongen_base_dir = settings.getValue('TRAFFICGEN_MOONGEN_BASE_DIR') moongen_user = settings.getValue('TRAFFICGEN_MOONGEN_USER') moongen_ports= settings.getValue('TRAFFICGEN_MOONGEN_PORTS') print(traffic) print("traffic['frame_rate'] = %s" % str(traffic['frame_rate'])) print("traffic['multistream'] = %s" % str(traffic['multistream'])) print("traffic['stream_type'] = %s" % str(traffic['stream_type'])) print("traffic['l2']['srcmac'] = %s" % str(traffic['l2']['srcmac'])) print("traffic['l2']['dstmac'] = %s" % str(traffic['l2']['dstmac'])) print("traffic['l3']['proto'] = %s" % str(traffic['l3']['proto'])) print("traffic['l3']['srcip'] = %s" % str(traffic['l3']['srcip'])) print("traffic['l3']['dstip'] = %s" % str(traffic['l3']['dstip'])) print("traffic['l4']['srcport'] = %s" % str(traffic['l4']['srcport'])) print("traffic['l4']['dstport'] = %s" % str(traffic['l4']['dstport'])) print("traffic['vlan']['enabled'] = %s" % str(traffic['vlan']['enabled'])) print("traffic['vlan']['id'] = %s" % str(traffic['vlan']['id'])) print("traffic['vlan']['priority'] = %s" % str(traffic['vlan']['priority'])) print("traffic['vlan']['cfi'] = %s" % str(traffic['vlan']['cfi'])) print(traffic['l2']['framesize']) out_file = open("opnfv-vsperf-cfg.lua", "wt") out_file.write("VSPERF {\n") out_file.write("testType = \"throughput\",\n") out_file.write("runBidirec = " + traffic['bidir'].lower() + ",\n") out_file.write("searchRunTime = " + str(duration) + ",\n") out_file.write("validationRunTime = " + str(duration) + ",\n") out_file.write("acceptableLossPct = " + str(acceptable_loss_pct) + ",\n") out_file.write("frameSize = " + str(traffic['l2']['framesize']) + ",\n") out_file.write("ports = " + str(moongen_ports) + ",\n") out_file.write("startRate = 4\n") out_file.write("}" + "\n") out_file.close() copy_moongen_cfg = "scp opnfv-vsperf-cfg.lua " + moongen_user + "@" + moongen_host_ip_addr + ":" + moongen_base_dir + "/. && rm opnfv-vsperf-cfg.lua" find_moongen = subprocess.Popen(copy_moongen_cfg, shell=True, stderr=subprocess.PIPE) output, error = find_moongen.communicate() if error: raise RuntimeError('MOONGEN: Error copying configuration file') return
def setup(self): """ Sets up the switch for overlay P2P (tunnel encap or decap) """ self._logger.debug('Setting up ' + str(self._tunnel_operation)) if self._tunnel_operation == "encapsulation": self._setup_encap() else: if settings.getValue('VSWITCH').endswith('Vanilla'): self._setup_decap_vanilla() else: self._setup_decap()
def _setup_json_config(self, trials, loss_rate, testtype=None): """ Create a 2bUsed json file that will be used for xena2544.exe execution. :param trials: Number of trials :param loss_rate: The acceptable loss rate as float :param testtype: Either '2544_b2b' or '2544_throughput' as string :return: None """ try: j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544') j_file.set_chassis_info( settings.getValue('TRAFFICGEN_XENA_IP'), settings.getValue('TRAFFICGEN_XENA_PASSWORD') ) j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'), settings.getValue('TRAFFICGEN_XENA_PORT1') ) j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'), settings.getValue('TRAFFICGEN_XENA_PORT2') ) j_file.set_test_options( packet_sizes=self._params['traffic']['l2']['framesize'], iterations=trials, loss_rate=loss_rate, duration=self._duration, micro_tpld=True if self._params[ 'traffic']['l2']['framesize'] == 64 else False) if testtype == '2544_throughput': j_file.enable_throughput_test() elif testtype == '2544_b2b': j_file.enable_back2back_test() j_file.set_header_layer2( dst_mac=self._params['traffic']['l2']['dstmac'], src_mac=self._params['traffic']['l2']['srcmac']) j_file.set_header_layer3( src_ip=self._params['traffic']['l3']['srcip'], dst_ip=self._params['traffic']['l3']['dstip'], protocol=self._params['traffic']['l3']['proto']) j_file.set_header_layer4_udp( source_port=self._params['traffic']['l4']['srcport'], destination_port=self._params['traffic']['l4']['dstport']) if self._params['traffic']['vlan']['enabled']: j_file.set_header_vlan( vlan_id=self._params['traffic']['vlan']['id'], id=self._params['traffic']['vlan']['cfi'], prio=self._params['traffic']['vlan']['priority']) j_file.add_header_segments( flows=self._params['traffic']['multistream'], multistream_layer=self._params['traffic']['stream_type']) # set duplex mode if self._params['traffic']['bidir']: j_file.set_topology_mesh() else: j_file.set_topology_blocks() j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544') except Exception as exc: self._logger.exception("Error during Xena XML setup: %s", exc) raise
def old_dpdk_config(): """Checks if ovs-vswitchd uses legacy dpdk configuration via --dpdk option :returns: True if legacy --dpdk option is supported, otherwise it returns False """ ovs_vswitchd_bin = S.getValue('TOOLS')['ovs-vswitchd'] try: subprocess.check_output(ovs_vswitchd_bin + r' --help | grep "\-\-dpdk"', shell=True) return True except subprocess.CalledProcessError: return False
def umount_hugepages(): """Ensure hugepages are unmounted. """ if not is_hugepage_mounted(): return try: tasks.run_task(['sudo', 'umount', settings.getValue('HUGEPAGE_DIR')], _LOGGER, 'Unmounting hugepages...', True) except subprocess.CalledProcessError: _LOGGER.error('Unable to umount hugepages.') if not deallocate_hugepages(): _LOGGER.error('Unable to deallocate previously allocated hugepages.')
def init(): """Setup system for DPDK. """ # pylint: disable=global-statement global _NICS global _NICS_PCI _NICS = S.getValue('NICS') _NICS_PCI = list(nic['pci'] for nic in _NICS) if not _is_linux(): _LOGGER.error('Not running on a compatible Linux version. Exiting...') return _insert_modules() _remove_vhost_net() _bind_nics()
def learning_packets(self, traffic): """ Send learning packets before testing :param traffic: traffic structure as per send_cont_traffic guidelines :return: None """ self._logger.info("T-Rex sending learning packets") learning_thresh_traffic = copy.deepcopy(traffic) learning_thresh_traffic["frame_rate"] = 1 self.generate_traffic(learning_thresh_traffic, settings.getValue("TRAFFICGEN_TREX_LEARNING_DURATION"), disable_capture=True) self._logger.info("T-Rex finished learning packets") time.sleep(3) # allow packets to complete before starting test traffic
def get_nic(): """Get NIC(s) information. :returns: Return NIC(s) information as a list """ nics = [] output = subprocess.check_output('lspci', shell=True) output = output.decode(locale.getdefaultlocale()[1]) for line in output.split('\n'): for nic in S.getValue('NICS'): # lspci shows PCI addresses without domain part, i.e. last 7 chars if line.startswith(nic['pci'][-7:]): nics.append(''.join(line.split(':')[2:]).strip()) return nics
def add_switch(self, switch_name, params=None): """See IVswitch for general description """ bridge = OFBridge(switch_name) if params is None: bridge.create( ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev']) else: bridge.create( ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev'] + params) bridge.set_db_attribute('Open_vSwitch', '.', 'other_config:max-idle', settings.getValue('VSWITCH_FLOW_TIMEOUT')) if settings.getValue('VSWITCH_AFFINITIZATION_ON') == 1: # Sets the PMD core mask to VSWITCH_PMD_CPU_MASK # for CPU core affinitization bridge.set_db_attribute('Open_vSwitch', '.', 'other_config:pmd-cpu-mask', settings.getValue('VSWITCH_PMD_CPU_MASK')) self._bridges[switch_name] = bridge
def add_vport(self, switch_name): """ Method adds virtual port into OVS vanilla See IVswitch for general description """ # Create tap devices for the VM tap_name = 'tap' + str(self._vport_id) self._vport_id += 1 tap_cmd_list = ['sudo', 'ip', 'tuntap', 'del', tap_name, 'mode', 'tap'] # let's assume, that all VMs have NIC QUEUES enabled or disabled # at the same time if int(settings.getValue('GUEST_NIC_QUEUES')[0]): tap_cmd_list += ['multi_queue'] tasks.run_task(tap_cmd_list, self._logger, 'Creating tap device...', False) tap_cmd_list = ['sudo', 'ip', 'tuntap', 'add', tap_name, 'mode', 'tap'] # let's assume, that all VMs have NIC QUEUES enabled or disabled # at the same time if int(settings.getValue('GUEST_NIC_QUEUES')[0]): tap_cmd_list += ['multi_queue'] tasks.run_task(tap_cmd_list, self._logger, 'Creating tap device...', False) if settings.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'): tasks.run_task(['ifconfig', tap_name, 'mtu', str(settings.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))], self._logger, 'Setting mtu size', False) tasks.run_task(['sudo', 'ip', 'addr', 'flush', 'dev', tap_name], self._logger, 'Remove IP', False) tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', tap_name, 'up'], self._logger, 'Bring up ' + tap_name, False) bridge = self._switches[switch_name] of_port = bridge.add_port(tap_name, []) return (tap_name, of_port)
def _affinitize(self): """ Affinitize the SMP cores of a QEMU instance. This is a bit of a hack. The 'socat' utility is used to interact with the QEMU HMP. This is necessary due to the lack of QMP in older versions of QEMU, like v1.6.2. In future releases, this should be replaced with calls to libvirt or another Python-QEMU wrapper library. :returns: None """ thread_id = (r'.* CPU #%d: .* thread_id=(\d+)') self._logger.info('Affinitizing guest...') cur_locale = locale.getdefaultlocale()[1] proc = subprocess.Popen(('echo', 'info cpus'), stdout=subprocess.PIPE) output = subprocess.check_output( ('sudo', 'socat', '-', 'UNIX-CONNECT:%s' % self._monitor), stdin=proc.stdout) proc.wait() for cpu in range(0, int(S.getValue('GUEST_SMP')[self._number])): match = None for line in output.decode(cur_locale).split('\n'): match = re.search(thread_id % cpu, line) if match: self._affinitize_pid( S.getValue('GUEST_CORE_BINDING')[self._number][cpu], match.group(1)) break if not match: self._logger.error( 'Failed to affinitize guest core #%d. Could' ' not parse tid.', cpu)
def _setup_json_config(self, trials, loss_rate, testtype=None): """ Create a 2bUsed json file that will be used for xena2544.exe execution. :param trials: Number of trials :param loss_rate: The acceptable loss rate as float :param testtype: Either '2544_b2b' or '2544_throughput' as string :return: None """ try: j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544') j_file.set_chassis_info( settings.getValue('TRAFFICGEN_XENA_IP'), settings.getValue('TRAFFICGEN_XENA_PASSWORD')) j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'), settings.getValue('TRAFFICGEN_XENA_PORT1')) j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'), settings.getValue('TRAFFICGEN_XENA_PORT2')) j_file.set_test_options( packet_sizes=self._params['traffic']['l2']['framesize'], iterations=trials, loss_rate=loss_rate, duration=self._duration, micro_tpld=True if self._params['traffic']['l2']['framesize'] == 64 else False) if testtype == '2544_throughput': j_file.enable_throughput_test() elif testtype == '2544_b2b': j_file.enable_back2back_test() j_file.set_header_layer2( dst_mac=self._params['traffic']['l2']['dstmac'], src_mac=self._params['traffic']['l2']['srcmac']) j_file.set_header_layer3( src_ip=self._params['traffic']['l3']['srcip'], dst_ip=self._params['traffic']['l3']['dstip'], protocol=self._params['traffic']['l3']['proto']) j_file.set_header_layer4_udp( source_port=self._params['traffic']['l4']['srcport'], destination_port=self._params['traffic']['l4']['dstport']) if self._params['traffic']['vlan']['enabled']: j_file.set_header_vlan( vlan_id=self._params['traffic']['vlan']['id'], id=self._params['traffic']['vlan']['cfi'], prio=self._params['traffic']['vlan']['priority']) j_file.add_header_segments( flows=self._params['traffic']['multistream'], multistream_layer=self._params['traffic']['stream_type']) # set duplex mode if self._params['traffic']['bidir']: j_file.set_topology_mesh() else: j_file.set_topology_blocks() j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544') except Exception as exc: self._logger.exception("Error during Xena XML setup: %s", exc) raise
def __init__(self, vswitch_class, traffic): """Initializes up the prerequisites for the ptunp deployment scenario. :vswitch_class: the vSwitch class to be used. """ self._logger = logging.getLogger(__name__) self._vswitch_class = vswitch_class self._vswitch = vswitch_class() self._deployment_scenario = "ptunp" self._traffic = traffic.copy() self.bridge_phy1 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE1') self.bridge_phy2 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE2') self.bridge_mod1 = settings.getValue('TUNNEL_MODIFY_BRIDGE1') self.bridge_mod2 = settings.getValue('TUNNEL_MODIFY_BRIDGE2') self.br_mod_mac1 = settings.getValue('TUNNEL_MODIFY_BRIDGE_MAC1') self.br_mod_mac2 = settings.getValue('TUNNEL_MODIFY_BRIDGE_MAC2') self.br_mod_ip1 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP1') self.br_mod_ip2 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP2') self.tunnel_type = settings.getValue('TUNNEL_TYPE') self._logger.debug('Creation using ' + str(self._vswitch_class))
def _configure_linux_bridge(self): """ Configure VM to perform L2 forwarding between NICs by linux bridge """ if int(S.getValue('GUEST_NIC_QUEUES')[self._number]): self._set_multi_queue_nic() self._configure_disable_firewall() # configure linux bridge self.execute_and_wait('brctl addbr br0') # add all NICs into the bridge for nic in self._nics: self.execute_and_wait('ip addr add ' + nic['ip'] + ' dev ' + nic['device']) if S.getValue('VSWITCH_JUMBO_FRAMES_ENABLED'): self.execute_and_wait('ifconfig {} mtu {}'.format( nic['device'], S.getValue('VSWITCH_JUMBO_FRAMES_SIZE'))) self.execute_and_wait('ip link set dev ' + nic['device'] + ' up') self.execute_and_wait('brctl addif br0 ' + nic['device']) self.execute_and_wait('ip addr add {} dev br0'.format( S.getValue('GUEST_BRIDGE_IP')[self._number])) self.execute_and_wait('ip link set dev br0 up') # Add the arp entries for the IXIA ports and the bridge you are using. # Use command line values if provided. trafficgen_mac = S.getValue('VANILLA_TGEN_PORT1_MAC') trafficgen_ip = S.getValue('VANILLA_TGEN_PORT1_IP') self.execute_and_wait('arp -s ' + trafficgen_ip + ' ' + trafficgen_mac) trafficgen_mac = S.getValue('VANILLA_TGEN_PORT2_MAC') trafficgen_ip = S.getValue('VANILLA_TGEN_PORT2_IP') self.execute_and_wait('arp -s ' + trafficgen_ip + ' ' + trafficgen_mac) # Enable forwarding self.execute_and_wait('sysctl -w net.ipv4.ip_forward=1') # Controls source route verification # 0 means no source validation self.execute_and_wait('sysctl -w net.ipv4.conf.all.rp_filter=0') for nic in self._nics: self.execute_and_wait('sysctl -w net.ipv4.conf.' + nic['device'] + '.rp_filter=0')
def run_vsctl(self, args, check_error=False): """Run ``ovs-vsctl`` with supplied arguments. In case that timeout is set to -1, then ovs-vsctl will be called with --no-wait option. :param args: Arguments to pass to ``ovs-vsctl`` :param check_error: Throw exception on error :return: None """ if self.timeout == -1: cmd = [ 'sudo', settings.getValue('TOOLS')['ovs-vsctl'], '--no-wait' ] + args else: cmd = [ 'sudo', settings.getValue('TOOLS')['ovs-vsctl'], '--timeout', str(self.timeout) ] + args return tasks.run_task(cmd, self.logger, 'Running ovs-vsctl...', check_error)
def run_appctl(self, args, check_error=False): """Run ``ovs-appctl`` with supplied arguments. :param args: Arguments to pass to ``ovs-appctl`` :param check_error: Throw exception on error :return: None """ cmd = [ 'sudo', settings.getValue('TOOLS')['ovs-appctl'], '--timeout', str(self.timeout) ] + args return tasks.run_task(cmd, self.logger, 'Running ovs-appctl...', check_error)
def _bind_nics(): """Bind NICs using the bind tool specified in the configuration. """ if not _NICS_PCI: _LOGGER.info('NICs are not configured - nothing to bind') return try: _driver = 'igb_uio' ''' if 'mlx' in S.getValue('TOOLS')['dpdk_modules']: return if 'vfio-pci' in S.getValue('TOOLS')['dpdk_modules']: _driver = 'vfio-pci' tasks.run_task(['sudo', 'chmod', 'a+x', '/dev/vfio'], _LOGGER, 'Setting VFIO permissions .. a+x', True) tasks.run_task(['sudo', 'chmod', '-R', '666', '/dev/vfio/'], _LOGGER, 'Setting VFIO permissions .. 0666', True) ''' if 'vfio-pci' in S.getValue('TOOLS')['dpdk_modules']: return if 'driverctl' in S.getValue('TOOLS')['bind-tool'].lower(): for nic in _NICS_PCI: tasks.run_task([ 'sudo', S.getValue('TOOLS')['bind-tool'], '-v', 'set-override' ] + [nic] + [_driver], _LOGGER, 'Binding NIC %s...' % nic, True) else: tasks.run_task([ 'sudo', S.getValue('TOOLS')['bind-tool'], '--bind=' + _driver ] + _NICS_PCI, _LOGGER, 'Binding NICs %s...' % _NICS_PCI, True) except subprocess.CalledProcessError: _LOGGER.error('Unable to bind NICs %s', str(_NICS_PCI))
def get_user_traffic(traffic_type, traffic_conf, flow_conf, traffic_stats): """ Request user input for traffic. :param traffic_type: Name of traffic type. :param traffic_conf: Configuration of traffic to be sent. :param traffic_conf: Configuration of flow to be sent. :param traffic_stats: Required output statistics (i.e. what's needed) :returns: List of stats corresponding to those in traffic_stats """ results = [] print('Please send \'%s\' traffic with the following stream config:\n%s\n' 'and the following flow config:\n%s' % (traffic_type, traffic_conf, json.dumps(flow_conf, indent=4))) for stat in traffic_stats: if stat in settings.getValue('TRAFFICGEN_DUMMY_RESULTS'): results.append(settings.getValue('TRAFFICGEN_DUMMY_RESULTS')[stat]) else: results.append(_get_user_traffic_stat(stat)) return results
def get_pids(proc_names_list): """ Get pid(s) of process(es) with given name(s) :returns: list with pid(s) of given processes or None if processes with given names are not running """ try: pids = subprocess.check_output(['sudo', 'LC_ALL=' + S.getValue('DEFAULT_CMD_LOCALE'), 'pidof'] + proc_names_list) except subprocess.CalledProcessError: # such process isn't running return None return list(map(str, map(int, pids.split())))
def __init__(self): """See IVswitch for general description """ self._logfile = os.path.join(S.getValue('LOG_DIR'), S.getValue('LOG_FILE_VPP')) self._logger = logging.getLogger(__name__) self._expect = r'vpp#' self._timeout = 30 self._vswitch_args = [] self._cmd = [] self._cmd_template = ['sudo', '-E', S.getValue('TOOLS')['vpp']] self._stamp = None self._logger = logging.getLogger(__name__) self._phy_ports = [] self._virt_ports = [] self._switches = {} # configure DPDK NICs tmp_args = copy.deepcopy(S.getValue('VSWITCH_VPP_ARGS')) if 'dpdk' not in tmp_args: tmp_args['dpdk'] = [] # override socket-mem settings for tmp_arg in tmp_args['dpdk']: if tmp_arg.startswith('socket-mem'): tmp_args['dpdk'].remove(tmp_arg) tmp_args['dpdk'].append('socket-mem ' + ','.join(S.getValue('DPDK_SOCKET_MEM'))) # create directory for vhostuser sockets if needed if not os.path.exists(S.getValue('TOOLS')['ovs_var_tmp']): tasks.run_task( ['sudo', 'mkdir', '-p', S.getValue('TOOLS')['ovs_var_tmp']], self._logger) # configure path to the plugins tmp_args['plugin_path'] = S.getValue('TOOLS')['vpp_plugin_path'] for nic in S.getValue('NICS'): tmp_args['dpdk'].append("dev {}".format(nic['pci'])) self._vswitch_args = self._process_vpp_args(tmp_args)
def dump_connections(self, switch_name): """See IVswitch for general description :raises: RuntimeError """ mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE') if mode == 'l2patch': self.dump_l2patch() elif mode == 'xconnect': self.dump_xconnect() elif mode == 'bridge': self.dump_bridge(switch_name) else: raise RuntimeError( 'VPP: Unsupported l2 connection mode detected %s', mode)
def del_connection(self, switch_name, port1, port2, bidir=False): """See IVswitch for general description :raises: RuntimeError """ mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE') if mode == 'l2patch': self.del_l2patch(port1, port2, bidir) elif mode == 'xconnect': self.del_xconnect(port1, port2, bidir) elif mode == 'bridge': self.del_bridge(switch_name, port1, port2) else: raise RuntimeError( 'VPP: Unsupported l2 connection mode detected %s', mode)
def _bind_dpdk_driver(self, driver, pci_slots): """ Bind the virtual nics to the driver specific in the conf file :return: None """ if driver == 'uio_pci_generic': if S.getValue('VNF') == 'QemuPciPassthrough': # unsupported config, bind to igb_uio instead and exit the # outer function after completion. self._logger.error('SR-IOV does not support uio_pci_generic. ' 'Igb_uio will be used instead.') self._bind_dpdk_driver('igb_uio_from_src', pci_slots) return self.execute_and_wait('modprobe uio_pci_generic') self.execute_and_wait('./*tools/dpdk*bind.py -b uio_pci_generic ' + pci_slots) elif driver == 'vfio_no_iommu': self.execute_and_wait('modprobe -r vfio') self.execute_and_wait('modprobe -r vfio_iommu_type1') self.execute_and_wait('modprobe vfio enable_unsafe_noiommu_mode=Y') self.execute_and_wait('modprobe vfio-pci') self.execute_and_wait('./*tools/dpdk*bind.py -b vfio-pci ' + pci_slots) elif driver == 'igb_uio_from_src': # build and insert igb_uio and rebind interfaces to it self.execute_and_wait('make RTE_OUTPUT=$RTE_SDK/$RTE_TARGET -C ' '$RTE_SDK/lib/librte_eal/linuxapp/igb_uio') self.execute_and_wait('modprobe uio') self.execute_and_wait('insmod %s/kmod/igb_uio.ko' % S.getValue('RTE_TARGET')) self.execute_and_wait('./*tools/dpdk*bind.py -b igb_uio ' + pci_slots) else: self._logger.error( 'Unknown driver for binding specified, defaulting to igb_uio') self._bind_dpdk_driver('igb_uio_from_src', pci_slots)
def _login(self, timeout=120): """ Login to QEMU instance. This can be used immediately after booting the machine, provided a sufficiently long ``timeout`` is given. :param timeout: Timeout to wait for login to complete. :returns: None """ # if no timeout was set, we likely started QEMU without waiting for it # to boot. This being the case, we best check that it has finished # first. if not self._timeout: self._expect_process(timeout=timeout) self._child.sendline(S.getValue('GUEST_USERNAME')[self._number]) self._child.expect(S.getValue('GUEST_PROMPT_PASSWORD')[self._number], timeout=5) self._child.sendline(S.getValue('GUEST_PASSWORD')[self._number]) self._expect_process(S.getValue('GUEST_PROMPT')[self._number], timeout=5)
def connect(self): """Configure system for IxNetwork. """ self._cfg = { 'lib_path': settings.getValue('TRAFFICGEN_IXNET_LIB_PATH'), # IxNetwork machine configuration 'machine': settings.getValue('TRAFFICGEN_IXNET_MACHINE'), 'port': settings.getValue('TRAFFICGEN_IXNET_PORT'), 'user': settings.getValue('TRAFFICGEN_IXNET_USER'), # IXIA chassis configuration 'chassis': settings.getValue('TRAFFICGEN_IXIA_HOST'), 'card': settings.getValue('TRAFFICGEN_IXIA_CARD'), 'port1': settings.getValue('TRAFFICGEN_IXIA_PORT1'), 'port2': settings.getValue('TRAFFICGEN_IXIA_PORT2'), 'output_dir': settings.getValue('TRAFFICGEN_IXNET_TESTER_RESULT_DIR'), } self._logger.debug('IXIA configuration configuration : %s', self._cfg) return self
def _vhost_user_cleanup(): """Remove files created by vhost-user tests. """ for sock in settings.getValue('VHOST_USER_SOCKS'): if os.path.exists(sock): try: tasks.run_task(['sudo', 'rm', sock], _LOGGER, 'Deleting vhost-user socket \'%s\'...' % sock, True) except subprocess.CalledProcessError: _LOGGER.error('Unable to delete vhost-user socket \'%s\'.', sock) continue
def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """ Send traffic per RFC2544 throughput test specifications. """ print("Run with Duration: {}, Tests: {} & Lossrate: {}".format( duration, tests, lossrate)) pkt_size = None if traffic and 'l2' in traffic: if 'framesize' in traffic['l2']: framesize = traffic['l2']['framesize'] pkt_size = '[' + str(framesize) + ']' if not settings.getValue('K8S'): # First render all the configurations and place it filesdir = settings.getValue('TRAFFICGEN_PROX_FILES_DIR') confdir = settings.getValue('TRAFFICGEN_PROX_CONF_DIR') render.render_content_jinja(pkt_size) # copy some static files to config folder. for stfile in settings.getValue( 'TRAFFICGEN_PROX_STATIC_CONF_FILES'): srcfile = os.path.join(filesdir, stfile) if os.path.exists(srcfile): cmd = ['cp', srcfile, confdir] tasks.run_task(cmd, self._logger, 'Copying Static Conf. Files') # in appropriate folder: pick /tmp or /opt or $HOME envfile = os.path.join( confdir, settings.getValue('TRAFFICGEN_PROX_ENV_FILE')) tstfile = os.path.join( confdir, settings.getValue('TRAFFICGEN_PROX_TEST_FILE')) mmapfile = os.path.join(confdir, 'machine.map') cmd = [ 'python', '-m', 'runrapid', '--env', envfile, '--test', tstfile, '--map', mmapfile, '--runtime', settings.getValue('TRAFFICGEN_PROX_RUNTIME') ] output, error = tasks.run_task(cmd, self._logger, 'Running RUN-RAPID command') if output: return self.get_rfc2544_results(output) else: self._logger.info(error) return None else: self._logger.info("Only Baremetal Support is included.") print("Only Baremetal Support is included") return None
def _add_connections(self): """ Add connections for Kubernetes Usecases """ logging.info("Kubernetes: Adding Connections") if self._evfctl: self._evfctl.add_connections() return if self._vswitch_none: logging.info("Vswitch cannot be None when switch is not external") return vswitch = self._vswitch_ctl.get_vswitch() bridge = S.getValue('VSWITCH_BRIDGE_NAME') if S.getValue('K8S') and 'sriov' not in S.getValue('PLUGIN'): if 'Ovs' in S.getValue('VSWITCH'): # Add OVS Flows if S.getValue('USCNI_INTERFACE_PAIRS') == 1: logging.info("Kubernetes: Adding 1-Pair OVS Connections") flow = {'table':'0', 'in_port':'1', 'idle_timeout':'0', 'actions': ['output:2']} vswitch.add_flow(bridge, flow) flow = {'table':'0', 'in_port':'2', 'idle_timeout':'0', 'actions': ['output:1']} vswitch.add_flow(bridge, flow) elif S.getValue('USCNI_INTERFACE_PAIRS') == 2: logging.info("Kubernetes: Adding 2-Pairs OVS Connections") flow = {'table':'0', 'in_port':'1', 'idle_timeout':'0', 'actions': ['output:3']} vswitch.add_flow(bridge, flow) flow = {'table':'0', 'in_port':'3', 'idle_timeout':'0', 'actions': ['output:1']} vswitch.add_flow(bridge, flow) flow = {'table':'0', 'in_port':'2', 'idle_timeout':'0', 'actions': ['output:4']} vswitch.add_flow(bridge, flow) flow = {'table':'0', 'in_port':'4', 'idle_timeout':'0', 'actions': ['output:2']} vswitch.add_flow(bridge, flow) elif 'vpp' in S.getValue('VSWITCH'): phy_ports = vswitch.get_ports() virt_port0 = 'memif1/0' virt_port1 = 'memif2/0' vswitch.add_connection(bridge, phy_ports[0], virt_port0, None) vswitch.add_connection(bridge, virt_port0, phy_ports[0], None) vswitch.add_connection(bridge, phy_ports[1], virt_port1, None) vswitch.add_connection(bridge, virt_port1, phy_ports[1], None)
def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20, lossrate=0.0): """See ITrafficGenerator for description """ results_file = self.start_rfc2544_throughput(traffic, tests, duration, lossrate) run_result = self.wait_rfc2544_throughput() dest_file_name = 'Traffic_Item_Statistics_' + str( random.randrange(1, 100)) + '.csv' self.copy_results_file( results_file, os.path.join(settings.getValue('RESULTS_PATH'), dest_file_name)) return run_result
def _configure_testpmd(self): """ Configure VM to perform L2 forwarding between NICs by DPDK's testpmd """ self._configure_copy_sources('DPDK') self._configure_disable_firewall() # Guest images _should_ have 1024 hugepages by default, # but just in case:''' self.execute_and_wait('sysctl vm.nr_hugepages=1024') # Mount hugepages self.execute_and_wait('mkdir -p /dev/hugepages') self.execute_and_wait('mount -t hugetlbfs hugetlbfs /dev/hugepages') # build and configure system for dpdk self.execute_and_wait('cd ' + S.getValue('GUEST_OVS_DPDK_DIR') + '/DPDK') self.execute_and_wait('export CC=gcc') self.execute_and_wait('export RTE_SDK=' + S.getValue('GUEST_OVS_DPDK_DIR') + '/DPDK') self.execute_and_wait('export RTE_TARGET=%s' % S.getValue('RTE_TARGET')) # modify makefile if needed self._modify_dpdk_makefile() self.execute_and_wait('make RTE_OUTPUT=$RTE_SDK/$RTE_TARGET -C ' '$RTE_SDK/lib/librte_eal/linuxapp/igb_uio') self.execute_and_wait('modprobe uio') self.execute_and_wait('insmod %s/kmod/igb_uio.ko' % S.getValue('RTE_TARGET')) self.execute_and_wait('./tools/dpdk_nic_bind.py --status') self.execute_and_wait( './tools/dpdk_nic_bind.py -b igb_uio' ' ' + S.getValue('GUEST_NET1_PCI_ADDRESS')[self._number] + ' ' + S.getValue('GUEST_NET2_PCI_ADDRESS')[self._number]) # build and run 'test-pmd' self.execute_and_wait('cd ' + S.getValue('GUEST_OVS_DPDK_DIR') + '/DPDK/app/test-pmd') self.execute_and_wait('make clean') self.execute_and_wait('make') self.execute_and_wait( './testpmd -c 0x3 -n 4 --socket-mem 512 --' ' --burst=64 -i --txqflags=0xf00 ' + '--disable-hw-vlan', 60, "Done") self.execute('set fwd mac_retry', 1) self.execute_and_wait('start', 20, 'TX RS bit threshold=0 - TXQ flags=0xf00')
def send_cont_traffic(self, traffic=None, duration=30): """See ITrafficGenerator for description """ self._logger.info("In Trex send_cont_traffic method") self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) if settings.getValue('TRAFFICGEN_TREX_LEARNING_MODE'): self.learning_packets(traffic) stats = self.generate_traffic(traffic, duration) return self.calculate_results(stats)
def _configure_copy_sources(self, dirname): """ Mount shared directory and copy DPDK and l2fwd sources """ # mount shared directory self.execute_and_wait('umount ' + S.getValue('OVS_DPDK_SHARE')) self.execute_and_wait('rm -rf ' + S.getValue('GUEST_OVS_DPDK_DIR')) self.execute_and_wait('mkdir -p ' + S.getValue('OVS_DPDK_SHARE')) self.execute_and_wait('mount -o iocharset=utf8 /dev/sdb1 ' + S.getValue('OVS_DPDK_SHARE')) self.execute_and_wait('mkdir -p ' + S.getValue('GUEST_OVS_DPDK_DIR')) self.execute_and_wait( 'cp -ra ' + os.path.join(S.getValue('OVS_DPDK_SHARE'), dirname) + ' ' + S.getValue('GUEST_OVS_DPDK_DIR'))
def calculate_results(stats): """Calculate results from Trex statistic """ result = OrderedDict() result[ResultsConstants.TX_FRAMES] = (stats["total"]["opackets"]) result[ResultsConstants.RX_FRAMES] = (stats["total"]["ipackets"]) result[ResultsConstants.TX_RATE_FPS] = ('{:.3f}'.format( float(stats["total"]["tx_pps"]))) result[ResultsConstants.THROUGHPUT_RX_FPS] = ('{:.3f}'.format( float(stats["total"]["rx_pps"]))) result[ResultsConstants.TX_RATE_MBPS] = ('{:.3f}'.format( float(stats["total"]["tx_bps"] / 1000000))) result[ResultsConstants.THROUGHPUT_RX_MBPS] = ('{:.3f}'.format( float(stats["total"]["rx_bps"] / 1000000))) result[ResultsConstants.TX_RATE_PERCENT] = 'Unknown' result[ResultsConstants.THROUGHPUT_RX_PERCENT] = 'Unknown' if stats["total"]["opackets"]: result[ResultsConstants.FRAME_LOSS_PERCENT] = ('{:.3f}'.format( float( (stats["total"]["opackets"] - stats["total"]["ipackets"]) * 100 / stats["total"]["opackets"]))) else: result[ResultsConstants.FRAME_LOSS_PERCENT] = 100 if settings.getValue( 'TRAFFICGEN_TREX_LATENCY_PPS') > 0 and stats['latency']: result[ResultsConstants.MIN_LATENCY_NS] = ('{:.3f}'.format((float( min(stats["latency"][0]["latency"]["total_min"], stats["latency"][1]["latency"]["total_min"]))))) result[ResultsConstants.MAX_LATENCY_NS] = ('{:.3f}'.format((float( max(stats["latency"][0]["latency"]["total_max"], stats["latency"][1]["latency"]["total_max"]))))) result[ResultsConstants.AVG_LATENCY_NS] = ('{:.3f}'.format( float((stats["latency"][0]["latency"]["average"] + stats["latency"][1]["latency"]["average"]) / 2))) else: result[ResultsConstants.MIN_LATENCY_NS] = 'Unknown' result[ResultsConstants.MAX_LATENCY_NS] = 'Unknown' result[ResultsConstants.AVG_LATENCY_NS] = 'Unknown' return result
def setup(self): """ Sets up the switch for pvp """ self._logger.debug('Setup using ' + str(self._vswitch_class)) try: self._vswitch.start() bridge = settings.getValue('VSWITCH_BRIDGE_NAME') self._vswitch.add_switch(bridge) (_, phy1_number) = self._vswitch.add_phy_port(bridge) (_, phy2_number) = self._vswitch.add_phy_port(bridge) (_, vport1_number) = self._vswitch.add_vport(bridge) (_, vport2_number) = self._vswitch.add_vport(bridge) self._vswitch.del_flow(bridge) # configure flows according to the TC definition flow_template = _FLOW_TEMPLATE.copy() if self._traffic['flow_type'] == 'IP': flow_template.update({'dl_type':'0x0800', 'nw_src':self._traffic['l3']['srcip'], 'nw_dst':self._traffic['l3']['dstip']}) flow1 = add_ports_to_flow(flow_template, phy1_number, vport1_number) flow2 = add_ports_to_flow(flow_template, vport2_number, phy2_number) self._vswitch.add_flow(bridge, flow1) self._vswitch.add_flow(bridge, flow2) if self._traffic['bidir'] == 'True': flow3 = add_ports_to_flow(flow_template, phy2_number, vport2_number) flow4 = add_ports_to_flow(flow_template, vport1_number, phy1_number) self._vswitch.add_flow(bridge, flow3) self._vswitch.add_flow(bridge, flow4) except: self._vswitch.stop() raise
def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20, lossrate=0.0): """Non-blocking version of 'send_rfc2544_throughput'. See ITrafficGenerator for description """ self._duration = duration self._params.clear() self._params['traffic'] = self.traffic_defaults.copy() if traffic: self._params['traffic'] = merge_spec(self._params['traffic'], traffic) self._setup_json_config(trials, lossrate, '2544_throughput') args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c", "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r", "./tools/pkt_gen/xena", "-u", settings.getValue('TRAFFICGEN_XENA_USER')] self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
def __init__(self, traffic_gen_class): """Initialise the trafficgen and store. :param traffic_gen_class: The traffic generator class to be used. """ self._logger = logging.getLogger(__name__) self._logger.debug("__init__") self._traffic_gen_class = traffic_gen_class() self._traffic_started = False self._traffic_started_call_count = 0 self._trials = int(get_test_param('rfc2544_trials', 1)) self._duration = int(get_test_param('duration', 30)) self._lossrate = int(get_test_param('lossrate', 0.002)) self._results = [] # If set, comma separated packet_sizes value from --test_params # on cli takes precedence over value in settings file. self._packet_sizes = None packet_sizes_cli = get_test_param('pkt_sizes') if packet_sizes_cli: self._packet_sizes = [int(x.strip()) for x in packet_sizes_cli.split(',')] else: self._packet_sizes = settings.getValue('TRAFFICGEN_PKT_SIZES')
def _run_moongen_and_collect_results(test_run=1): moongen_host_ip_addr = settings.getValue('TRAFFICGEN_MOONGEN_HOST_IP_ADDR') moongen_base_dir = settings.getValue('TRAFFICGEN_MOONGEN_BASE_DIR') moongen_user = settings.getValue('TRAFFICGEN_MOONGEN_USER') connect_moongen = "ssh " + moongen_user + "@" + moongen_host_ip_addr cmd_moongen = " 'cd " + moongen_base_dir + "; ./build/MoonGen examples/opnfv-vsperf.lua | tee moongen_log.txt'" cmd_start_moongen = connect_moongen + cmd_moongen start_moongen = subprocess.Popen(cmd_start_moongen, shell=True, stderr=subprocess.PIPE) output, error = start_moongen.communicate() print(output) if error: raise RuntimeError('MOONGEN: Error starting MoonGen program at %s within %s' \ % (moongen_host_ip_addr, moongen_base_dir)) cmd_moongen = "mkdir -p /tmp/moongen/" + str(test_run) moongen_create_log_dir = subprocess.Popen(cmd_moongen, shell=True, stderr=subprocess.PIPE) output, error = moongen_create_log_dir.communicate() print(output) if error: raise RuntimeError('MOONGEN: Error obtaining MoonGen log from %s within %s' \ % (moongen_host_ip_addr, moongen_base_dir)) cmd_moongen = " scp " + moongen_user + "@" + moongen_host_ip_addr + ":" + \ moongen_base_dir + "/moongen_log.txt /tmp/moongen/" + str(test_run) + "/moongen-run.log" copy_moongen_log = subprocess.Popen(cmd_moongen, shell=True, stderr=subprocess.PIPE) output, error = copy_moongen_log.communicate() print(output) if error: raise RuntimeError('MOONGEN: Error obtaining MoonGen log from %s within %s' \ % (moongen_host_ip_addr, moongen_base_dir)) cmd_gather_moongen_results = "grep 'REPORT.*total' /tmp/moongen/" + str(test_run) + "/moongen-run.log | grep -Po '(?<=Tx Mpps:\s)[^\s]*'" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file for Tx') string_aggregate_tx_mpps_stats = output.decode(encoding='UTF-8') throughput_tx_fps = float(float(string_aggregate_tx_mpps_stats) * 1000000) #throughput_tx_fps = '{:,.6f}'.format(float(float(string_aggregate_tx_mpps_stats) * 1000000)) print("MOONGEN: Tx Mpps = %s string" % (string_aggregate_tx_mpps_stats)) cmd_gather_moongen_results = "grep 'REPORT.*total' /tmp/moongen/" + str(test_run) + "/moongen-run.log | grep -Po '(?<=Rx Mpps:\s)[^\s]*'" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file') string_aggregate_rx_mpps_stats = output.decode(encoding='UTF-8') # throughput_rx_fps = '{:,.6f}'.format(float(float(string_aggregate_rx_mpps_stats) * 1000000)) # print("MOONGEN: Rx Mpps = %s string" % (string_aggregate_rx_mpps_stats)) throughput_rx_fps = float(float(string_aggregate_rx_mpps_stats) * 1000000) cmd_gather_moongen_results = "grep -Po '(?<=frameSize:\s)[^\s]*' /tmp/moongen/" + str(test_run) + "/moongen-run.log" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file') string_framesize = output.decode(encoding='UTF-8') print("********* string_framesize START *******") print(string_framesize) print("********* string_framesize END *******") #string_mbps = (float(string_aggregate_rx_mpps_stats) * (float(string_framesize) + 20) * 8) #throughput_rx_mbps = '{:,.3f}'.format(float(string_mbps)) string_mbps = float(string_aggregate_rx_mpps_stats) * (float(string_framesize) + 20) * 8 throughput_rx_mbps = float(string_mbps) string_mbps = float(string_aggregate_tx_mpps_stats) * (float(string_framesize) + 20) * 8 throughput_tx_mbps = float(string_mbps) #throughput_tx_mbps = '{:,.3f}'.format(float(string_mbps)) # Assume for now 10G link speed max_theoretical_mfps = (10000000000 / 8) / (float(string_framesize) + 20) #throughput_rx_percent = '{:,.2f}'.format((float(string_aggregate_rx_mpps_stats) * 1000000 / max_theoretical_mfps) * 100) #throughput_tx_percent = '{:,.2f}'.format((float(string_aggregate_tx_mpps_stats) * 1000000 / max_theoretical_mfps) * 100) throughput_rx_percent = float(string_aggregate_rx_mpps_stats) * 1000000 / max_theoretical_mfps * 100 throughput_tx_percent = float(string_aggregate_tx_mpps_stats) * 1000000 / max_theoretical_mfps * 100 cmd_gather_moongen_results = "grep 'REPORT.*total' /tmp/moongen/" + str(test_run) + "/moongen-run.log | grep -Po '(?<=Tx frames:\s)[^\s]*'" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file for Tx frames') aggregate_tx_frames_string = output.decode(encoding='UTF-8') aggregate_tx_frames = int(aggregate_tx_frames_string.strip()) cmd_gather_moongen_results = "grep 'REPORT.*total' /tmp/moongen/" + str(test_run) + "/moongen-run.log | grep -Po '(?<=Rx Frames:\s)[^\s]*'" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file for Rx frames') aggregate_rx_frames_string = output.decode(encoding='UTF-8') print("*********** aggregate_rx_frames_string START *********") print(aggregate_rx_frames_string) print(aggregate_rx_frames_string.strip()) print("*********** aggregate_rx_frames_string END *********") aggregate_rx_frames = float(aggregate_rx_frames_string.strip()) cmd_gather_moongen_results = "grep 'REPORT.*total' /tmp/moongen/" + str(test_run) + "/moongen-run.log | grep -Po '(?<=frame loss:\s)[^\s]*' | sed 's/,$//'" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file for frame loss count') frame_loss_count_string = output.decode(encoding='UTF-8') frame_loss_count = float(frame_loss_count_string.strip()) cmd_gather_moongen_results = "grep 'REPORT.*total' /tmp/moongen/" + str(test_run) + "/moongen-run.log | grep -o 'frame loss.*'| sed 's/%.*//' | awk {'print $4'}" gather_moongen_results = subprocess.Popen(cmd_gather_moongen_results, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = gather_moongen_results.communicate() if error: raise RuntimeError('MOONGEN: Error parsing MoonGen log file for frame loss count') frame_loss_percent_string = output.decode(encoding='UTF-8') frame_loss_percent = float(frame_loss_percent_string.strip()) moongen_results = OrderedDict() moongen_results[ResultsConstants.THROUGHPUT_RX_FPS] = throughput_rx_fps moongen_results[ResultsConstants.THROUGHPUT_RX_MBPS] = throughput_rx_mbps moongen_results[ResultsConstants.THROUGHPUT_RX_PERCENT] = throughput_rx_percent moongen_results[ResultsConstants.TX_RATE_FPS] = throughput_tx_fps moongen_results[ResultsConstants.TX_RATE_MBPS] = throughput_tx_mbps moongen_results[ResultsConstants.TX_RATE_PERCENT] = throughput_tx_percent moongen_results[ResultsConstants.B2B_TX_COUNT] = aggregate_tx_frames moongen_results[ResultsConstants.B2B_FRAMES] = aggregate_rx_frames moongen_results[ResultsConstants.B2B_FRAME_LOSS_FRAMES] = frame_loss_count moongen_results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = frame_loss_percent print("*******************************************************") print("throughput_rx_fps = %f" % throughput_rx_fps) print("throughput_rx_mbps = %f" % throughput_rx_mbps) print("throughput_rx_percent = %f" % throughput_rx_percent) print("throughput_tx_fps = %f" % throughput_tx_fps) print("throughput_tx_mbps = %f" % throughput_tx_mbps) print("throughput_tx_percent = %f" % throughput_tx_percent) print("aggregate_tx_frames = %d" % aggregate_tx_frames) print("aggregate_rx_frames = %d" % aggregate_rx_frames) print("frame_loss_count = %d" % frame_loss_count) print("frame_loss_percent = %f" % frame_loss_percent) print("*******************************************************") return moongen_results
def _setup_encap(self): """ Sets up the switch for overlay P2P encapsulation test Create 2 bridges br0 (integration bridge) and br-ext and a VXLAN port for encapsulation. """ self._logger.debug('Setup using ' + str(self._vswitch_class)) try: self._vswitch.start() bridge = settings.getValue('TUNNEL_INTEGRATION_BRIDGE') bridge_ext = settings.getValue('TUNNEL_EXTERNAL_BRIDGE') bridge_ext_ip = settings.getValue('TUNNEL_EXTERNAL_BRIDGE_IP') tg_port2_mac = settings.getValue('TRAFFICGEN_PORT2_MAC') vtep_ip2 = settings.getValue('VTEP_IP2') self._vswitch.add_switch(bridge) tasks.run_task(['sudo', 'ifconfig', bridge, settings.getValue('VTEP_IP1')], self._logger, 'Assign ' + settings.getValue('VTEP_IP1') + ' to ' + bridge, False) tunnel_type = self._traffic['tunnel_type'] self._vswitch.add_switch(bridge_ext) (_, phy1_number) = self._vswitch.add_phy_port(bridge) (_, phy2_number) = self._vswitch.add_tunnel_port(bridge, vtep_ip2, tunnel_type) self._vswitch.add_phy_port(bridge_ext) tasks.run_task(['sudo', 'ip', 'addr', 'add', bridge_ext_ip, 'dev', bridge_ext], self._logger, 'Assign ' + bridge_ext_ip + ' to ' + bridge_ext) tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', bridge_ext, 'up'], self._logger, 'Set ' + bridge_ext + 'status to up') self._vswitch.add_route(bridge, settings.getValue('VTEP_IP2_SUBNET'), bridge_ext) if settings.getValue('VSWITCH').endswith('Vanilla'): tasks.run_task(['sudo', 'arp', '-s', vtep_ip2, tg_port2_mac], self._logger, 'Set ' + bridge_ext + ' status to up') else: self._vswitch.set_tunnel_arp(vtep_ip2, tg_port2_mac, bridge_ext) # Test is unidirectional for now self._vswitch.del_flow(bridge) flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number, phy2_number) self._vswitch.add_flow(bridge, flow1) except: self._vswitch.stop() raise
def dump_vswitch_flows(self): """See IVswitchController for description """ self._vswitch.dump_flows(settings.getValue('VSWITCH_BRIDGE_NAME'))
def get_ports_info(self): """See IVswitchController for description """ self._logger.debug('get_ports_info using ' + str(self._vswitch_class)) return self._vswitch.get_ports(settings.getValue('VSWITCH_BRIDGE_NAME'))
def _start_traffic_api(self, packet_limit): """ Start the Xena traffic using the socket API driver :param packet_limit: packet limit for stream, set to -1 for no limit :return: None """ if not self.xmanager: self._xsocket = XenaSocketDriver( settings.getValue('TRAFFICGEN_XENA_IP')) self.xmanager = XenaManager( self._xsocket, settings.getValue('TRAFFICGEN_XENA_USER'), settings.getValue('TRAFFICGEN_XENA_PASSWORD')) if not len(self.xmanager.ports): self.xmanager.ports[0] = self.xmanager.add_module_port( settings.getValue('TRAFFICGEN_XENA_MODULE1'), settings.getValue('TRAFFICGEN_XENA_PORT1')) if not self.xmanager.ports[0].reserve_port(): self._logger.error( 'Unable to reserve port 0. Please release Xena Port') sys.exit(1) if len(self.xmanager.ports) < 2: self.xmanager.ports[1] = self.xmanager.add_module_port( settings.getValue('TRAFFICGEN_XENA_MODULE2'), settings.getValue('TRAFFICGEN_XENA_PORT2')) if not self.xmanager.ports[1].reserve_port(): self._logger.error( 'Unable to reserve port 1. Please release Xena Port') sys.exit(1) # Clear port configuration for a clean start self.xmanager.ports[0].reset_port() self.xmanager.ports[1].reset_port() self.xmanager.ports[0].clear_stats() self.xmanager.ports[1].clear_stats() s1_p0 = self.xmanager.ports[0].add_stream() s1_p0.set_on() s1_p0.set_packet_limit(packet_limit) s1_p0.set_rate_fraction(10000 * self._params['traffic']['frame_rate']) s1_p0.set_packet_header(self._build_packet_header()) s1_p0.set_header_protocol( 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][ 'enabled'] else 'ETHERNET IP UDP') s1_p0.set_packet_length( 'fixed', self._params['traffic']['l2']['framesize'], 16383) s1_p0.set_packet_payload('incrementing', '0x00') s1_p0.set_payload_id(0) self.xmanager.ports[0].set_port_time_limit(self._duration * 1000000) if self._params['traffic']['l2']['framesize'] == 64: # set micro tpld self.xmanager.ports[0].micro_tpld_enable() if self._params['traffic']['multistream']: s1_p0.enable_multistream( flows=self._params['traffic']['multistream'], layer=self._params['traffic']['stream_type']) if self._params['traffic']['bidir']: s1_p1 = self.xmanager.ports[1].add_stream() s1_p1.set_on() s1_p1.set_packet_limit(packet_limit) s1_p1.set_rate_fraction(10000 * self._params['traffic'][ 'frame_rate']) s1_p1.set_packet_header(self._build_packet_header(reverse=True)) s1_p1.set_header_protocol( 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][ 'enabled'] else 'ETHERNET IP UDP') s1_p1.set_packet_length( 'fixed', self._params['traffic']['l2']['framesize'], 16383) s1_p1.set_packet_payload('incrementing', '0x00') s1_p1.set_payload_id(1) self.xmanager.ports[1].set_port_time_limit(self._duration * 1000000) if self._params['traffic']['l2']['framesize'] == 64: # set micro tpld self.xmanager.ports[1].micro_tpld_enable() if self._params['traffic']['multistream']: s1_p1.enable_multistream( flows=self._params['traffic']['multistream'], layer=self._params['traffic']['stream_type']) if not self.xmanager.ports[0].traffic_on(): self._logger.error( "Failure to start port 0. Check settings and retry.") if self._params['traffic']['bidir']: if not self.xmanager.ports[1].traffic_on(): self._logger.error( "Failure to start port 1. Check settings and retry.") Time.sleep(self._duration) # getting results if self._params['traffic']['bidir']: # need to average out both ports and assign that data self.rx_stats = self.xmanager.ports[1].get_rx_stats() self.tx_stats = self.xmanager.ports[0].get_tx_stats() self.tx_stats.data = average_stats( self.tx_stats.data, self.xmanager.ports[1].get_tx_stats().data) self.rx_stats.data = average_stats( self.rx_stats.data, self.xmanager.ports[0].get_rx_stats().data) else: # no need to average, just grab the appropriate port stats self.tx_stats = self.xmanager.ports[0].get_tx_stats() self.rx_stats = self.xmanager.ports[1].get_rx_stats() Time.sleep(1)
def get_stc_common_settings(): """ Return the common Settings These settings would apply to almost all the tests. """ args = ["--lab_server_addr", settings.getValue("TRAFFICGEN_STC_LAB_SERVER_ADDR"), "--license_server_addr", settings.getValue("TRAFFICGEN_STC_LICENSE_SERVER_ADDR"), "--east_chassis_addr", settings.getValue("TRAFFICGEN_STC_EAST_CHASSIS_ADDR"), "--east_slot_num", settings.getValue("TRAFFICGEN_STC_EAST_SLOT_NUM"), "--east_port_num", settings.getValue("TRAFFICGEN_STC_EAST_PORT_NUM"), "--west_chassis_addr", settings.getValue("TRAFFICGEN_STC_WEST_CHASSIS_ADDR"), "--west_slot_num", settings.getValue("TRAFFICGEN_STC_WEST_SLOT_NUM"), "--west_port_num", settings.getValue("TRAFFICGEN_STC_WEST_PORT_NUM"), "--test_session_name", settings.getValue("TRAFFICGEN_STC_TEST_SESSION_NAME"), "--results_dir", settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"), "--csv_results_file_prefix", settings.getValue("TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX")] return args
def get_rfc2544_common_settings(): """ Retrun Generic RFC 2544 settings. These settings apply to all the 2544 tests """ args = [settings.getValue("TRAFFICGEN_STC_PYTHON2_PATH"), os.path.join( settings.getValue("TRAFFICGEN_STC_TESTCENTER_PATH"), settings.getValue( "TRAFFICGEN_STC_RFC2544_TPUT_TEST_FILE_NAME")), "--metric", settings.getValue("TRAFFICGEN_STC_RFC2544_METRIC"), "--search_mode", settings.getValue("TRAFFICGEN_STC_SEARCH_MODE"), "--learning_mode", settings.getValue("TRAFFICGEN_STC_LEARNING_MODE"), "--rate_lower_limit_pct", settings.getValue("TRAFFICGEN_STC_RATE_LOWER_LIMIT_PCT"), "--rate_upper_limit_pct", settings.getValue("TRAFFICGEN_STC_RATE_UPPER_LIMIT_PCT"), "--rate_initial_pct", settings.getValue("TRAFFICGEN_STC_RATE_INITIAL_PCT"), "--rate_step_pct", settings.getValue("TRAFFICGEN_STC_RATE_STEP_PCT"), "--resolution_pct", settings.getValue("TRAFFICGEN_STC_RESOLUTION_PCT"), "--acceptable_frame_loss_pct", settings.getValue("TRAFFICGEN_STC_ACCEPTABLE_FRAME_LOSS_PCT"), "--east_intf_addr", settings.getValue("TRAFFICGEN_STC_EAST_INTF_ADDR"), "--east_intf_gateway_addr", settings.getValue("TRAFFICGEN_STC_EAST_INTF_GATEWAY_ADDR"), "--west_intf_addr", settings.getValue("TRAFFICGEN_STC_WEST_INTF_ADDR"), "--west_intf_gateway_addr", settings.getValue("TRAFFICGEN_STC_WEST_INTF_GATEWAY_ADDR"), "--num_trials", settings.getValue("TRAFFICGEN_STC_NUMBER_OF_TRIALS"), "--trial_duration_sec", settings.getValue("TRAFFICGEN_STC_TRIAL_DURATION_SEC"), "--traffic_pattern", settings.getValue("TRAFFICGEN_STC_TRAFFIC_PATTERN")] return args