Upload the contribution of vstf as bottleneck network framework.
[bottlenecks.git] / vstf / vstf / agent / perf / pktgen.py
diff --git a/vstf/vstf/agent/perf/pktgen.py b/vstf/vstf/agent/perf/pktgen.py
new file mode 100755 (executable)
index 0000000..58c0e6c
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author:
+# date: 2015-09-15
+# see license for license details
+import subprocess
+import time
+import logging
+import vstf.agent.perf.utils as utils
+import vstf.common.decorator as deco
+from vstf.common.utils import my_popen
+
+LOG = logging.getLogger(__name__)
+
+
+class Pktgen(object):
+    def __init__(self):
+        utils.modprobe_pktgen()
+        self._send_processes = []
+
+    def _psetpg(self, dev):
+        self._dev = dev
+
+    def _vsetpg(self, key, value=''):
+        with open(self._dev, 'w') as f:
+            txt = "%(key)s %(value)s\n" % {'key': key, 'value': value}
+            f.write(txt)
+            LOG.info("write(%s) to %s", txt.strip(), self._dev)
+
+    def _start(self):
+        cmd = 'echo start > /proc/net/pktgen/pgctrl'
+        process = my_popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        LOG.info('running pid:%s', process.pid)
+        time.sleep(0.5)
+        ret = process.poll()
+        if ret is None:
+            ret = 0
+            self._send_processes.append(process)
+            error_str = "start pktgen send success"
+        else:
+            error_str = "start pktgen send failed, stdout:%s,stderr:%s" % (process.stdout.read(), process.stderr.read())
+            LOG.info(error_str)
+        return ret, error_str
+
+    def _rem_device_all(self):
+        cpu_num = utils.get_cpu_num()
+        for thread in range(0, cpu_num - 1):
+            self._psetpg("/proc/net/pktgen/kpktgend_%s" % thread)
+            self._vsetpg('rem_device_all')
+        return True
+
+    @deco.check("protocol", choices=['udp_bw'], defaults='udp_bw')
+    @deco.check("namespace", defaults=None)
+    @deco.check("dst")
+    @deco.check("src")
+    @deco.check("size", defaults=64)
+    @deco.check("threads", defaults=utils.get_default_threads())
+    @deco.check("clone_skb", defaults=1)
+    @deco.check("count", defaults=0)
+    @deco.check("ratep", defaults=0)
+    def send_start(self, **kwargs):
+        # ensure that all sends is exit
+        self.send_stop()
+
+        interface_num = len(kwargs['src'])
+        interfaces = []
+        for i in range(interface_num):
+            device = kwargs['src'][i]['iface']
+            interfaces.append(device)
+            utils.iface_up(device)
+
+        self._rem_device_all()
+
+        threads = kwargs['threads']
+        for i in range(interface_num):
+            dev_min = i * threads
+            dev_max = (i + 1) * threads
+            device = interfaces[i]
+            for dev_id in range(dev_min, dev_max):
+                queue_id = dev_id % threads
+                self._psetpg("/proc/net/pktgen/kpktgend_%s" % dev_id)
+                self._vsetpg('add_device', "%s@%s" % (device, queue_id))
+                self._psetpg("/proc/net/pktgen/%s@%s" % (device, queue_id))
+                self._vsetpg('pkt_size', kwargs['size'])
+                self._vsetpg('clone_skb', kwargs['clone_skb'])
+                self._vsetpg('dst_mac', kwargs['dst'][i]['mac'])
+                self._vsetpg('src_mac', kwargs['src'][i]['mac'])
+                self._vsetpg('count', kwargs['count'])
+                if kwargs['ratep']:
+                    self._vsetpg('ratep', kwargs['ratep'])
+        return self._start()
+
+    def send_stop(self, **kwargs):
+        results = []
+        ret = 0
+        for process in self._send_processes:
+            process.kill()
+            process.wait()
+            LOG.info("process.kill(pktgen:%s)", process.pid)
+            results.append((ret, process.stdout.read()))
+        self._send_processes = []
+        return results
+
+    def receive_start(self, **kwargs):
+        ret = 0
+        error_str = "%s pktgen neednt receive start" % (self.__class__)
+        LOG.debug(error_str)
+        return ret, error_str
+
+    def receive_stop(self, **kwargs):
+        ret = 0
+        error_str = "pktgen neednt receive stop"
+        LOG.debug(error_str)
+        return ret, error_str
+
+    def clean(self):
+        self.send_stop()
+        return True
+
+    def force_clean(self):
+        LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+        return self.clean()
+
+
+def unit_test():
+    perf = Pktgen()
+    print perf.receive_start()
+    send = {
+        "src": [
+            {"iface": 'eth4', "mac": "90:e2:ba:20:1f:d8"}
+        ],
+        "dst": [
+            {"mac": '90:e2:ba:20:1f:d9'}
+        ],
+        "size": 64,
+        "threads": 1,
+        'ratep': 0
+    }
+    print perf.send_start(**send)
+    time.sleep(30)
+    print perf.send_stop()
+    print perf.receive_stop()
+
+
+if __name__ == "__main__":
+    from vstf.common.log import setup_logging
+
+    setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-pktgen.log", clevel=logging.DEBUG)
+    unit_test()