From 8953fa3d53019571a222a1aedb7cf796c5d67aec Mon Sep 17 00:00:00 2001 From: "wu.zhihui" Date: Fri, 22 Jul 2016 22:11:53 +0800 Subject: [Yardstick-233]latency measurment by using pktgen-dpdk VM A runs pktgen-dpdk as a traffic generator and is connected back-to-back with VM B running testpmd for forwarding packets. 1. use linux expect to fetch the latency statics data. 2. fetch 10 samples of latency and calculate avg_latency. 3. use screen to keep test scripts running in the background. 4. add a function send_command() for screen in ssh.py JIRA:YARDSTICK-233 Change-Id: I90ae64b3d198c79f159275ae35715eb284f05080 Signed-off-by: wu.zhihui --- .../scenarios/networking/test_pktgen_dpdk.py | 173 +++++++++++++++++++++ tests/unit/test_ssh.py | 9 ++ .../benchmark/scenarios/networking/pktgen_dpdk.py | 162 +++++++++++++++++++ .../networking/pktgen_dpdk_latency_benchmark.bash | 147 +++++++++++++++++ .../scenarios/networking/testpmd_fwd.bash | 55 +++++++ yardstick/ssh.py | 5 + 6 files changed, 551 insertions(+) create mode 100644 tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py create mode 100644 yardstick/benchmark/scenarios/networking/pktgen_dpdk.py create mode 100644 yardstick/benchmark/scenarios/networking/pktgen_dpdk_latency_benchmark.bash create mode 100644 yardstick/benchmark/scenarios/networking/testpmd_fwd.bash diff --git a/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py b/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py new file mode 100644 index 000000000..afc87abfb --- /dev/null +++ b/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python + +############################################################################## +# Copyright (c) 2015 ZTE 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 +############################################################################## + +# Unittest for yardstick.benchmark.scenarios.networking.pktgen.Pktgen + +import mock +import unittest +import json + +from yardstick.benchmark.scenarios.networking import pktgen_dpdk + +@mock.patch('yardstick.benchmark.scenarios.networking.pktgen_dpdk.ssh') +class PktgenDPDKLatencyTestCase(unittest.TestCase): + + def setUp(self): + self.ctx = { + 'host': { + 'ip': '172.16.0.137', + 'user': 'root', + 'key_filename': 'mykey.key' + }, + 'target': { + 'ip': '172.16.0.138', + 'user': 'root', + 'key_filename': 'mykey.key', + 'ipaddr': '172.16.0.138' + } + } + + def test_pktgen_dpdk_successful_setup(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + } + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + p.setup() + + mock_ssh.SSH().execute.return_value = (0, '', '') + self.assertIsNotNone(p.server) + self.assertIsNotNone(p.client) + self.assertEqual(p.setup_done, True) + + def test_pktgen_dpdk_successful_get_port_ip(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + } + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + p.server = mock_ssh.SSH() + + mock_ssh.SSH().execute.return_value = (0, '', '') + + p.get_port_ip(p.server, "eth1") + + mock_ssh.SSH().execute.assert_called_with( + "ifconfig eth1 |grep 'inet addr' |awk '{print $2}' \ + |cut -d ':' -f2 ") + + def test_pktgen_dpdk_unsuccessful_get_port_ip(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + } + + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + p.server = mock_ssh.SSH() + + mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR') + self.assertRaises(RuntimeError, p.get_port_ip, p.server, "eth1") + + def test_pktgen_dpdk_successful_get_port_mac(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + } + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + p.server = mock_ssh.SSH() + + mock_ssh.SSH().execute.return_value = (0, '', '') + + p.get_port_mac(p.server, "eth1") + + mock_ssh.SSH().execute.assert_called_with( + "ifconfig |grep HWaddr |grep eth1 |awk '{print $5}' ") + + def test_pktgen_dpdk_unsuccessful_get_port_mac(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + } + + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + p.server = mock_ssh.SSH() + + mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR') + self.assertRaises(RuntimeError, p.get_port_mac, p.server, "eth1") + + def test_pktgen_dpdk_successful_no_sla(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + } + + result = {} + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + + sample_output = '100\n110\n112\n130\n149\n150\n90\n150\n200\n162\n' + mock_ssh.SSH().execute.return_value = (0, sample_output, '') + + p.run(result) + self.assertEqual(result, {"avg_latency": 132}) + + def test_pktgen_dpdk_successful_sla(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + 'sla': {'max_latency': 100} + } + result = {} + + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + + sample_output = '100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n' + mock_ssh.SSH().execute.return_value = (0, sample_output, '') + + p.run(result) + + self.assertEqual(result, {"avg_latency": 100}) + + def test_pktgen_dpdk_unsuccessful_sla(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + 'sla': {'max_latency': 100} + } + result = {} + + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + + p.server = mock_ssh.SSH() + p.client = mock_ssh.SSH() + + sample_output = '100\n110\n112\n130\n149\n150\n90\n150\n200\n162\n' + mock_ssh.SSH().execute.return_value = (0, sample_output, '') + self.assertRaises(AssertionError, p.run, result) + + def test_pktgen_dpdk_unsuccessful_script_error(self, mock_ssh): + + args = { + 'options': {'packetsize': 60}, + 'sla': {'max_latency': 100} + } + result = {} + + p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + + mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR') + self.assertRaises(RuntimeError, p.run, result) + + +def main(): + unittest.main() + +if __name__ == '__main__': + main() diff --git a/tests/unit/test_ssh.py b/tests/unit/test_ssh.py index 4260b39bc..574da0343 100644 --- a/tests/unit/test_ssh.py +++ b/tests/unit/test_ssh.py @@ -156,6 +156,15 @@ class SSHTestCase(unittest.TestCase): self.assertEqual([mock.call("uname")] * 3, self.test_client.execute.mock_calls) + @mock.patch("yardstick.ssh.paramiko") + def test_send_command(self, mock_paramiko): + paramiko_sshclient = self.test_client._get_client() + with mock.patch.object(paramiko_sshclient, "exec_command") \ + as mock_paramiko_exec_command: + self.test_client.send_command('cmd') + mock_paramiko_exec_command.assert_called_once_with('cmd', + get_pty=True) + class SSHRunTestCase(unittest.TestCase): """Test SSH.run method in different aspects. diff --git a/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py b/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py new file mode 100644 index 000000000..86585eca3 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py @@ -0,0 +1,162 @@ +############################################################################## +# Copyright (c) 2016 ZTE corporation 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 +############################################################################## +import pkg_resources +import logging +import time + +import yardstick.ssh as ssh +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class PktgenDPDKLatency(base.Scenario): + """Execute pktgen-dpdk on one vm and execute testpmd on the other vm + + Parameters + packetsize - packet size in bytes without the CRC + type: int + unit: bytes + default: 64 + """ + __scenario_type__ = "PktgenDPDKLatency" + + PKTGEN_DPDK_SCRIPT = 'pktgen_dpdk_latency_benchmark.bash' + TESTPMD_SCRIPT = 'testpmd_fwd.bash' + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.setup_done = False + + def setup(self): + '''scenario setup''' + self.pktgen_dpdk_script = pkg_resources.resource_filename( + 'yardstick.benchmark.scenarios.networking', + PktgenDPDKLatency.PKTGEN_DPDK_SCRIPT) + self.testpmd_script = pkg_resources.resource_filename( + 'yardstick.benchmark.scenarios.networking', + PktgenDPDKLatency.TESTPMD_SCRIPT) + host = self.context_cfg['host'] + host_user = host.get('user', 'ubuntu') + host_ip = host.get('ip', None) + host_key_filename = host.get('key_filename', '~/.ssh/id_rsa') + target = self.context_cfg['target'] + target_user = target.get('user', 'ubuntu') + target_ip = target.get('ip', None) + target_key_filename = target.get('key_filename', '~/.ssh/id_rsa') + LOG.info("user:%s, target:%s", target_user, target_ip) + self.server = ssh.SSH(target_user, target_ip, + key_filename=target_key_filename) + self.server.wait(timeout=600) + + # copy script to host + self.server.run("cat > ~/testpmd_fwd.sh", + stdin=open(self.testpmd_script, "rb")) + + LOG.info("user:%s, host:%s", host_user, host_ip) + self.client = ssh.SSH(host_user, host_ip, + key_filename=host_key_filename) + self.client.wait(timeout=600) + + # copy script to host + self.client.run("cat > ~/pktgen_dpdk.sh", + stdin=open(self.pktgen_dpdk_script, "rb")) + + self.setup_done = True + self.testpmd_args = '' + self.pktgen_args = [] + + @staticmethod + def get_port_mac(sshclient, port): + cmd = "ifconfig |grep HWaddr |grep %s |awk '{print $5}' " % port + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = sshclient.execute(cmd) + + if status: + raise RuntimeError(stderr) + else: + return stdout.rstrip() + + @staticmethod + def get_port_ip(sshclient, port): + cmd = "ifconfig %s |grep 'inet addr' |awk '{print $2}' \ + |cut -d ':' -f2 " % port + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = sshclient.execute(cmd) + + if status: + raise RuntimeError(stderr) + else: + return stdout.rstrip() + + def run(self, result): + """execute the benchmark""" + + if not self.setup_done: + self.setup() + + if not self.testpmd_args: + self.testpmd_args = self.get_port_mac(self.client, 'eth2') + + if not self.pktgen_args: + server_rev_mac = self.get_port_mac(self.server, 'eth1') + server_send_mac = self.get_port_mac(self.server, 'eth2') + client_src_ip = self.get_port_ip(self.client, 'eth1') + client_dst_ip = self.get_port_ip(self.client, 'eth2') + + self.pktgen_args = [client_src_ip, client_dst_ip, + server_rev_mac, server_send_mac] + + options = self.scenario_cfg['options'] + packetsize = options.get("packetsize", 64) + rate = options.get("rate", 100) + + cmd = "screen sudo -E bash ~/testpmd_fwd.sh %s " % (self.testpmd_args) + LOG.debug("Executing command: %s", cmd) + self.server.send_command(cmd) + + time.sleep(1) + + cmd = "screen sudo -E bash ~/pktgen_dpdk.sh %s %s %s %s %s %s" % \ + (self.pktgen_args[0], self.pktgen_args[1], self.pktgen_args[2], + self.pktgen_args[3], rate, packetsize) + LOG.debug("Executing command: %s", cmd) + self.client.send_command(cmd) + + # wait for finishing test + time.sleep(1) + + cmd = "cat ~/result.log -vT \ + |awk '{match($0,/\[8;40H +[0-9]+/)} \ + {print substr($0,RSTART,RLENGTH)}' \ + |grep -v ^$ |awk '{if ($2 != 0) print $2}'" + client_status, client_stdout, client_stderr = self.client.execute(cmd) + + if client_status: + raise RuntimeError(client_stderr) + + avg_latency = 0 + if client_stdout: + latency_list = client_stdout.split('\n')[0:-2] + LOG.info("10 samples of latency: %s", latency_list) + latency_sum = 0 + for i in latency_list: + latency_sum += int(i) + avg_latency = latency_sum/len(latency_list) + + result.update({"avg_latency": avg_latency}) + + if avg_latency and "sla" in self.scenario_cfg: + sla_max_latency = int(self.scenario_cfg["sla"]["max_latency"]) + LOG.info("avg_latency : %d ", avg_latency) + LOG.info("sla_max_latency: %d", sla_max_latency) + debug_info = "avg_latency %d > sla_max_latency %d" \ + % (avg_latency, sla_max_latency) + assert avg_latency <= sla_max_latency, debug_info diff --git a/yardstick/benchmark/scenarios/networking/pktgen_dpdk_latency_benchmark.bash b/yardstick/benchmark/scenarios/networking/pktgen_dpdk_latency_benchmark.bash new file mode 100644 index 000000000..f6f361e80 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/pktgen_dpdk_latency_benchmark.bash @@ -0,0 +1,147 @@ +!/bin/sh + +set -e + +# Commandline arguments +SRC_IP=$1 # source IP address of sender in VM A +DST_IP=$2 # destination IP address of receiver in VM A +FWD_REV_MAC=$3 # MAC address of forwarding receiver in VM B +FWD_SEND_MAC=$4 # MAC address of forwarding sender in VM B +RATE=$5 # packet rate in percentage +PKT_SIZE=$6 # packet size + + +load_modules() +{ + if lsmod | grep "uio" &> /dev/null ; then + echo "uio module is loaded" + else + modprobe uio + fi + + if lsmod | grep "igb_uio" &> /dev/null ; then + echo "igb_uio module is loaded" + else + insmod /dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko + fi + + if lsmod | grep "rte_kni" &> /dev/null ; then + echo "rte_kni module is loaded" + else + insmod /dpdk/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}') + /dpdk/tools/dpdk-devbind.py --bind=igb_uio $interfaces + +} + +create_pktgen_config_lua() +{ + touch /home/ubuntu/pktgen_latency.lua + lua_file="/home/ubuntu/pktgen_latency.lua" + chmod 777 $lua_file + echo $lua_file + + cat << EOF > "/home/ubuntu/pktgen_latency.lua" +package.path = package.path ..";?.lua;test/?.lua;app/?.lua;" + + -- require "Pktgen"; +function pktgen_config() + + pktgen.screen("off"); + + pktgen.set_ipaddr("0", "dst", "$DST_IP"); + pktgen.set_ipaddr("0", "src", "$SRC_IP/24"); + pktgen.set_mac("0", "$FWD_REV_MAC"); + pktgen.set_ipaddr("1", "dst", "$SRC_IP"); + pktgen.set_ipaddr("1", "src", "$DST_IP/24"); + pktgen.set_mac("1", "$FWD_SEND_MAC"); + pktgen.set(0, "rate", $RATE); + pktgen.set(0, "size", $PKT_SIZE); + pktgen.set_proto("all", "udp"); + pktgen.latency("all","enable"); + pktgen.latency("all","on"); + + pktgen.start(0); + end + +pktgen_config() +EOF +} + + +create_expect_file() +{ + touch /home/ubuntu/pktgen.exp + expect_file="/home/ubuntu/pktgen.exp" + chmod 777 $expect_file + echo $expect_file + + cat << 'EOF' > "/home/ubuntu/pktgen.exp" +#!/usr/bin/expect + +set blacklist [lindex $argv 0] +set log [lindex $argv 1] +set result {} +set timeout 15 +spawn ./app/app/x86_64-native-linuxapp-gcc/pktgen -c 0x07 -n 4 -b $blacklist -- -P -m "1.0, 2.1" -f /home/ubuntu/pktgen_latency.lua +expect "Pktgen>" +send "\n" +expect "Pktgen>" +send "screen on\n" +expect "Pktgen>" +set count 10 +while { $count } { + send "page latency\n" + expect { + timeout { send "\n" } + -regexp {..*} { + set result "${result}$expect_out(0,string)" + set timeout 1 + exp_continue + } + "Pktgen>" + } + set count [expr $count-1] +} +send "stop 0\n" +expect "Pktgen>" +send "quit\n" +expect "#" + +set file [ open $log w ] +puts $file $result +EOF + +} + +run_pktgen() +{ + blacklist=$(lspci |grep Eth |awk '{print $1}'|head -1) + cd /pktgen-dpdk + touch /home/ubuntu/result.log + result_log="/home/ubuntu/result.log" + sudo expect /home/ubuntu/pktgen.exp $blacklist $result_log +} + +main() +{ + load_modules + change_permissions + create_pktgen_config_lua + create_expect_file + add_interface_to_dpdk + run_pktgen +} + +main + diff --git a/yardstick/benchmark/scenarios/networking/testpmd_fwd.bash b/yardstick/benchmark/scenarios/networking/testpmd_fwd.bash new file mode 100644 index 000000000..ac18db491 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/testpmd_fwd.bash @@ -0,0 +1,55 @@ +#!/bin/sh + +set -e + +# Commandline arguments +DST_MAC=$1 # MAC address of the peer port + +load_modules() +{ + if lsmod | grep "uio" &> /dev/null ; then + echo "uio module is loaded" + else + modprobe uio + fi + + if lsmod | grep "igb_uio" &> /dev/null ; then + echo "igb_uio module is loaded" + else + insmod /dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko + fi + + if lsmod | grep "rte_kni" &> /dev/null ; then + echo "rte_kni module is loaded" + else + insmod /dpdk/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}') + /dpdk/tools/dpdk-devbind.py --bind=igb_uio $interfaces +} + +run_testpmd() +{ + blacklist=$(lspci |grep Eth |awk '{print $1}'|head -1) + cd /dpdk + sudo ./destdir/bin/testpmd -c 0x07 -n 4 -b $blacklist -- -a --eth-peer=1,$DST_MAC --forward-mode=mac +} + +main() +{ + load_modules + change_permissions + add_interface_to_dpdk + run_testpmd +} + +main diff --git a/yardstick/ssh.py b/yardstick/ssh.py index 339f834b7..2816a1c7d 100644 --- a/yardstick/ssh.py +++ b/yardstick/ssh.py @@ -261,3 +261,8 @@ class SSH(object): with SCPClient(client.get_transport()) as scp: scp.put(files, remote_path, recursive) + + # keep shell running in the background, e.g. screen + def send_command(self, command): + client = self._get_client() + client.exec_command(command, get_pty=True) -- cgit 1.2.3-korg