5a1178509b020af325fd3a22699c86e635490497
[vswitchperf.git] / tools / pkt_gen / dummy / dummy.py
1 # Copyright 2015 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """
16 Dummy traffic generator, designed for user intput.
17
18 Provides a model for the Dummy traffic generator - a psuedo "traffic
19 generator" that doesn't actually generate any traffic. Instead the
20 user is required to send traffic using their own choice of traffic
21 generator *outside of the framework*. The Dummy traffic generator
22 then returns the results - manually entered by the user - as its
23 own.
24 """
25
26 import json
27
28 from tools.pkt_gen import trafficgen
29 from core.results.results_constants import ResultsConstants
30
31 def _get_user_traffic_stat(stat_type):
32     """
33     Request user input for traffic.
34
35     :param stat_type: Name of statistic required from user
36
37     :returns: Value of stat provided by user
38     """
39     true_vals = ('yes', 'y', 'ye', None)
40     false_vals = ('no', 'n')
41
42     while True:
43         result = input('What was the result for \'%s\'? ' % stat_type)
44
45         try:
46             result = int(result)
47         except ValueError:
48             print('That was not a valid integer result. Try again.')
49             continue
50
51         while True:
52             choice = input('Is \'%d\' correct? ' % result).lower()
53             if not choice or choice in true_vals:
54                 return result
55             elif choice and choice in false_vals:
56                 break
57             else:
58                 print('Please respond with \'yes\' or \'no\' ', end='')
59
60
61 def get_user_traffic(traffic_type, traffic_conf, flow_conf, traffic_stats):
62     """
63     Request user input for traffic.
64
65     :param traffic_type: Name of traffic type.
66     :param traffic_conf: Configuration of traffic to be sent.
67     :param traffic_conf: Configuration of flow to be sent.
68     :param traffic_stats: Required output statistics (i.e. what's needed)
69
70     :returns: List of stats corresponding to those in traffic_stats
71     """
72     results = []
73
74     print('Please send \'%s\' traffic with the following stream config:\n%s\n'
75           'and the following flow config:\n%s'
76           % (traffic_type, traffic_conf, json.dumps(flow_conf, indent=4)))
77
78     for stat in traffic_stats:
79         results.append(_get_user_traffic_stat(stat))
80
81     return results
82
83
84 class Dummy(trafficgen.ITrafficGenerator):
85     """
86     A dummy traffic generator whose data is generated by the user.
87
88     This traffic generator is useful when a user does not wish to write
89     a wrapper for a given type of traffic generator. By using this
90     "traffic generator", the user is asked to send traffic when
91     required and enter the results manually. The user controls the
92     real traffic generator and is responsible for ensuring the flows
93     are setup correctly.
94     """
95     def connect(self):
96         """
97         Do nothing.
98         """
99         return self
100
101     def disconnect(self):
102         """
103         Do nothing.
104         """
105         pass
106
107     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
108         """
109         Send a burst of traffic.
110         """
111         traffic_ = self.traffic_defaults.copy()
112         result = {}
113
114         if traffic:
115             traffic_ = trafficgen.merge_spec(traffic_, traffic)
116
117         results = get_user_traffic(
118             'burst',
119             '%dpkts, %dmS' % (numpkts, duration),
120             traffic_,
121             ('frames rx', 'payload errors', 'sequence errors'))
122
123         # builds results by using user-supplied values where possible
124         # and guessing remainder using available info
125         result[ResultsConstants.TX_FRAMES] = numpkts
126         result[ResultsConstants.RX_FRAMES] = results[0]
127         result[ResultsConstants.TX_BYTES] = traffic_['l2']['framesize'] \
128                                             * numpkts
129         result[ResultsConstants.RX_BYTES] = traffic_['l2']['framesize'] \
130                                             * results[0]
131         result[ResultsConstants.PAYLOAD_ERR] = results[1]
132         result[ResultsConstants.SEQ_ERR] = results[2]
133
134         return trafficgen.BurstResult(*results)
135
136     def send_cont_traffic(self, traffic=None, duration=30, multistream=False):
137         """
138         Send a continuous flow of traffic.
139         """
140         traffic_ = self.traffic_defaults.copy()
141         result = {}
142
143         if traffic:
144             traffic_ = trafficgen.merge_spec(traffic_, traffic)
145
146         results = get_user_traffic(
147             'continuous',
148             '%dmpps, multistream %s duration %d' % (traffic['frame_rate'],
149                                                     multistream, duration), traffic_,
150             ('frames tx', 'frames rx', 'tx rate %','rx rate %' ,'min latency',
151              'max latency','avg latency', 'frameloss %'))
152
153         framesize = traffic_['l2']['framesize']
154
155         # builds results by using user-supplied values
156         # and guessing remainder using available info
157         result[ResultsConstants.TX_RATE_FPS] = float(results[0]) / duration
158         result[ResultsConstants.THROUGHPUT_RX_FPS] = float(results[1]) / duration
159         result[ResultsConstants.TX_RATE_MBPS] = (float(results[0]) / duration) \
160                                                  * (framesize * 8 / 1000000)
161         result[ResultsConstants.THROUGHPUT_RX_MBPS] = (float(results[1]) / duration) \
162                                                  * (framesize * 8 / 1000000)
163         result[ResultsConstants.TX_RATE_PERCENT] = float(results[2])
164         result[ResultsConstants.THROUGHPUT_RX_PERCENT] = float(results[3])
165         result[ResultsConstants.MIN_LATENCY_NS] = float(results[4])
166         result[ResultsConstants.MAX_LATENCY_NS] = float(results[5])
167         result[ResultsConstants.AVG_LATENCY_NS] = float(results[6])
168         result[ResultsConstants.FRAME_LOSS_PERCENT] = float(results[7])
169         return result
170
171     def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
172                                 lossrate=0.0, multistream=False):
173         """
174         Send traffic per RFC2544 throughput test specifications.
175         """
176         traffic_ = self.traffic_defaults.copy()
177         result = {}
178
179         if traffic:
180             traffic_ = trafficgen.merge_spec(traffic_, traffic)
181
182         results = get_user_traffic(
183             'throughput',
184             '%d trials, %d seconds iterations, %f packet loss, multistream '
185             '%s' % (trials, duration, lossrate,
186                     'enabled' if multistream else 'disabled'),
187             traffic_,
188              ('frames tx', 'frames rx', 'tx rate %','rx rate %' ,'min latency',
189              'max latency','avg latency', 'frameloss %'))
190
191         framesize = traffic_['l2']['framesize']
192
193         # builds results by using user-supplied values
194         # and guessing remainder using available info
195         result[ResultsConstants.TX_RATE_FPS] = float(results[0]) / duration
196         result[ResultsConstants.THROUGHPUT_RX_FPS] = float(results[1]) / duration
197         result[ResultsConstants.TX_RATE_MBPS] = (float(results[0]) / duration) \
198                                                  * (framesize * 8 / 1000000)
199         result[ResultsConstants.THROUGHPUT_RX_MBPS] = (float(results[1]) / duration) \
200                                                  * (framesize * 8 / 1000000)
201         result[ResultsConstants.TX_RATE_PERCENT] = float(results[2])
202         result[ResultsConstants.THROUGHPUT_RX_PERCENT] = float(results[3])
203         result[ResultsConstants.MIN_LATENCY_NS] = float(results[4])
204         result[ResultsConstants.MAX_LATENCY_NS] = float(results[5])
205         result[ResultsConstants.AVG_LATENCY_NS] = float(results[6])
206         result[ResultsConstants.FRAME_LOSS_PERCENT] = float(results[7])
207         return result
208
209
210 if __name__ == '__main__':
211     TRAFFIC = {
212         'l3': {
213             'proto': 'tcp',
214             'srcip': '1.1.1.1',
215             'dstip': '90.90.90.90',
216         },
217     }
218
219     with Dummy() as dev:
220         print(dev.send_burst_traffic(traffic=TRAFFIC))
221         print(dev.send_cont_traffic(traffic=TRAFFIC))
222         print(dev.send_rfc(traffic=TRAFFIC))