-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtraffic_utils.py
189 lines (156 loc) · 6.15 KB
/
traffic_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import bitmath
# IMIX frame size including the 4-byte FCS field
IMIX_L2_SIZES = [64, 594, 1518]
IMIX_RATIOS = [7, 4, 1]
# weighted average l2 frame size includng the 4-byte FCS
IMIX_AVG_L2_FRAME_SIZE = sum(
[1.0 * imix[0] * imix[1] for imix in zip(IMIX_L2_SIZES, IMIX_RATIOS)]) / sum(IMIX_RATIOS)
def convert_rates(l2frame_size, rate, intf_speed):
"""Convert a given rate unit into the other rate units.
l2frame_size: size of the L2 frame in bytes (includes 32-bit FCS) or 'IMIX'
rate: a dict that has at least one of the following key:
'rate_pps', 'rate_bps', 'rate_percent'
with the corresponding input value
intf_speed: the line rate speed in bits per second
"""
avg_packet_size = get_average_packet_size(l2frame_size)
if 'rate_pps' in rate:
# input = packets/sec
initial_rate_type = 'rate_pps'
pps = rate['rate_pps']
bps = pps_to_bps(pps, avg_packet_size)
load = bps_to_load(bps, intf_speed)
elif 'rate_bps' in rate:
# input = bits per second
initial_rate_type = 'rate_bps'
bps = rate['rate_bps']
load = bps_to_load(bps, intf_speed)
pps = bps_to_pps(bps, avg_packet_size)
elif 'rate_percent' in rate:
# input = percentage of the line rate (between 0.0 and 100.0)
initial_rate_type = 'rate_percent'
load = rate['rate_percent']
bps = load_to_bps(load, intf_speed)
pps = bps_to_pps(bps, avg_packet_size)
else:
raise Exception('Traffic config needs to have a rate type key')
return {
'initial_rate_type': initial_rate_type,
'rate_pps': int(pps),
'rate_percent': load,
'rate_bps': int(bps)
}
def get_average_packet_size(l2frame_size):
"""Retrieve the average L2 frame size
l2frame_size: an L2 frame size in bytes (including FCS) or 'IMIX'
return: average l2 frame size inlcuding the 32-bit FCS
"""
if l2frame_size.upper() == 'IMIX':
return IMIX_AVG_L2_FRAME_SIZE
return float(l2frame_size)
def load_to_bps(load_percentage, intf_speed):
return float(load_percentage) / 100.0 * intf_speed
def bps_to_load(bps, intf_speed):
return float(bps) / intf_speed * 100.0
def bps_to_pps(bps, avg_packet_size):
return float(bps) / (avg_packet_size + 20.0) / 8
def pps_to_bps(pps, avg_packet_size):
return float(pps) * (avg_packet_size + 20.0) * 8
def weighted_avg(weight, count):
if sum(weight):
return sum([x[0] * x[1] for x in zip(weight, count)]) / sum(weight)
return float('nan')
def _get_bitmath_rate(rate_bps):
rate = rate_bps.replace('ps', '').strip()
bitmath_rate = bitmath.parse_string(rate)
if bitmath_rate.bits <= 0:
raise Exception('%s is out of valid range' % rate_bps)
return bitmath_rate
def parse_rate_str(rate_str):
if rate_str.endswith('pps'):
rate_pps = rate_str[:-3]
if not rate_pps:
raise Exception('%s is missing a numeric value' % rate_str)
try:
multiplier = multiplier_map[rate_pps[-1].upper()]
rate_pps = rate_pps[:-1]
except KeyError:
multiplier = 1
rate_pps = int(rate_pps.strip()) * multiplier
if rate_pps <= 0:
raise Exception('%s is out of valid range' % rate_str)
return {'rate_pps': str(rate_pps)}
elif rate_str.endswith('ps'):
rate = rate_str.replace('ps', '').strip()
bit_rate = bitmath.parse_string(rate).bits
if bit_rate <= 0:
raise Exception('%s is out of valid range' % rate_str)
return {'rate_bps': str(int(bit_rate))}
elif rate_str.endswith('%'):
rate_percent = float(rate_str.replace('%', '').strip())
if rate_percent <= 0 or rate_percent > 100.0:
raise Exception('%s is out of valid range (must be 1-100%%)' % rate_str)
return {'rate_percent': str(rate_percent)}
else:
raise Exception('Unknown rate string format %s' % rate_str)
def get_load_from_rate(rate_str, avg_frame_size=64, line_rate='10Gbps'):
'''From any rate string (with unit) return the corresponding load (in % unit)
:param str rate_str: the rate to convert - must end with a unit (e.g. 1Mpps, 30%, 1Gbps)
:param int avg_frame_size: average frame size in bytes (needed only if pps is given)
:param str line_rate: line rate ending with bps unit (e.g. 1Mbps, 10Gbps) is the rate that
corresponds to 100% rate
:return float: the corresponding rate in % of line rate
'''
rate_dict = parse_rate_str(rate_str)
if 'rate_percent' in rate_dict:
return float(rate_dict['rate_percent'])
lr_bps = _get_bitmath_rate(line_rate).bits
if 'rate_bps' in rate_dict:
bps = int(rate_dict['rate_bps'])
else:
# must be rate_pps
pps = rate_dict['rate_pps']
bps = pps_to_bps(pps, avg_frame_size)
return bps_to_load(bps, lr_bps)
def divide_rate(rate, divisor):
if 'rate_pps' in rate:
key = 'rate_pps'
value = int(rate[key])
elif 'rate_bps' in rate:
key = 'rate_bps'
value = int(rate[key])
else:
key = 'rate_percent'
value = float(rate[key])
value /= divisor
rate = dict(rate)
rate[key] = str(value) if value else str(1)
return rate
def to_rate_str(rate):
if 'rate_pps' in rate:
pps = rate['rate_pps']
return '{}pps'.format(pps)
elif 'rate_bps' in rate:
bps = rate['rate_bps']
return '{}bps'.format(bps)
elif 'rate_percent' in rate:
load = rate['rate_percent']
return '{}%'.format(load)
assert False
# avert pylint warning
return None
def nan_replace(d):
"""Replaces every occurence of 'N/A' with float nan."""
for k, v in d.iteritems():
if isinstance(v, dict):
nan_replace(v)
elif v == 'N/A':
d[k] = float('nan')
def mac_to_int(mac):
"""Converts MAC address to integer representation."""
return int(mac.translate(None, ":.- "), 16)
def int_to_mac(i):
"""Converts integer representation of MAC address to hex string."""
mac = format(i, 'x').zfill(12)
blocks = [mac[x:x + 2] for x in xrange(0, len(mac), 2)]
return ':'.join(blocks)