From 8ae63e17a4f6934895d69f4c8b4dbc7628d48526 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Tue, 19 Sep 2017 01:37:02 -0700 Subject: Enabling multi_VM & multi port launch in standalone context new context names: - SRIOV - StandaloneSriov - OvsDpdk - StandaloneOvsDpdk - Seperate helper, libvirt, server info class - Allow multi-port and multi-VM support. Change-Id: I3c65e4535082fa0e2f4c6ee11c3bca9ccfdc01b8 Signed-off-by: Deepak S Signed-off-by: Martin Banszel --- .../benchmark/contexts/standalone/__init__.py | 211 ------- yardstick/benchmark/contexts/standalone/model.py | 493 ++++++++++++++++ .../benchmark/contexts/standalone/ovs_dpdk.py | 383 +++++++++++++ yardstick/benchmark/contexts/standalone/ovsdpdk.py | 369 ------------ yardstick/benchmark/contexts/standalone/sriov.py | 624 ++++++++------------- yardstick/network_services/utils.py | 57 ++ 6 files changed, 1160 insertions(+), 977 deletions(-) create mode 100644 yardstick/benchmark/contexts/standalone/model.py create mode 100644 yardstick/benchmark/contexts/standalone/ovs_dpdk.py delete mode 100644 yardstick/benchmark/contexts/standalone/ovsdpdk.py (limited to 'yardstick') diff --git a/yardstick/benchmark/contexts/standalone/__init__.py b/yardstick/benchmark/contexts/standalone/__init__.py index f0ef1d560..e69de29bb 100644 --- a/yardstick/benchmark/contexts/standalone/__init__.py +++ b/yardstick/benchmark/contexts/standalone/__init__.py @@ -1,211 +0,0 @@ -# Copyright (c) 2016-2017 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. -"""This module handle non managed standalone virtualization node.""" - -from __future__ import absolute_import -import logging -import os -import errno -import collections -import time - -from yardstick.benchmark.contexts.base import Context -from yardstick.common.constants import YARDSTICK_ROOT_PATH -from yardstick.common.utils import import_modules_from_package, itersubclasses -from yardstick.common.yaml_loader import yaml_load - -LOG = logging.getLogger(__name__) - - -class StandaloneContext(Context): - """ This class handles standalone nodes - VM running on Non-Managed NFVi - Configuration: vswitch, ovs, ovs-dpdk, sr-iov, linuxbridge - """ - - __context_type__ = "Standalone" - - def __init__(self): - self.name = None - self.file_path = None - self.nodes = [] - self.networks = {} - self.nfvi_node = [] - self.nfvi_obj = None - self.attrs = {} - super(StandaloneContext, self).__init__() - - def read_config_file(self): - """Read from config file""" - - with open(self.file_path) as stream: - LOG.info("Parsing pod file: %s", self.file_path) - cfg = yaml_load(stream) - return cfg - - def get_nfvi_obj(self): - print("{0}".format(self.nfvi_node[0]['role'])) - context_type = self.get_context_impl(self.nfvi_node[0]['role']) - nfvi_obj = context_type() - nfvi_obj.__init__() - nfvi_obj.parse_pod_and_get_data(self.file_path) - return nfvi_obj - - def init(self, attrs): - """initializes itself from the supplied arguments""" - - self.name = attrs["name"] - self.file_path = file_path = attrs.get("file", "pod.yaml") - - try: - cfg = self.read_config_file() - except IOError as io_error: - if io_error.errno != errno.ENOENT: - raise - self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path) - cfg = self.read_config_file() - - self.vm_deploy = attrs.get("vm_deploy", True) - self.nodes.extend([node for node in cfg["nodes"] - if str(node["role"]) != "Sriov" and - str(node["role"]) != "Ovsdpdk"]) - for node in cfg["nodes"]: - if str(node["role"]) == "Sriov": - self.nfvi_node.extend([node for node in cfg["nodes"] - if str(node["role"]) == "Sriov"]) - if str(node["role"]) == "Ovsdpdk": - self.nfvi_node.extend([node for node in cfg["nodes"] - if str(node["role"]) == "Ovsdpdk"]) - LOG.info("{0}".format(node["role"])) - else: - LOG.debug("Node role is other than SRIOV and OVS") - self.nfvi_obj = self.get_nfvi_obj() - self.attrs = attrs - # add optional static network definition - self.networks.update(cfg.get("networks", {})) - self.nfvi_obj = self.get_nfvi_obj() - LOG.debug("Nodes: %r", self.nodes) - LOG.debug("NFVi Node: %r", self.nfvi_node) - LOG.debug("Networks: %r", self.networks) - - def deploy(self): - """don't need to deploy""" - - # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. - if not self.vm_deploy: - return - - # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. - self.nfvi_obj.ssh_remote_machine() - if self.nfvi_obj.first_run is True: - self.nfvi_obj.install_req_libs() - - nic_details = self.nfvi_obj.get_nic_details() - print("{0}".format(nic_details)) - - if self.nfvi_node[0]["role"] == "Sriov": - self.nfvi_obj.setup_sriov_context( - self.nfvi_obj.sriov[0]['phy_ports'], - nic_details, - self.nfvi_obj.sriov[0]['phy_driver']) - if self.nfvi_node[0]["role"] == "Ovsdpdk": - self.nfvi_obj.setup_ovs(self.nfvi_obj.ovs[0]["phy_ports"]) - self.nfvi_obj.start_ovs_serverswitch() - time.sleep(5) - self.nfvi_obj.setup_ovs_bridge() - self.nfvi_obj.add_oflows() - self.nfvi_obj.setup_ovs_context( - self.nfvi_obj.ovs[0]['phy_ports'], - nic_details, - self.nfvi_obj.ovs[0]['phy_driver']) - pass - - def undeploy(self): - """don't need to undeploy""" - - if not self.vm_deploy: - return - # Todo: NFVi undeploy (sriov, vswitch, ovs etc) based on the config. - # self.nfvi_obj = self.get_nfvi_obj() - self.nfvi_obj.ssh_remote_machine() - self.nfvi_obj.destroy_vm() - pass - - def _get_server(self, attr_name): - """lookup server info by name from context - - Keyword arguments: - attr_name -- A name for a server listed in nodes config file - """ - node_name, name = self.split_name(attr_name) - if name is None or self.name != name: - return None - - matching_nodes = (n for n in self.nodes if n["name"] == node_name) - try: - # A clone is created in order to avoid affecting the - # original one. - node = dict(next(matching_nodes)) - except StopIteration: - return None - - try: - duplicate = next(matching_nodes) - except StopIteration: - pass - else: - raise ValueError("Duplicate nodes!!! Nodes: %s %s", - (node, duplicate)) - - node["name"] = attr_name - return node - - def _get_network(self, attr_name): - if not isinstance(attr_name, collections.Mapping): - network = self.networks.get(attr_name) - - else: - # Don't generalize too much Just support vld_id - vld_id = attr_name.get('vld_id', {}) - # for standalone context networks are dicts - iter1 = (n for n in self.networks.values() if n.get('vld_id') == vld_id) - network = next(iter1, None) - - if network is None: - return None - - result = { - # name is required - "name": network["name"], - "vld_id": network.get("vld_id"), - "segmentation_id": network.get("segmentation_id"), - "network_type": network.get("network_type"), - "physical_network": network.get("physical_network"), - } - return result - - def get_context_impl(self, nfvi_type): - """ Find the implementing class from vnf_model["vnf"]["name"] field - - :param vnf_model: dictionary containing a parsed vnfd - :return: subclass of GenericVNF - """ - import_modules_from_package( - "yardstick.benchmark.contexts") - expected_name = nfvi_type - impl = [c for c in itersubclasses(StandaloneContext) - if c.__name__ == expected_name] - try: - return next(iter(impl)) - except StopIteration: - raise ValueError("No implementation for %s", expected_name) diff --git a/yardstick/benchmark/contexts/standalone/model.py b/yardstick/benchmark/contexts/standalone/model.py new file mode 100644 index 000000000..4491660e0 --- /dev/null +++ b/yardstick/benchmark/contexts/standalone/model.py @@ -0,0 +1,493 @@ +# Copyright (c) 2016-2017 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. + +from __future__ import absolute_import +import os +import re +import time +import glob +import uuid +import random +import logging +import itertools +import errno + +from netaddr import IPNetwork +import xml.etree.ElementTree as ET + +from yardstick import ssh +from yardstick.common.constants import YARDSTICK_ROOT_PATH +from yardstick.common.yaml_loader import yaml_load +from yardstick.network_services.utils import PciAddress +from yardstick.common.utils import write_file + +LOG = logging.getLogger(__name__) + +VM_TEMPLATE = """ + + {vm_name} + {random_uuid} + {memory} + {memory} + + + + {vcpu} + + hvm + + + + + + + + + + + + + + + + + + + destroy + restart + restart + + /usr/bin/kvm-spice + + + + + + + + + + + + + +""" +WAIT_FOR_BOOT = 30 + + +class Libvirt(object): + """ This class handles all the libvirt updates to lauch VM + """ + + @staticmethod + def check_if_vm_exists_and_delete(vm_name, connection): + cmd_template = "virsh list --name | grep -i %s" + status = connection.execute(cmd_template % vm_name)[0] + if status == 0: + LOG.info("VM '%s' is already present.. destroying" % vm_name) + connection.execute("virsh destroy %s" % vm_name) + + @staticmethod + def virsh_create_vm(connection, cfg): + err = connection.execute("virsh create %s" % cfg)[0] + LOG.info("VM create status: %s" % (err)) + + @staticmethod + def virsh_destroy_vm(vm_name, connection): + connection.execute("virsh destroy %s" % vm_name) + + @staticmethod + def add_interface_address(interface, pci_address): + vm_pci = ET.SubElement(interface, 'address') + vm_pci.set('type', 'pci') + vm_pci.set('domain', '0x%s' % pci_address.domain) + vm_pci.set('bus', '0x%s' % pci_address.bus) + vm_pci.set('slot', '0x%s' % pci_address.slot) + vm_pci.set('function', '0x%s' % pci_address.function) + return vm_pci + + @classmethod + def add_ovs_interface(cls, vpath, port_num, vpci, vports_mac, xml): + vhost_path = '{0}/var/run/openvswitch/dpdkvhostuser{1}' + root = ET.parse(xml) + pci_address = PciAddress.parse_address(vpci.strip(), multi_line=True) + device = root.find('devices') + + interface = ET.SubElement(device, 'interface') + interface.set('type', 'vhostuser') + mac = ET.SubElement(interface, 'mac') + mac.set('address', vports_mac) + + source = ET.SubElement(interface, 'source') + source.set('type', 'unix') + source.set('path', vhost_path.format(vpath, port_num)) + source.set('mode', 'client') + + model = ET.SubElement(interface, 'model') + model.set('type', 'virtio') + + driver = ET.SubElement(interface, 'driver') + driver.set('queues', '4') + + host = ET.SubElement(driver, 'host') + host.set('mrg_rxbuf', 'off') + + cls.add_interface_address(interface, pci_address) + + root.write(xml) + + @classmethod + def add_sriov_interfaces(cls, vm_pci, vf_pci, vfmac, xml): + root = ET.parse(xml) + pci_address = PciAddress.parse_address(vf_pci.strip(), multi_line=True) + device = root.find('devices') + + interface = ET.SubElement(device, 'interface') + interface.set('managed', 'yes') + interface.set('type', 'hostdev') + + mac = ET.SubElement(interface, 'mac') + mac.set('address', vfmac) + source = ET.SubElement(interface, 'source') + + addr = ET.SubElement(source, "address") + addr.set('domain', "0x0") + addr.set('bus', "{0}".format(pci_address.bus)) + addr.set('function', "{0}".format(pci_address.function)) + addr.set('slot', "0x{0}".format(pci_address.slot)) + addr.set('type', "pci") + + pci_vm_address = PciAddress.parse_address(vm_pci.strip(), multi_line=True) + cls.add_interface_address(interface, pci_vm_address) + + root.write(xml) + + @staticmethod + def create_snapshot_qemu(connection, index, vm_image): + # build snapshot image + image = "/var/lib/libvirt/images/%s.qcow2" % index + connection.execute("rm %s" % image) + qemu_template = "qemu-img create -f qcow2 -o backing_file=%s %s" + connection.execute(qemu_template % (vm_image, image)) + + return image + + @classmethod + def build_vm_xml(cls, connection, flavor, cfg, vm_name, index): + memory = flavor.get('ram', '4096') + extra_spec = flavor.get('extra_specs', {}) + cpu = extra_spec.get('hw:cpu_cores', '2') + socket = extra_spec.get('hw:cpu_sockets', '1') + threads = extra_spec.get('hw:cpu_threads', '2') + vcpu = int(cpu) * int(threads) + numa_cpus = '0-%s' % (vcpu - 1) + + mac = StandaloneContextHelper.get_mac_address(0x00) + image = cls.create_snapshot_qemu(connection, index, + flavor.get("images", None)) + vm_xml = VM_TEMPLATE.format( + vm_name=vm_name, + random_uuid=uuid.uuid4(), + mac_addr=mac, + memory=memory, vcpu=vcpu, cpu=cpu, + numa_cpus=numa_cpus, + socket=socket, threads=threads, + vm_image=image) + + write_file(cfg, vm_xml) + + return [vcpu, mac] + + @staticmethod + def split_cpu_list(cpu_list): + if not cpu_list: + return [] + + ranges = cpu_list.split(',') + bounds = ([int(b) for b in r.split('-')] for r in ranges) + range_objects = \ + (range(bound[0], bound[1] + 1 if len(bound) == 2 + else bound[0] + 1) for bound in bounds) + + return sorted(itertools.chain.from_iterable(range_objects)) + + @classmethod + def get_numa_nodes(cls): + nodes_sysfs = glob.iglob("/sys/devices/system/node/node*") + nodes = {} + for node_sysfs in nodes_sysfs: + num = os.path.basename(node_sysfs).replace("node", "") + with open(os.path.join(node_sysfs, "cpulist")) as cpulist_file: + cpulist = cpulist_file.read().strip() + nodes[num] = cls.split_cpu_list(cpulist) + LOG.info("nodes: {0}".format(nodes)) + return nodes + + @staticmethod + def update_interrupts_hugepages_perf(connection): + connection.execute("echo 1 > /sys/module/kvm/parameters/allow_unsafe_assigned_interrupts") + connection.execute("echo never > /sys/kernel/mm/transparent_hugepage/enabled") + + @classmethod + def pin_vcpu_for_perf(cls, connection, vm_name, cpu): + nodes = cls.get_numa_nodes() + num_nodes = len(nodes) + vcpi_pin_template = "virsh vcpupin {0} {1} {2}" + for i in range(0, int(cpu)): + core = nodes[str(num_nodes - 1)][i % len(nodes[str(num_nodes - 1)])] + connection.execute(vcpi_pin_template.format(vm_name, i, core)) + cls.update_interrupts_hugepages_perf(connection) + + +class StandaloneContextHelper(object): + """ This class handles all the common code for standalone + """ + def __init__(self): + self.file_path = None + super(StandaloneContextHelper, self).__init__() + + @staticmethod + def install_req_libs(connection, extra_pkgs=[]): + pkgs = ["qemu-kvm", "libvirt-bin", "bridge-utils", "numactl", "fping"] + pkgs.extend(extra_pkgs) + cmd_template = "dpkg-query -W --showformat='${Status}\\n' \"%s\"|grep 'ok installed'" + for pkg in pkgs: + if connection.execute(cmd_template % pkg)[0]: + connection.execute("apt-get update") + connection.execute("apt-get -y install %s" % pkg) + else: + # all installed + return + + @staticmethod + def get_kernel_module(connection, pci, driver): + if not driver: + out = connection.execute("lspci -k -s %s" % pci)[1] + driver = out.split("Kernel modules:").pop().strip() + return driver + + @classmethod + def get_nic_details(cls, connection, networks, dpdk_nic_bind): + for key, ports in networks.items(): + if key == "mgmt": + continue + + phy_ports = ports['phy_port'] + phy_driver = ports.get('phy_driver', None) + driver = cls.get_kernel_module(connection, phy_ports, phy_driver) + + # Make sure that ports are bound to kernel drivers e.g. i40e/ixgbe + bind_cmd = "{dpdk_nic_bind} --force -b {driver} {port}" + lshw_cmd = "lshw -c network -businfo | grep '{port}'" + link_show_cmd = "ip -s link show {interface}" + + cmd = bind_cmd.format(dpdk_nic_bind=dpdk_nic_bind, + driver=driver, port=ports['phy_port']) + connection.execute(cmd) + + out = connection.execute(lshw_cmd.format(port=phy_ports))[1] + interface = out.split()[1] + + connection.execute(link_show_cmd.format(interface=interface)) + + ports.update({ + 'interface': str(interface), + 'driver': driver + }) + LOG.info("{0}".format(networks)) + + return networks + + @staticmethod + def get_virtual_devices(connection, pci): + cmd = "cat /sys/bus/pci/devices/{0}/virtfn0/uevent" + output = connection.execute(cmd.format(pci))[1] + + pattern = "PCI_SLOT_NAME=({})".format(PciAddress.PCI_PATTERN_STR) + m = re.search(pattern, output, re.MULTILINE) + + pf_vfs = {} + if m: + pf_vfs = {pci: m.group(1).rstrip()} + + LOG.info("pf_vfs:\n%s", pf_vfs) + + return pf_vfs + + def read_config_file(self): + """Read from config file""" + + with open(self.file_path) as stream: + LOG.info("Parsing pod file: %s", self.file_path) + cfg = yaml_load(stream) + return cfg + + def parse_pod_file(self, file_path, nfvi_role='Sriov'): + self.file_path = file_path + nodes = [] + nfvi_host = [] + try: + cfg = self.read_config_file() + except IOError as io_error: + if io_error.errno != errno.ENOENT: + raise + self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path) + cfg = self.read_config_file() + + nodes.extend([node for node in cfg["nodes"] if str(node["role"]) != nfvi_role]) + nfvi_host.extend([node for node in cfg["nodes"] if str(node["role"]) == nfvi_role]) + if not nfvi_host: + raise("Node role is other than SRIOV") + + host_mgmt = {'user': nfvi_host[0]['user'], + 'ip': str(IPNetwork(nfvi_host[0]['ip']).ip), + 'password': nfvi_host[0]['password'], + 'ssh_port': nfvi_host[0].get('ssh_port', 22), + 'key_filename': nfvi_host[0].get('key_filename')} + + return [nodes, nfvi_host, host_mgmt] + + @staticmethod + def get_mac_address(end=0x7f): + mac = [0x52, 0x54, 0x00, + random.randint(0x00, end), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff)] + mac_address = ':'.join('%02x' % x for x in mac) + return mac_address + + @staticmethod + def get_mgmt_ip(connection, mac, cidr, node): + mgmtip = None + times = 10 + while not mgmtip and times: + connection.execute("fping -c 1 -g %s > /dev/null 2>&1" % cidr) + out = connection.execute("ip neighbor | grep '%s'" % mac)[1] + LOG.info("fping -c 1 -g %s > /dev/null 2>&1" % cidr) + if out.strip(): + mgmtip = str(out.split(" ")[0]).strip() + client = ssh.SSH.from_node(node, overrides={"ip": mgmtip}) + client.wait() + break + + time.sleep(WAIT_FOR_BOOT) # FixMe: How to find if VM is booted? + times = times - 1 + return mgmtip + + @classmethod + def wait_for_vnfs_to_start(cls, connection, servers, nodes): + for node in nodes: + vnf = servers[node["name"]] + mgmtip = vnf["network_ports"]["mgmt"]["cidr"] + ip = cls.get_mgmt_ip(connection, node["mac"], mgmtip, node) + if ip: + node["ip"] = ip + return nodes + + +class Server(object): + """ This class handles geting vnf nodes + """ + + @staticmethod + def build_vnf_interfaces(vnf, ports): + interfaces = {} + index = 0 + + for key, vfs in vnf["network_ports"].items(): + if key == "mgmt": + mgmtip = str(IPNetwork(vfs['cidr']).ip) + continue + + vf = ports[vfs[0]] + ip = IPNetwork(vf['cidr']) + interfaces.update({ + key: { + 'vpci': vf['vpci'], + 'driver': "%svf" % vf['driver'], + 'local_mac': vf['mac'], + 'dpdk_port_num': index, + 'local_ip': str(ip.ip), + 'netmask': str(ip.netmask) + }, + }) + index = index + 1 + + return mgmtip, interfaces + + @classmethod + def generate_vnf_instance(cls, flavor, ports, ip, key, vnf, mac): + mgmtip, interfaces = cls.build_vnf_interfaces(vnf, ports) + + result = { + "ip": mgmtip, + "mac": mac, + "host": ip, + "user": flavor.get('user', 'root'), + "interfaces": interfaces, + "routing_table": [], + # empty IPv6 routing table + "nd_route_tbl": [], + "name": key, "role": key + } + + try: + result['key_filename'] = flavor['key_filename'] + except KeyError: + pass + + try: + result['password'] = flavor['password'] + except KeyError: + pass + LOG.info(result) + return result + + +class OvsDeploy(object): + """ This class handles deploy of ovs dpdk + Configuration: ovs_dpdk + """ + + OVS_DEPLOY_SCRIPT = "ovs_deploy.bash" + + def __init__(self, connection, bin_path, ovs_properties): + self.connection = connection + self.bin_path = bin_path + self.ovs_properties = ovs_properties + + def prerequisite(self): + pkgs = ["git", "build-essential", "pkg-config", "automake", + "autotools-dev", "libltdl-dev", "cmake", "libnuma-dev", + "libpcap-dev"] + StandaloneContextHelper.install_req_libs(self.connection, pkgs) + + def ovs_deploy(self): + ovs_deploy = os.path.join(YARDSTICK_ROOT_PATH, + "yardstick/resources/scripts/install/", + self.OVS_DEPLOY_SCRIPT) + if os.path.isfile(ovs_deploy): + self.prerequisite() + remote_ovs_deploy = os.path.join(self.bin_path, self.OVS_DEPLOY_SCRIPT) + LOG.info(remote_ovs_deploy) + self.connection.put(ovs_deploy, remote_ovs_deploy) + + http_proxy = os.environ.get('http_proxy', '') + ovs_details = self.ovs_properties.get("version", {}) + ovs = ovs_details.get("ovs", "2.6.0") + dpdk = ovs_details.get("dpdk", "16.11.1") + + cmd = "sudo -E %s --ovs='%s' --dpdk='%s' -p='%s'" % (remote_ovs_deploy, + ovs, dpdk, http_proxy) + self.connection.execute(cmd) diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py new file mode 100644 index 000000000..833c3fb80 --- /dev/null +++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py @@ -0,0 +1,383 @@ +# Copyright (c) 2016-2017 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. + +from __future__ import absolute_import +import os +import logging +import collections +import time + +from collections import OrderedDict + +from yardstick import ssh +from yardstick.network_services.utils import get_nsb_option +from yardstick.network_services.utils import provision_tool +from yardstick.benchmark.contexts.base import Context +from yardstick.benchmark.contexts.standalone.model import Libvirt +from yardstick.benchmark.contexts.standalone.model import StandaloneContextHelper +from yardstick.benchmark.contexts.standalone.model import Server +from yardstick.benchmark.contexts.standalone.model import OvsDeploy +from yardstick.network_services.utils import PciAddress + +LOG = logging.getLogger(__name__) + + +class OvsDpdkContext(Context): + """ This class handles OVS standalone nodes - VM running on Non-Managed NFVi + Configuration: ovs_dpdk + """ + + __context_type__ = "StandaloneOvsDpdk" + + SUPPORTED_OVS_TO_DPDK_MAP = { + '2.6.0': '16.07.1', + '2.6.1': '16.07.2', + '2.7.0': '16.11.1', + '2.7.1': '16.11.2', + '2.7.2': '16.11.3', + '2.8.0': '17.05.2' + } + + DEFAULT_OVS = '2.6.0' + + PKILL_TEMPLATE = "pkill %s %s" + + def __init__(self): + self.file_path = None + self.sriov = [] + self.first_run = True + self.dpdk_nic_bind = "" + self.vm_names = [] + self.name = None + self.nfvi_host = [] + self.nodes = [] + self.networks = {} + self.attrs = {} + self.vm_flavor = None + self.servers = None + self.helper = StandaloneContextHelper() + self.vnf_node = Server() + self.ovs_properties = {} + self.wait_for_vswitchd = 10 + super(OvsDpdkContext, self).__init__() + + def init(self, attrs): + """initializes itself from the supplied arguments""" + + self.name = attrs["name"] + self.file_path = attrs.get("file", "pod.yaml") + + self.nodes, self.nfvi_host, self.host_mgmt = \ + self.helper.parse_pod_file(self.file_path, 'OvsDpdk') + + self.attrs = attrs + self.vm_flavor = attrs.get('flavor', {}) + self.servers = attrs.get('servers', {}) + self.vm_deploy = attrs.get("vm_deploy", True) + self.ovs_properties = attrs.get('ovs_properties', {}) + # add optional static network definition + self.networks = attrs.get("networks", {}) + + LOG.debug("Nodes: %r", self.nodes) + LOG.debug("NFVi Node: %r", self.nfvi_host) + LOG.debug("Networks: %r", self.networks) + + def setup_ovs(self): + vpath = self.ovs_properties.get("vpath", "/usr/local") + xargs_kill_cmd = self.PKILL_TEMPLATE % ('-9', 'ovs') + + create_from = os.path.join(vpath, 'etc/openvswitch/conf.db') + create_to = os.path.join(vpath, 'share/openvswitch/vswitch.ovsschema') + + cmd_list = [ + "chmod 0666 /dev/vfio/*", + "chmod a+x /dev/vfio", + "pkill -9 ovs", + xargs_kill_cmd, + "killall -r 'ovs*'", + "mkdir -p {0}/etc/openvswitch".format(vpath), + "mkdir -p {0}/var/run/openvswitch".format(vpath), + "rm {0}/etc/openvswitch/conf.db".format(vpath), + "ovsdb-tool create {0} {1}".format(create_from, create_to), + "modprobe vfio-pci", + "chmod a+x /dev/vfio", + "chmod 0666 /dev/vfio/*", + ] + for cmd in cmd_list: + self.connection.execute(cmd) + bind_cmd = "{dpdk_nic_bind} --force -b {driver} {port}" + phy_driver = "vfio-pci" + for key, port in self.networks.items(): + vpci = port.get("phy_port") + self.connection.execute(bind_cmd.format(dpdk_nic_bind=self.dpdk_nic_bind, + driver=phy_driver, port=vpci)) + + def start_ovs_serverswitch(self): + vpath = self.ovs_properties.get("vpath") + pmd_nums = int(self.ovs_properties.get("pmd_threads", 2)) + ovs_sock_path = '/var/run/openvswitch/db.sock' + log_path = '/var/log/openvswitch/ovs-vswitchd.log' + + pmd_mask = hex(sum(2 ** num for num in range(pmd_nums)) << 1) + socket0 = self.ovs_properties.get("ram", {}).get("socket_0", "2048") + socket1 = self.ovs_properties.get("ram", {}).get("socket_1", "2048") + + ovs_other_config = "ovs-vsctl {0}set Open_vSwitch . other_config:{1}" + detach_cmd = "ovs-vswitchd unix:{0}{1} --pidfile --detach --log-file={2}" + + cmd_list = [ + "mkdir -p /usr/local/var/run/openvswitch", + "ovsdb-server --remote=punix:/{0}/{1} --pidfile --detach".format(vpath, + ovs_sock_path), + ovs_other_config.format("--no-wait ", "dpdk-init=true"), + ovs_other_config.format("--no-wait ", "dpdk-socket-mem='%s,%s'" % (socket0, socket1)), + detach_cmd.format(vpath, ovs_sock_path, log_path), + ovs_other_config.format("", "pmd-cpu-mask=%s" % pmd_mask), + ] + + for cmd in cmd_list: + LOG.info(cmd) + self.connection.execute(cmd) + time.sleep(self.wait_for_vswitchd) + + def setup_ovs_bridge_add_flows(self): + dpdk_args = "" + dpdk_list = [] + vpath = self.ovs_properties.get("vpath", "/usr/local") + version = self.ovs_properties.get('version', {}) + ovs_ver = [int(x) for x in version.get('ovs', self.DEFAULT_OVS).split('.')] + ovs_add_port = \ + "ovs-vsctl add-port {br} {port} -- set Interface {port} type={type_}{dpdk_args}" + ovs_add_queue = "ovs-vsctl set Interface {port} options:n_rxq={queue}" + chmod_vpath = "chmod 0777 {0}/var/run/openvswitch/dpdkvhostuser*" + + cmd_dpdk_list = [ + "ovs-vsctl del-br br0", + "rm -rf /usr/local/var/run/openvswitch/dpdkvhostuser*", + "ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev", + ] + + ordered_network = OrderedDict(self.networks) + for index, (key, vnf) in enumerate(ordered_network.items()): + if ovs_ver >= [2, 7, 0]: + dpdk_args = " options:dpdk-devargs=%s" % vnf.get("phy_port") + dpdk_list.append(ovs_add_port.format(br='br0', port='dpdk%s' % vnf.get("port_num", 0), + type_='dpdk', dpdk_args=dpdk_args)) + dpdk_list.append(ovs_add_queue.format(port='dpdk%s' % vnf.get("port_num", 0), + queue=self.ovs_properties.get("queues", 4))) + + # Sorting the array to make sure we execute dpdk0... in the order + list.sort(dpdk_list) + cmd_dpdk_list.extend(dpdk_list) + + # Need to do two for loop to maintain the dpdk/vhost ports. + for index, _ in enumerate(ordered_network): + cmd_dpdk_list.append(ovs_add_port.format(br='br0', port='dpdkvhostuser%s' % index, + type_='dpdkvhostuser', dpdk_args="")) + + for cmd in cmd_dpdk_list: + LOG.info(cmd) + self.connection.execute(cmd) + + # Fixme: add flows code + ovs_flow = "ovs-ofctl add-flow br0 in_port=%s,action=output:%s" + + network_count = len(ordered_network) + 1 + for in_port, out_port in zip(range(1, network_count), + range(network_count, network_count * 2)): + self.connection.execute(ovs_flow % (in_port, out_port)) + self.connection.execute(ovs_flow % (out_port, in_port)) + + self.connection.execute(chmod_vpath.format(vpath)) + + def cleanup_ovs_dpdk_env(self): + self.connection.execute("ovs-vsctl del-br br0") + self.connection.execute("pkill -9 ovs") + + def check_ovs_dpdk_env(self): + self.cleanup_ovs_dpdk_env() + + version = self.ovs_properties.get("version", {}) + ovs_ver = version.get("ovs", self.DEFAULT_OVS) + dpdk_ver = version.get("dpdk", "16.07.2").split('.') + + supported_version = self.SUPPORTED_OVS_TO_DPDK_MAP.get(ovs_ver, None) + if supported_version is None or supported_version.split('.')[:2] != dpdk_ver[:2]: + raise Exception("Unsupported ovs '{}'. Please check the config...".format(ovs_ver)) + + status = self.connection.execute("ovs-vsctl -V | grep -i '%s'" % ovs_ver)[0] + if status: + deploy = OvsDeploy(self.connection, + get_nsb_option("bin_path"), + self.ovs_properties) + deploy.ovs_deploy() + + def deploy(self): + """don't need to deploy""" + + # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. + if not self.vm_deploy: + return + + self.connection = ssh.SSH.from_node(self.host_mgmt) + self.dpdk_nic_bind = provision_tool( + self.connection, + os.path.join(get_nsb_option("bin_path"), "dpdk-devbind.py")) + + # Check dpdk/ovs version, if not present install + self.check_ovs_dpdk_env() + # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. + StandaloneContextHelper.install_req_libs(self.connection) + self.networks = StandaloneContextHelper.get_nic_details(self.connection, + self.networks, + self.dpdk_nic_bind) + + self.setup_ovs() + self.start_ovs_serverswitch() + self.setup_ovs_bridge_add_flows() + self.nodes = self.setup_ovs_dpdk_context() + LOG.debug("Waiting for VM to come up...") + self.nodes = StandaloneContextHelper.wait_for_vnfs_to_start(self.connection, + self.servers, + self.nodes) + + def undeploy(self): + + if not self.vm_deploy: + return + + # Cleanup the ovs installation... + self.cleanup_ovs_dpdk_env() + + # Bind nics back to kernel + bind_cmd = "{dpdk_nic_bind} --force -b {driver} {port}" + for key, port in self.networks.items(): + vpci = port.get("phy_port") + phy_driver = port.get("driver") + self.connection.execute(bind_cmd.format(dpdk_nic_bind=self.dpdk_nic_bind, + driver=phy_driver, port=vpci)) + + # Todo: NFVi undeploy (sriov, vswitch, ovs etc) based on the config. + for vm in self.vm_names: + Libvirt.check_if_vm_exists_and_delete(vm, self.connection) + + def _get_server(self, attr_name): + """lookup server info by name from context + + Keyword arguments: + attr_name -- A name for a server listed in nodes config file + """ + node_name, name = self.split_name(attr_name) + if name is None or self.name != name: + return None + + matching_nodes = (n for n in self.nodes if n["name"] == node_name) + try: + # A clone is created in order to avoid affecting the + # original one. + node = dict(next(matching_nodes)) + except StopIteration: + return None + + try: + duplicate = next(matching_nodes) + except StopIteration: + pass + else: + raise ValueError("Duplicate nodes!!! Nodes: %s %s", + (node, duplicate)) + + node["name"] = attr_name + return node + + def _get_network(self, attr_name): + if not isinstance(attr_name, collections.Mapping): + network = self.networks.get(attr_name) + + else: + # Don't generalize too much Just support vld_id + vld_id = attr_name.get('vld_id', {}) + # for standalone context networks are dicts + iter1 = (n for n in self.networks.values() if n.get('vld_id') == vld_id) + network = next(iter1, None) + + if network is None: + return None + + result = { + # name is required + "name": network["name"], + "vld_id": network.get("vld_id"), + "segmentation_id": network.get("segmentation_id"), + "network_type": network.get("network_type"), + "physical_network": network.get("physical_network"), + } + return result + + def configure_nics_for_ovs_dpdk(self): + portlist = OrderedDict(self.networks) + for key, ports in portlist.items(): + mac = StandaloneContextHelper.get_mac_address() + portlist[key].update({'mac': mac}) + self.networks = portlist + LOG.info("Ports %s" % self.networks) + + def _enable_interfaces(self, index, vfs, cfg): + vpath = self.ovs_properties.get("vpath", "/usr/local") + vf = self.networks[vfs[0]] + port_num = vf.get('port_num', 0) + vpci = PciAddress.parse_address(vf['vpci'].strip(), multi_line=True) + # Generate the vpci for the interfaces + slot = index + port_num + 10 + vf['vpci'] = \ + "{}:{}:{:02x}.{}".format(vpci.domain, vpci.bus, slot, vpci.function) + Libvirt.add_ovs_interface(vpath, port_num, vf['vpci'], vf['mac'], str(cfg)) + + def setup_ovs_dpdk_context(self): + nodes = [] + + self.configure_nics_for_ovs_dpdk() + + for index, (key, vnf) in enumerate(OrderedDict(self.servers).items()): + cfg = '/tmp/vm_ovs_%d.xml' % index + vm_name = "vm_%d" % index + + # 1. Check and delete VM if already exists + Libvirt.check_if_vm_exists_and_delete(vm_name, self.connection) + + vcpu, mac = Libvirt.build_vm_xml(self.connection, self.vm_flavor, cfg, vm_name, index) + # 2: Cleanup already available VMs + for idx, (vkey, vfs) in enumerate(OrderedDict(vnf["network_ports"]).items()): + if vkey == "mgmt": + continue + self._enable_interfaces(index, vfs, cfg) + + # copy xml to target... + self.connection.put(cfg, cfg) + + # FIXME: launch through libvirt + LOG.info("virsh create ...") + Libvirt.virsh_create_vm(self.connection, cfg) + + # 5: Tunning for better performace + Libvirt.pin_vcpu_for_perf(self.connection, vm_name, vcpu) + self.vm_names.append(vm_name) + + # build vnf node details + nodes.append(self.vnf_node.generate_vnf_instance(self.vm_flavor, + self.networks, + self.host_mgmt.get('ip'), + key, vnf, mac)) + + return nodes diff --git a/yardstick/benchmark/contexts/standalone/ovsdpdk.py b/yardstick/benchmark/contexts/standalone/ovsdpdk.py deleted file mode 100644 index cf5529d89..000000000 --- a/yardstick/benchmark/contexts/standalone/ovsdpdk.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (c) 2016-2017 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. - -from __future__ import absolute_import -import os -import yaml -import time -import glob -import itertools -import logging -from yardstick import ssh -from yardstick.benchmark.contexts.standalone import StandaloneContext - -BIN_PATH = "/opt/isb_bin/" -DPDK_NIC_BIND = "dpdk_nic_bind.py" - -log = logging.getLogger(__name__) - -VM_TEMPLATE = """ - - vm1 - 18230c0c-635d-4c50-b2dc-a213d30acb34 - 20971520 - 20971520 - - - - 20 - - hvm - - - - - - - - - - - destroy - restart - destroy - - /usr/bin/qemu-system-x86_64 - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - - -class Ovsdpdk(StandaloneContext): - def __init__(self): - self.name = None - self.file_path = None - self.nodes = [] - self.vm_deploy = False - self.ovs = [] - self.first_run = True - self.dpdk_nic_bind = BIN_PATH + DPDK_NIC_BIND - self.user = "" - self.ssh_ip = "" - self.passwd = "" - self.ssh_port = "" - self.auth_type = "" - - def init(self): - '''initializes itself''' - log.debug("In init") - self.parse_pod_and_get_data() - - def parse_pod_and_get_data(self, file_path): - self.file_path = file_path - print("parsing pod file: {0}".format(self.file_path)) - try: - with open(self.file_path) as stream: - cfg = yaml.load(stream) - except IOError: - print("File {0} does not exist".format(self.file_path)) - raise - - self.ovs.extend([node for node in cfg["nodes"] - if node["role"] == "Ovsdpdk"]) - self.user = self.ovs[0]['user'] - self.ssh_ip = self.ovs[0]['ip'] - if self.ovs[0]['auth_type'] == "password": - self.passwd = self.ovs[0]['password'] - else: - self.ssh_port = self.ovs[0]['ssh_port'] - self.key_filename = self.ovs[0]['key_filename'] - - def ssh_remote_machine(self): - if self.ovs[0]['auth_type'] == "password": - self.connection = ssh.SSH( - self.user, - self.ssh_ip, - password=self.passwd) - self.connection.wait() - else: - if self.ssh_port is not None: - ssh_port = self.ssh_port - else: - ssh_port = ssh.DEFAULT_PORT - self.connection = ssh.SSH( - self.user, - self.ssh_ip, - port=ssh_port, - key_filename=self.key_filename) - self.connection.wait() - - def get_nic_details(self): - nic_details = {} - nic_details['interface'] = {} - nic_details['pci'] = self.ovs[0]['phy_ports'] - nic_details['phy_driver'] = self.ovs[0]['phy_driver'] - nic_details['vports_mac'] = self.ovs[0]['vports_mac'] - # Make sure that ports are bound to kernel drivers e.g. i40e/ixgbe - for i, _ in enumerate(nic_details['pci']): - err, out, _ = self.connection.execute( - "{dpdk_nic_bind} --force -b {driver} {port}".format( - dpdk_nic_bind=self.dpdk_nic_bind, - driver=self.ovs[0]['phy_driver'], - port=self.ovs[0]['phy_ports'][i])) - err, out, _ = self.connection.execute( - "lshw -c network -businfo | grep '{port}'".format( - port=self.ovs[0]['phy_ports'][i])) - a = out.split()[1] - err, out, _ = self.connection.execute( - "ip -s link show {interface}".format( - interface=out.split()[1])) - nic_details['interface'][i] = str(a) - print("{0}".format(nic_details)) - return nic_details - - def install_req_libs(self): - if self.first_run: - err, out, _ = self.connection.execute("apt-get update") - print("{0}".format(out)) - err, out, _ = self.connection.execute( - "apt-get -y install qemu-kvm libvirt-bin") - print("{0}".format(out)) - err, out, _ = self.connection.execute( - "apt-get -y install libvirt-dev bridge-utils numactl") - print("{0}".format(out)) - self.first_run = False - - def setup_ovs(self, vpcis): - self.connection.execute("/usr/bin/chmod 0666 /dev/vfio/*") - self.connection.execute("/usr/bin/chmod a+x /dev/vfio") - self.connection.execute("pkill -9 ovs") - self.connection.execute("ps -ef | grep ovs | grep -v grep | " - "awk '{print $2}' | xargs -r kill -9") - self.connection.execute("killall -r 'ovs*'") - self.connection.execute( - "mkdir -p {0}/etc/openvswitch".format(self.ovs[0]["vpath"])) - self.connection.execute( - "mkdir -p {0}/var/run/openvswitch".format(self.ovs[0]["vpath"])) - self.connection.execute( - "rm {0}/etc/openvswitch/conf.db".format(self.ovs[0]["vpath"])) - self.connection.execute( - "ovsdb-tool create {0}/etc/openvswitch/conf.db " - "{0}/share/openvswitch/" - "vswitch.ovsschema".format(self.ovs[0]["vpath"])) - self.connection.execute("modprobe vfio-pci") - self.connection.execute("chmod a+x /dev/vfio") - self.connection.execute("chmod 0666 /dev/vfio/*") - for vpci in vpcis: - self.connection.execute( - "/opt/isb_bin/dpdk_nic_bind.py " - "--bind=vfio-pci {0}".format(vpci)) - - def start_ovs_serverswitch(self): - self.connection.execute("mkdir -p /usr/local/var/run/openvswitch") - self.connection.execute( - "ovsdb-server --remote=punix:" - "/usr/local/var/run/openvswitch/db.sock --pidfile --detach") - self.connection.execute( - "ovs-vsctl --no-wait set " - "Open_vSwitch . other_config:dpdk-init=true") - self.connection.execute( - "ovs-vsctl --no-wait set " - "Open_vSwitch . other_config:dpdk-lcore-mask=0x3") - self.connection.execute( - "ovs-vsctl --no-wait set " - "Open_vSwitch . other_config:dpdk-socket-mem='2048,0'") - self.connection.execute( - "ovs-vswitchd unix:{0}/" - "var/run/openvswitch/db.sock --pidfile --detach " - "--log-file=/var/log/openvswitch/" - "ovs-vswitchd.log".format( - self.ovs[0]["vpath"])) - self.connection.execute( - "ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=2C") - - def setup_ovs_bridge(self): - self.connection.execute("ovs-vsctl del-br br0") - self.connection.execute( - "rm -rf /usr/local/var/run/openvswitch/dpdkvhostuser*") - self.connection.execute( - "ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev") - self.connection.execute( - "ovs-vsctl add-port br0 dpdk0 -- set Interface dpdk0 type=dpdk") - self.connection.execute( - "ovs-vsctl add-port br0 dpdk1 -- set Interface dpdk1 type=dpdk") - self.connection.execute( - "ovs-vsctl add-port br0 dpdkvhostuser0 -- set Interface " - "dpdkvhostuser0 type=dpdkvhostuser") - self.connection.execute("ovs-vsctl add-port br0 dpdkvhostuser1 " - "-- set Interface dpdkvhostuser1 " - "type=dpdkvhostuser") - self.connection.execute( - "chmod 0777 {0}/var/run/" - "openvswitch/dpdkvhostuser*".format(self.ovs[0]["vpath"])) - - def add_oflows(self): - self.connection.execute("ovs-ofctl del-flows br0") - for flow in self.ovs[0]["flow"]: - self.connection.execute(flow) - self.connection.execute("ovs-ofctl dump-flows br0") - self.connection.execute( - "ovs-vsctl set Interface dpdk0 options:n_rxq=4") - self.connection.execute( - "ovs-vsctl set Interface dpdk1 options:n_rxq=4") - - def setup_ovs_context(self, pcis, nic_details, host_driver): - - ''' 1: Setup vm_ovs.xml to launch VM.''' - cfg_ovs = '/tmp/vm_ovs.xml' - vm_ovs_xml = VM_TEMPLATE.format(vm_image=self.ovs[0]["images"]) - with open(cfg_ovs, 'w') as f: - f.write(vm_ovs_xml) - - ''' 2: Create and start the VM''' - self.connection.put(cfg_ovs, cfg_ovs) - time.sleep(10) - err, out = self.check_output("virsh list --name | grep -i vm1") - if out == "vm1": - print("VM is already present") - else: - ''' FIXME: launch through libvirt''' - print("virsh create ...") - err, out, _ = self.connection.execute( - "virsh create /tmp/vm_ovs.xml") - time.sleep(10) - print("err : {0}".format(err)) - print("{0}".format(_)) - print("out : {0}".format(out)) - - ''' 3: Tuning for better performace.''' - self.pin_vcpu(pcis) - self.connection.execute( - "echo 1 > /sys/module/kvm/parameters/" - "allow_unsafe_assigned_interrupts") - self.connection.execute( - "echo never > /sys/kernel/mm/transparent_hugepage/enabled") - print("After tuning performance ...") - - ''' This is roughly compatible with check_output function in subprocess - module which is only available in python 2.7.''' - def check_output(self, cmd, stderr=None): - '''Run a command and capture its output''' - err, out, _ = self.connection.execute(cmd) - return err, out - - def read_from_file(self, filename): - data = "" - with open(filename, 'r') as the_file: - data = the_file.read() - return data - - def write_to_file(self, filename, content): - with open(filename, 'w') as the_file: - the_file.write(content) - - def pin_vcpu(self, pcis): - nodes = self.get_numa_nodes() - print("{0}".format(nodes)) - num_nodes = len(nodes) - for i in range(0, 10): - self.connection.execute( - "virsh vcpupin vm1 {0} {1}".format( - i, nodes[str(num_nodes - 1)][i % len(nodes[str(num_nodes - 1)])])) - - def get_numa_nodes(self): - nodes_sysfs = glob.iglob("/sys/devices/system/node/node*") - nodes = {} - for node_sysfs in nodes_sysfs: - num = os.path.basename(node_sysfs).replace("node", "") - with open(os.path.join(node_sysfs, "cpulist")) as cpulist_file: - cpulist = cpulist_file.read().strip() - print("cpulist: {0}".format(cpulist)) - nodes[num] = self.split_cpu_list(cpulist) - print("nodes: {0}".format(nodes)) - return nodes - - def split_cpu_list(self, cpu_list): - if cpu_list: - ranges = cpu_list.split(',') - bounds = ([int(b) for b in r.split('-')] for r in ranges) - range_objects =\ - (range(bound[0], bound[1] + 1 if len(bound) == 2 - else bound[0] + 1) for bound in bounds) - - return sorted(itertools.chain.from_iterable(range_objects)) - else: - return [] - - def destroy_vm(self): - host_driver = self.ovs[0]['phy_driver'] - err, out = self.check_output("virsh list --name | grep -i vm1") - print("{0}".format(out)) - if err == 0: - self.connection.execute("virsh shutdown vm1") - self.connection.execute("virsh destroy vm1") - self.check_output("rmmod {0}".format(host_driver))[1].splitlines() - self.check_output("modprobe {0}".format(host_driver))[ - 1].splitlines() - else: - print("error : ", err) diff --git a/yardstick/benchmark/contexts/standalone/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py index fe27d2579..55d7057a9 100644 --- a/yardstick/benchmark/contexts/standalone/sriov.py +++ b/yardstick/benchmark/contexts/standalone/sriov.py @@ -14,418 +14,248 @@ from __future__ import absolute_import import os -import yaml -import re -import time -import glob -import uuid -import random import logging -import itertools -import xml.etree.ElementTree as ET +import collections +from collections import OrderedDict + from yardstick import ssh from yardstick.network_services.utils import get_nsb_option from yardstick.network_services.utils import provision_tool -from yardstick.benchmark.contexts.standalone import StandaloneContext - -log = logging.getLogger(__name__) - -VM_TEMPLATE = """ - - vm1 - {random_uuid} - 102400 - 102400 - - - - 20 - - hvm - - - - - - - - - SandyBridge - - - - - - - - destroy - restart - restart - - /usr/bin/kvm-spice - - - - -
- - -
- - - -
- - - -
- - - -
- - - - - - - - - - - - -