2.0 beta NFVBENCH-91 Allow multi-chaining with separate edge networks
[nfvbench.git] / nfvbench / traffic_gen / dummy.py
1 # Copyright 2016 Cisco Systems, Inc.  All rights reserved.
2 #
3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
4 #    not use this file except in compliance with the License. You may obtain
5 #    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, WITHOUT
11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 #    License for the specific language governing permissions and limitations
13 #    under the License.
14
15 from nfvbench.log import LOG
16 from traffic_base import AbstractTrafficGenerator
17 import traffic_utils as utils
18
19
20 class DummyTG(AbstractTrafficGenerator):
21     """Experimental dummy traffic generator.
22
23     This traffic generator will pretend to generate traffic and return fake data.
24     Useful for unit testing without actually generating any traffic.
25     """
26
27     def __init__(self, traffic_client):
28         AbstractTrafficGenerator.__init__(self, traffic_client)
29         self.port_handle = []
30         self.rates = []
31         self.l2_frame_size = 0
32         self.duration_sec = traffic_client.config.duration_sec
33         self.intf_speed = traffic_client.generator_config.intf_speed
34         self.set_response_curve()
35         # for packet capture, generate 2*scc random packets
36         # normally we should generate packets coming from the right dest macs
37         scc = traffic_client.config.service_chain_count
38         self.packet_list = [self._get_packet_capture(mac_id) for mac_id in range(scc * 2)]
39
40     def _get_packet_capture(self, mac_id):
41         return {'binary': 'SSSSSS01234' + str(mac_id)}
42
43     def get_version(self):
44         return "0.1"
45
46     def get_tx_pps_dropped_pps(self, tx_rate):
47         """Get actual tx packets based on requested tx rate.
48
49         :param tx_rate: requested TX rate with unit ('40%', '1Mbps', '1000pps')
50
51         :return: the actual TX pps and the dropped pps corresponding to the requested TX rate
52         """
53         dr, tx = self.__get_dr_actual_tx(tx_rate)
54         actual_tx_bps = utils.load_to_bps(tx, self.intf_speed)
55         avg_packet_size = utils.get_average_packet_size(self.l2_frame_size)
56         tx_packets = utils.bps_to_pps(actual_tx_bps, avg_packet_size)
57
58         dropped = tx_packets * dr / 100
59         # print '===get_tx_pkts_dropped_pkts req tex=', tx_rate, 'dr=', dr,
60         # 'actual tx rate=', tx, 'actual tx pkts=', tx_packets, 'dropped=', dropped
61         return int(tx_packets), int(dropped)
62
63     def set_response_curve(self, lr_dr=0, ndr=100, max_actual_tx=100, max_11_tx=100):
64         """Set traffic gen response characteristics.
65
66         Specifies the drop rate curve and the actual TX curve
67         :param float lr_dr: The actual drop rate at TX line rate (in %, 0..100)
68         :param float ndr: The true NDR  (0 packet drop) in % (0..100) of line rate"
69         :param float max_actual_tx: highest actual TX when requested TX is 100%
70         :param float max_11_tx: highest requested TX that results in same actual TX
71         """
72         self.target_ndr = ndr
73         if ndr < 100:
74             self.dr_slope = float(lr_dr) / (100 - ndr)
75         else:
76             self.dr_slope = 0
77         self.max_11_tx = max_11_tx
78         self.max_actual_tx = max_actual_tx
79         if max_11_tx < 100:
80             self.tx_slope = float(max_actual_tx - max_11_tx) / (100 - max_11_tx)
81         else:
82             self.tx_slope = 0
83
84     def __get_dr_actual_tx(self, requested_tx_rate):
85         """Get drop rate at given requested tx rate.
86
87         :param float requested_tx_rate: requested tx rate in % (0..100)
88         :return: the drop rate and actual tx rate at that requested_tx_rate in % (0..100)
89         """
90         if requested_tx_rate <= self.max_11_tx:
91             actual_tx = requested_tx_rate
92         else:
93             actual_tx = self.max_11_tx + (requested_tx_rate - self.max_11_tx) * self.tx_slope
94         if actual_tx <= self.target_ndr:
95             dr = 0.0
96         else:
97             dr = (actual_tx - self.target_ndr) * self.dr_slope
98         return dr, actual_tx
99
100     def connect(self):
101         ports = list(self.traffic_client.generator_config.ports)
102         self.port_handle = ports
103
104     def create_traffic(self, l2frame_size, rates, bidirectional, latency=True):
105         self.rates = [utils.to_rate_str(rate) for rate in rates]
106         self.l2_frame_size = l2frame_size
107
108     def clear_streamblock(self):
109         pass
110
111     def get_stats(self):
112         """Get stats from current run.
113
114         The binary search mainly looks at 2 results to make the decision:
115             actual tx packets
116             actual rx dropped packets
117         From the Requested TX rate - we get the Actual TX rate and the RX drop rate
118         From the Run duration and actual TX rate - we get the actual total tx packets
119         From the Actual tx packets and RX drop rate - we get the RX dropped packets
120         """
121         result = {}
122         total_tx_pps = 0
123
124         # use dummy values for all other result field as the goal is to
125         # test the ndr/pdr convergence code
126         for idx, ph in enumerate(self.port_handle):
127             requested_tx_rate = utils.get_load_from_rate(self.rates[idx])
128             tx_pps, dropped_pps = self.get_tx_pps_dropped_pps(requested_tx_rate)
129
130             # total packets sent per direction - used by binary search
131             total_pkts = tx_pps * self.duration_sec
132             dropped_pkts = dropped_pps * self.duration_sec
133             _, tx_pkt_rate = self.__get_dr_actual_tx(requested_tx_rate)
134             result[ph] = {
135                 'tx': {
136                     'total_pkts': total_pkts,
137                     'total_pkt_bytes': 100000,
138                     'pkt_rate': tx_pkt_rate,
139                     'pkt_bit_rate': 1000000
140                 },
141                 'rx': {
142                     # total packets received
143                     'total_pkts': total_pkts - dropped_pkts,
144                     'total_pkt_bytes': 100000,
145                     'pkt_rate': 100,
146                     'pkt_bit_rate': 1000000,
147                     'dropped_pkts': dropped_pkts
148                 }
149             }
150             result[ph]['rx']['max_delay_usec'] = 10.0
151             result[ph]['rx']['min_delay_usec'] = 1.0
152             result[ph]['rx']['avg_delay_usec'] = 2.0
153             total_tx_pps += tx_pps
154         # actual total tx rate in pps
155         result['total_tx_rate'] = total_tx_pps
156         return result
157
158     def get_stream_stats(self, tg_stats, if_stats, latencies, chain_idx):
159         for port in range(2):
160             if_stats[port].tx = 1000
161             if_stats[port].rx = 1000
162             latencies[port].min_usec = 10
163             latencies[port].max_usec = 100
164             latencies[port].avg_usec = 50
165
166     def get_macs(self):
167         return ['00.00.00.00.00.01', '00.00.00.00.00.02']
168
169     def get_port_speed_gbps(self):
170         """Return the local port speeds.
171
172         return: a list of speed in Gbps indexed by the port#
173         """
174         return [10, 10]
175
176     def clear_stats(self):
177         pass
178
179     def start_traffic(self):
180         pass
181
182     def fetch_capture_packets(self):
183         pass
184
185     def stop_traffic(self):
186         pass
187
188     def start_capture(self):
189         pass
190
191     def stop_capture(self):
192         pass
193
194     def cleanup(self):
195         pass
196
197     def set_mode(self):
198         pass
199
200     def resolve_arp(self):
201         """Resolve ARP sucessfully."""
202         LOG.info('Dummy TG ARP OK')
203         return True