1 # Copyright (c) 2016-2017 Intel Corporation
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """ Trex acts as traffic generation and vnf definitions based on IETS Spec """
16 from __future__ import absolute_import
17 from __future__ import print_function
24 from yardstick.common.utils import mac_address_to_hex_list, try_int
25 from yardstick.network_services.utils import get_nsb_option
26 from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
27 from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
28 from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper
30 LOG = logging.getLogger(__name__)
33 class TrexDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper):
41 class TrexResourceHelper(ClientResourceHelper):
43 CONF_FILE = '/tmp/trex_cfg.yaml'
45 RESOURCE_WORD = 'trex'
51 def generate_cfg(self):
52 port_names = self.vnfd_helper.port_pairs.all_ports
56 port_nums = sorted(self.vnfd_helper.port_nums(port_names))
57 for port_num in port_nums:
58 interface = self.vnfd_helper.find_interface_by_port(port_num)
59 virtual_interface = interface['virtual-interface']
60 dst_mac = virtual_interface["dst_mac"]
62 # why skip?, ordering is based on DPDK port number so we can't skip
65 # TRex ports must be in DPDK port number, so order of append matters
66 vpci_list.append(virtual_interface["vpci"])
67 local_mac = virtual_interface["local_mac"]
69 "src_mac": mac_address_to_hex_list(local_mac),
70 "dest_mac": mac_address_to_hex_list(dst_mac),
73 'interfaces': vpci_list,
74 'port_info': port_list,
75 "port_limit": len(port_names),
80 cfg_str = yaml.safe_dump(cfg_file, default_flow_style=False, explicit_start=True)
81 self.ssh_helper.upload_config_file(os.path.basename(self.CONF_FILE), cfg_str)
83 def check_status(self):
84 status, _, _ = self.ssh_helper.execute("sudo lsof -i:%s" % self.SYNC_PORT)
91 super(TrexResourceHelper, self).setup()
92 if self.DISABLE_DEPLOY:
95 trex_path = self.ssh_helper.join_bin_path('trex')
97 err = self.ssh_helper.execute("which {}".format(trex_path))[0]
101 LOG.info("Copying %s to destination...", self.RESOURCE_WORD)
102 self.ssh_helper.run("sudo mkdir -p '{}'".format(os.path.dirname(trex_path)))
103 self.ssh_helper.put("~/.bash_profile", "~/.bash_profile")
104 self.ssh_helper.put(trex_path, trex_path, True)
105 ko_src = os.path.join(trex_path, "scripts/ko/src/")
106 self.ssh_helper.execute(self.MAKE_INSTALL.format(ko_src))
108 def start(self, ports=None, *args, **kwargs):
109 cmd = "sudo fuser -n tcp {0.SYNC_PORT} {0.ASYNC_PORT} -k > /dev/null 2>&1"
110 self.ssh_helper.execute(cmd.format(self))
112 self.ssh_helper.execute("sudo pkill -9 rex > /dev/null 2>&1")
114 # We MUST default to 1 because TRex won't work on single-queue devices with
115 # more than one core per port
116 # We really should be trying to find the number of queues in the driver,
117 # but there doesn't seem to be a way to do this
118 # TRex Error: the number of cores should be 1 when the driver
119 # support only one tx queue and one rx queue. Please use -c 1
120 threads_per_port = try_int(self.scenario_helper.options.get("queues_per_port"), 1)
122 trex_path = self.ssh_helper.join_bin_path("trex", "scripts")
123 path = get_nsb_option("trex_path", trex_path)
125 cmd = "./t-rex-64 --no-scapy-server -i -c {} --cfg '{}'".format(threads_per_port,
128 if self.scenario_helper.options.get("trex_server_debug"):
129 # if there are errors we want to see them
133 # we have to sudo cd because the path might be owned by root
134 trex_cmd = """sudo bash -c "cd '{}' ; {}" {}""".format(path, cmd, redir)
136 self.ssh_helper.execute(trex_cmd)
139 super(TrexResourceHelper, self).terminate()
140 cmd = "sudo fuser -n tcp %s %s -k > /dev/null 2>&1"
141 self.ssh_helper.execute(cmd % (self.SYNC_PORT, self.ASYNC_PORT))
144 class TrexTrafficGen(SampleVNFTrafficGen):
146 This class handles mapping traffic profile and generating
147 traffic for given testcase
152 def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
153 if resource_helper_type is None:
154 resource_helper_type = TrexResourceHelper
156 if setup_env_helper_type is None:
157 setup_env_helper_type = TrexDpdkVnfSetupEnvHelper
159 super(TrexTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
160 resource_helper_type)
162 def _check_status(self):
163 return self.resource_helper.check_status()
165 def _start_server(self):
166 super(TrexTrafficGen, self)._start_server()
167 self.resource_helper.start()
169 def scale(self, flavor=""):
172 def listen_traffic(self, traffic_profile):
176 self.resource_helper.terminate()