JIRA: BOTTLENECKS-29
[bottlenecks.git] / vstf / vstf / agent / perf / pktgen.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 import subprocess
11 import time
12 import logging
13 import vstf.agent.perf.utils as utils
14 import vstf.common.decorator as deco
15 from vstf.common.utils import my_popen
16
17 LOG = logging.getLogger(__name__)
18
19
20 class Pktgen(object):
21     def __init__(self):
22         utils.modprobe_pktgen()
23         self._send_processes = []
24
25     def _psetpg(self, dev):
26         self._dev = dev
27
28     def _vsetpg(self, key, value=''):
29         with open(self._dev, 'w') as f:
30             txt = "%(key)s %(value)s\n" % {'key': key, 'value': value}
31             f.write(txt)
32             LOG.info("write(%s) to %s", txt.strip(), self._dev)
33
34     def _start(self):
35         cmd = 'echo start > /proc/net/pktgen/pgctrl'
36         process = my_popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
37         LOG.info('running pid:%s', process.pid)
38         time.sleep(0.5)
39         ret = process.poll()
40         if ret is None:
41             ret = 0
42             self._send_processes.append(process)
43             error_str = "start pktgen send success"
44         else:
45             error_str = "start pktgen send failed, stdout:%s,stderr:%s" % (process.stdout.read(), process.stderr.read())
46             LOG.info(error_str)
47         return ret, error_str
48
49     def _rem_device_all(self):
50         cpu_num = utils.get_cpu_num()
51         for thread in range(0, cpu_num - 1):
52             self._psetpg("/proc/net/pktgen/kpktgend_%s" % thread)
53             self._vsetpg('rem_device_all')
54         return True
55
56     @deco.check("protocol", choices=['udp_bw'], defaults='udp_bw')
57     @deco.check("namespace", defaults=None)
58     @deco.check("dst")
59     @deco.check("src")
60     @deco.check("size", defaults=64)
61     @deco.check("threads", defaults=utils.get_default_threads())
62     @deco.check("clone_skb", defaults=1)
63     @deco.check("count", defaults=0)
64     @deco.check("ratep", defaults=0)
65     def send_start(self, **kwargs):
66         # ensure that all sends is exit
67         self.send_stop()
68
69         interface_num = len(kwargs['src'])
70         interfaces = []
71         for i in range(interface_num):
72             device = kwargs['src'][i]['iface']
73             interfaces.append(device)
74             utils.iface_up(device)
75
76         self._rem_device_all()
77
78         threads = kwargs['threads']
79         for i in range(interface_num):
80             dev_min = i * threads
81             dev_max = (i + 1) * threads
82             device = interfaces[i]
83             for dev_id in range(dev_min, dev_max):
84                 queue_id = dev_id % threads
85                 self._psetpg("/proc/net/pktgen/kpktgend_%s" % dev_id)
86                 self._vsetpg('add_device', "%s@%s" % (device, queue_id))
87                 self._psetpg("/proc/net/pktgen/%s@%s" % (device, queue_id))
88                 self._vsetpg('pkt_size', kwargs['size'])
89                 self._vsetpg('clone_skb', kwargs['clone_skb'])
90                 self._vsetpg('dst_mac', kwargs['dst'][i]['mac'])
91                 self._vsetpg('src_mac', kwargs['src'][i]['mac'])
92                 self._vsetpg('count', kwargs['count'])
93                 if kwargs['ratep']:
94                     self._vsetpg('ratep', kwargs['ratep'])
95         return self._start()
96
97     def send_stop(self, **kwargs):
98         results = []
99         ret = 0
100         for process in self._send_processes:
101             process.kill()
102             process.wait()
103             LOG.info("process.kill(pktgen:%s)", process.pid)
104             results.append((ret, process.stdout.read()))
105         self._send_processes = []
106         return results
107
108     def receive_start(self, **kwargs):
109         ret = 0
110         error_str = "%s pktgen neednt receive start" % (self.__class__)
111         LOG.debug(error_str)
112         return ret, error_str
113
114     def receive_stop(self, **kwargs):
115         ret = 0
116         error_str = "pktgen neednt receive stop"
117         LOG.debug(error_str)
118         return ret, error_str
119
120     def clean(self):
121         self.send_stop()
122         return True
123
124     def force_clean(self):
125         LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
126         return self.clean()
127
128
129 def unit_test():
130     perf = Pktgen()
131     print perf.receive_start()
132     send = {
133         "src": [
134             {"iface": 'eth4', "mac": "90:e2:ba:20:1f:d8"}
135         ],
136         "dst": [
137             {"mac": '90:e2:ba:20:1f:d9'}
138         ],
139         "size": 64,
140         "threads": 1,
141         'ratep': 0
142     }
143     print perf.send_start(**send)
144     time.sleep(30)
145     print perf.send_stop()
146     print perf.receive_stop()
147
148
149 if __name__ == "__main__":
150     from vstf.common.log import setup_logging
151
152     setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-pktgen.log", clevel=logging.DEBUG)
153     unit_test()