add pktgen scenario and sample 68/768/4
authorJörgen Karlsson <jorgen.w.karlsson@ericsson.com>
Thu, 4 Jun 2015 07:11:46 +0000 (09:11 +0200)
committerJörgen Karlsson <jorgen.w.karlsson@ericsson.com>
Tue, 9 Jun 2015 13:03:20 +0000 (13:03 +0000)
Supports measuring network throughput UDP.
SLA can be verified for packet lost per million packets (ppm)

Change-Id: Ie5972f189bbe58b39a2fae98630b2f117c176ae5
JIRA: YARDSTICK-5
Signed-off-by: Jorgen Karlsson <jorgen.w.karlsson@ericsson.com>
samples/pktgen.yaml
yardstick/benchmark/runners/arithmetic.py
yardstick/benchmark/scenarios/networking/pktgen.py [new file with mode: 0644]
yardstick/benchmark/scenarios/networking/pktgen_benchmark.bash [new file with mode: 0644]

index a17cffd..000a7cd 100644 (file)
@@ -17,11 +17,13 @@ scenarios:
   runner:
     type: Arithmetic
     name: number_of_ports
-    stop: 100
+    # run twice with values 10 and 20
+    stop: 20
     step: 10
 
   sla:
-    max_ppm: 1
+    max_ppm: 1000
+    action: monitor
 
 context:
   name: demo
@@ -29,15 +31,21 @@ context:
   flavor: yardstick-flavor
   user: ec2-user
 
+  placement_groups:
+    pgrp1:
+      policy: "availability"
+
   servers:
     client:
-      instances: 1
       floating_ip: true
+      placement: "pgrp1"
     server:
       floating_ip: true
+      placement: "pgrp1"
 
   networks:
     test:
       cidr: '10.0.1.0/24'
       external_network: "net04_ext"
 
+
index a3aceb3..acf14d0 100644 (file)
@@ -49,7 +49,7 @@ def _worker_process(queue, cls, method_name, context, scenario_args):
     if "sla" in scenario_args:
         sla_action = scenario_args["sla"].get("action", "assert")
 
-    for value in range(start, stop, step):
+    for value in range(start, stop+step, step):
 
         options[arg_name] = value
 
