Exemple #1
0
    def __init__(self, deployment, pod_class):
        """Sets up the POD infrastructure based on deployment scenario

        :param pod_class: The POD class to be used.
        """
        # reset POD ID counter for each testcase
        IPod.reset_pod_counter()
        pod_number = 0
        # setup controller with requested number of pods
        self._logger = logging.getLogger(__name__)
        self._pod_class = pod_class
        self._deployment = deployment.lower()
        self._pods = []
        single_pods = ['pcp', 'c2c']
        two_pods = ['pccp', 'c2c2c']
        if any(item in self._deployment for item in single_pods):
            pod_number = 1
        elif any(item in self._deployment for item in two_pods):
            pod_number = 2
        print("POD COUNTING DONE")
        settings.setValue('POD_COUNT', pod_number)
        # we will have single controller for all pods
        if pod_number:
            self._pods.append(pod_class())
            self._logger.debug('Initializing the pod')
Exemple #2
0
def terminate_task(pid, signal='-15', sleep=10, logger=None):
    """Terminate process with given pid

    Function will sent given signal to the process. In case
    that process will not terminate within given sleep interval
    and signal was not SIGKILL, then process will be killed by SIGKILL.

    :param pid: Process ID to terminate
    :param signal: Signal to be sent to the process
    :param sleep: Maximum delay in seconds after signal is sent
    :param logger: Logger to write details to
    """
    if systeminfo.pid_isalive(pid):
        run_task(['sudo', 'kill', signal, str(pid)], logger)
        logger.debug('Wait for process %s to terminate after signal %s', pid,
                     signal)
        for dummy in range(sleep):
            time.sleep(1)
            if not systeminfo.pid_isalive(pid):
                break

        if signal.lstrip('-').upper() not in (
                '9', 'KILL', 'SIGKILL') and systeminfo.pid_isalive(pid):
            terminate_task(pid, '-9', sleep, logger)

    pids = settings.getValue('_EXECUTED_PIDS')
    if pid in pids:
        pids.remove(pid)
        settings.setValue('_EXECUTED_PIDS', pids)
Exemple #3
0
def terminate_all_tasks(logger):
    """Terminate all processes executed by vsperf, just for case they were not
    terminated by standard means.
    """
    pids = settings.getValue('_EXECUTED_PIDS')
    if pids:
        logger.debug('Following processes will be terminated: %s', pids)
        for pid in pids:
            terminate_task_subtree(pid, logger=logger)
        settings.setValue('_EXECUTED_PIDS', [])
Exemple #4
0
    def __init__(self, deployment, vnf_class, extra_vnfs):
        """Sets up the VNF infrastructure based on deployment scenario

        :param vnf_class: The VNF class to be used.
        :param extra_vnfs: The number of VNFs not involved in given
            deployment scenario. It will be used to correctly expand
            configuration values and initialize shared dirs. This parameter
            is used in case, that additional VNFs are executed by TestSteps.
        """
        # reset VNF ID counter for each testcase
        IVnf.reset_vnf_counter()

        # setup controller with requested number of VNFs
        self._logger = logging.getLogger(__name__)
        self._vnf_class = vnf_class
        self._deployment = deployment.lower()
        self._vnfs = []
        if self._deployment == 'pvp':
            vm_number = 1
        elif (self._deployment.startswith('pvvp')
              or self._deployment.startswith('pvpv')):
            if len(self._deployment) > 4:
                vm_number = int(self._deployment[4:])
            else:
                vm_number = 2
        else:
            # VnfController is created for all deployments, including deployments
            # without VNFs like p2p
            vm_number = 0

        if vm_number + extra_vnfs > 0:
            self._logger.debug('Check configuration for %s guests.',
                               vm_number + extra_vnfs)
            settings.check_vm_settings(vm_number + extra_vnfs)
            # enforce that GUEST_NIC_NR is 1 or even number of NICs
            updated = False
            nics_nr = settings.getValue('GUEST_NICS_NR')
            for index, value in enumerate(nics_nr):
                if value > 1 and value % 2:
                    updated = True
                    nics_nr[index] = int(value / 2) * 2
            if updated:
                settings.setValue('GUEST_NICS_NR', nics_nr)
                self._logger.warning(
                    'Odd number of NICs was detected. Configuration '
                    'was updated to GUEST_NICS_NR = %s',
                    settings.getValue('GUEST_NICS_NR'))

        if vm_number:
            self._vnfs = [vnf_class() for _ in range(vm_number)]

            self._logger.debug('__init__ ' + str(len(self._vnfs)) +
                               ' VNF[s] with ' +
                               ' '.join(map(str, self._vnfs)))
    def _update_settings(self, param, value):
        """ Check value of given configuration parameter
        In case that new value is different, then testcase
        specific settings is updated and original value stored

        :param param: Name of parameter inside settings
        :param value: Disired parameter value
        """
        orig_value = S.getValue(param)
        if orig_value != value:
            self._settings_original[param] = copy.deepcopy(orig_value)
            S.setValue(param, value)
