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 """ vPE (Power Edge router) VNF model definitions based on IETS Spec """
16 from __future__ import absolute_import
17 from __future__ import print_function
24 from yardstick.common import utils
25 from yardstick.common.process import check_if_process_failed
26 from yardstick.network_services.helpers.samplevnf_helper import PortPairs
27 from yardstick.network_services.pipeline import PipelineRules
28 from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper
29 from yardstick.benchmark.contexts import base as ctx_base
31 LOG = logging.getLogger(__name__)
33 VPE_PIPELINE_COMMAND = "sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script} {hwlb}"
35 VPE_COLLECT_KPI = """\
36 Pkts in:\\s(\\d+)\r\n\
37 \tPkts dropped by AH:\\s(\\d+)\r\n\
38 \tPkts dropped by other:\\s(\\d+)\
42 class ConfigCreate(object):
44 def __init__(self, vnfd_helper, socket):
45 super(ConfigCreate, self).__init__()
49 self.vnfd_helper = vnfd_helper
50 self.uplink_ports = self.vnfd_helper.port_pairs.uplink_ports
51 self.downlink_ports = self.vnfd_helper.port_pairs.downlink_ports
52 self.pipeline_per_port = 9
54 self._dpdk_port_to_link_id_map = None
57 def generate_vpe_script(self, interfaces):
58 rules = PipelineRules(pipeline_id=1)
59 for uplink_port, downlink_port in zip(self.uplink_ports, self.downlink_ports):
62 next(intf["virtual-interface"] for intf in interfaces
63 if intf["name"] == uplink_port)
65 next(intf["virtual-interface"] for intf in interfaces
66 if intf["name"] == downlink_port)
68 dst_port0_ip = uplink_intf["dst_ip"]
69 dst_port1_ip = downlink_intf["dst_ip"]
70 dst_port0_mac = uplink_intf["dst_mac"]
71 dst_port1_mac = downlink_intf["dst_mac"]
73 rules.add_firewall_script(dst_port0_ip)
75 rules.add_flow_classification_script()
77 rules.add_flow_action()
79 rules.add_flow_action2()
81 rules.add_route_script(dst_port1_ip, dst_port1_mac)
83 rules.add_route_script2(dst_port0_ip, dst_port0_mac)
84 rules.next_pipeline(num=4)
86 return rules.get_string()
89 class VpeApproxSetupEnvHelper(DpdkVnfSetupEnvHelper):
92 CFG_SCRIPT = "/tmp/vpe_script"
93 TM_CONFIG = "/tmp/full_tm_profile_10G.cfg"
94 CORES = ['0', '1', '2', '3', '4', '5']
95 PIPELINE_COMMAND = VPE_PIPELINE_COMMAND
97 def _build_vnf_ports(self):
98 self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
99 self.uplink_ports = self._port_pairs.uplink_ports
100 self.downlink_ports = self._port_pairs.downlink_ports
101 self.all_ports = self._port_pairs.all_ports
103 def build_config(self):
104 vnf_cfg = self.scenario_helper.vnf_cfg
105 task_path = self.scenario_helper.task_path
106 action_bulk_file = vnf_cfg.get('action_bulk_file', '/tmp/action_bulk_512.txt')
107 full_tm_profile_file = vnf_cfg.get('full_tm_profile_file', '/tmp/full_tm_profile_10G.cfg')
108 config_file = vnf_cfg.get('file', '/tmp/vpe_config')
109 script_file = vnf_cfg.get('script_file', None)
111 "bin_path": self.ssh_helper.bin_path,
112 "socket": self.socket,
114 self._build_vnf_ports()
115 vpe_conf = ConfigCreate(self.vnfd_helper, self.socket)
117 if script_file is None:
118 # autogenerate vpe_script if not given
119 vpe_script = vpe_conf.generate_vpe_script(self.vnfd_helper.interfaces)
120 script_file = self.CFG_SCRIPT
122 with utils.open_relative_file(script_file, task_path) as handle:
123 vpe_script = handle.read()
125 config_basename = posixpath.basename(config_file)
126 script_basename = posixpath.basename(script_file)
128 with utils.open_relative_file(action_bulk_file, task_path) as handle:
129 action_bulk = handle.read()
131 with utils.open_relative_file(full_tm_profile_file, task_path) as handle:
132 full_tm_profile = handle.read()
134 with utils.open_relative_file(config_file, task_path) as handle:
135 vpe_config = handle.read()
137 # upload the 4 config files to the target server
138 self.ssh_helper.upload_config_file(config_basename, vpe_config.format(**vpe_vars))
139 self.ssh_helper.upload_config_file(script_basename, vpe_script.format(**vpe_vars))
140 self.ssh_helper.upload_config_file(posixpath.basename(action_bulk_file),
141 action_bulk.format(**vpe_vars))
142 self.ssh_helper.upload_config_file(posixpath.basename(full_tm_profile_file),
143 full_tm_profile.format(**vpe_vars))
145 LOG.info("Provision and start the %s", self.APP_NAME)
146 LOG.info(config_file)
147 LOG.info(self.CFG_SCRIPT)
148 self._build_pipeline_kwargs(cfg_file='/tmp/' + config_basename,
149 script='/tmp/' + script_basename)
150 return self.PIPELINE_COMMAND.format(**self.pipeline_kwargs)
153 class VpeApproxVnf(SampleVNF):
154 """ This class handles vPE VNF model-driver definitions """
158 COLLECT_KPI = VPE_COLLECT_KPI
161 def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
162 if setup_env_helper_type is None:
163 setup_env_helper_type = VpeApproxSetupEnvHelper
165 super(VpeApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type)
167 def get_stats(self, *args, **kwargs):
168 raise NotImplementedError
170 def collect_kpi(self):
171 # we can't get KPIs if the VNF is down
172 check_if_process_failed(self._vnf_process)
173 physical_node = ctx_base.Context.get_physical_node_from_server(
174 self.scenario_helper.nodes[self.name])
177 "physical_node": physical_node,
178 'pkt_in_up_stream': 0,
179 'pkt_drop_up_stream': 0,
180 'pkt_in_down_stream': 0,
181 'pkt_drop_down_stream': 0,
182 'collect_stats': self.resource_helper.collect_kpi(),
186 indexes_drop = [2, 3]
187 command = 'p {0} stats port {1} 0'
188 for index, direction in ((5, 'up'), (9, 'down')):
189 key_in = "pkt_in_{0}_stream".format(direction)
190 key_drop = "pkt_drop_{0}_stream".format(direction)
191 for mode in ('in', 'out'):
192 stats = self.vnf_execute(command.format(index, mode))
193 match = re.search(self.COLLECT_KPI, stats, re.MULTILINE)
196 result[key_in] += sum(int(match.group(x)) for x in indexes_in)
197 result[key_drop] += sum(int(match.group(x)) for x in indexes_drop)
199 LOG.debug("%s collect KPIs %s", self.APP_NAME, result)