X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=nfvbench%2Ftraffic_gen%2Ftraffic_utils.py;h=c875a5d7a17c8812bbcd2d42cddf39041d23a29a;hb=95f2491ed89ac99b0d8bd006b4a13cbeb1eb96ce;hp=7cf44a88157f2edfaa9183ad11710988162c4ce0;hpb=97b452affb0e99816ad503a5f79b01f38b93059a;p=nfvbench.git diff --git a/nfvbench/traffic_gen/traffic_utils.py b/nfvbench/traffic_gen/traffic_utils.py index 7cf44a8..c875a5d 100644 --- a/nfvbench/traffic_gen/traffic_utils.py +++ b/nfvbench/traffic_gen/traffic_utils.py @@ -14,43 +14,63 @@ import bitmath -from traffic_base import AbstractTrafficGenerator +from nfvbench.utils import multiplier_map +# 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_pps': int(float(pps)), 'rate_percent': load, - 'rate_bps': int(bps) + 'rate_bps': int(float(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 AbstractTrafficGenerator.imix_avg_l2_size - else: - return float(l2frame_size) + return IMIX_AVG_L2_FRAME_SIZE + return float(l2frame_size) def load_to_bps(load_percentage, intf_speed): @@ -71,15 +91,16 @@ def pps_to_bps(pps, avg_packet_size): 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 -} + 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'): @@ -91,24 +112,43 @@ def parse_rate_str(rate_str): rate_pps = rate_pps[:-1] except KeyError: multiplier = 1 - rate_pps = int(rate_pps.strip()) * multiplier + rate_pps = int(float(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'): + if 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('%'): + if 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)} + 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: - raise Exception('Unknown rate string format %s' % rate_str) - + # 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: @@ -130,19 +170,20 @@ def to_rate_str(rate): if 'rate_pps' in rate: pps = rate['rate_pps'] return '{}pps'.format(pps) - elif 'rate_bps' in rate: + if 'rate_bps' in rate: bps = rate['rate_bps'] return '{}bps'.format(bps) - elif 'rate_percent' in rate: + if 'rate_percent' in rate: load = rate['rate_percent'] return '{}%'.format(load) - else: - assert False + 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(): + for k, v in d.items(): if isinstance(v, dict): nan_replace(v) elif v == 'N/A': @@ -157,5 +198,5 @@ def mac_to_int(mac): 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)] + blocks = [mac[x:x + 2] for x in range(0, len(mac), 2)] return ':'.join(blocks)