aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/network_services/traffic_profile/traffic_profile.py
diff options
context:
space:
mode:
Diffstat (limited to 'yardstick/network_services/traffic_profile/traffic_profile.py')
-rw-r--r--yardstick/network_services/traffic_profile/traffic_profile.py499
1 files changed, 499 insertions, 0 deletions
diff --git a/yardstick/network_services/traffic_profile/traffic_profile.py b/yardstick/network_services/traffic_profile/traffic_profile.py
new file mode 100644
index 000000000..156cc6644
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/traffic_profile.py
@@ -0,0 +1,499 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# 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.
+""" Trex Traffic Profile definitions """
+
+from __future__ import absolute_import
+import struct
+import socket
+import logging
+from random import SystemRandom
+import six
+
+from yardstick.network_services.traffic_profile.base import TrafficProfile
+from stl.trex_stl_lib.trex_stl_client import STLStream
+from stl.trex_stl_lib.trex_stl_streams import STLFlowLatencyStats
+from stl.trex_stl_lib.trex_stl_streams import STLTXCont
+from stl.trex_stl_lib.trex_stl_streams import STLProfile
+from stl.trex_stl_lib.trex_stl_packet_builder_scapy import STLVmWrFlowVar
+from stl.trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVar
+from stl.trex_stl_lib.trex_stl_packet_builder_scapy import STLPktBuilder
+from stl.trex_stl_lib.trex_stl_packet_builder_scapy import STLScVmRaw
+from stl.trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFixIpv4
+from stl.trex_stl_lib import api as Pkt
+
+
+class TrexProfile(TrafficProfile):
+ """ This class handles Trex Traffic profile generation and execution """
+
+ 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)
+
+ 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",
+ 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')
+ self.vm_flow_vars.append(stl_vm_wr_flow_var)
+
+ def set_src_ip4(self, src_ip4):
+ """ 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 = STLVmFlowVar(name="ip4_src",
+ min_value=min_value,
+ max_value=max_value,
+ size=4,
+ op='random',
+ step=1)
+ 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):
+ """ 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 = STLVmFlowVar(name="dst_ip4",
+ min_value=min_value,
+ max_value=max_value,
+ size=4,
+ op='random',
+ step=1)
+ self.vm_flow_vars.append(stl_vm_flow_var)
+ stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='dst_ip4',
+ pkt_offset='IP.dst')
+ 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_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",
+ 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',
+ offset_fixup=8)
+ self.vm_flow_vars.append(stl_vm_wr_flow_var)
+
+ 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:
+ stl_vm_flow_var = STLVmFlowVar(name="dscp",
+ min_value=min_value,
+ max_value=max_value,
+ size=2,
+ op='inc',
+ step=8)
+ self.vm_flow_vars.append(stl_vm_flow_var)
+ 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):
+ """ 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 = STLVmFlowVar(name="port_src",
+ min_value=min_value,
+ max_value=max_value,
+ size=2,
+ op='random',
+ step=1)
+ self.vm_flow_vars.append(stl_vm_flow_var)
+ stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_src',
+ pkt_offset=self.udp_sport)
+ self.vm_flow_vars.append(stl_vm_wr_flow_var)
+
+ def set_dst_port(self, dst_port):
+ """ 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)
+ else:
+ max_value = int(dst_ports[1])
+ stl_vm_flow_var = STLVmFlowVar(name="port_dst",
+ min_value=min_value,
+ max_value=max_value,
+ size=2,
+ op='random',
+ step=1)
+ 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)
+
+ def set_svlan_cvlan(self, svlan, cvlan):
+ """ set svlan & cvlan """
+ self.qinq = True
+ ether_params = {'type': 0x8100}
+ self._set_ether_fields(**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])
+ if len(svlans) == 2:
+ svlan = self._get_random_value(svlan_min, svlan_max)
+ else:
+ svlan = svlan_min
+ cvlans = str(cvlan['id']).split('-')
+ cvlan_min = int(cvlans[0])
+ cvlan_max = int(cvlans[1]) if len(cvlans) == 2 else int(cvlans[0])
+ if len(cvlans) == 2:
+ cvlan = self._get_random_value(cvlan_min, cvlan_max)
+ else:
+ cvlan = cvlan_min
+ self.qinq_packet = Pkt.Dot1Q(vlan=svlan) / Pkt.Dot1Q(vlan=cvlan)
+
+ def set_qinq(self, qinq):
+ """ set qinq in packet """
+ self.set_svlan_cvlan(qinq['S-VLAN'], qinq['C-VLAN'])
+
+ 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)
+ if 'srcmac' in outer_l2:
+ self.set_src_mac(outer_l2['srcmac'])
+ if 'dstmac' in outer_l2:
+ self.set_dst_mac(outer_l2['dstmac'])
+ if 'QinQ' in outer_l2:
+ self.set_qinq(outer_l2['QinQ'])
+
+ 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']
+ if outer_l3v4['proto'] == 'tcp':
+ self.udp_packet = Pkt.TCP()
+ self.udp_dport = 'TCP.dport'
+ self.udp_sport = 'TCP.sport'
+ tcp_params = {'flags': '', 'window': 0}
+ self._set_udp_fields(**tcp_params)
+ if 'ttl' in outer_l3v4:
+ ip_params['ttl'] = outer_l3v4['ttl']
+ self._set_ip_fields(**ip_params)
+ if 'dscp' in outer_l3v4:
+ self.set_dscp(outer_l3v4['dscp'])
+ if 'srcip4' in outer_l3v4:
+ self.set_src_ip4(outer_l3v4['srcip4'])
+ if 'dstip4' in outer_l3v4:
+ self.set_dst_ip4(outer_l3v4['dstip4'])
+
+ 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)
+ 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'
+ tcp_params = {'flags': '', 'window': 0}
+ self._set_udp_fields(**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)
+ if 'srcip6' in outer_l3v6:
+ self.set_src_ip6(outer_l3v6['srcip6'])
+ if 'dstip6' in outer_l3v6:
+ self.set_dst_ip6(outer_l3v6['dstip6'])
+
+ 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'])
+ if 'dstport' in outer_l4:
+ self.set_dst_port(outer_l4['dstport'])
+
+ def generate_imix_data(self, packet_definition):
+ """ generate packet size for a given traffic profile """
+ imix_count = {}
+ imix_data = {}
+ if not packet_definition:
+ return imix_count
+ imix = packet_definition.get('framesize')
+ if imix:
+ for size in imix:
+ data = imix[size]
+ imix_data[int(size[:-1])] = int(data)
+ imix_sum = sum(imix_data.values())
+ if imix_sum > 100:
+ raise SystemExit("Error in IMIX data")
+ elif imix_sum < 100:
+ imix_data[64] = imix_data.get(64, 0) + (100 - imix_sum)
+
+ avg_size = 0.0
+ for size in imix_data:
+ count = int(imix_data[size])
+ if count:
+ avg_size += round(size * count / 100, 2)
+ pps = round(self.pps * count / 100, 0)
+ imix_count[size] = pps
+ self.rate = round(1342177280 / avg_size, 0) * 2
+ logging.debug("Imax: %s rate: %s", imix_count, self.rate)
+ return imix_count
+
+ def get_streams(self):
+ """ generate trex stream """
+ self.streams = []
+ self.pps = self.params['traffic_profile'].get('frame_rate', 100)
+ for packet_name in self.profile_data:
+ outer_l2 = self.profile_data[packet_name].get('outer_l2')
+ imix_data = self.generate_imix_data(outer_l2)
+ if not imix_data:
+ imix_data = {64: self.pps}
+ self.generate_vm(self.profile_data[packet_name])
+ for size in imix_data:
+ self._generate_streams(size, imix_data[size])
+ self._generate_profile()
+ return self.profile
+
+ def generate_vm(self, packet_definition):
+ """ generate trex vm with flows setup """
+ self.ether_packet = Pkt.Ether()
+ 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.qinq = False
+ self.vm_flow_vars = []
+ outer_l2 = packet_definition.get('outer_l2', None)
+ outer_l3v4 = packet_definition.get('outer_l3v4', None)
+ 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)
+ if outer_l3v4:
+ self.set_outer_l3v4_fields(outer_l3v4)
+ if outer_l3v6:
+ self.set_outer_l3v6_fields(outer_l3v6)
+ if outer_l4:
+ self.set_outer_l4_fields(outer_l4)
+ self.trex_vm = STLScVmRaw(self.vm_flow_vars)
+
+ def generate_packets(self):
+ """ generate packets from trex TG """
+ base_pkt = self.base_pkt
+ size = self.fsize - 4
+ pad = max(0, size - len(base_pkt)) * 'x'
+ self.packets = [STLPktBuilder(pkt=base_pkt / pad,
+ vm=vm) for vm in self.vms]
+
+ def _create_single_packet(self, size=64):
+ size = size - 4
+ ether_packet = self.ether_packet
+ ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet
+ udp_packet = self.udp_packet
+ if self.qinq:
+ qinq_packet = self.qinq_packet
+ base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet
+ else:
+ base_pkt = ether_packet / ip_packet / udp_packet
+ pad = max(0, size - len(base_pkt)) * 'x'
+ packet = STLPktBuilder(pkt=base_pkt / pad, vm=self.trex_vm)
+ return packet
+
+ def _create_single_stream(self, packet_size, pps, isg=0):
+ packet = self._create_single_packet(packet_size)
+ if self.pg_id:
+ self.pg_id += 1
+ stl_flow = STLFlowLatencyStats(pg_id=self.pg_id)
+ stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps),
+ flow_stats=stl_flow)
+ else:
+ stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps))
+ return stream
+
+ def _generate_streams(self, packet_size, pps):
+ self.streams.append(self._create_single_stream(packet_size, pps))
+
+ def _generate_profile(self):
+ self.profile = STLProfile(self.streams)
+
+ @classmethod
+ def _get_start_end_ipv6(cls, start_ip, end_ip):
+ try:
+ ip1 = socket.inet_pton(socket.AF_INET6, start_ip)
+ ip2 = socket.inet_pton(socket.AF_INET6, end_ip)
+ hi1, lo1 = struct.unpack('!QQ', ip1)
+ hi2, lo2 = struct.unpack('!QQ', ip2)
+ if ((hi1 << 64) | lo1) > ((hi2 << 64) | lo2):
+ raise SystemExit("IPv6: start_ip is greater then end_ip")
+ max_p1 = abs(int(lo1) - int(lo2))
+ base_p1 = lo1
+ except Exception as ex_error:
+ raise SystemExit(ex_error)
+ else:
+ return base_p1, max_p1 + base_p1
+
+ @classmethod
+ def _get_random_value(cls, min_port, max_port):
+ cryptogen = SystemRandom()
+ return cryptogen.randrange(min_port, max_port)