Exemple #6
0
def main():
    """Main function.
    """
    #args = parse_arguments()

    # define the timestamp to be used by logs and results
    date = datetime.datetime.fromtimestamp(time.time())
    timestamp = date.strftime('%Y-%m-%d_%H-%M-%S')
    S.setValue('LOG_TIMESTAMP', timestamp)

    # configure settings
    S.load_from_dir(os.path.join(_CURR_DIR, 'conf'))
    openstack_params = utils.pack_openstack_params()
    print(openstack_params)
    output = act()
    print(output)
    def run(self):
        """Run the test

        All setup and teardown through controllers is included.
        """
        # prepare test execution environment
        self.run_initialize()

        try:
            with self._vswitch_ctl, self._loadgen:
                with self._vnf_ctl, self._collector:
                    if not self._vswitch_none:
                        self._add_flows()

                    self._versions += self._vswitch_ctl.get_vswitch(
                    ).get_version()

                    with self._traffic_ctl:
                        # execute test based on TestSteps definition if needed...
                        if self.step_run():
                            # ...and continue with traffic generation, but keep
                            # in mind, that clean deployment does not configure
                            # OVS nor executes the traffic
                            if self.deployment != 'clean':
                                self._traffic_ctl.send_traffic(self._traffic)

                        # dump vswitch flows before they are affected by VNF termination
                        if not self._vswitch_none:
                            self._vswitch_ctl.dump_vswitch_flows()

                    # garbage collection for case that TestSteps modify existing deployment
                    self.step_stop_vnfs()

        finally:
            # tear down test execution environment and log results
            self.run_finalize()

        self._testcase_run_time = time.strftime(
            "%H:%M:%S", time.gmtime(time.time() - self._testcase_start_time))
        logging.info("Testcase execution time: " + self._testcase_run_time)
        # report test results
        self.run_report()

        # restore original settings
        for key in self._settings_original:
            S.setValue(key, self._settings_original[key])
Exemple #8
0
def update_vsperf_configuration(agents):
    """
    Create Configuration file for VSPERF.
    """
    tgen = S.getValue('TRAFFICGEN')
    east_chassis_ip = agents[0]['public_ip']
    # east_data_ip = agents[0]['private_ip']
    if len(agents) == 2:
        west_chassis_ip = agents[1]['public_ip']
    #    west_data_ip = agents[1]['private_ip']
    else:
        west_chassis_ip = east_chassis_ip
    #    west_data_ip = east_chassis_ip
    if "TestCenter" in tgen:
        S.setValue('TRAFFICGEN_STC_EAST_CHASSIS_ADDR', east_chassis_ip)
        S.setValue('TRAFFICGEN_STC_WEST_CHASSIS_ADDR', west_chassis_ip)
    if "Ix" in tgen:
        S.setValue("TRAFFICGEN_EAST_IXIA_HOST", east_chassis_ip)
        S.setValue("TRAFFICGEN_WEST_IXIA_HOST", west_chassis_ip)
Exemple #9
0
    def _create_throughput_result(root):
        """
        Create the results based off the output xml file from the Xena2544.exe
        execution
        :param root: root dictionary from xml import
        :return: Results Ordered dictionary based off ResultsConstants
        """
        # get the test type from the report file
        test_type = root[0][1].get('TestType')
        # set the version from the report file
        settings.setValue('XENA_VERSION', root[0][0][1].get('GeneratedBy'))

        if test_type == 'Throughput':
            results = OrderedDict()
            results[ResultsConstants.THROUGHPUT_RX_FPS] = float(
                root[0][1][0][0].get('PortRxPps')) + float(
                    root[0][1][0][1].get('PortRxPps'))
            results[ResultsConstants.THROUGHPUT_RX_MBPS] = (float(
                root[0][1][0][0].get('PortRxBpsL1')) + float(
                    root[0][1][0][1].get('PortRxBpsL1')))/ 1000000
            results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
                100 - float(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
                    root[0][1][0].get('TotalTxRatePcnt'))/100
            results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
                'TotalTxRateFps')
            results[ResultsConstants.TX_RATE_MBPS] = float(
                root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
            results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
                'TotalTxRatePcnt')
            try:
                results[ResultsConstants.MIN_LATENCY_NS] = float(
                    root[0][1][0][0].get('MinLatency')) * 1000
            except ValueError:
                # Stats for latency returned as N/A so just post them
                results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
                    'MinLatency')
            try:
                results[ResultsConstants.MAX_LATENCY_NS] = float(
                    root[0][1][0][0].get('MaxLatency')) * 1000
            except ValueError:
                # Stats for latency returned as N/A so just post them
                results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
                    'MaxLatency')
            try:
                results[ResultsConstants.AVG_LATENCY_NS] = float(
                    root[0][1][0][0].get('AvgLatency')) * 1000
            except ValueError:
                # Stats for latency returned as N/A so just post them
                results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
                    'AvgLatency')
        elif test_type == 'Back2Back':
            results = OrderedDict()

            # Just mimic what Ixia does and only return the b2b frame count.
            # This may change later once its decided the common results stats
            # to be returned should be.
            results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
                'TotalTxBurstFrames')
        else:
            raise NotImplementedError('Unknown test type in report file.')

        return results