diff --git a/yardstick/benchmark/scenarios/networking/pktgen.py b/yardstick/benchmark/scenarios/networking/pktgen.py
new file mode 100644 (file)
index 0000000..8038cad
--- /dev/null
@@ -0,0 +1,135 @@
+##############################################################################
+# Copyright (c) 2015 Ericsson AB 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 json
+
+import yardstick.ssh as ssh
+from yardstick.benchmark.scenarios import base
+
+LOG = logging.getLogger(__name__)
+LOG.setLevel(logging.DEBUG)
+
+
+class Pktgen(base.Scenario):
+    """Executes a pktgen benchmark between two hosts"""
+    __scenario_type__ = "Pktgen"
+
+    TARGET_SCRIPT = 'pktgen_benchmark.bash'
+
+    def __init__(self, context):
+        self.context = context
+        self.setup_done = False
+
+    def setup(self):
+        '''scenario setup'''
+        self.target_script = pkg_resources.resource_filename(
+            'yardstick.benchmark.scenarios.networking',
+            Pktgen.TARGET_SCRIPT)
+        user = self.context.get('user', 'ubuntu')
+        host = self.context.get('host', None)
+        target = self.context.get('target', None)
+        key_filename = self.context.get('key_filename', '~/.ssh/id_rsa')
+
+        LOG.debug("user:%s, target:%s", user, target)
+        self.server = ssh.SSH(user, target, key_filename=key_filename)
+        self.server.wait(timeout=600)
+
+        LOG.debug("user:%s, host:%s", user, host)
+        self.client = ssh.SSH(user, host, key_filename=key_filename)
+        self.client.wait(timeout=600)
+
+        # copy script to host
+        self.client.run("cat > ~/pktgen.sh",
+                        stdin=open(self.target_script, "rb"))
+
+        self.setup_done = True
+
+    def _iptables_setup(self):
+        """Setup iptables on server to monitor for received packets"""
+        cmd = "sudo iptables -F; " \
+              "sudo iptables -A INPUT -p udp --dport 1000:%s -j DROP" \
+              % (1000 + self.number_of_ports)
+        LOG.debug("Executing command: %s", cmd)
+        status, _, stderr = self.server.execute(cmd)
+        if status:
+            raise RuntimeError(stderr)
+
+    def _iptables_get_result(self):
+        """Get packet statistics from server"""
+        cmd = "sudo iptables -L INPUT -vnx |" \
+              "awk '/dpts:1000:%s/ {{printf \"%%s\", $1}}'" \
+              % (1000 + self.number_of_ports)
+        LOG.debug("Executing command: %s", cmd)
+        status, stdout, stderr = self.server.execute(cmd)
+        if status:
+            raise RuntimeError(stderr)
+        return int(stdout)
+
+    def run(self, args):
+        """execute the benchmark"""
+
+        if not self.setup_done:
+            self.setup()
+
+        ipaddr = args.get("ipaddr", '127.0.0.1')
+
+        options = args['options']
+        packetsize = options.get("packetsize", 60)
+        self.number_of_ports = options.get("number_of_ports", 10)
+
+        self._iptables_setup()
+
+        cmd = "sudo bash pktgen.sh %s %s %s" \
+            % (ipaddr, self.number_of_ports, packetsize)
+        LOG.debug("Executing command: %s", cmd)
+        status, stdout, stderr = self.client.execute(cmd)
+
+        if status:
+            raise RuntimeError(stderr)
+
+        data = json.loads(stdout)
+
+        data['packets_received'] = self._iptables_get_result()
+
+        if "sla" in args:
+            sent = data['packets_sent']
+            received = data['packets_received']
+            ppm = 1000000 * (sent - received) / sent
+            sla_max_ppm = int(args["sla"]["max_ppm"])
+            assert ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d" \
+                % (ppm, sla_max_ppm)
+
+        return data
+
+
+def _test():
+    '''internal test function'''
+    key_filename = pkg_resources.resource_filename('yardstick.resources',
+                                                   'files/yardstick_key')
+    ctx = {'host': '172.16.0.137',
+           'target': '172.16.0.138',
+           'user': 'ubuntu',
+           'key_filename': key_filename
+           }
+
+    logger = logging.getLogger('yardstick')
+    logger.setLevel(logging.DEBUG)
+
+    p = Pktgen(ctx)
+
+    options = {'packetsize': 120}
+
+    args = {'options': options,
+            'ipaddr': '192.168.111.31'}
+    result = p.run(args)
+    print result
+
+if __name__ == '__main__':
+    _test()
diff --git a/yardstick/benchmark/scenarios/networking/pktgen_benchmark.bash b/yardstick/benchmark/scenarios/networking/pktgen_benchmark.bash
new file mode 100644 (file)
index 0000000..f5df50f
--- /dev/null
@@ -0,0 +1,158 @@
+#!/bin/sh
+
+##############################################################################
+# Copyright (c) 2015 Ericsson AB 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
+##############################################################################
+
+set -e
+
+# Commandline arguments
+DST_IP=$1         # destination IP address
+shift
+NUM_PORTS=$1      # number of source ports
+shift
+PKT_SIZE=$1       # packet size
+
+# Configuration
+UDP_SRC_MIN=1000                               # UDP source port min
+UDP_SRC_MAX=$(( UDP_SRC_MIN + NUM_PORTS - 1 )) # UDP source port max
+UDP_DST_MIN=1000                               # UDP destination port min
+UDP_DST_MAX=$(( UDP_DST_MIN + NUM_PORTS ))     # UDP destination port max
+DURATION=20                                    # test duration (seconds)
+
+# helper function to send commands to pktgen
+pgset()
+{
+    local result
+
+    echo $1 > $PGDEV
+
+    result=$(cat $PGDEV | fgrep "Result: OK:")
+    if [ "$result" = "" ]; then
+        cat $PGDEV | fgrep "Result:" >/dev/stderr
+        exit 1
+    fi
+}
+
+# configure pktgen (see pktgen doc for details)
+pgconfig()
+{
+    #
+    # Thread commands
+    #
+
+    PGDEV=/proc/net/pktgen/kpktgend_0
+
+    # Remove all devices from this thread
+    pgset "rem_device_all"
+
+    # Add device to thread
+    pgset "add_device $DEV"
+
+    #
+    # Device commands
+    #
+
+    PGDEV=/proc/net/pktgen/$DEV
+
+    # 0 means continious sends untill explicitly stopped
+    pgset "count 0"
+
+    # use single SKB for all transmits
+    pgset "clone_skb 0"
+
+    # packet size, NIC adds 4 bytes CRC
+    pgset "pkt_size $PKT_SIZE"
+
+    # random address within the min-max range
+    pgset "flag IPDST_RND UDPSRC_RND UDPDST_RND"
+
+    # destination IP
+    pgset "dst_min $DST_IP"
+    pgset "dst_max $DST_IP"
+
+    # destination MAC address
+    pgset "dst_mac $MAC"
+
+    # source UDP port range
+    pgset "udp_src_min $UDP_SRC_MIN"
+    pgset "udp_src_max $UDP_SRC_MAX"
+
+    # destination UDP port range
+    pgset "udp_dst_min $UDP_DST_MIN"
+    pgset "udp_dst_max $UDP_DST_MAX"
+}
+
+# run pktgen
+pgrun()
+{
+    # Time to run, result can be vieved in /proc/net/pktgen/$DEV
+    PGDEV=/proc/net/pktgen/pgctrl
+    # Will hang, Ctrl-C or SIGINT to stop
+    pgset "start" start
+}
+
+# run pktgen for ${DURATION} seconds
+run_test()
+{
+    pgrun &
+    pid=$!
+
+    sleep $DURATION
+
+    kill -INT $pid
+
+    wait; sleep 1
+}
+
+# write the result to stdout in json format
+output_json()
+{
+    sent=$(awk '/^Result:/{print $5}' <$PGDEV)
+    pps=$(awk 'match($0,/'\([0-9]+\)pps'/, a) {print a[1]}' <$PGDEV)
+    errors=$(awk '/errors:/{print $5}' <$PGDEV)
+
+    flows=$(( NUM_PORTS * (NUM_PORTS + 1) ))
+
+    echo { '"packets_sent"':$sent , '"packets_per_second"':$pps, '"flows"':$flows, '"errors"':$errors }
+}
+
+# main entry
+main()
+{
+    modprobe pktgen
+
+    ping -c 3 $DST_IP >/dev/null
+
+    # destination MAC address
+    MAC=`arp -n | grep -w $DST_IP | awk '{print $3}'`
+
+    # outgoing interface
+    DEV=`arp -n | grep -w $DST_IP | awk '{print $5}'`
+
+    # setup the test
+    pgconfig
+
+    # run the test
+    run_test >/dev/null
+
+    PGDEV=/proc/net/pktgen/$DEV
+
+    # check result
+    result=$(cat $PGDEV | fgrep "Result: OK:")
+    if [ "$result" = "" ]; then
+         cat $PGDEV | fgrep Result: >/dev/stderr
+         exit 1
+    fi
+
+    # output result
+    output_json
+}
+
+main
+