summaryrefslogtreecommitdiffstats
path: root/nfvbench/traffic_gen/traffic_utils.py
blob: e5dc4635b22d8aabdba02fe782f467a1ab68f123 (plain)
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
# Copyright 2016 Cisco Systems, Inc.  All rights reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.


import bitmath
from traffic_base import AbstractTrafficGenerator


def convert_rates(l2frame_size, rate, intf_speed):
    avg_packet_size = get_average_packet_size(l2frame_size)
    if 'rate_pps' in rate:
        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:
        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:
        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': pps,
        'rate_percent': load,
        'rate_bps': bps
    }


def get_average_packet_size(l2frame_size):
    if l2frame_size.upper() == 'IMIX':
        return AbstractTrafficGenerator.imix_avg_l2_size
    else:
        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(map(lambda x: x[0] * x[1], zip(weight, count))) / sum(weight)
    else:
        return float('nan')

multiplier_map = {
    'K': 1000,
    'M': 1000000,
    'G': 1000000000
}

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 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)
    else:
        assert False


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)