From 0a1d1ffb8134806e86a78c6b5577f7eff34e4400 Mon Sep 17 00:00:00 2001 From: Ace Lee Date: Fri, 8 Dec 2017 09:13:58 +0000 Subject: Add l2fwd module in Tgen mode JIRA: YARDSTICK-796 Add l2fwd testcase in Tgen mode(Moongen) fix offiline problem in Tgen mode. Change-Id: I2ee224157a4f1d78e85fcae192a65afd33a1a515 Signed-off-by: Ace Lee --- ansible/roles/download_l2fwd/defaults/main.yml | 4 + ansible/roles/download_l2fwd/tasks/main.yml | 28 ++ ansible/ubuntu_server_cloudimg_modify.yml | 1 + samples/MoongenL2fwd.yaml | 96 ++++++ samples/MoongenTestPMD.yaml | 106 ++++++ .../scenarios/networking/moongen_testpmd.bash | 62 ++++ .../scenarios/networking/moongen_testpmd.py | 378 +++++++++++++++++++++ .../scenarios/networking/test_moongen_testpmd.py | 353 +++++++++++++++++++ 8 files changed, 1028 insertions(+) create mode 100644 ansible/roles/download_l2fwd/defaults/main.yml create mode 100644 ansible/roles/download_l2fwd/tasks/main.yml create mode 100644 samples/MoongenL2fwd.yaml create mode 100644 samples/MoongenTestPMD.yaml create mode 100644 yardstick/benchmark/scenarios/networking/moongen_testpmd.bash create mode 100644 yardstick/benchmark/scenarios/networking/moongen_testpmd.py create mode 100644 yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py diff --git a/ansible/roles/download_l2fwd/defaults/main.yml b/ansible/roles/download_l2fwd/defaults/main.yml new file mode 100644 index 000000000..1bc76ef3e --- /dev/null +++ b/ansible/roles/download_l2fwd/defaults/main.yml @@ -0,0 +1,4 @@ +--- +l2fwd_url: "http://artifacts.opnfv.org/yardstick/third-party/l2fwd.tar" +l2fwd_file: "l2fwd.tar" +l2fwd_dest: "/home" diff --git a/ansible/roles/download_l2fwd/tasks/main.yml b/ansible/roles/download_l2fwd/tasks/main.yml new file mode 100644 index 000000000..7f2ea25c4 --- /dev/null +++ b/ansible/roles/download_l2fwd/tasks/main.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# 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. +--- +- file: + path: "{{ l2fwd_dest }}" + state: directory + +- name: fetch dpdk + get_url: + url: "{{ l2fwd_url }}" + dest: "{{ l2fwd_dest }}" + +- unarchive: + src: "{{ l2fwd_dest }}/{{ l2fwd_file }}" + dest: "{{ l2fwd_dest }}/" + copy: no + mode: 0777 diff --git a/ansible/ubuntu_server_cloudimg_modify.yml b/ansible/ubuntu_server_cloudimg_modify.yml index 099d5803f..90235cc81 100644 --- a/ansible/ubuntu_server_cloudimg_modify.yml +++ b/ansible/ubuntu_server_cloudimg_modify.yml @@ -27,6 +27,7 @@ - modify_cloud_config - role: set_package_installer_proxy when: proxy_env is defined and proxy_env + - download_l2fwd - install_image_dependencies - download_unixbench - install_unixbench diff --git a/samples/MoongenL2fwd.yaml b/samples/MoongenL2fwd.yaml new file mode 100644 index 000000000..8c00bfec6 --- /dev/null +++ b/samples/MoongenL2fwd.yaml @@ -0,0 +1,96 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# 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 specific configuration file for execution of RFC2544 throughput +# traffic. Traffic executed by traffic generator is forwarded directly +# between interfaces connected to the traffic generator. So test will only +# benchmark the performance of OVS external bridge at controller node. +# Details about supported test options and test case execution can be +# found in VSPERF documentation: +# +# http://artifacts.opnfv.org/vswitchperf/docs/userguide/yardstick.html + +schema: "yardstick:task:0.1" + +scenarios: +{% for multistream in [1, 1000] %} +- + type: MoongenTestPMD + options: + multistream: {{multistream}} + frame_size: 1024 + testpmd_queue: 2 + trafficgen_port1: 'ens4' + trafficgen_port2: 'ens5' + moongen_host_user: 'root' + moongen_host_passwd: 'root' + moongen_host_ip: '192.168.37.2' + moongen_dir: '/home/lua-trafficgen' + moongen_runBidirec: 'true' + Package_Loss: 0 + SearchRuntime: 60 + moongen_port1_mac: '88:cf:98:2f:4d:ed' + moongen_port2_mac: '88:cf:98:2f:4d:ee' + forward_type: 'l2fwd' + + host: testpmd.demo + + runner: + type: Sequence + scenario_option_name: frame_size + sequence: + - 64 + + sla: + # The throughput SLA (or any other SLA) cannot be set to a meaningful + # value without knowledge of the server and networking environment, + # possibly including prior testing in that environment to establish + # a baseline SLA level under well-understood circumstances. + throughput_rx_mpps: 0.5 +{% endfor %} + +context: + name: demo + image: yardstick-image + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:mem_page_size: "1GB" + hw:cpu_policy: "dedicated" + hw:vif_multiqueue_enabled: "true" + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + testpmd: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' + test2: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + test3: + cidr: '10.0.3.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' diff --git a/samples/MoongenTestPMD.yaml b/samples/MoongenTestPMD.yaml new file mode 100644 index 000000000..b389a19bc --- /dev/null +++ b/samples/MoongenTestPMD.yaml @@ -0,0 +1,106 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# 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 specific configuration file for execution of RFC2544 throughput +# traffic. Traffic executed by traffic generator is forwarded directly +# between interfaces connected to the traffic generator. So test will only +# benchmark the performance of OVS external bridge at controller node. +# Details about supported test options and test case execution can be +# found in VSPERF documentation: +# +# http://artifacts.opnfv.org/vswitchperf/docs/userguide/yardstick.html + +schema: "yardstick:task:0.1" + +scenarios: +{% for multistream in [1, 1000] %} +- + type: MoongenTestPMD + options: + multistream: {{multistream}} + frame_size: 1024 + testpmd_queue: 2 + trafficgen_port1: 'ens5' + trafficgen_port2: 'ens6' + moongen_host_user: 'root' + moongen_host_passwd: 'root' + moongen_host_ip: '192.168.37.2' + moongen_dir: '/home/lua-trafficgen' + moongen_runBidirec: 'true' + Package_Loss: 0 + SearchRuntime: 60 + moongen_port1_mac: '88:cf:98:2f:4d:ed' + moongen_port2_mac: '88:cf:98:2f:4d:ee' + forward_type: 'testpmd' + + host: testpmd.demo + + runner: + type: Sequence + scenario_option_name: frame_size + sequence: + - 64 + + sla: + # The throughput SLA (or any other SLA) cannot be set to a meaningful + # value without knowledge of the server and networking environment, + # possibly including prior testing in that environment to establish + # a baseline SLA level under well-understood circumstances. + throughput_rx_mpps: 0.5 +{% endfor %} + +context: + name: demo + #image: yardstick-image + image: yardstick-nsb-image + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:mem_page_size: "1GB" + hw:cpu_policy: "dedicated" + hw:vif_multiqueue_enabled: "true" + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + testpmd: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1063" + test2: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1061" + #port_security_enabled: False + enable_dhcp: 'false' + test3: + cidr: '10.0.3.0/24' + provider: "sriov" + physical_network: "sriov2" + segmentation_id: "1062" + gateway_ip: 'null' + #port_security_enabled: False + enable_dhcp: 'false' diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash b/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash new file mode 100644 index 000000000..3e92cc900 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.bash @@ -0,0 +1,62 @@ +############################################################################## +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +#!/bin/bash + +set -e + +# Commandline arguments +MOONGEN_PORT1_MAC=$1 # MAC address of the peer port +MOONGEN_PORT2_MAC=$2 # MAC address of the peer port +TESTPMD_QUEUE=$3 + +BIND_ROOT='/opt/nsb_bin' +DRIVER_ROOT='/opt/tempT/dpdk-17.02/' + +load_modules() +{ + if ! lsmod | grep "uio" &> /dev/null; then + modprobe uio + fi + + if ! lsmod | grep "igb_uio" &> /dev/null; then + insmod ${DRIVER_ROOT}/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko + fi + + if ! lsmod | grep "rte_kni" &> /dev/null; then + insmod ${DRIVER_ROOT}/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko + fi +} + +change_permissions() +{ + chmod 777 /sys/bus/pci/drivers/virtio-pci/* + chmod 777 /sys/bus/pci/drivers/igb_uio/* +} + +add_interface_to_dpdk(){ + interfaces=$(lspci |grep Eth |tail -n +2 |awk '{print $1}') + ${BIND_ROOT}/dpdk_nic_bind.py --bind=igb_uio $interfaces &> /dev/null +} + +run_testpmd() +{ + blacklist=$(lspci |grep Eth |awk '{print $1}'|head -1) + cd ${DRIVER_ROOT} + sudo ./x86_64-native-linuxapp-gcc/app/testpmd -c 0x3f -n 4 -b $blacklist -- -a --nb-cores=4 --coremask=0x3c --burst=64 --txd=4096 --rxd=4096 --rxq=$TESTPMD_QUEUE --txq=$TESTPMD_QUEUE --rss-udp --eth-peer=0,$MOONGEN_PORT1_MAC --eth-peer=1,$MOONGEN_PORT2_MAC --forward-mode=mac +} + +main() +{ + load_modules + change_permissions + add_interface_to_dpdk + run_testpmd +} + +main diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py new file mode 100644 index 000000000..86173c9da --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py @@ -0,0 +1,378 @@ +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# +# 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. +""" VsperfDPDK specific scenario definition """ + +from __future__ import absolute_import +import pkg_resources +import logging +import subprocess +import time +import re +from oslo_serialization import jsonutils + +import yardstick.ssh as ssh +import yardstick.common.utils as utils +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class MoongenTestPMD(base.Scenario): + """Execute vsperf with defined parameters + + Parameters: + frame_size - a frame size for which test should be executed; + Multiple frame sizes can be tested by modification of sequence runner + section inside TC YAML definition. + type: string + default: "64" + multistream - the number of simulated streams + type: string + default: 0 (disabled) + testpmd_queue - specifies how many queues you will use the VM + only useful when forward_type is true. + type: int + default: 1(one queue) + trafficgen_port1 - specifies device name of 1st interface connected to + the trafficgen + type: string + default: NA + trafficgen_port2 - specifies device name of 2nd interface connected to + the trafficgen + type: string + default: NA + moongen_host_user - specifies moongen host ssh user name + type: string + default: root + moongen_host_passwd - specifies moongen host ssh user password + type: string + default: root + moongen_host_ip - specifies moongen host ssh ip address + type: string + default NA + moongen_dir - specifies where is the moongen installtion dir + type: string + default NA + moongen_runBidirec - specifies moongen will run in one traffic + or two traffic. + type: string + default true + Package_Loss - specifies the package_Loss number in moongen server. + type: int + default 0(0%) + SearchRuntime - specifies the SearchRuntime and validation time + on moongen server. + type: int + default 60(s) + moongen_port1_mac - moongen server port1 mac address. + type: string + default NA + moongen_port2_mac - moongen server port2 mac address. + type: string + default NA + forward_type - VM forward type is l2fwd or testpmd. + type: string + default: testpmd + """ + __scenario_type__ = "MoongenTestPMD" + + TESTPMD_SCRIPT = 'moongen_testpmd.bash' + VSPERF_CONFIG = '/tmp/opnfv-vsperf-cfg.lua' + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.forward_setup_done = False + self.options = scenario_cfg.get('options', {}) + self.moongen_host_user = \ + self.options.get('moongen_host_user', "root") + self.moongen_host_passwd = \ + self.options.get('moongen_host_passwd', "r00t") + self.moongen_dir = \ + self.options.get('moongen_dir', '~/moongen.py') + self.testpmd_queue = \ + self.options.get('testpmd_queue', 1) + self.moongen_host_ip = \ + self.options.get('moongen_host_ip', "127.0.0.1") + self.moongen_port1_mac = \ + self.options.get('moongen_port1_mac', None) + self.moongen_port2_mac = \ + self.options.get('moongen_port2_mac', None) + self.tg_port1 = \ + self.options.get('trafficgen_port1', "enp2s0f0") + self.tg_port2 = \ + self.options.get('trafficgen_port2', "enp2s0f1") + self.forward_type = \ + self.options.get('forward_type', 'testpmd') + self.tgen_port1_mac = None + self.tgen_port2_mac = None + + def setup(self): + """scenario setup""" + host = self.context_cfg['host'] + + task_id = self.scenario_cfg['task_id'] + context_number = task_id.split('-')[0] + self.tg_port1_nw = 'demo' + \ + "-" + context_number + "-" + \ + self.options.get('trafficgen_port1_nw', 'test2') + self.tg_port2_nw = 'demo' + \ + "-" + context_number + "-" + \ + self.options.get('trafficgen_port2_nw', 'test3') + + # copy vsperf conf to VM + self.client = ssh.SSH.from_node(host, defaults={"user": "ubuntu"}) + # traffic generation could last long + self.client.wait(timeout=1800) + + self.server = ssh.SSH( + self.moongen_host_user, + self.moongen_host_ip, + password=self.moongen_host_passwd + ) + # traffic generation could last long + self.server.wait(timeout=1800) + + self.setup_done = True + + def forward_setup(self): + """forward tool setup""" + + # setup forward loopback in VM + self.testpmd_script = pkg_resources.resource_filename( + 'yardstick.benchmark.scenarios.networking', + self.TESTPMD_SCRIPT) + + self.client._put_file_shell(self.testpmd_script, + '~/testpmd_vsperf.sh') + + # disable Address Space Layout Randomization (ASLR) + cmd = "echo 0 | sudo tee /proc/sys/kernel/randomize_va_space" + self.client.send_command(cmd) + + if not self._is_forward_setup(): + self.tgen_port1_ip = \ + utils.get_port_ip(self.client, self.tg_port1) + self.tgen_port1_mac = \ + utils.get_port_mac(self.client, self.tg_port1) + self.client.run("tee ~/.testpmd.ipaddr.port1 > /dev/null", + stdin=self.tgen_port1_ip) + self.client.run("tee ~/.testpmd.macaddr.port1 > /dev/null", + stdin=self.tgen_port1_mac) + self.tgen_port2_ip = \ + utils.get_port_ip(self.client, self.tg_port2) + self.tgen_port2_mac = \ + utils.get_port_mac(self.client, self.tg_port2) + self.client.run("tee ~/.testpmd.ipaddr.port2 > /dev/null", + stdin=self.tgen_port2_ip) + self.client.run("tee ~/.testpmd.macaddr.port2 > /dev/null", + stdin=self.tgen_port2_mac) + else: + cmd = "cat ~/.testpmd.macaddr.port1" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port1_mac = stdout + cmd = "cat ~/.testpmd.ipaddr.port1" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port1_ip = stdout + cmd = "cat ~/.testpmd.macaddr.port2" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port2_mac = stdout + cmd = "cat ~/.testpmd.ipaddr.port2" + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + self.tgen_port2_ip = stdout + + LOG.info("forward type is %s", self.forward_type) + if self.forward_type == 'testpmd': + cmd = "sudo ip link set %s down" % (self.tg_port1) + LOG.debug("Executing command: %s", cmd) + self.client.execute(cmd) + cmd = "sudo ip link set %s down" % (self.tg_port2) + LOG.debug("Executing command: %s", cmd) + self.client.execute(cmd) + cmd = "screen -d -m sudo -E bash ~/testpmd_vsperf.sh %s %s %d" % \ + (self.moongen_port1_mac, self.moongen_port2_mac, + self.testpmd_queue) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + + elif self.forward_type == 'l2fwd': + cmd = ('sed -i "s/static char *net1 = \\\"eth1\\\";' + '/static char *net1 = \\\"%s %s %s\\\";/g" /home/l2fwd/l2fwd.c' + % (self.tg_port1, self.tgen_port1_ip, self.moongen_port1_mac)) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + cmd = ('sed -i "s/static char *net2 = \\\"eth2\\\";' + '/static char *net2 = \\\"%s %s %s\\\";/g" /home/l2fwd/l2fwd.c' + % (self.tg_port2, self.tgen_port2_ip, self.moongen_port2_mac)) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + cmd = ('cd /home/l2fwd/;make;./gen_debian_package.sh;' + 'sudo dpkg -i *.deb;' + 'sudo modprobe l2fwd') + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + time.sleep(1) + + self.forward_setup_done = True + + def _is_forward_setup(self): + """Is forward already setup in the host?""" + if self.forward_type is 'testpmd': + is_run = True + cmd = "ip a | grep %s 2>/dev/null" % (self.tg_port1) + LOG.debug("Executing command: %s", cmd) + _, stdout, _ = self.client.execute(cmd) + if stdout: + is_run = False + return is_run + elif self.forward_type is 'l2fwd': + cmd = ('sudo lsmod |grep l2fwd') + LOG.debug("Executing command: %s", cmd) + _, stdout, _ = self.client.execute(cmd) + if stdout: + return True + else: + return False + + def generate_config_file(self, frame_size, multistream, + runBidirec, tg_port1_vlan, tg_port2_vlan, + SearchRuntime, Package_Loss): + out_text = """\ +VSPERF { +testType = 'throughput', +nrFlows = %d, +runBidirec = %s, +frameSize = %d, +srcMacs = {\'%s\', \'%s\'}, +dstMacs = {\'%s\', \'%s\'}, +vlanIds = {%d, %d}, +searchRunTime = %d, +validationRunTime = %d, +acceptableLossPct = %d, +ports = {0,1}, +} +""" % (multistream, runBidirec, frame_size, self.moongen_port1_mac, + self.moongen_port2_mac, self.tgen_port1_mac, self.tgen_port2_mac, + tg_port1_vlan, tg_port2_vlan, SearchRuntime, SearchRuntime, Package_Loss) + with open(self.VSPERF_CONFIG, "wt") as out_file: + out_file.write(out_text) + self.CONFIG_FILE = True + + def result_to_data(self, result): + search_pattern = re.compile( + r'\[REPORT\]\s+total\:\s+' + r'Tx\s+frames\:\s+(\d+)\s+' + r'Rx\s+Frames\:\s+(\d+)\s+' + r'frame\s+loss\:\s+(\d+)\,' + r'\s+(\d+\.\d+|\d+)%\s+' + r'Tx\s+Mpps\:\s+(\d+.\d+|\d+)\s+' + r'Rx\s+Mpps\:\s+(\d+\.\d+|\d+)', + re.IGNORECASE) + results_match = search_pattern.search(result) + if results_match: + rx_mpps = float(results_match.group(6)) + tx_mpps = float(results_match.group(5)) + else: + rx_mpps = 0 + tx_mpps = 0 + test_result = {"rx_mpps": rx_mpps, "tx_mpps": tx_mpps} + self.TO_DATA = True + return test_result + + def run(self, result): + """ execute the vsperf benchmark and return test results + within result dictionary + """ + + if not self.setup_done: + self.setup() + + # get vsperf options + multistream = self.options.get("multistream", 1) + + if not self.forward_setup_done: + self.forward_setup() + + if 'frame_size' in self.options: + frame_size = self.options.get("frame_size", 64) + Package_Loss = self.options.get("Package_Loss", 0) + runBidirec = self.options.get("moongen_runBidirec", + "true") + SearchRuntime = self.options.get("SearchRuntime", 10) + + cmd = "openstack network show %s --format json -c " \ + "provider:segmentation_id" % (self.tg_port1_nw) + LOG.debug("Executing command: %s", cmd) + output = subprocess.check_output(cmd, shell=True) + try: + tg_port1_vlan = jsonutils.loads(output).get("provider:segmentation_id", 1) + except TypeError: + tg_port1_vlan = 1 + + cmd = "openstack network show %s --format json -c " \ + "provider:segmentation_id" % (self.tg_port2_nw) + LOG.debug("Executing command: %s", cmd) + output = subprocess.check_output(cmd, shell=True) + try: + tg_port2_vlan = jsonutils.loads(output).get("provider:segmentation_id", 2) + except TypeError: + tg_port2_vlan = 2 + + self.generate_config_file(frame_size, multistream, + runBidirec, tg_port1_vlan, + tg_port2_vlan, SearchRuntime, Package_Loss) + + self.server.execute("rm -f -- %s/opnfv-vsperf-cfg.lua" % + (self.moongen_dir)) + self.server._put_file_shell(self.VSPERF_CONFIG, + "%s/opnfv-vsperf-cfg.lua" + % (self.moongen_dir)) + + # execute moongen + cmd = ("cd %s;./MoonGen/build/MoonGen ./trafficgen.lua" + % (self.moongen_dir)) + status, stdout, stderr = self.server.execute(cmd) + if status: + raise RuntimeError(stderr) + + moongen_result = self.result_to_data(stdout) + LOG.info(moongen_result) + result.update(moongen_result) + + if "sla" in self.scenario_cfg: + throughput_rx_mpps = int( + self.scenario_cfg["sla"]["throughput_rx_mpps"]) + + assert throughput_rx_mpps <= moongen_result["tx_mpps"], \ + "sla_throughput_rx_mpps %f > throughput_rx_mpps(%f); " % \ + (throughput_rx_mpps, moongen_result["tx_mpps"]) + + def teardown(self): + """cleanup after the test execution""" + + # execute external setup script + self.setup_done = False diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py new file mode 100644 index 000000000..620155c7e --- /dev/null +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_moongen_testpmd.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python + +# Copyright 2017 Nokia +# +# 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. + +# Unittest for yardstick.benchmark.scenarios.networking.MoongenTestPMD + +from __future__ import absolute_import +try: + from unittest import mock +except ImportError: + import mock +import unittest + +from yardstick.benchmark.scenarios.networking import moongen_testpmd + + +@mock.patch('yardstick.benchmark.scenarios.networking.moongen_testpmd.subprocess') +class MoongenTestPMDTestCase(unittest.TestCase): + + def setUp(self): + self.ctx = { + "host": { + "ip": "10.229.47.137", + "user": "ubuntu", + "password": "ubuntu", + }, + } + self.TestPMDargs = { + 'task_id': "1234-5678", + 'options': { + 'multistream': 1, + 'frame_size': 1024, + 'testpmd_queue': 2, + 'trafficgen_port1': 'ens5', + 'trafficgen_port2': 'ens6', + 'moongen_host_user': 'root', + 'moongen_host_passwd': 'root', + 'moongen_host_ip': '10.5.201.151', + 'moongen_dir': '/home/lua-trafficgen', + 'moongen_runBidirec': 'true', + 'Package_Loss': 0, + 'SearchRuntime': 60, + 'moongen_port1_mac': '88:cf:98:2f:4d:ed', + 'moongen_port2_mac': '88:cf:98:2f:4d:ee', + 'forward_type': 'testpmd', + }, + 'sla': { + 'metrics': 'throughput_rx_mpps', + 'throughput_rx_mpps': 0.5, + 'action': 'monitor', + } + } + self.L2fwdargs = { + 'task_id': "1234-5678", + 'options': { + 'multistream': 1, + 'frame_size': 1024, + 'testpmd_queue': 2, + 'trafficgen_port1': 'ens5', + 'trafficgen_port2': 'ens6', + 'moongen_host_user': 'root', + 'moongen_host_passwd': 'root', + 'moongen_host_ip': '10.5.201.151', + 'moongen_dir': '/home/lua-trafficgen', + 'moongen_runBidirec': 'true', + 'Package_Loss': 0, + 'SearchRuntime': 60, + 'moongen_port1_mac': '88:cf:98:2f:4d:ed', + 'moongen_port2_mac': '88:cf:98:2f:4d:ee', + 'forward_type': 'l2fwd', + }, + 'sla': { + 'metrics': 'throughput_rx_mpps', + 'throughput_rx_mpps': 0.5, + 'action': 'monitor', + } + } + + self._mock_ssh = mock.patch( + 'yardstick.benchmark.scenarios.networking.moongen_testpmd.ssh') + self.mock_ssh = self._mock_ssh.start() + + self.addCleanup(self._cleanup) + + def _cleanup(self): + self._mock_ssh.stop() + + def test_MoongenTestPMD_setup(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + def test_MoongenTestPMD_teardown(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.teardown() + self.assertFalse(p.setup_done) + + def test_MoongenTestPMD_l2fwd_is_forward_setup_no(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + result = p._is_forward_setup() + self.assertFalse(result) + + def test_MoongenTestPMD_l2fwd_is_forward_setup_yes(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + result = p._is_forward_setup() + self.assertTrue(result) + + def test_MoongenTestPMD_testpmd_is_forward_setup_no(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + result = p._is_forward_setup() + self.assertFalse(result) + + def test_MoongenTestPMD_testpmd_is_forward_setup_yes(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + result = p._is_forward_setup() + self.assertTrue(result) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_testpmd_forward_setup_first(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + + p.forward_setup() + self.assertFalse(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_testpmd_dpdk_setup_next(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.forward_setup() + self.assertTrue(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_l2fwd_forward_setup_first(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # is_dpdk_setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + p.forward_setup() + self.assertFalse(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + @mock.patch('time.sleep') + def test_MoongenTestPMD_l2fwd_dpdk_setup_next(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.L2fwdargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + p.forward_setup() + self.assertTrue(p._is_forward_setup()) + self.assertTrue(p.forward_setup_done) + + def test_moongen_testpmd_generate_config_file(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + mock_subprocess.call().execute.return_value = None + + p.generate_config_file(frame_size=1, multistream=1, + runBidirec="True", tg_port1_vlan=1, + tg_port2_vlan=2, SearchRuntime=1, + Package_Loss=0) + self.assertTrue(p.CONFIG_FILE) + + def test_moongen_testpmd_result_to_data_match(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + mock_subprocess.call().execute.return_value = None + result = ("[REPORT]Device 1->0: Tx frames: 420161490 Rx Frames: 420161490" + " frame loss: 0, 0.000000% Rx Mpps: 7.002708\n[REPORT] " + "total: Tx frames: 840321216 Rx Frames: 840321216 frame loss: " + "0, 0.000000% Tx Mpps: 14.005388 Rx Mpps: 14.005388\n'") + p.result_to_data(result=result) + self.assertTrue(p.TO_DATA) + + def test_moongen_testpmd_result_to_data_not_match(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + mock_subprocess.call().execute.return_value = None + result = ("") + p.result_to_data(result=result) + self.assertTrue(p.TO_DATA) + + @mock.patch('time.sleep') + def test_moongen_testpmd_run_ok(self, _, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + p.setup_done = True + p.forward_setup_done = True + p.setup() + + # run() specific mocks + p.server = self.mock_ssh.SSH.from_node() + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + result = ("[REPORT]Device 1->0: Tx frames: 420161490 Rx Frames: 420161490" + " frame loss: 0, 0.000000% Rx Mpps: 7.002708\n[REPORT] " + "total: Tx frames: 840321216 Rx Frames: 840321216 frame loss: " + "0, 0.000000% Tx Mpps: 14.005388 Rx Mpps: 14.005388\n'") + self.mock_ssh.SSH.from_node().execute.return_value = ( + 0, result, '') + + test_result = {} + p.run(test_result) + + self.assertEqual(test_result['rx_mpps'], 14.005388) + + def test_moongen_testpmd_run_falied_vsperf_execution(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # run() specific mocks + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + + result = {} + self.assertRaises(RuntimeError, p.run, result) + + def test_moongen_testpmd_run_falied_csv_report(self, mock_subprocess): + p = moongen_testpmd.MoongenTestPMD(self.TestPMDargs, self.ctx) + + # setup() specific mocks + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + mock_subprocess.call().execute.return_value = None + + p.setup() + self.assertIsNotNone(p.client) + self.assertTrue(p.setup_done) + + # run() specific mocks + mock_subprocess.call().execute.return_value = None + mock_subprocess.call().execute.return_value = None + self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + + result = {} + self.assertRaises(RuntimeError, p.run, result) + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() -- cgit 1.2.3-korg