Exemple #10
0
    def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
                                lossrate=0.0):
        """Send traffic per RFC2544 throughput 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(tests, lossrate, '2544_throughput')
        self._start_xena_2544()
        self._wait_xena_2544_complete()

        root = ET.parse(os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()

        if settings.getValue('TRAFFICGEN_XENA_RFC2544_VERIFY'):
            # make sure we have a pass before even trying the verify. No need
            # to run verify on a failed iteration.
            root = ET.parse(
                os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
            if root[0][1][0].get('TestState') == "FAIL":
                self._logger.info('Test failed, skipping verify')
                return Xena._create_throughput_result(root)

            # record the previous settings so we can revert to them if needed to
            # run the binary search again if the verify fails.
            old_tests = tests
            old_duration = self._duration
            old_min = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE')

            # record the original values to restore after execution
            orig_min = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE')
            orig_max = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE')
            orig_init = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE')

            for attempt in range(
                    1, settings.getValue(
                        'TRAFFICGEN_XENA_RFC2544_MAXIMUM_VERIFY_ATTEMPTS')+1):
                self._logger.info('Running verify attempt %s', attempt)
                # get the last pass tx rate from the binary search
                pass_rate = float(root[0][1][0].get('TotalTxRatePcnt'))
                # run a one pass rfc2544 with the pass rate to see if it passes
                # the verify duration
                settings.setValue(
                    'TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE', pass_rate)
                settings.setValue(
                    'TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE', pass_rate)
                settings.setValue(
                    'TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE', pass_rate)
                self.start_rfc2544_throughput(
                    traffic, 1, settings.getValue(
                        'TRAFFICGEN_XENA_RFC2544_VERIFY_DURATION'), lossrate)
                self.wait_rfc2544_throughput()
                root = ET.parse(
                    os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()

                # If it passed, report the number of lost frames and exit the
                # loop
                if root[0][1][0].get('TestState') == "PASS":
                    self._logger.info('Verify passed, packets lost = %s',
                                      root[0][1][0].get('TotalLossFrames'))
                    break
                elif attempt < settings.getValue(
                        'TRAFFICGEN_XENA_RFC2544_MAXIMUM_VERIFY_ATTEMPTS'):
                    self._logger.info(
                        'Verify failed, resuming binary search, packets lost = %s',
                        root[0][1][0].get('TotalLossFrames'))
                    settings.setValue(
                        'TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE',
                        pass_rate - float(settings.getValue(
                            'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION')))
                    if settings.getValue(
                            'TRAFFICGEN_XENA_RFC2544_BINARY_RESTART_SMART_SEARCH'):
                        settings.setValue(
                            'TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE',
                            (pass_rate - float(old_min)) / 2)
                    else:
                        settings.setValue(
                            'TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE',
                            pass_rate - float(settings.getValue(
                                'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION')))
                    settings.setValue(
                        'TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE', old_min)
                    self._logger.debug(
                        'RFC2544 Initial rate: %s',
                        settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE'))
                    self._logger.debug(
                        'RFC2544 Maximum rate: %s',
                        settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE'))
                    self._logger.debug(
                        'RFC2544 Minimum rate: %s',
                        settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE'))
                    self._duration = old_duration
                    self.start_rfc2544_throughput(
                        traffic, old_tests, self._duration, lossrate)
                    self.wait_rfc2544_throughput()
                    root = ET.parse(
                        os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
                else:
                    self._logger.error(
                        'Maximum number of verify attempts reached. Reporting last result')

            #restore original values
            settings.setValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE', orig_min)
            settings.setValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE', orig_max)
            settings.setValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE', orig_init)

        return Xena._create_throughput_result(root)
Exemple #11
0
    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'))

        # for the report file version info ask the chassis directly for its
        # software versions
        settings.setValue('XENA_VERSION', 'XENA Socket API - {}'.format(
            self.xmanager.get_version()))

        if not 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')

        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')

        # Clear port configuration for a clean start
        self.xmanager.ports[0].reset_port()
        self.xmanager.ports[1].reset_port()
        if settings.getValue('TRAFFICGEN_XENA_CONT_PORT_LEARNING_ENABLED'):
            # turn on port learning
            self.xmanager.ports[0].set_port_learning(1)
            self.xmanager.ports[1].set_port_learning(1)
            sleep(settings.getValue('TRAFFICGEN_XENA_CONT_PORT_LEARNING_DURATION'))
            # turn off port learning
            self.xmanager.ports[0].set_port_learning(0)
            self.xmanager.ports[1].set_port_learning(0)
            sleep(1)
        self.xmanager.ports[0].clear_stats()
        self.xmanager.ports[1].clear_stats()

        # set the port IP from the conf file
        self.xmanager.ports[0].set_port_ip(
            settings.getValue('TRAFFICGEN_XENA_PORT0_IP'),
            settings.getValue('TRAFFICGEN_XENA_PORT0_CIDR'),
            settings.getValue('TRAFFICGEN_XENA_PORT0_GATEWAY'))
        self.xmanager.ports[1].set_port_ip(
            settings.getValue('TRAFFICGEN_XENA_PORT1_IP'),
            settings.getValue('TRAFFICGEN_XENA_PORT1_CIDR'),
            settings.getValue('TRAFFICGEN_XENA_PORT1_GATEWAY'))
        self.xmanager.ports[0].set_port_time_limit(self._duration)
        self.xmanager.ports[1].set_port_time_limit(self._duration)

        def setup_stream(stream, port, payload_id, flip_addr=False):
            """
            Helper function to configure streams.
            :param stream: Stream object from XenaDriver module
            :param port: Port object from XenaDriver module
            :param payload_id: payload ID as int
            :param flip_addr: Boolean if the source and destination addresses
            should be flipped.
            :return: None
            """
            stream.set_on()
            if packet_limit != -1:
                stream.set_packet_limit(packet_limit)

            port.set_port_arp_reply(is_on=True)
            port.set_port_arp_reply(is_on=True, ipv6=True)
            port.set_port_ping_reply(is_on=True)
            port.set_port_ping_reply(is_on=True, ipv6=True)

            stream.set_rate_fraction(int(
                10000 * self._params['traffic']['frame_rate']))
            stream.set_packet_header(self._build_packet_header(
                reverse=flip_addr))
            stream.set_header_protocol(
                'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][
                    'enabled'] else 'ETHERNET IP UDP')
            stream.set_packet_length(
                'fixed', self._params['traffic']['l2']['framesize'],
                self._params['traffic']['l2']['framesize'])
            stream.set_packet_payload('incrementing', '0x00')
            stream.set_payload_id(payload_id)
            port.set_port_time_limit(self._duration * 1000000)

            if self._params['traffic']['l2']['framesize'] == 64:
                # set micro tpld
                port.micro_tpld_enable()

            if self._params['traffic']['multistream']:
                if self._params['traffic']['stream_type'] == 'L2':
                    modobj = ModSet(mod_src_mac=True, mod_dst_mac=True)
                elif self._params['traffic']['stream_type'] == 'L3':
                    modobj = ModSet(mod_src_ip=True, mod_dst_ip=True)
                elif self._params['traffic']['stream_type'] == 'L4':
                    modobj = ModSet(mod_src_port=True, mod_dst_port=True)
                else:
                    self._logger.error('Invalid segment for multistream. Using L2..')
                    modobj = ModSet(mod_src_mac=True, mod_dst_mac=True)
                stream.enable_multistream(
                    flows=self._params['traffic']['multistream'], mod_class=modobj)

        s1_p0 = self.xmanager.ports[0].add_stream()
        setup_stream(s1_p0, self.xmanager.ports[0], 0)

        if self._params['traffic']['bidir'] == 'True':
            s1_p1 = self.xmanager.ports[1].add_stream()
            setup_stream(s1_p1, self.xmanager.ports[1], 1, flip_addr=True)

        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'] == 'True':
            if not self.xmanager.ports[1].traffic_on():
                self._logger.error(
                    "Failure to start port 1. Check settings and retry.")
        sleep(self._duration + 5) # the extra 5 seconds is to allow packets in flight to complete
        # getting results
        if self._params['traffic']['bidir'] == 'True':
            # need to aggregate out both ports stats 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 = aggregate_stats(
                self.tx_stats.data,
                self.xmanager.ports[1].get_tx_stats().data)
            self.rx_stats.data = aggregate_stats(
                self.rx_stats.data,
                self.xmanager.ports[0].get_rx_stats().data)
        else:
            # no need to aggregate, 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()
        sleep(1)
Exemple #12
0
def settings_update_paths():
    """ Configure paths to OVS, DPDK and QEMU sources and binaries based on
        selected vswitch type and src/binary switch. Data are taken from
        PATHS dictionary and after their processing they are stored inside TOOLS.
        PATHS dictionary has specific section for 'vswitch', 'qemu' and 'dpdk'
        Following processing is done for every item:
            item 'type' - string, which defines the type of paths ('src' or 'bin') to be selected
                  for a given section:
                      'src' means, that VSPERF will use OVS, DPDK or QEMU built from sources
                          e.g. by execution of systems/build_base_machine.sh script during VSPERF
                          installation
                      'bin' means, that VSPERF will use OVS, DPDK or QEMU binaries installed
                          in the OS, e.g. via OS specific packaging system
            item 'path' - string with valid path; Its content is checked for existence, prefixed
                  with section name and stored into TOOLS for later use
                  e.g. TOOLS['dpdk_src'] or TOOLS['vswitch_src']
            item 'modules' - list of strings; Every value from given list is checked for '.ko'
                  suffix. In case it matches and it is not an absolute path to the module, then
                  module name is prefixed with 'path' defined for the same section
                  e.g. TOOLS['vswitch_modules'] = [
                      '/tmp/vsperf/src_vanilla/ovs/ovs/datapath/linux/openvswitch.ko']
            all other items - string - if given string is a relative path and item 'path'
                  is defined for a given section, then item content will be prefixed with
                  content of the 'path'. Otherwise tool name will be searched within
                  standard system directories. Also any OS filename wildcards will be
                  expanded to the real path. At the end of processing, every absolute
                  path is checked for its existence. In case that temporary path (i.e. path
                  with '_tmp' suffix) doesn't exist, then log will be written and vsperf will
                  continue. If any other path will not exist, then vsperf execution will
                  be terminated with runtime error.

        Note: In case that 'bin' type is set for DPDK, then TOOLS['dpdk_src'] will be set to
        the value of PATHS['dpdk']['src']['path']. The reason is, that VSPERF uses downloaded
        DPDK sources to copy DPDK and testpmd into the GUEST, where testpmd is built. In case,
        that DPDK sources are not available, then vsperf will continue with test execution,
        but testpmd can't be used as a guest loopback. This is useful in case, that other guest
        loopback applications (e.g. buildin) are used by CI jobs, etc.
    """
    # set dpdk and ovs paths according to VNF, VSWITCH and TRAFFICGEN selection
    paths = {}
    if S.getValue("mode") != 'trafficgen':
        # VSWITCH & (probably) VNF are needed
        vswitch_type = S.getValue('PATHS')['vswitch'][S.getValue(
            'VSWITCH')]['type']
        paths['vswitch'] = S.getValue('PATHS')['vswitch'][S.getValue(
            'VSWITCH')][vswitch_type]
        paths['dpdk'] = S.getValue('PATHS')['dpdk'][S.getValue('PATHS')['dpdk']
                                                    ['type']]
        paths['qemu'] = S.getValue('PATHS')['qemu'][S.getValue('PATHS')['qemu']
                                                    ['type']]
        paths['paths'] = {}
        paths['paths']['ovs_var_tmp'] = S.getValue(
            'PATHS')['vswitch']['ovs_var_tmp']
        paths['paths']['ovs_etc_tmp'] = S.getValue(
            'PATHS')['vswitch']['ovs_etc_tmp']

    if S.getValue("mode") != 'trafficgen-off':
        # TRAFFCIGEN is required
        if S.getValue('TRAFFICGEN') in S.getValue('PATHS')['trafficgen']:
            tmp_trafficgen = S.getValue('PATHS')['trafficgen'][S.getValue(
                'TRAFFICGEN')]
            paths['trafficgen'] = tmp_trafficgen[tmp_trafficgen['type']]

    tools = {}
    # pylint: disable=too-many-nested-blocks
    for path_class in paths:
        for tool in paths[path_class]:
            tmp_tool = paths[path_class][tool]

            # store valid path of given class into tools dict
            if tool == 'path':
                if os.path.isdir(tmp_tool):
                    tools['{}_src'.format(path_class)] = tmp_tool
                    continue
                else:
                    raise RuntimeError(
                        'Path {} does not exist.'.format(tmp_tool))

            # store list of modules of given class into tools dict
            if tool == 'modules':
                tmp_modules = []
                for module in tmp_tool:
                    # add path to the .ko modules and check it for existence
                    if module.endswith('.ko') and not os.path.isabs(module):
                        module = os.path.join(paths[path_class]['path'],
                                              module)
                        if not os.path.exists(module):
                            raise RuntimeError(
                                'Cannot locate modlue {}'.format(module))

                    tmp_modules.append(module)

                tools['{}_modules'.format(path_class)] = tmp_modules
                continue

            # if path to the tool is relative, then 'path' will be prefixed
            # in case that 'path' is not defined, then tool will be searched
            # within standard system paths
            if not os.path.isabs(tmp_tool):
                if 'path' in paths[path_class]:
                    tmp_tool = os.path.join(paths[path_class]['path'],
                                            tmp_tool)
                elif shutil.which(tmp_tool):
                    tmp_tool = shutil.which(tmp_tool)
                else:
                    raise RuntimeError(
                        'Cannot locate tool {}'.format(tmp_tool))

            # expand OS wildcards in paths if needed
            if glob.has_magic(tmp_tool):
                tmp_glob = glob.glob(tmp_tool)
                if not tmp_glob:
                    raise RuntimeError(
                        'Path to the {} is not valid: {}.'.format(
                            tool, tmp_tool))
                elif len(tmp_glob) > 1:
                    raise RuntimeError('Path to the {} is ambiguous {}'.format(
                        tool, tmp_glob))
                elif len(tmp_glob) == 1:
                    tmp_tool = tmp_glob[0]
            elif not os.path.exists(tmp_tool):
                if tool.endswith('_tmp'):
                    logging.getLogger().debug(
                        'Temporary path to the %s does not '
                        'exist: %s', tool, tmp_tool)
                else:
                    raise RuntimeError(
                        'Path to the {} is not valid: {}'.format(
                            tool, tmp_tool))

            tools[tool] = tmp_tool

    # ensure, that dpkg_src for bin will be set to downloaded DPDK sources, so it can
    # be copied to the guest share dir and used by GUEST to build and run testpmd
    # Validity of the path is not checked by purpose, so user can use VSPERF without
    # downloading DPDK sources. In that case guest loopback can't be set to 'testpmd'
    if S.getValue('PATHS')['dpdk']['type'] == 'bin':
        tools['dpdk_src'] = S.getValue('PATHS')['dpdk']['src']['path']

    S.setValue('TOOLS', tools)
Exemple #13
0
    def __init__(self, test_cfg):
        """Pull out fields from test config

        :param test_cfg: A dictionary of string-value pairs describing the test
            configuration. Both the key and values strings use well-known
            values.
        :param results_dir: Where the csv formatted results are written.
        """
        # make a local copy of test configuration to avoid modification of
        # original content used in vsperf main script
        cfg = copy.deepcopy(test_cfg)

        self._testcase_start_time = time.time()
        self._testcase_stop_time = self._testcase_start_time
        self._hugepages_mounted = False
        self._traffic_ctl = None
        self._vnf_ctl = None
        self._pod_ctl = None
        self._vswitch_ctl = None
        self._collector = None
        self._loadgen = None
        self._output_file = None
        self._tc_results = None
        self._settings_paths_modified = False
        self._testcast_run_time = None
        self._versions = []
        self._k8s = False
        # initialization of step driven specific members
        self._step_check = False  # by default don't check result for step driven testcases
        self._step_vnf_list = {}
        self._step_result = []
        self._step_result_mapping = {}
        self._step_status = None
        self._step_send_traffic = False  # indication if send_traffic was called within test steps
        self._vnf_list = []
        self._testcase_run_time = None

        S.setValue('VSWITCH', cfg.get('vSwitch', S.getValue('VSWITCH')))
        S.setValue('VNF', cfg.get('VNF', S.getValue('VNF')))
        S.setValue('TRAFFICGEN', cfg.get('Trafficgen',
                                         S.getValue('TRAFFICGEN')))
        S.setValue('TUNNEL_TYPE',
                   cfg.get('Tunnel Type', S.getValue('TUNNEL_TYPE')))
        test_params = copy.deepcopy(S.getValue('TEST_PARAMS'))
        tc_test_params = cfg.get('Parameters', S.getValue('TEST_PARAMS'))
        test_params = merge_spec(test_params, tc_test_params)

        # ensure that parameters from TC definition have the highest priority, see MAPPING_TC_CFG2CONF
        for (cfg_param, param) in MAPPING_TC_CFG2CONF.items():
            if cfg_param in cfg and param in test_params:
                del test_params[param]

        S.setValue('TEST_PARAMS', test_params)
        S.check_test_params()

        # override all redefined GUEST_ values to have them expanded correctly
        tmp_test_params = copy.deepcopy(S.getValue('TEST_PARAMS'))
        for key in tmp_test_params:
            if key.startswith('GUEST_'):
                S.setValue(key, S.getValue(key))
                S.getValue('TEST_PARAMS').pop(key)

        # update global settings
        functions.settings_update_paths()

        # set test parameters; CLI options take precedence to testcase settings
        self._logger = logging.getLogger(__name__)
        self.name = cfg['Name']
        self.desc = cfg.get('Description', 'No description given.')
        self.test = cfg.get('TestSteps', None)

        # log testcase name and details
        tmp_desc = functions.format_description(self.desc, 50)
        self._logger.info(
            '############################################################')
        self._logger.info('# Test:    %s', self.name)
        self._logger.info('# Details: %s', tmp_desc[0])
        for i in range(1, len(tmp_desc)):
            self._logger.info('#          %s', tmp_desc[i])
        self._logger.info(
            '############################################################')

        bidirectional = S.getValue('TRAFFIC')['bidir']
        if not isinstance(S.getValue('TRAFFIC')['bidir'], str):
            raise TypeError('Bi-dir value must be of type string')
        bidirectional = bidirectional.title()  # Keep things consistent

        self.deployment = cfg['Deployment']
        self._frame_mod = cfg.get('Frame Modification', None)

        self._tunnel_operation = cfg.get('Tunnel Operation', None)

        # check if test requires background load and which generator it uses
        self._load_cfg = cfg.get('Load', None)

        if self._frame_mod:
            self._frame_mod = self._frame_mod.lower()
        self._results_dir = S.getValue('RESULTS_PATH')

        # set traffic details, so they can be passed to vswitch and traffic ctls
        self._traffic = copy.deepcopy(S.getValue('TRAFFIC'))
        self._traffic.update({'bidir': bidirectional})

        # Packet Forwarding mode
        self._vswitch_none = str(
            S.getValue('VSWITCH')).strip().lower() == 'none'

        # trafficgen configuration required for tests of tunneling protocols
        if self._tunnel_operation:
            self._traffic.update({'tunnel_type': S.getValue('TUNNEL_TYPE')})
            self._traffic['l2'].update({
                'srcmac':
                S.getValue('TRAFFICGEN_PORT1_MAC'),
                'dstmac':
                S.getValue('TRAFFICGEN_PORT2_MAC')
            })

            self._traffic['l3'].update({
                'srcip':
                S.getValue('TRAFFICGEN_PORT1_IP'),
                'dstip':
                S.getValue('TRAFFICGEN_PORT2_IP')
            })

            if self._tunnel_operation == "decapsulation":
                self._traffic['l2'].update(
                    S.getValue(
                        S.getValue('TUNNEL_TYPE').upper() + '_FRAME_L2'))
                self._traffic['l3'].update(
                    S.getValue(
                        S.getValue('TUNNEL_TYPE').upper() + '_FRAME_L3'))
                self._traffic['l4'].update(
                    S.getValue(
                        S.getValue('TUNNEL_TYPE').upper() + '_FRAME_L4'))
                self._traffic['l2']['dstmac'] = S.getValue('NICS')[1]['mac']
        elif len(S.getValue('NICS')) >= 2 and \
             (S.getValue('NICS')[0]['type'] == 'vf' or
              S.getValue('NICS')[1]['type'] == 'vf'):
            mac1 = S.getValue('NICS')[0]['mac']
            mac2 = S.getValue('NICS')[1]['mac']
            if mac1 and mac2:
                self._traffic['l2'].update({'srcmac': mac2, 'dstmac': mac1})
            else:
                self._logger.debug("MAC addresses can not be read")

        self._traffic = functions.check_traffic(self._traffic)

        # count how many VNFs are involved in TestSteps
        if self.test:
            for step in self.test:
                if step[0].startswith('vnf'):
                    self._step_vnf_list[step[0]] = None

        # if llc allocation is required, initialize it.
        if S.getValue('LLC_ALLOCATION'):
            self._rmd = rmd.CacheAllocator()
Exemple #14
0
def update_pids(pid):
    """update list of running pids, so they can be terminated at the end
    """
    pids = settings.getValue('_EXECUTED_PIDS')
    pids.append(pid)
    settings.setValue('_EXECUTED_PIDS', pids)
Exemple #15
0
    def __init__(self, test_cfg):
        """Pull out fields from test config

        :param test_cfg: A dictionary of string-value pairs describing the test
            configuration. Both the key and values strings use well-known
            values.
        :param results_dir: Where the csv formatted results are written.
        """
        # make a local copy of test configuration to avoid modification of
        # original content used in vsperf main script
        cfg = copy.deepcopy(test_cfg)

        self._testcase_start_time = time.time()
        self._hugepages_mounted = False
        self._traffic_ctl = None
        self._vnf_ctl = None
        self._vswitch_ctl = None
        self._collector = None
        self._loadgen = None
        self._output_file = None
        self._tc_results = None
        self._settings_original = {}
        self._settings_paths_modified = False
        self._testcast_run_time = None
        self._versions = []
        # initialization of step driven specific members
        self._step_check = False  # by default don't check result for step driven testcases
        self._step_vnf_list = {}
        self._step_result = []
        self._step_status = None
        self._testcase_run_time = None

        # store all GUEST_ specific settings to keep original values before their expansion
        for key in S.__dict__:
            if key.startswith('GUEST_'):
                self._settings_original[key] = S.getValue(key)

        self._update_settings('VSWITCH',
                              cfg.get('vSwitch', S.getValue('VSWITCH')))
        self._update_settings('VNF', cfg.get('VNF', S.getValue('VNF')))
        self._update_settings('TRAFFICGEN',
                              cfg.get('Trafficgen', S.getValue('TRAFFICGEN')))
        test_params = copy.deepcopy(S.getValue('TEST_PARAMS'))
        tc_test_params = cfg.get('Parameters', S.getValue('TEST_PARAMS'))
        test_params = merge_spec(test_params, tc_test_params)
        self._update_settings('TEST_PARAMS', test_params)
        S.check_test_params()

        # override all redefined GUEST_ values to have them expanded correctly
        tmp_test_params = copy.deepcopy(S.getValue('TEST_PARAMS'))
        for key in tmp_test_params:
            if key.startswith('GUEST_'):
                S.setValue(key, S.getValue(key))
                S.getValue('TEST_PARAMS').pop(key)

        # update global settings
        functions.settings_update_paths()

        # set test parameters; CLI options take precedence to testcase settings
        self._logger = logging.getLogger(__name__)
        self.name = cfg['Name']
        self.desc = cfg.get('Description', 'No description given.')
        self.test = cfg.get('TestSteps', None)

        bidirectional = S.getValue('TRAFFIC')['bidir']
        if not isinstance(S.getValue('TRAFFIC')['bidir'], str):
            raise TypeError('Bi-dir value must be of type string')
        bidirectional = bidirectional.title()  # Keep things consistent

        self.deployment = cfg['Deployment']
        self._frame_mod = cfg.get('Frame Modification', None)

        self._tunnel_type = None
        self._tunnel_operation = None

        if self.deployment == 'op2p':
            self._tunnel_operation = cfg['Tunnel Operation']

            if 'Tunnel Type' in cfg:
                self._tunnel_type = cfg['Tunnel Type']
                self._tunnel_type = get_test_param('TUNNEL_TYPE',
                                                   self._tunnel_type)

        # check if test requires background load and which generator it uses
        self._load_cfg = cfg.get('Load', None)
        if self._load_cfg and 'tool' in self._load_cfg:
            self._loadgen = self._load_cfg['tool']
        else:
            # background load is not requested, so use dummy implementation
            self._loadgen = "Dummy"

        if self._frame_mod:
            self._frame_mod = self._frame_mod.lower()
        self._results_dir = S.getValue('RESULTS_PATH')

        # set traffic details, so they can be passed to vswitch and traffic ctls
        self._traffic = copy.deepcopy(S.getValue('TRAFFIC'))
        self._traffic.update({
            'bidir': bidirectional,
            'tunnel_type': self._tunnel_type,
        })

        self._traffic = functions.check_traffic(self._traffic)

        # Packet Forwarding mode
        self._vswitch_none = str(
            S.getValue('VSWITCH')).strip().lower() == 'none'

        # trafficgen configuration required for tests of tunneling protocols
        if self.deployment == "op2p":
            self._traffic['l2'].update({
                'srcmac':
                S.getValue('TRAFFICGEN_PORT1_MAC'),
                'dstmac':
                S.getValue('TRAFFICGEN_PORT2_MAC')
            })

            self._traffic['l3'].update({
                'srcip':
                S.getValue('TRAFFICGEN_PORT1_IP'),
                'dstip':
                S.getValue('TRAFFICGEN_PORT2_IP')
            })

            if self._tunnel_operation == "decapsulation":
                self._traffic['l2'] = S.getValue(self._tunnel_type.upper() +
                                                 '_FRAME_L2')
                self._traffic['l3'] = S.getValue(self._tunnel_type.upper() +
                                                 '_FRAME_L3')
                self._traffic['l4'] = S.getValue(self._tunnel_type.upper() +
                                                 '_FRAME_L4')
        elif len(S.getValue('NICS')) and \
             (S.getValue('NICS')[0]['type'] == 'vf' or
              S.getValue('NICS')[1]['type'] == 'vf'):
            mac1 = S.getValue('NICS')[0]['mac']
            mac2 = S.getValue('NICS')[1]['mac']
            if mac1 and mac2:
                self._traffic['l2'].update({'srcmac': mac2, 'dstmac': mac1})
            else:
                self._logger.debug("MAC addresses can not be read")

        # count how many VNFs are involved in TestSteps
        if self.test:
            for step in self.test:
                if step[0].startswith('vnf'):
                    self._step_vnf_list[step[0]] = None
Exemple #16
0
    def create(self):
        """
        Creation Process
        """
        print("Entering Create Function")
        config.load_kube_config(S.getValue('K8S_CONFIG_FILEPATH'))
        # create vswitchperf namespace
        api = client.CoreV1Api()
        namespace = 'default'
        pod_manifests = S.getValue('POD_MANIFEST_FILEPATH')
        pod_count = int(S.getValue('POD_COUNT'))
        if S.hasValue('POD_NAMESPACE'):
            namespace = S.getValue('POD_NAMESPACE')
        else:
            namespace = 'default'
        dep_pod_list = []

        # sriov configmap
        if S.getValue('PLUGIN') == 'sriov':
            configmap = load_manifest(S.getValue('CONFIGMAP_FILEPATH'))
            self._sriov_config = configmap['metadata']['name']
            self._sriov_config_ns = configmap['metadata']['namespace']
            api.create_namespaced_config_map(self._sriov_config_ns, configmap)


        # create nad(network attachent definitions)
        group = 'k8s.cni.cncf.io'
        version = 'v1'
        kind_plural = 'network-attachment-definitions'
        api = client.CustomObjectsApi()
        assert pod_count <= len(pod_manifests)

        for nad_filepath in S.getValue('NETWORK_ATTACHMENT_FILEPATH'):
            nad_manifest = load_manifest(nad_filepath)

            try:
                response = api.create_namespaced_custom_object(group, version, namespace,
                                                               kind_plural, nad_manifest)
                self._logger.info(str(response))
                self._logger.info("Created Network Attachment Definition: %s", nad_filepath)
            except ApiException as err:
                raise Exception from err

        #create pod workloads
        api = client.CoreV1Api()
        for count in range(pod_count):
            dep_pod_info = {}
            pod_manifest = load_manifest(pod_manifests[count])
            dep_pod_info['name'] = pod_manifest["metadata"]["name"]
            try:
                response = api.create_namespaced_pod(namespace, pod_manifest)
                self._logger.info(str(response))
                self._logger.info("Created POD %d ...", self._number)
            except ApiException as err:
                raise Exception from err

            # Wait for the pod to start
            time.sleep(5)
            status = "Unknown"
            count = 0
            while True:
                if count == 10:
                    break
                try:
                    response = api.read_namespaced_pod_status(dep_pod_info['name'],
                            namespace)
                    status = response.status.phase
                except ApiException as err:
                    raise Exception from err
                if status in ("Running", "Failed", "Unknown"):
                    break
                time.sleep(5)
                count = count + 1
            # Now Get the Pod-IP
            try:
                response = api.read_namespaced_pod_status(dep_pod_info['name'],
                        namespace)
                dep_pod_info['pod_ip'] = response.status.pod_ip
            except ApiException as err:
                raise Exception from err
            dep_pod_info['namespace'] = namespace
            cmd = ['cat', '/etc/podnetinfo/annotations']
            output = util.execute_command(api, dep_pod_info, cmd)
            dep_pod_info['annotations'] = output
            dep_pod_list.append(dep_pod_info)

        S.setValue('POD_LIST',dep_pod_list)
        return dep_pod_list