Source code for yardstick.vTC.apexlake.experimental_framework.packet_generators.dpdk_packet_generator

# Copyright (c) 2015 Intel Research and Development Ireland Ltd.
#
# 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 os
import base_packet_generator
import experimental_framework.common as common
import time
from experimental_framework.constants import conf_file_sections as conf_file
from experimental_framework.constants import framework_parameters as fp


[docs]class DpdkPacketGenerator(base_packet_generator.BasePacketGenerator): def __init__(self): base_packet_generator.BasePacketGenerator.__init__(self) self.command = '' self.directory = '' self.program_name = '' self.command_options = list() self.dpdk_interfaces = -1
[docs] def send_traffic(self): ''' Calls the packet generator and starts to send traffic Blocking call ''' current_dir = os.path.dirname(os.path.realpath(__file__)) DpdkPacketGenerator._chdir(self.directory) dpdk_vars = common.get_dpdk_pktgen_vars() self._init_physical_nics(self.dpdk_interfaces, dpdk_vars) common.run_command(self.command) self._finalize_physical_nics(self.dpdk_interfaces, dpdk_vars) DpdkPacketGenerator._chdir(current_dir)
[docs] def init_dpdk_pktgen(self, dpdk_interfaces, lua_script='generic_test.lua', pcap_file_0='', pcap_file_1='', vlan_0='', vlan_1=''): """ Initializes internal parameters and configuration of the module. Needs to be called before the send_traffic :param dpdk_interfaces: Number of interfaces to be used (type: int) :param lua_script: Full path of the Lua script to be used (type: str) :param pcap_file_0: Full path of the Pcap file to be used for port 0 (type: str) :param pcap_file_1: Full path of the Pcap file to be used for port 1 (type: str) :param vlan_0: VLAN tag to be used for port 0 (type: str) :param vlan_1: VLAN tag to be used for port 1 (type: str) :return: """ # Input Validation if pcap_file_0 and not vlan_0: message = 'In order to use NIC_0, the parameter vlan_0 is required' raise ValueError(message) if dpdk_interfaces > 1 and pcap_file_1 and not vlan_1: message = 'in order to use NIC_1, the parameter vlan_1 is required' raise ValueError(message) self.dpdk_interfaces = dpdk_interfaces vars = common.get_dpdk_pktgen_vars() lua_directory = common.get_base_dir() lua_directory += fp.EXPERIMENTAL_FRAMEWORK_DIR lua_directory += fp.DPDK_PKTGEN_DIR pcap_directory = common.get_base_dir() pcap_directory += fp.EXPERIMENTAL_FRAMEWORK_DIR pcap_directory += fp.PCAP_DIR DpdkPacketGenerator._init_input_validation(pcap_file_0, pcap_file_1, lua_script, pcap_directory, lua_directory, vars) self.directory = vars[conf_file.CFSP_DPDK_PKTGEN_DIRECTORY] self.program_name = vars[conf_file.CFSP_DPDK_PROGRAM_NAME] core_nics = DpdkPacketGenerator.\ _get_core_nics(dpdk_interfaces, vars[conf_file.CFSP_DPDK_COREMASK]) self.command_options = ['-c ' + vars[conf_file.CFSP_DPDK_COREMASK], '-n ' + vars[conf_file. CFSP_DPDK_MEMORY_CHANNEL], '--proc-type auto', '--file-prefix pg', '-- -T', '-P', '-m "' + core_nics + '"', '-f ' + lua_directory + lua_script, '-s 0:' + pcap_directory + pcap_file_0] if pcap_file_1: self.command_options.append('-s 1:' + pcap_directory + pcap_file_1) # Avoid to show the output of the packet generator self.command_options.append('> /dev/null') # Prepare the command to be invoked self.command = 'sudo ' + self.directory + self.program_name for opt in self.command_options: self.command += (' ' + opt) if pcap_file_0 and vlan_0: DpdkPacketGenerator._change_vlan(pcap_directory, pcap_file_0, vlan_0) if pcap_file_1 and vlan_1: DpdkPacketGenerator._change_vlan(pcap_directory, pcap_file_1, vlan_1)
@staticmethod def _get_core_nics(dpdk_interfaces, coremask): """ Retruns the core_nics string to be used in the dpdk pktgen command :param dpdk_interfaces: number of interfaces to be used in the pktgen (type: int) :param coremask: hexadecimal value representing the cores assigned to the pktgen (type: str) :return: Returns the core nics param for pktgen (type: str) """ if dpdk_interfaces == 1: return DpdkPacketGenerator._cores_configuration(coremask, 1, 2, 0) elif dpdk_interfaces == 2: return DpdkPacketGenerator._cores_configuration(coremask, 1, 2, 2) raise ValueError("This framework only supports two ports to generate " "traffic") @staticmethod def _change_vlan(pcap_directory, pcap_file, vlan): common.LOG.info("Changing VLAN Tag on Packet: " + pcap_file + ". New VLAN Tag is " + vlan) command = "chmod +x {}{}".format(pcap_directory, 'vlan_tag.sh') common.run_command(command) command = pcap_directory + 'vlan_tag.sh ' command += pcap_directory + pcap_file + ' ' + vlan common.run_command(command) @staticmethod def _init_input_validation(pcap_file_0, pcap_file_1, lua_script, pcap_directory, lua_directory, variables): """ Validates the input parameters values and raises an exception if there is any non valid param :param pcap_file_0: file name of the pcap file for NIC 0 (it does not includes the path) (type: str) :param pcap_file_1: file name of the pcap file for NIC 1 (it does not includes the path) (type: str) :param lua_script: file name of the lua script to be used (it does not includes the path) (type: str) :param pcap_directory: directory where the pcap files are located (type: str) :param lua_directory: directory where the lua scripts are located (type: str) :param variables: variables for the packet gen from configuration file (type: dict) :return: None """ if not pcap_directory: raise ValueError("pcap_directory not provided correctly") if not pcap_file_0: raise ValueError("pcap_file_0 not provided correctly") if not pcap_file_1: raise ValueError("pcap_file_1 not provided correctly") if not lua_script: raise ValueError("lua_script not provided correctly") if not os.path.isfile(pcap_directory + pcap_file_0): raise ValueError("The file " + pcap_file_0 + " does not exist") if not os.path.isfile(pcap_directory + pcap_file_1): raise ValueError("The file " + pcap_file_1 + " does not exist") if not os.path.isfile(lua_directory + lua_script): raise ValueError("The file " + lua_script + " does not exist") for var in [conf_file.CFSP_DPDK_PKTGEN_DIRECTORY, conf_file.CFSP_DPDK_PROGRAM_NAME, conf_file.CFSP_DPDK_COREMASK, conf_file.CFSP_DPDK_MEMORY_CHANNEL]: if var not in variables.keys() or (var in variables.keys() and variables[var] is ''): raise ValueError("The variable " + var + " does not exist") @staticmethod def _chdir(directory): """ Changes the current directory :param directory: directory where to move (type: str) :return: None """ os.chdir(directory) def _init_physical_nics(self, dpdk_interfaces, dpdk_vars): """ Initializes the physical interfaces :param dpdk_interfaces: Number of interfaces to be used (type: int) :param dpdk_vars: variables from config file related to DPDK pktgen (type: dict) :return: None """ if not dpdk_interfaces == 1 and not dpdk_interfaces == 2: raise ValueError('The number of NICs can be 1 or 2') # Initialize NIC 1 # bus_address_1 = dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_1] interface_1 = dpdk_vars[conf_file.CFSP_DPDK_NAME_IF_1] common.run_command('sudo ifconfig ' + interface_1 + ' down') common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --unbind ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_1]) common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --bind=igb_uio ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_1]) if dpdk_interfaces == 2: # Initialize NIC 2 # bus_address_2 = dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_2] interface_2 = dpdk_vars[conf_file.CFSP_DPDK_NAME_IF_2] common.run_command('sudo ifconfig ' + interface_2 + ' down') common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --unbind ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_2]) common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --bind=igb_uio ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_2]) def _finalize_physical_nics(self, dpdk_interfaces, dpdk_vars): """ Finalizes the physical interfaces :param dpdk_interfaces: Number of interfaces to be used (type: int) :param dpdk_vars: variables from config file related to DPDK pktgen (type: dict) :return: None """ if not dpdk_interfaces == 1 and not dpdk_interfaces == 2: raise ValueError('No interfaces have been indicated for packet ' 'generation usage. Please specify one or two ' 'NICs') # Initialize NIC 1 common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --unbind ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_1]) time.sleep(5) common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --bind=ixgbe ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_1]) common.run_command('sudo ifconfig ' + dpdk_vars[conf_file.CFSP_DPDK_NAME_IF_1] + ' up') if dpdk_interfaces == 2: # Initialize NIC 2 common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --unbind ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_2]) time.sleep(5) common.run_command('sudo ' + dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] + 'tools/dpdk_nic_bind.py --bind=ixgbe ' + dpdk_vars[conf_file.CFSP_DPDK_BUS_SLOT_NIC_2]) common.run_command('sudo ifconfig ' + dpdk_vars[conf_file.CFSP_DPDK_NAME_IF_2] + ' up') @staticmethod def _cores_configuration(coremask, pktgen_cores=1, nic_1_cores=2, nic_2_cores=2): """ Calculation of the core_nics parameter which is necessary for the packet generator to run :param coremask: Hexadecimal value indicating the cores to be assigned to the whole dpdk pktgen software (included the ones to receive and send packets from NICs) (type: str) :param pktgen_cores: number of cores to be assigned to main thread of the pktgen directly :param nic_1_cores: number of cores to be assigned to the first NIC :param nic_2_nics: number of cores to be assigned to the second NIC :return: returns the core_nics parameter (type: str) """ required_cores = pktgen_cores + nic_1_cores + nic_2_cores bin_coremask = bin(int(coremask, 16))[2:] index = len(bin_coremask) cores = [] while index >= 0: index -= 1 if bin_coremask[index] == '1': core = index cores.append(core) if len(cores) < required_cores: raise ValueError('The provided coremask does not provide' ' enough cores for the DPDK packet generator') # ret_pktgen_cores = [] ret_nic_1_cores = [] ret_nic_2_cores = [] current_core = 0 if nic_2_cores > 0: ret_nic_2_cores.append(cores[current_core]) current_core += 1 if nic_2_cores > 1: ret_nic_2_cores.append(cores[current_core]) current_core += 1 if nic_1_cores > 0: ret_nic_1_cores.append(cores[current_core]) current_core += 1 if nic_1_cores > 1: ret_nic_1_cores.append(cores[current_core]) current_core += 1 # for n in range(0, pktgen_cores): # ret_pktgen_cores.append(cores[n]) # for n in range(0, nic_1_cores): # ret_nic_1_cores.append(cores[pktgen_cores + n]) # for n in range(0, nic_2_cores): # ret_nic_2_cores.append(cores[pktgen_cores + nic_1_cores + n]) corenics = '' if nic_1_cores > 0: if nic_1_cores < 2: corenics += str(ret_nic_1_cores[0]) + '.0' if nic_1_cores == 2: corenics += '[' + str(ret_nic_1_cores[0]) corenics += ':' + str(ret_nic_1_cores[1]) corenics += '].0' if nic_2_cores > 0: corenics += ',' if nic_2_cores < 2: corenics += str(ret_nic_2_cores[0]) + '.1' if nic_2_cores == 2: corenics += '[' + str(ret_nic_2_cores[0]) corenics += ':' + str(ret_nic_2_cores[1]) corenics += '].1' return corenics