X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=yardstick%2Fnetwork_services%2Ftraffic_profile%2Ftraffic_profile.py;h=3b19ff9be82a2fd9d36d79cbd3f98ffbfb8dc534;hb=4e5893873d684069e57b2ef91a75b446bb319d56;hp=7bbe89268b78bbf5e9457e60d4d0ed3a7341f1de;hpb=f782dba09843df25cefb243dab9bc24d9a9c93b6;p=yardstick.git diff --git a/yardstick/network_services/traffic_profile/traffic_profile.py b/yardstick/network_services/traffic_profile/traffic_profile.py index 7bbe89268..3b19ff9be 100644 --- a/yardstick/network_services/traffic_profile/traffic_profile.py +++ b/yardstick/network_services/traffic_profile/traffic_profile.py @@ -19,6 +19,7 @@ import socket import logging from random import SystemRandom import six +import ipaddress from yardstick.network_services.traffic_profile.base import TrafficProfile from trex_stl_lib.trex_stl_client import STLStream @@ -33,203 +34,100 @@ from trex_stl_lib.trex_stl_packet_builder_scapy import STLScVmRaw from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFixIpv4 from trex_stl_lib import api as Pkt +SRC = 'src' +DST = 'dst' +ETHERNET = 'Ethernet' +IP = 'IP' +IPv6 = 'IPv6' +UDP = 'UDP' +DSCP = 'DSCP' +SRC_PORT = 'sport' +DST_PORT = 'dport' +TYPE_OF_SERVICE = 'tos' -class TrexProfile(TrafficProfile): - """ This class handles Trex Traffic profile generation and execution """ +LOG = logging.getLogger(__name__) - def __init__(self, yaml_data): - super(TrexProfile, self).__init__(yaml_data) - self.flows = 100 - self.pps = 100 - self.pg_id = 0 - self.first_run = True - self.streams = 1 - self.profile_data = [] - self.profile = None - self.base_pkt = None - self.fsize = None - self.trex_vm = None - self.vms = [] - self.rate = None - self.ip_packet = None - self.ip6_packet = None - self.udp_packet = None - self.udp_dport = '' - self.udp_sport = '' - self.qinq_packet = None - self.qinq = False - self.vm_flow_vars = [] - self.packets = [] - self.ether_packet = [] - def execute(self, traffic_generator): - """ Generate the stream and run traffic on the given ports """ - pass - - def _set_ether_fields(self, **kwargs): - """ set ethernet protocol fields """ - if not self.ether_packet: - self.ether_packet = Pkt.Ether() - for key, value in six.iteritems(kwargs): - setattr(self.ether_packet, key, value) - - def _set_ip_fields(self, **kwargs): - """ set l3 ipv4 protocol fields """ - - if not self.ip_packet: - self.ip_packet = Pkt.IP() - for key in kwargs: - setattr(self.ip_packet, key, kwargs[key]) - - def _set_ip6_fields(self, **kwargs): - """ set l3 ipv6 protocol fields """ - if not self.ip6_packet: - self.ip6_packet = Pkt.IPv6() - for key in kwargs: - setattr(self.ip6_packet, key, kwargs[key]) - - def _set_udp_fields(self, **kwargs): - """ set l4 udp ports fields """ - if not self.udp_packet: - self.udp_packet = Pkt.UDP() - for key in kwargs: - setattr(self.udp_packet, key, kwargs[key]) - - def set_src_mac(self, src_mac): - """ set source mac address fields """ - src_macs = src_mac.split('-') - min_value = src_macs[0] - if len(src_macs) == 1: - src_mac = min_value - self._set_ether_fields(src=src_mac) - else: - stl_vm_flow_var = STLVmFlowVar(name="mac_src", - min_value=1, - max_value=30, - size=4, - op='inc', - step=1) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_src', - pkt_offset='Ether.src') - self.vm_flow_vars.append(stl_vm_wr_flow_var) +class TrexProfile(TrafficProfile): + """ This class handles Trex Traffic profile generation and execution """ - def set_dst_mac(self, dst_mac): - """ set destination mac address fields """ - dst_macs = dst_mac.split('-') - min_value = dst_macs[0] - if len(dst_macs) == 1: - dst_mac = min_value - self._set_ether_fields(dst=dst_mac) - else: - stl_vm_flow_var = STLVmFlowVar(name="mac_dst", + PROTO_MAP = { + ETHERNET: ('ether_packet', Pkt.Ether), + IP: ('ip_packet', Pkt.IP), + IPv6: ('ip6_packet', Pkt.IPv6), + UDP: ('udp_packet', Pkt.UDP), + } + + def _general_single_action_partial(self, protocol): + def f(field): + def partial(value): + kwargs = { + field: value + } + self._set_proto_fields(protocol, **kwargs) + return partial + return f + + def _ethernet_range_action_partial(self, direction, _): + def partial(min_value, max_value, count): + # pylint: disable=unused-argument + stl_vm_flow_var = STLVmFlowVar(name="mac_{}".format(direction), min_value=1, max_value=30, size=4, op='inc', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_dst', - pkt_offset='Ether.dst') + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_{}'.format(direction), + pkt_offset='Ether.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) - - def set_src_ip4(self, src_ip4, count=1): - """ set source ipv4 address fields """ - src_ips = src_ip4.split('-') - min_value = src_ips[0] - max_value = src_ips[1] if len(src_ips) == 2 else src_ips[0] - if len(src_ips) == 1: - src_ip4 = min_value - self._set_ip_fields(src=src_ip4) - else: - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="ip4_src", - min_value=min_value, - max_value=max_value, - size=4, - limit=int(count), - seed=0x1235) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip4_src', - pkt_offset='IP.src') - self.vm_flow_vars.append(stl_vm_wr_flow_var) - stl_vm_fix_ipv4 = STLVmFixIpv4(offset="IP") - self.vm_flow_vars.append(stl_vm_fix_ipv4) - - def set_dst_ip4(self, dst_ip4, count=1): - """ set destination ipv4 address fields """ - dst_ips = dst_ip4.split('-') - min_value = dst_ips[0] - max_value = dst_ips[1] if len(dst_ips) == 2 else dst_ips[0] - if len(dst_ips) == 1: - dst_ip4 = min_value - self._set_ip_fields(dst=dst_ip4) - else: - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="dst_ip4", + return partial + + def _ip_range_action_partial(self, direction, count=1): + # pylint: disable=unused-argument + def partial(min_value, max_value, count): + ip1 = int(ipaddress.IPv4Address(min_value)) + ip2 = int(ipaddress.IPv4Address(max_value)) + actual_count = (ip2 - ip1) + if not actual_count: + count = 1 + elif actual_count < int(count): + count = actual_count + + stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="ip4_{}".format(direction), min_value=min_value, max_value=max_value, size=4, limit=int(count), seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='dst_ip4', - pkt_offset='IP.dst') + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip4_{}'.format(direction), + pkt_offset='IP.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) stl_vm_fix_ipv4 = STLVmFixIpv4(offset="IP") self.vm_flow_vars.append(stl_vm_fix_ipv4) + return partial - def set_src_ip6(self, src_ip6): - """ set source ipv6 address fields """ - src_ips = src_ip6.split('-') - min_value = src_ips[0] - max_value = src_ips[1] if len(src_ips) == 2 else src_ips[0] - src_ip6 = min_value - self._set_ip6_fields(src=src_ip6) - if len(src_ips) == 2: - min_value, max_value = \ - self._get_start_end_ipv6(min_value, max_value) - stl_vm_flow_var = STLVmFlowVar(name="ip6_src", - min_value=min_value, - max_value=max_value, - size=8, - op='random', - step=1) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip6_src', - pkt_offset='IPv6.src', - offset_fixup=8) - self.vm_flow_vars.append(stl_vm_wr_flow_var) - - def set_dst_ip6(self, dst_ip6): - """ set destination ipv6 address fields """ - dst_ips = dst_ip6.split('-') - min_value = dst_ips[0] - max_value = dst_ips[1] if len(dst_ips) == 2 else dst_ips[0] - dst_ip6 = min_value - self._set_ip6_fields(dst=dst_ip6) - if len(dst_ips) == 2: - min_value, max_value = \ - self._get_start_end_ipv6(min_value, max_value) - stl_vm_flow_var = STLVmFlowVar(name="dst_ip6", + def _ip6_range_action_partial(self, direction, _): + def partial(min_value, max_value, count): + # pylint: disable=unused-argument + min_value, max_value = self._get_start_end_ipv6(min_value, max_value) + stl_vm_flow_var = STLVmFlowVar(name="ip6_{}".format(direction), min_value=min_value, max_value=max_value, size=8, op='random', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='dst_ip6', - pkt_offset='IPv6.dst', + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip6_{}'.format(direction), + pkt_offset='IPv6.{}'.format(direction), offset_fixup=8) self.vm_flow_vars.append(stl_vm_wr_flow_var) + return partial - def set_dscp(self, dscp): - """ set dscp for trex """ - dscps = str(dscp).split('-') - min_value = int(dscps[0]) - max_value = int(dscps[1]) if len(dscps) == 2 else int(dscps[0]) - if len(dscps) == 1: - dscp = min_value - self._set_ip_fields(tos=dscp) - else: + def _dscp_range_action_partial(self, *_): + def partial(min_value, max_value, count): + # pylint: disable=unused-argument stl_vm_flow_var = STLVmFlowVar(name="dscp", min_value=min_value, max_value=max_value, @@ -240,55 +138,122 @@ class TrexProfile(TrafficProfile): stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='dscp', pkt_offset='IP.tos') self.vm_flow_vars.append(stl_vm_wr_flow_var) - - def set_src_port(self, src_port, count=1): - """ set packet source port """ - src_ports = str(src_port).split('-') - min_value = int(src_ports[0]) - if len(src_ports) == 1: - max_value = int(src_ports[0]) - src_port = min_value - self._set_udp_fields(sport=src_port) - else: - max_value = int(src_ports[1]) - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="port_src", + return partial + + def _udp_range_action_partial(self, field, count=1): + # pylint: disable=unused-argument + def partial(min_value, max_value, count): + actual_count = int(max_value) - int(min_value) + if not actual_count: + count = 1 + elif int(count) > actual_count: + count = actual_count + + stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="port_{}".format(field), min_value=min_value, max_value=max_value, size=2, limit=int(count), seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_src', - pkt_offset=self.udp_sport) + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_{}'.format(field), + pkt_offset=self.udp[field]) self.vm_flow_vars.append(stl_vm_wr_flow_var) + return partial + + def __init__(self, yaml_data): + super(TrexProfile, self).__init__(yaml_data) + self.flows = 100 + self.pps = 100 + self.pg_id = 0 + self.first_run = True + self.streams = 1 + self.profile_data = [] + self.profile = None + self.base_pkt = None + self.fsize = None + self.trex_vm = None + self.vms = [] + self.rate = None + self.ether_packet = None + self.ip_packet = None + self.ip6_packet = None + self.udp_packet = None + self.udp = { + SRC_PORT: '', + DST_PORT: '', + } + self.qinq_packet = None + self.qinq = False + self.vm_flow_vars = [] + self.packets = [] + + self._map_proto_actions = { + # the tuple is (single value function, range value function, if the values should be + # converted to integer). + ETHERNET: (self._general_single_action_partial(ETHERNET), + self._ethernet_range_action_partial, + False, + ), + IP: (self._general_single_action_partial(IP), + self._ip_range_action_partial, + False, + ), + IPv6: (self._general_single_action_partial(IPv6), + self._ip6_range_action_partial, + False, + ), + DSCP: (self._general_single_action_partial(IP), + self._dscp_range_action_partial, + True, + ), + UDP: (self._general_single_action_partial(UDP), + self._udp_range_action_partial, + True, + ), + } + + def execute_traffic(self, traffic_generator): + """ Generate the stream and run traffic on the given ports """ + raise NotImplementedError() - def set_dst_port(self, dst_port, count=1): - """ set packet destnation port """ - dst_ports = str(dst_port).split('-') - min_value = int(dst_ports[0]) - if len(dst_ports) == 1: - max_value = int(dst_ports[0]) - dst_port = min_value - self._set_udp_fields(dport=dst_port) + def _call_on_range(self, range, single_action, range_action, count=1, to_int=False): + def convert_to_int(val): + return int(val) if to_int else val + + range_iter = iter(str(range).split('-')) + min_value = convert_to_int(next(range_iter)) + try: + max_value = convert_to_int(next(range_iter)) + except StopIteration: + single_action(min_value) else: - max_value = int(dst_ports[1]) - stl_vm_flow_var = \ - STLVmFlowVarRepeatableRandom(name="port_dst", - min_value=min_value, - max_value=max_value, - size=2, - limit=int(count), - seed=0x1235) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_dst', - pkt_offset=self.udp_dport) - self.vm_flow_vars.append(stl_vm_wr_flow_var) + range_action(min_value=min_value, max_value=max_value, count=count) + + def _set_proto_addr(self, protocol, field, address, count=1): + single_action, range_action, to_int = self._map_proto_actions[protocol] + self._call_on_range(address, + single_action(field), + range_action(field, count), + count=count, + to_int=to_int, + ) + + def _set_proto_fields(self, protocol, **kwargs): + _attr_name, _class = self.PROTO_MAP[protocol] + + if not getattr(self, _attr_name): + setattr(self, _attr_name, _class()) + + _attr = getattr(self, _attr_name) + for key, value in six.iteritems(kwargs): + setattr(_attr, key, value) def set_svlan_cvlan(self, svlan, cvlan): """ set svlan & cvlan """ self.qinq = True ether_params = {'type': 0x8100} - self._set_ether_fields(**ether_params) + self._set_proto_fields(ETHERNET, **ether_params) svlans = str(svlan['id']).split('-') svlan_min = int(svlans[0]) svlan_max = int(svlans[1]) if len(svlans) == 2 else int(svlans[0]) @@ -309,69 +274,69 @@ class TrexProfile(TrafficProfile): """ set qinq in packet """ self.set_svlan_cvlan(qinq['S-VLAN'], qinq['C-VLAN']) - def set_outer_l2_fields(self, outer_l2): + def _set_outer_l2_fields(self, outer_l2): """ setup outer l2 fields from traffic profile """ ether_params = {'type': 0x800} - self._set_ether_fields(**ether_params) + self._set_proto_fields(ETHERNET, **ether_params) if 'srcmac' in outer_l2: - self.set_src_mac(outer_l2['srcmac']) + self._set_proto_addr(ETHERNET, SRC, outer_l2['srcmac']) if 'dstmac' in outer_l2: - self.set_dst_mac(outer_l2['dstmac']) + self._set_proto_addr(ETHERNET, DST, outer_l2['dstmac']) if 'QinQ' in outer_l2: self.set_qinq(outer_l2['QinQ']) - def set_outer_l3v4_fields(self, outer_l3v4): + def _set_outer_l3v4_fields(self, outer_l3v4): """ setup outer l3v4 fields from traffic profile """ ip_params = {} if 'proto' in outer_l3v4: - ip_params['proto'] = outer_l3v4['proto'] + ip_params['proto'] = socket.getprotobyname(outer_l3v4['proto']) if outer_l3v4['proto'] == 'tcp': self.udp_packet = Pkt.TCP() - self.udp_dport = 'TCP.dport' - self.udp_sport = 'TCP.sport' + self.udp[DST_PORT] = 'TCP.dport' + self.udp[SRC_PORT] = 'TCP.sport' tcp_params = {'flags': '', 'window': 0} - self._set_udp_fields(**tcp_params) + self._set_proto_fields(UDP, **tcp_params) if 'ttl' in outer_l3v4: ip_params['ttl'] = outer_l3v4['ttl'] - self._set_ip_fields(**ip_params) + self._set_proto_fields(IP, **ip_params) if 'dscp' in outer_l3v4: - self.set_dscp(outer_l3v4['dscp']) + self._set_proto_addr(DSCP, TYPE_OF_SERVICE, outer_l3v4['dscp']) if 'srcip4' in outer_l3v4: - self.set_src_ip4(outer_l3v4['srcip4'], outer_l3v4['count']) + self._set_proto_addr(IP, SRC, outer_l3v4['srcip4'], outer_l3v4['count']) if 'dstip4' in outer_l3v4: - self.set_dst_ip4(outer_l3v4['dstip4'], outer_l3v4['count']) + self._set_proto_addr(IP, DST, outer_l3v4['dstip4'], outer_l3v4['count']) - def set_outer_l3v6_fields(self, outer_l3v6): + def _set_outer_l3v6_fields(self, outer_l3v6): """ setup outer l3v6 fields from traffic profile """ ether_params = {'type': 0x86dd} - self._set_ether_fields(**ether_params) + self._set_proto_fields(ETHERNET, **ether_params) ip6_params = {} if 'proto' in outer_l3v6: ip6_params['proto'] = outer_l3v6['proto'] if outer_l3v6['proto'] == 'tcp': self.udp_packet = Pkt.TCP() - self.udp_dport = 'TCP.dport' - self.udp_sport = 'TCP.sport' + self.udp[DST_PORT] = 'TCP.dport' + self.udp[SRC_PORT] = 'TCP.sport' tcp_params = {'flags': '', 'window': 0} - self._set_udp_fields(**tcp_params) + self._set_proto_fields(UDP, **tcp_params) if 'ttl' in outer_l3v6: ip6_params['ttl'] = outer_l3v6['ttl'] if 'tc' in outer_l3v6: ip6_params['tc'] = outer_l3v6['tc'] if 'hlim' in outer_l3v6: ip6_params['hlim'] = outer_l3v6['hlim'] - self._set_ip6_fields(**ip6_params) + self._set_proto_fields(IPv6, **ip6_params) if 'srcip6' in outer_l3v6: - self.set_src_ip6(outer_l3v6['srcip6']) + self._set_proto_addr(IPv6, SRC, outer_l3v6['srcip6']) if 'dstip6' in outer_l3v6: - self.set_dst_ip6(outer_l3v6['dstip6']) + self._set_proto_addr(IPv6, DST, outer_l3v6['dstip6']) - def set_outer_l4_fields(self, outer_l4): + def _set_outer_l4_fields(self, outer_l4): """ setup outer l4 fields from traffic profile """ if 'srcport' in outer_l4: - self.set_src_port(outer_l4['srcport'], outer_l4['count']) + self._set_proto_addr(UDP, SRC_PORT, outer_l4['srcport'], outer_l4['count']) if 'dstport' in outer_l4: - self.set_dst_port(outer_l4['dstport'], outer_l4['count']) + self._set_proto_addr(UDP, DST_PORT, outer_l4['dstport'], outer_l4['count']) def generate_imix_data(self, packet_definition): """ generate packet size for a given traffic profile """ @@ -425,8 +390,8 @@ class TrexProfile(TrafficProfile): self.ip_packet = Pkt.IP() self.ip6_packet = None self.udp_packet = Pkt.UDP() - self.udp_dport = 'UDP.dport' - self.udp_sport = 'UDP.sport' + self.udp[DST_PORT] = 'UDP.dport' + self.udp[SRC_PORT] = 'UDP.sport' self.qinq = False self.vm_flow_vars = [] outer_l2 = packet_definition.get('outer_l2', None) @@ -434,13 +399,13 @@ class TrexProfile(TrafficProfile): outer_l3v6 = packet_definition.get('outer_l3v6', None) outer_l4 = packet_definition.get('outer_l4', None) if outer_l2: - self.set_outer_l2_fields(outer_l2) + self._set_outer_l2_fields(outer_l2) if outer_l3v4: - self.set_outer_l3v4_fields(outer_l3v4) + self._set_outer_l3v4_fields(outer_l3v4) if outer_l3v6: - self.set_outer_l3v6_fields(outer_l3v6) + self._set_outer_l3v6_fields(outer_l3v6) if outer_l4: - self.set_outer_l4_fields(outer_l4) + self._set_outer_l4_fields(outer_l4) self.trex_vm = STLScVmRaw(self.vm_flow_vars) def generate_packets(self):