From c9cd093f2f441adc9dd33627255326008e021a67 Mon Sep 17 00:00:00 2001 From: Martin Klozik Date: Tue, 16 Aug 2016 14:59:05 +0100 Subject: multi VM: Multi VMs in serial or parallel Support for deployment scenarios with any number of VMs in both serial and parallel configuration. Detailed content of the patch: * VswitchControllerPXP class for multi VM support * pvvpxx and pvpvxx deployments for xx VMs in serial respective parallel configuration * special GUEST_ options expansion to requested number of VMs; * support of GUEST_ options specific macros #VMINDEX, #MAC(), #IP() and #EVAL() * all GUEST specific options are turned to lists to be VM specific * support for VM with 1 NIC * support for VM with multiple NIC pairs; traffic is routed in serial or parallel between NIC paris based on deployment scenario * support for PVVP and PVPV scenarios using VMs with different numbers of NICs JIRA: VSPERF-361 Change-Id: I05bedbdfa9a81ea0166d9b03d83ae49d6cb8b19b Signed-off-by: Martin Klozik Reviewed-by: Maryam Tahhan Reviewed-by: Al Morton Reviewed-by: Christian Trautman Reviewed-by: Bill Michalowski Reviewed-by: Antonio Fischetti --- conf/01_testcases.conf | 8 +++ conf/02_vswitch.conf | 8 +-- conf/04_vnf.conf | 168 +++++++++++++++++++++++++++---------------------- conf/__init__.py | 75 +++++++++++++++++++++- 4 files changed, 175 insertions(+), 84 deletions(-) (limited to 'conf') diff --git a/conf/01_testcases.conf b/conf/01_testcases.conf index 23a3ae57..b9c59a11 100755 --- a/conf/01_testcases.conf +++ b/conf/01_testcases.conf @@ -170,6 +170,14 @@ PERFORMANCE_TESTS = [ "biDirectional": "True", "iLoad": "100", }, + { + "Name": "pvpv_cont", + "Traffic Type": "continuous", + "Deployment": "pvpv", + "Description": "Two VMs in parallel with Continuous Stream", + "biDirectional": "True", + "iLoad": "100", + }, { "Name": "phy2phy_scalability", "Traffic Type": "rfc2544", diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf index cd2b8d26..abca63bb 100644 --- a/conf/02_vswitch.conf +++ b/conf/02_vswitch.conf @@ -60,13 +60,7 @@ SYS_MODULES = ['uio', 'cuse'] VHOST_DEV_FILE = 'ovs-vhost-net' # location of vhost-user sockets -VHOST_USER_SOCKS = ['/tmp/dpdkvhostuser0', '/tmp/dpdkvhostuser1', - '/tmp/dpdkvhostuser2', '/tmp/dpdkvhostuser3', - '/tmp/dpdkvhostuser4', '/tmp/dpdkvhostuser5', - '/tmp/dpdkvhostuser6', '/tmp/dpdkvhostuser7', - '/tmp/dpdkvhostuser8', '/tmp/dpdkvhostuser9', - '/tmp/dpdkvhostuser10', '/tmp/dpdkvhostuser11', - '/tmp/myport0', '/tmp/helloworld123', '/tmp/abcstuff0'] +VHOST_USER_SOCKS = os.path.join(OVS_VAR_DIR, 'dpdkvhostuser*') # ############################ # vswitch configuration diff --git a/conf/04_vnf.conf b/conf/04_vnf.conf index 05893fb8..2e86b358 100644 --- a/conf/04_vnf.conf +++ b/conf/04_vnf.conf @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# 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. @@ -17,30 +17,68 @@ # ############################ VNF_DIR = 'vnfs/' VNF = 'QemuDpdkVhostUser' +VNF_AFFINITIZATION_ON = True + +# ############################ +# Executables and log files +# ############################ + +QEMU_BIN = os.path.join(QEMU_DIR, 'x86_64-softmmu/qemu-system-x86_64') + +# log file for qemu +LOG_FILE_QEMU = 'qemu.log' + +# log file for all commands executed on guest(s) +# multiple guests will result in log files with the guest number appended +LOG_FILE_GUEST_CMDS = 'guest-cmds.log' # ############################ # Guest configuration # ############################ +# All configuration options related to a particular VM instance are defined as +# lists and prefixed with `GUEST_` label. It is essential, that there is enough +# items in all `GUEST_` options to cover all VM instances involved in the test. +# In case there is not enough items, then VSPERF will use the first item of +# particular `GUEST_` option to expand the list to required length. First option +# can contain macros starting with `#` to generate VM specific values. These +# macros can be used only for options of `list` or `str` types with `GUEST_` +# prefix. +# Following macros are supported: +# +# * #VMINDEX - it is replaced by index of VM being executed; This macro is +# expanded first, so it can be used inside other macros. +# +# * #MAC(mac_address[, step]) - it will iterate given `mac_address` with +# optional `step`. In case that step is not defined, then it is set to 1. +# It means, that first VM will use the value of `mac_address`, second VM +# value of `mac_address` increased by `step`, etc. +# +# * #IP(ip_address[, step]) - it will iterate given `ip_address` with optional +# step. In case that step is not defined, then it is set to 1. +# It means, that first VM will use the value of `ip_address`, second VM +# value of `ip_address` increased by `step`, etc. +# +# * #EVAL(expression) - it will evaluate given `expression` as python code; +# Only simple expressions should be used. Call of the functions is not +# supported. # directory which is shared to QEMU guests. Useful for exchanging files # between host and guest, VNF specific share will be created # For 2 VNFs you may use ['/tmp/qemu0_share', '/tmp/qemu1_share'] -GUEST_SHARE_DIR = ['/tmp/qemu0_share', '/tmp/qemu1_share', \ - '/tmp/qemu2_share', '/tmp/qemu3_share', \ - '/tmp/qemu4_share', '/tmp/qemu5_share'] +GUEST_SHARE_DIR = ['/tmp/qemu0_share'] # location of guest disk image # For 2 VNFs you may use ['guest1.img', 'guest2.img'] -GUEST_IMAGE = ['', '', '', '', '', ''] +GUEST_IMAGE = [''] # guarding timer for VM start up # For 2 VNFs you may use [180, 180] -GUEST_TIMEOUT = [180, 180, 180, 180, 180, 180] +GUEST_TIMEOUT = [180] # Guest images may require different drive types such as ide to mount shared # locations and/or boot correctly. You can modify the types here. -GUEST_BOOT_DRIVE_TYPE = 'scsi' -GUEST_SHARED_DRIVE_TYPE = 'scsi' +GUEST_BOOT_DRIVE_TYPE = ['scsi'] +GUEST_SHARED_DRIVE_TYPE = ['scsi'] # packet forwarding mode supported by testpmd; Please see DPDK documentation # for comprehensive list of modes supported by your version. @@ -57,71 +95,50 @@ GUEST_TESTPMD_FWD_MODE = 'csum' # This configuration option can be overridden by CLI SCALAR option # guest_loopback, e.g. --test-params "guest_loopback=l2fwd" # For 2 VNFs you may use ['testpmd', 'l2fwd'] -GUEST_LOOPBACK = ['testpmd', 'testpmd', \ - 'testpmd', 'testpmd', \ - 'testpmd', 'testpmd'] +GUEST_LOOPBACK = ['testpmd'] # username for guest image -GUEST_USERNAME = 'root' +GUEST_USERNAME = ['root'] # password for guest image -GUEST_PASSWORD = 'root' +GUEST_PASSWORD = ['root'] # login username prompt for guest image -GUEST_PROMPT_LOGIN = '.* login:' +GUEST_PROMPT_LOGIN = ['.* login:'] # login password prompt for guest image -GUEST_PROMPT_PASSWORD = 'Password: ' +GUEST_PROMPT_PASSWORD = ['Password: '] # standard prompt for guest image -GUEST_PROMPT = 'root.*#' +GUEST_PROMPT = ['root.*#'] -# log file for qemu -LOG_FILE_QEMU = 'qemu.log' +# defines the number of NICs configured for each guest, it must be less or equal to +# the number of NICs configured in GUEST_NICS +GUEST_NICS_NR = [2] -# log file for all commands executed on guest(s) -# multiple guests will result in log files with the guest number appended -LOG_FILE_GUEST_CMDS = 'guest-cmds.log' +# template for guests with 4 NICS, but only GUEST_NICS_NR NICS will be configured at runtime +GUEST_NICS = [[{'device' : 'eth0', 'mac' : '#MAC(00:00:00:00:00:01,2)', 'pci' : '00:04.0', 'ip' : '#IP(192.168.1.2,4)/24'}, + {'device' : 'eth1', 'mac' : '#MAC(00:00:00:00:00:02,2)', 'pci' : '00:05.0', 'ip' : '#IP(192.168.1.3,4)/24'}, + {'device' : 'eth2', 'mac' : '#MAC(cc:00:00:00:00:01,2)', 'pci' : '00:06.0', 'ip' : '#IP(192.168.1.4,4)/24'}, + {'device' : 'eth3', 'mac' : '#MAC(cc:00:00:00:00:02,2)', 'pci' : '00:07.0', 'ip' : '#IP(192.168.1.5,4)/24'}, + ]] -# ############################ -# Executables -# ############################ - -QEMU_BIN = os.path.join(QEMU_DIR, 'x86_64-softmmu/qemu-system-x86_64') - -# For 2 VNFs you may use ['eth0', 'eth2'] -GUEST_NIC1_NAME = ['eth0', 'eth0', 'eth0', 'eth0', 'eth0', 'eth0'] -GUEST_NIC2_NAME = ['eth1', 'eth1', 'eth1', 'eth1', 'eth1', 'eth1'] - -# For 2 VNFs you may use ['00:00:00:00:00:01', '00:00:00:00:00:03'] -GUEST_NET1_MAC = ['00:00:00:00:00:01', '00:00:00:00:00:03', \ - '00:00:00:00:00:05', '00:00:00:00:00:07', \ - '00:00:00:00:00:09', '00:00:00:00:00:0b'] -GUEST_NET2_MAC = ['00:00:00:00:00:02', '00:00:00:00:00:04', \ - '00:00:00:00:00:06', '00:00:00:00:00:08', \ - '00:00:00:00:00:0a', '00:00:00:00:00:0c'] - -# For 2 VNFs you may use ['00:04.0', '00:04.0'] -GUEST_NET1_PCI_ADDRESS = ['00:04.0', '00:04.0', \ - '00:04.0', '00:04.0', \ - '00:04.0', '00:04.0'] -GUEST_NET2_PCI_ADDRESS = ['00:05.0', '00:05.0', \ - '00:05.0', '00:05.0', \ - '00:05.0', '00:05.0'] - -GUEST_MEMORY = ['4096', '4096', '2048', '2048', '2048', '2048'] +# amount of host memory allocated for each guest +GUEST_MEMORY = ['2048'] +# number of hugepages configured inside each guest +GUEST_HUGEPAGES_NR = ['1024'] # test-pmd requires 2 VM cores -GUEST_SMP = ['2', '2', '2', '2', '2', '2'] +GUEST_SMP = ['2'] # Host cores to use to affinitize the SMP cores of a QEMU instance # For 2 VNFs you may use [(4,5), (6, 7)] -GUEST_CORE_BINDING = [(6, 7), (9, 10), (11, 12), (13, 14), (15, 16), (17, 18)] +GUEST_CORE_BINDING = [('#EVAL(6+2*#VMINDEX)', '#EVAL(7+2*#VMINDEX)')] # Queues per NIC inside guest for multi-queue configuration, requires switch # multi-queue to be enabled for dpdk. Set to 0 for disabled. Can be enabled if # using Vanilla OVS without enabling switch multi-queue. -GUEST_NIC_QUEUES = 0 +GUEST_NIC_QUEUES = [0] # Virtio-Net vhost thread CPU mapping. If using vanilla OVS with virtio-net, # you can affinitize the vhost-net threads by enabling the below setting. There @@ -131,22 +148,11 @@ GUEST_NIC_QUEUES = 0 VSWITCH_VHOST_NET_AFFINITIZATION = False VSWITCH_VHOST_CPU_MAP = [4,5,8,11] -GUEST_START_TIMEOUT = 120 -GUEST_OVS_DPDK_DIR = '/root/ovs_dpdk' -OVS_DPDK_SHARE = '/mnt/ovs_dpdk_share' - -# Set the CPU mask for testpmd loopback. To bind to specific guest CPUs use -l -# GUEST_TESTPMD_CPU_MASK = '-l 0,1' -GUEST_TESTPMD_CPU_MASK = '-c 0x3' - -# Testpmd multi-core config. Leave at 0's for disabled. Will not enable unless -# GUEST_NIC_QUEUES are > 0. For bi directional traffic NB_CORES must be equal -# to (RXQ + TXQ). -GUEST_TESTPMD_NB_CORES = 0 -GUEST_TESTPMD_TXQ = 0 -GUEST_TESTPMD_RXQ = 0 +GUEST_START_TIMEOUT = [120] +GUEST_OVS_DPDK_DIR = ['/root/ovs_dpdk'] +GUEST_OVS_DPDK_SHARE = ['/mnt/ovs_dpdk_share'] -# IP addresses to use for Vanilla OVS PVP testing +# IP addresses to use for Vanilla OVS PXP testing # Consider using RFC 2544/3330 recommended IP addresses for benchmark testing. # Network: 198.18.0.0/15 # Netmask: 255.254.0.0 @@ -163,15 +169,25 @@ VANILLA_TGEN_PORT1_MAC = 'AA:BB:CC:DD:EE:FF' VANILLA_TGEN_PORT2_IP = '1.1.2.10' VANILLA_TGEN_PORT2_MAC = 'AA:BB:CC:DD:EE:F0' -VANILLA_BRIDGE_IP = ['1.1.1.5/16', '1.1.1.6/16', \ - '1.1.1.7/16', '1.1.1.8/16', \ - '1.1.1.9/16', '1.1.1.10/16'] +GUEST_BRIDGE_IP = ['#IP(1.1.1.5)/16'] + +# ############################ +# Guest TESTPMD configuration +# ############################ + +# packet forwarding mode supported by testpmd; Please see DPDK documentation +# for comprehensive list of modes supported by your version. +# e.g. io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho|... +# Note: Option "mac_retry" has been changed to "mac retry" since DPDK v16.07 +GUEST_TESTPMD_FWD_MODE = ['csum'] -VANILLA_NIC1_IP_CIDR = ['192.168.1.2/24', '192.168.1.4/24', \ - '192.168.1.6/24', '192.168.1.8/24', \ - '192.168.1.10/24', '192.168.1.12/24'] -VANILLA_NIC2_IP_CIDR = ['192.168.1.3/24', '192.168.1.5/24', \ - '192.168.1.7/24', '192.168.1.9/24', \ - '192.168.1.11/24', '192.168.1.13/24'] +# Set the CPU mask for testpmd loopback. To bind to specific guest CPUs use -l +# GUEST_TESTPMD_CPU_MASK = ['-l 0,1'] +GUEST_TESTPMD_CPU_MASK = ['-c 0x3'] -VNF_AFFINITIZATION_ON = True +# Testpmd multi-core config. Leave at 0's for disabled. Will not enable unless +# GUEST_NIC_QUEUES are > 0. For bi directional traffic NB_CORES must be equal +# to (RXQ + TXQ). +GUEST_TESTPMD_NB_CORES = [0] +GUEST_TESTPMD_TXQ = [0] +GUEST_TESTPMD_RXQ = [0] diff --git a/conf/__init__.py b/conf/__init__.py index 46228235..88e8cec6 100644 --- a/conf/__init__.py +++ b/conf/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# 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. @@ -22,7 +22,22 @@ and any user provided settings file. import os import re +import logging import pprint +import ast +import netaddr + +_LOGGER = logging.getLogger(__name__) + +# regex to parse configuration macros from 04_vnf.conf +# it will select all patterns starting with # sign +# and returns macro parameters and step +# examples of valid macros: +# #VMINDEX +# #MAC(AA:BB:CC:DD:EE:FF) or #MAC(AA:BB:CC:DD:EE:FF,2) +# #IP(192.168.1.2) or #IP(192.168.1.2,2) +# #EVAL(2*#VMINDEX) +_PARSE_PATTERN = r'(#[A-Z]+)(\(([^(),]+)(,([0-9]+))?\))?' class Settings(object): """Holding class for settings. @@ -121,6 +136,64 @@ class Settings(object): for key in os.environ: setattr(self, key, os.environ[key]) + def check_vm_settings(self, vm_number): + """ + Check all VM related settings starting with GUEST_ prefix. + If it is not available for defined number of VMs, then vsperf + will try to expand it automatically. Expansion is performed + also in case that first list item contains a macro. + """ + for key in self.__dict__: + if key.startswith('GUEST_'): + if (isinstance(self.__dict__[key], str) and + self.__dict__[key].find('#') >= 0): + self.__dict__[key] = [self.__dict__[key]] + self._expand_vm_settings(key, 1) + self.__dict__[key] = self.__dict__[key][0] + + if isinstance(self.__dict__[key], list): + if (len(self.__dict__[key]) < vm_number or + str(self.__dict__[key][0]).find('#') >= 0): + # expand configuration for all VMs + self._expand_vm_settings(key, vm_number) + + def _expand_vm_settings(self, key, vm_number): + """ + Expand VM option with given key for given number of VMs + """ + master_value = self.__dict__[key][0] + master_value_str = str(master_value) + if master_value_str.find('#') >= 0: + self.__dict__[key] = [] + for vmindex in range(vm_number): + value = master_value_str.replace('#VMINDEX', str(vmindex)) + for macro, args, param, _, step in re.findall(_PARSE_PATTERN, value): + multi = int(step) if len(step) and int(step) else 1 + if macro == '#EVAL': + tmp_result = str(eval(param)) + elif macro == '#MAC': + mac_value = netaddr.EUI(param).value + mac = netaddr.EUI(mac_value + vmindex * multi) + mac.dialect = netaddr.mac_unix_expanded + tmp_result = str(mac) + elif macro == '#IP': + ip_value = netaddr.IPAddress(param).value + tmp_result = str(netaddr.IPAddress(ip_value + vmindex * multi)) + else: + raise RuntimeError('Unknown configuration macro {} in {}'.format(macro, key)) + + value = value.replace("{}{}".format(macro, args), tmp_result) + + # retype value to original type if needed + if not isinstance(master_value, str): + value = ast.literal_eval(value) + self.__dict__[key].append(value) + else: + for vmindex in range(len(self.__dict__[key]), vm_number): + self.__dict__[key].append(master_value) + + _LOGGER.debug("Expanding option: %s = %s", key, self.__dict__[key]) + def __str__(self): """Provide settings as a human-readable string. -- cgit 1.2.3-korg