NFVBENCH-32 Check nan result values before integer casting
[nfvbench.git] / nfvbench / traffic_gen / traffic_utils.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
16 import bitmath
17 from traffic_base import AbstractTrafficGenerator
18
19
20
21 def convert_rates(l2frame_size, rate, intf_speed):
22     avg_packet_size = get_average_packet_size(l2frame_size)
23     if 'rate_pps' in rate:
24         initial_rate_type = 'rate_pps'
25         pps = rate['rate_pps']
26         bps = pps_to_bps(pps, avg_packet_size)
27         load = bps_to_load(bps, intf_speed)
28     elif 'rate_bps' in rate:
29         initial_rate_type = 'rate_bps'
30         bps = rate['rate_bps']
31         load = bps_to_load(bps, intf_speed)
32         pps = bps_to_pps(bps, avg_packet_size)
33     elif 'rate_percent' in rate:
34         initial_rate_type = 'rate_percent'
35         load = rate['rate_percent']
36         bps = load_to_bps(load, intf_speed)
37         pps = bps_to_pps(bps, avg_packet_size)
38     else:
39         raise Exception('Traffic config needs to have a rate type key')
40
41     return {
42         'initial_rate_type': initial_rate_type,
43         'rate_pps': int(pps),
44         'rate_percent': load,
45         'rate_bps': int(bps)
46     }
47
48
49 def get_average_packet_size(l2frame_size):
50     if l2frame_size.upper() == 'IMIX':
51         return AbstractTrafficGenerator.imix_avg_l2_size
52     else:
53         return float(l2frame_size)
54
55
56 def load_to_bps(load_percentage, intf_speed):
57     return float(load_percentage) / 100.0 * intf_speed
58
59
60 def bps_to_load(bps, intf_speed):
61     return float(bps) / intf_speed * 100.0
62
63
64 def bps_to_pps(bps, avg_packet_size):
65     return float(bps) / (avg_packet_size + 20.0) / 8
66
67
68 def pps_to_bps(pps, avg_packet_size):
69     return float(pps) * (avg_packet_size + 20.0) * 8
70
71
72 def weighted_avg(weight, count):
73     if sum(weight):
74         return sum(map(lambda x: x[0] * x[1], zip(weight, count))) / sum(weight)
75     else:
76         return float('nan')
77
78 multiplier_map = {
79     'K': 1000,
80     'M': 1000000,
81     'G': 1000000000
82 }
83
84 def parse_rate_str(rate_str):
85     if rate_str.endswith('pps'):
86         rate_pps = rate_str[:-3]
87         if not rate_pps:
88             raise Exception('%s is missing a numeric value' % rate_str)
89         try:
90             multiplier = multiplier_map[rate_pps[-1].upper()]
91             rate_pps = rate_pps[:-1]
92         except KeyError:
93             multiplier = 1
94         rate_pps = int(rate_pps.strip()) * multiplier
95         if rate_pps <= 0:
96             raise Exception('%s is out of valid range' % rate_str)
97         return {'rate_pps': str(rate_pps)}
98     elif rate_str.endswith('ps'):
99         rate = rate_str.replace('ps', '').strip()
100         bit_rate = bitmath.parse_string(rate).bits
101         if bit_rate <= 0:
102             raise Exception('%s is out of valid range' % rate_str)
103         return {'rate_bps': str(int(bit_rate))}
104     elif rate_str.endswith('%'):
105         rate_percent = float(rate_str.replace('%', '').strip())
106         if rate_percent <= 0 or rate_percent > 100.0:
107             raise Exception('%s is out of valid range (must be 1-100%%)' % rate_str)
108         return {'rate_percent': str(rate_percent)}
109     else:
110         raise Exception('Unknown rate string format %s' % rate_str)
111
112
113 def divide_rate(rate, divisor):
114     if 'rate_pps' in rate:
115         key = 'rate_pps'
116         value = int(rate[key])
117     elif 'rate_bps' in rate:
118         key = 'rate_bps'
119         value = int(rate[key])
120     else:
121         key = 'rate_percent'
122         value = float(rate[key])
123     value /= divisor
124     rate = dict(rate)
125     rate[key] = str(value) if value else str(1)
126     return rate
127
128
129 def to_rate_str(rate):
130     if 'rate_pps' in rate:
131         pps = rate['rate_pps']
132         return '{}pps'.format(pps)
133     elif 'rate_bps' in rate:
134         bps = rate['rate_bps']
135         return '{}bps'.format(bps)
136     elif 'rate_percent' in rate:
137         load = rate['rate_percent']
138         return '{}%'.format(load)
139     else:
140         assert False
141
142
143 def nan_replace(d):
144     """Replaces every occurence of 'N/A' with float nan."""
145     for k, v in d.iteritems():
146         if isinstance(v, dict):
147             nan_replace(v)
148         elif v == 'N/A':
149             d[k] = float('nan')
150
151
152 def mac_to_int(mac):
153     """Converts MAC address to integer representation."""
154     return int(mac.translate(None, ":.- "), 16)
155
156
157 def int_to_mac(i):
158     """Converts integer representation of MAC address to hex string."""
159     mac = format(i, 'x').zfill(12)
160     blocks = [mac[x:x + 2] for x in xrange(0, len(mac), 2)]
161     return ':'.join(blocks)