/*
* Probing flash chips with QINFO records.
* (C) 2008 Korolev Alexey <akorolev@infradead.org>
* (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mtd/xip.h>
#include <linux/mtd/map.h>
#include <linux/mtd/pfow.h>
#include <linux/mtd/qinfo.h>
static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr);
struct mtd_info *lpddr_probe(struct map_info *map);
static struct lpddr_private *lpddr_probe_chip(struct map_info *map);
static int lpddr_pfow_present(struct map_info *map,
struct lpddr_private *lpddr);
static struct qinfo_query_info qinfo_array[] = {
/* General device info */
{0, 0, "DevSizeShift", "Device size 2^n bytes"},
{0, 3, "BufSizeShift", "Program buffer size 2^n bytes"},
/* Erase block information */
{1, 1, "TotalBlocksNum", "Total number of blocks"},
{1, 2, "UniformBlockSizeShift", "Uniform block size 2^n bytes"},
/* Partition information */
{2, 1, "HWPartsNum", "Number of hardware partitions"},
/* Optional features */
{5, 1, "SuspEraseSupp", "Suspend erase supported"},
/* Operation typical time */
{10
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
#!/usr/bin/env python3
# Copyright 2015-2016 Intel Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""VSPERF main script.
"""
import logging
import os
import sys
import argparse
import time
import datetime
import shutil
import unittest
import xmlrunner
import locale
import copy
import glob
import subprocess
sys.dont_write_bytecode = True
from conf import settings
from conf import get_test_param
from core.loader import Loader
from testcases import PerformanceTestCase
from testcases import IntegrationTestCase
from tools import tasks
from tools import networkcard
from tools import functions
from tools.pkt_gen import trafficgen
from tools.opnfvdashboard import opnfvdashboard
from tools.pkt_gen.trafficgen.trafficgenhelper import TRAFFIC_DEFAULTS
import core.component_factory as component_factory
VERBOSITY_LEVELS = {
'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL
}
_TEMPLATE_RST = {'head' : 'tools/report/report_head.rst',
'foot' : 'tools/report/report_foot.rst',
'final' : 'test_report.rst',
'tmp' : 'tools/report/report_tmp_caption.rst'
}
_LOGGER = logging.getLogger()
def parse_arguments():
"""
Parse command line arguments.
"""
class _SplitTestParamsAction(argparse.Action):
"""
Parse and split the '--test-params' argument.
This expects either 'x=y', 'x=y,z' or 'x' (implicit true)
values. For multiple overrides use a ; separated list for
e.g. --test-params 'x=z; y=a,b'
"""
def __call__(self, parser, namespace, values, option_string=None):
results = {}
for value in values.split(';'):
result = [key.strip() for key in value.split('=')]
if len(result) == 1:
results[result[0]] = True
elif len(result) == 2:
results[result[0]] = result[1]
else:
raise argparse.ArgumentTypeError(
'expected \'%s\' to be of format \'key=val\' or'
' \'key\'' % result)
setattr(namespace, self.dest, results)
class _ValidateFileAction(argparse.Action):
"""Validate a file can be read from before using it.
"""
def __call__(self, parser, namespace, values, option_string=None):
if not os.path.isfile(values):
raise argparse.ArgumentTypeError(
'the path \'%s\' is not a valid path' % values)
elif not os.access(values, os.R_OK):
raise argparse.ArgumentTypeError(
'the path \'%s\' is not accessible' % values)
setattr(namespace, self.dest, values)
class _ValidateDirAction(argparse.Action):
"""Validate a directory can be written to before using it.
"""
def __call__(self, parser, namespace, values, option_string=None):
if not os.path.isdir(values):
raise argparse.ArgumentTypeError(
'the path \'%s\' is not a valid path' % values)
elif not os.access(values, os.W_OK):
raise argparse.ArgumentTypeError(
'the path \'%s\' is not accessible' % values)
setattr(namespace, self.dest, values)
def list_logging_levels():
"""Give a summary of all available logging levels.
:return: List of verbosity level names in decreasing order of
verbosity
"""
return sorted(VERBOSITY_LEVELS.keys(),
key=lambda x: VERBOSITY_LEVELS[x])
parser = argparse.ArgumentParser(prog=__file__, formatter_class=
argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--version', action='version', version='%(prog)s 0.2')
parser.add_argument('--list', '--list-tests', action='store_true',
help='list all tests and exit')
parser.add_argument('--list-trafficgens', action='store_true',
help='list all traffic generators and exit')
parser.add_argument('--list-collectors', action='store_true',
help='list all system metrics loggers and exit')
parser.add_argument('--list-vswitches', action='store_true',
help='list all system vswitches and exit')
parser.add_argument('--list-fwdapps', action='store_true',
help='list all system forwarding applications and exit')
parser.add_argument('--list-vnfs', action='store_true',
help='list all system vnfs and exit')
parser.add_argument('--list-settings', action='store_true',
help='list effective settings configuration and exit')
parser.add_argument('exact_test_name', nargs='*', help='Exact names of\
tests to run. E.g "vsperf phy2phy_tput phy2phy_cont"\
runs only the two tests with those exact names.\
To run all tests omit both positional args and --tests arg.')
group = parser.add_argument_group('test selection options')
group.add_argument('-m', '--mode', help='vsperf mode of operation;\
Values: "normal" - execute vSwitch, VNF and traffic generator;\
"trafficgen" - execute only traffic generator; "trafficgen-off" \
- execute vSwitch and VNF; trafficgen-pause - execute vSwitch \
and VNF but pause before traffic transmission ', default='normal')
group.add_argument('-f', '--test-spec', help='test specification file')
group.add_argument('-d', '--test-dir', help='directory containing tests')
group.add_argument('-t', '--tests', help='Comma-separated list of terms \
indicating tests to run. e.g. "RFC2544,!p2p" - run all tests whose\
name contains RFC2544 less those containing "p2p"; "!back2back" - \
run all tests except those containing back2back')
group.add_argument('--verbosity', choices=list_logging_levels(),
help='debug level')
group.add_argument('--integration', action='store_true', help='execute integration tests')
group.add_argument('--trafficgen', help='traffic generator to use')
group.add_argument('--vswitch', help='vswitch implementation to use')
group.add_argument('--fwdapp', help='packet forwarding application to use')
group.add_argument('--vnf', help='vnf to use')
group.add_argument('--sysmetrics', help='system metrics logger to use')
group = parser.add_argument_group('test behavior options')
group.add_argument('--xunit', action='store_true',
help='enable xUnit-formatted output')
group.add_argument('--xunit-dir', action=_ValidateDirAction,
help='output directory of xUnit-formatted output')
group.add_argument('--load-env', action='store_true',
help='enable loading of settings from the environment')
group.add_argument('--conf-file', action=_ValidateFileAction,
help='settings file')
group.add_argument('--test-params', action=_SplitTestParamsAction,
help='csv list of test parameters: key=val; e.g.'
'including pkt_sizes=x,y; duration=x; '
'rfc2544_tests=x ...')
group.add_argument('--opnfvpod', help='name of POD in opnfv')
args = vars(parser.parse_args())
return args
def configure_logging(level):
"""Configure logging.
"""
log_file_default = os.path.join(
settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_DEFAULT'))
log_file_host_cmds = os.path.join(
settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_HOST_CMDS'))
log_file_traffic_gen = os.path.join(
settings.getValue('LOG_DIR'),
settings.getValue('LOG_FILE_TRAFFIC_GEN'))
_LOGGER.setLevel(logging.DEBUG)
stream_logger = logging.StreamHandler(sys.stdout)
stream_logger.setLevel(VERBOSITY_LEVELS[level])
stream_logger.setFormatter(logging.Formatter(
'[%(levelname)-5s] %(asctime)s : (%(name)s) - %(message)s'))
_LOGGER.addHandler(stream_logger)
file_logger = logging.FileHandler(filename=log_file_default)
file_logger.setLevel(logging.DEBUG)
_LOGGER.addHandler(file_logger)
class CommandFilter(logging.Filter):
"""Filter out strings beginning with 'cmd :'"""
def filter(self, record):
return record.getMessage().startswith(tasks.CMD_PREFIX)
class TrafficGenCommandFilter(logging.Filter):
"""Filter out strings beginning with 'gencmd :'"""
def filter(self, record):
return record.getMessage().startswith(trafficgen.CMD_PREFIX)
cmd_logger = logging.FileHandler(filename=log_file_host_cmds)
cmd_logger.setLevel(logging.DEBUG)
cmd_logger.addFilter(CommandFilter())
_LOGGER.addHandler(cmd_logger)
gen_logger = logging.FileHandler(filename=log_file_traffic_gen)
gen_logger.setLevel(logging.DEBUG)
gen_logger.addFilter(TrafficGenCommandFilter())
_LOGGER.addHandler(gen_logger)
def apply_filter(tests, tc_filter):
"""Allow a subset of tests to be conveniently selected
:param tests: The list of Tests from which to select.
:param tc_filter: A case-insensitive string of comma-separated terms
indicating the Tests to select.
e.g. 'RFC' - select all tests whose name contains 'RFC'
e.g. 'RFC,burst' - select all tests whose name contains 'RFC' or
'burst'
e.g. 'RFC,burst,!p2p' - select all tests whose name contains 'RFC'
or 'burst' and from these remove any containing 'p2p'.
e.g. '' - empty string selects all tests.
:return: A list of the selected Tests.
"""
# if negative filter is first we have to start with full list of tests
if tc_filter.strip()[0] == '!':
result = tests
else:
result = []
if tc_filter is None:
tc_filter = ""
for term in [x.strip() for x in tc_filter.lower().split(",")]:
if not term or term[0] != '!':
# Add matching tests from 'tests' into results
result.extend([test for test in tests \
if test['Name'].lower().find(term) >= 0])
else:
# Term begins with '!' so we remove matching tests
result = [test for test in result \
if test['Name'].lower().find(term[1:]) < 0]
return result
def check_and_set_locale():
""" Function will check locale settings. In case, that it isn't configured
properly, then default values specified by DEFAULT_LOCALE will be used.
"""
system_locale = locale.getdefaultlocale()
if None in system_locale:
os.environ['LC_ALL'] = settings.getValue('DEFAULT_LOCALE')
_LOGGER.warning("Locale was not properly configured. Default values were set. Old locale: %s, New locale: %s",
system_locale, locale.getdefaultlocale())
def generate_final_report():
""" Function will check if partial test results are available
and generates final report in rst format.
"""
path = settings.getValue('RESULTS_PATH')
# check if there are any results in rst format
rst_results = glob.glob(os.path.join(path, 'result*rst'))
if len(rst_results):
try:
test_report = os.path.join(path, '{}_{}'.format(settings.getValue('VSWITCH'), _TEMPLATE_RST['final']))
# create report caption directly - it is not worth to execute jinja machinery
if settings.getValue('VSWITCH').lower() != 'none':
pkt_processor = Loader().get_vswitches()[settings.getValue('VSWITCH')].__doc__.strip().split('\n')[0]
else:
pkt_processor = Loader().get_pktfwds()[settings.getValue('PKTFWD')].__doc__.strip().split('\n')[0]
report_caption = '{}\n{} {}\n{}\n\n'.format(
'============================================================',
'Performance report for',
pkt_processor,
'============================================================')
with open(_TEMPLATE_RST['tmp'], 'w') as file_:
file_.write(report_caption)
retval = subprocess.call('cat {} {} {} {} > {}'.format(_TEMPLATE_RST['tmp'], _TEMPLATE_RST['head'],
' '.join(rst_results), _TEMPLATE_RST['foot'],
test_report), shell=True)
if retval == 0 and os.path.isfile(test_report):
_LOGGER.info('Overall test report written to "%s"', test_report)
else:
_LOGGER.error('Generatrion of overall test report has failed.')
# remove temporary file
os.remove(_TEMPLATE_RST['tmp'])
except subprocess.CalledProcessError:
_LOGGER.error('Generatrion of overall test report has failed.')
def enable_sriov(nic_list):
""" Enable SRIOV for given enhanced PCI IDs
:param nic_list: A list of enhanced PCI IDs
"""
# detect if sriov is required
sriov_nic = {}
for nic in nic_list:
if networkcard.is_sriov_nic(nic):
tmp_nic = nic.split('|')
if tmp_nic[0] in sriov_nic:
if int(tmp_nic[1][2:]) > sriov_nic[tmp_nic[0]]:
sriov_nic[tmp_nic[0]] = int(tmp_nic[1][2:])
else:
sriov_nic.update({tmp_nic[0] : int(tmp_nic[1][2:])})
# sriov is required for some NICs
if len(sriov_nic):
for nic in sriov_nic:
# check if SRIOV is supported and enough virt interfaces are available
if not networkcard.is_sriov_supported(nic) \
or networkcard.get_sriov_numvfs(nic) <= sriov_nic[nic]:
# if not, enable and set appropriate number of VFs
if not networkcard.set_sriov_numvfs(nic, sriov_nic[nic] + 1):
_LOGGER.error("SRIOV cannot be enabled for NIC %s", nic)
raise
else:
_LOGGER.debug("SRIOV enabled for NIC %s", nic)
# WORKAROUND: it has been observed with IXGBE(VF) driver,
# that NIC doesn't correclty dispatch traffic to VFs based
# on their MAC address. Unbind and bind to the same driver
# solves this issue.
networkcard.reinit_vfs(nic)
# After SRIOV is enabled it takes some time until network drivers
# properly initialize all cards.
# Wait also in case, that SRIOV was already configured as it can be
# configured automatically just before vsperf execution.
time.sleep(2)
return True
return False
def disable_sriov(nic_list):
""" Disable SRIOV for given PCI IDs
:param nic_list: A list of enhanced PCI IDs
"""
for nic in nic_list:
if networkcard.is_sriov_nic(nic):
if not networkcard.set_sriov_numvfs(nic.split('|')[0], 0):
_LOGGER.error("SRIOV cannot be disabled for NIC %s", nic)
raise
else:
_LOGGER.debug("SRIOV disabled for NIC %s", nic.split('|')[0])
def handle_list_options(args):
""" Process --list cli arguments if needed
:param args: A dictionary with all CLI arguments
"""
if args['list_trafficgens']:
print(Loader().get_trafficgens_printable())
sys.exit(0)
if args['list_collectors']:
print(Loader().get_collectors_printable())
sys.exit(0)
if args['list_vswitches']:
print(Loader().get_vswitches_printable())
sys.exit(0)
if args['list_vnfs']:
print(Loader().get_vnfs_printable())
sys.exit(0)
if args['list_fwdapps']:
print(Loader().get_pktfwds_printable())
sys.exit(0)
if args['list_settings']:
print(str(settings))
sys.exit(0)
if args['list']:
# configure tests
if args['integration']:
testcases = settings.getValue('INTEGRATION_TESTS')
else:
testcases = settings.getValue('PERFORMANCE_TESTS')
print("Available Tests:")
print("================")
for test in testcases:
print('* %-30s %s' % ('%s:' % test['Name'], test['Description']))
sys.exit(0)
def vsperf_finalize():
""" Clean up before exit
"""
# remove directory if no result files were created
try:
results_path = settings.getValue('RESULTS_PATH')
if os.path.exists(results_path):
files_list = os.listdir(results_path)
if files_list == []:
_LOGGER.info("Removing empty result directory: " + results_path)
shutil.rmtree(results_path)
except AttributeError:
# skip it if parameter doesn't exist
pass
# disable SRIOV if needed
try:
if settings.getValue('SRIOV_ENABLED'):
disable_sriov(settings.getValue('WHITELIST_NICS_ORIG'))
except AttributeError:
# skip it if parameter doesn't exist
pass
class MockTestCase(unittest.TestCase):
"""Allow use of xmlrunner to generate Jenkins compatible output without
using xmlrunner to actually run tests.
Usage:
suite = unittest.TestSuite()
suite.addTest(MockTestCase('Test1 passed ', True, 'Test1'))
suite.addTest(MockTestCase('Test2 failed because...', False, 'Test2'))
xmlrunner.XMLTestRunner(...).run(suite)
"""
def __init__(self, msg, is_pass, test_name):
#remember the things
self.msg = msg
self.is_pass = is_pass
#dynamically create a test method with the right name
#but point the method at our generic test method
setattr(MockTestCase, test_name, self.generic_test)
super(MockTestCase, self).__init__(test_name)
def generic_test(self):
"""Provide a generic function that raises or not based
on how self.is_pass was set in the constructor"""
self.assertTrue(self.is_pass, self.msg)
def main():
"""Main function.
"""
args = parse_arguments()
# configure settings
settings.load_from_dir('conf')
# Load non performance/integration tests
if args['integration']:
settings.load_from_dir('conf/integration')
# load command line parameters first in case there are settings files
# to be used
settings.load_from_dict(args)
if args['conf_file']:
settings.load_from_file(args['conf_file'])
if args['load_env']:
settings.load_from_env()
# reload command line parameters since these should take higher priority
# than both a settings file and environment variables
settings.load_from_dict(args)
# set dpdk and ovs paths accorfing to VNF and VSWITCH
functions.settings_update_paths()
# if required, handle list-* operations
handle_list_options(args)
configure_logging(settings.getValue('VERBOSITY'))
# check and fix locale
check_and_set_locale()
# configure trafficgens
if args['trafficgen']:
trafficgens = Loader().get_trafficgens()
if args['trafficgen'] not in trafficgens:
_LOGGER.error('There are no trafficgens matching \'%s\' found in'
' \'%s\'. Exiting...', args['trafficgen'],
settings.getValue('TRAFFICGEN_DIR'))
sys.exit(1)
# configuration validity checks
if args['vswitch']:
vswitch_none = 'none' == args['vswitch'].strip().lower()
if vswitch_none:
settings.setValue('VSWITCH', 'none')
else:
vswitches = Loader().get_vswitches()
if args['vswitch'] not in vswitches:
_LOGGER.error('There are no vswitches matching \'%s\' found in'
' \'%s\'. Exiting...', args['vswitch'],
settings.getValue('VSWITCH_DIR'))
sys.exit(1)
if args['fwdapp']:
settings.setValue('PKTFWD', args['fwdapp'])
fwdapps = Loader().get_pktfwds()
if args['fwdapp'] not in fwdapps:
_LOGGER.error('There are no forwarding application'
' matching \'%s\' found in'
' \'%s\'. Exiting...', args['fwdapp'],
settings.getValue('PKTFWD_DIR'))
sys.exit(1)
if args['vnf']:
vnfs = Loader().get_vnfs()
if args['vnf'] not in vnfs:
_LOGGER.error('there are no vnfs matching \'%s\' found in'
' \'%s\'. exiting...', args['vnf'],
settings.getValue('vnf_dir'))
sys.exit(1)
if args['exact_test_name'] and args['tests']:
_LOGGER.error("Cannot specify tests with both positional args and --test.")
sys.exit(1)
# sriov handling
settings.setValue('SRIOV_ENABLED', enable_sriov(settings.getValue('WHITELIST_NICS')))
# modify NIC configuration to decode enhanced PCI IDs
wl_nics_orig = list(networkcard.check_pci(pci) for pci in settings.getValue('WHITELIST_NICS'))
settings.setValue('WHITELIST_NICS_ORIG', wl_nics_orig)
nic_list = []
for nic in wl_nics_orig:
tmp_nic = networkcard.get_nic_info(nic)
if tmp_nic:
nic_list.append({'pci' : tmp_nic,
'type' : 'vf' if networkcard.get_sriov_pf(tmp_nic) else 'pf',
'mac' : networkcard.get_mac(tmp_nic),
'driver' : networkcard.get_driver(tmp_nic),
'device' : networkcard.get_device_name(tmp_nic)})
else:
_LOGGER.error("Invalid network card PCI ID: '%s'", nic)
vsperf_finalize()
raise
settings.setValue('NICS', nic_list)
# for backward compatibility
settings.setValue('WHITELIST_NICS', list(nic['pci'] for nic in nic_list))
# update global settings
guest_loopback = get_test_param('guest_loopback', None)
if guest_loopback:
tmp_gl = []
for dummy_i in range(len(settings.getValue('GUEST_LOOPBACK'))):
tmp_gl.append(guest_loopback)
settings.setValue('GUEST_LOOPBACK', tmp_gl)
settings.setValue('mode', args['mode'])
# generate results directory name
date = datetime.datetime.fromtimestamp(time.time())
results_dir = "results_" + date.strftime('%Y-%m-%d_%H-%M-%S')
results_path = os.path.join(settings.getValue('LOG_DIR'), results_dir)
settings.setValue('RESULTS_PATH', results_path)
# create results directory
if not os.path.exists(results_path):
_LOGGER.info("Creating result directory: " + results_path)
os.makedirs(results_path)
if settings.getValue('mode') == 'trafficgen':
# execute only traffic generator
_LOGGER.debug("Executing traffic generator:")
loader = Loader()
# set traffic details, so they can be passed to traffic ctl
traffic = copy.deepcopy(TRAFFIC_DEFAULTS)
traffic.update({'traffic_type': get_test_param('traffic_type', 'rfc2544'),
'bidir': get_test_param('bidirectional', 'False'),
'multistream': int(get_test_param('multistream', 0)),
'stream_type': get_test_param('stream_type', 'L4'),
'frame_rate': int(get_test_param('iload', 100))})
traffic_ctl = component_factory.create_traffic(
traffic['traffic_type'],
loader.get_trafficgen_class())
with traffic_ctl:
traffic_ctl.send_traffic(traffic)
_LOGGER.debug("Traffic Results:")
traffic_ctl.print_results()
# write results into CSV file
result_file = os.path.join(results_path, "result.csv")
PerformanceTestCase.write_result_to_file(traffic_ctl.get_results(), result_file)
else:
# configure tests
if args['integration']:
testcases = settings.getValue('INTEGRATION_TESTS')
else:
testcases = settings.getValue('PERFORMANCE_TESTS')
if args['exact_test_name']:
exact_names = args['exact_test_name']
# positional args => exact matches only
selected_tests = [test for test in testcases if test['Name'] in exact_names]
elif args['tests']:
# --tests => apply filter to select requested tests
selected_tests = apply_filter(testcases, args['tests'])
else:
# Default - run all tests
selected_tests = testcases
if not len(selected_tests):
_LOGGER.error("No tests matched --tests option or positional args. Done.")
vsperf_finalize()
sys.exit(1)
# run tests
suite = unittest.TestSuite()
for cfg in selected_tests:
test_name = cfg.get('Name', '<Name not set>')
try:
if args['integration']:
test = IntegrationTestCase(cfg)
else:
test = PerformanceTestCase(cfg)
test.run()
suite.addTest(MockTestCase('', True, test.name))
#pylint: disable=broad-except
except (Exception) as ex:
_LOGGER.exception("Failed to run test: %s", test_name)
suite.addTest(MockTestCase(str(ex), False, test_name))
_LOGGER.info("Continuing with next test...")
# generate final rst report with results of all executed TCs
generate_final_report()
if settings.getValue('XUNIT'):
xmlrunner.XMLTestRunner(
output=settings.getValue('XUNIT_DIR'), outsuffix="",
verbosity=0).run(suite)
if args['opnfvpod']:
pod_name = args['opnfvpod']
installer_name = settings.getValue('OPNFV_INSTALLER')
opnfv_url = settings.getValue('OPNFV_URL')
pkg_list = settings.getValue('PACKAGE_LIST')
int_data = {'cuse': False,
'vanilla': False,
'pod': pod_name,
'installer': installer_name,
'pkg_list': pkg_list,
'db_url': opnfv_url}
if settings.getValue('VSWITCH').endswith('Vanilla'):
int_data['vanilla'] = True
if settings.getValue('VNF').endswith('Cuse'):
int_data['cuse'] = True
opnfvdashboard.results2opnfv_dashboard(results_path, int_data)
# cleanup before exit
vsperf_finalize()
if __name__ == "__main__":
main()