NSB support for [core x-y] NSB PROX NFVI configuration
[yardstick.git] / yardstick / network_services / vnf_generic / vnf / vpe_vnf.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
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
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
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 """
15
16 from __future__ import absolute_import
17 from __future__ import print_function
18
19
20 import logging
21 import re
22 import posixpath
23
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
30
31 LOG = logging.getLogger(__name__)
32
33 VPE_PIPELINE_COMMAND = "sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script} {hwlb}"
34
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+)\
39 """
40
41
42 class ConfigCreate(object):
43
44     def __init__(self, vnfd_helper, socket):
45         super(ConfigCreate, self).__init__()
46         self.sw_q = -1
47         self.sink_q = -1
48         self.n_pipeline = 1
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
53         self.socket = socket
54         self._dpdk_port_to_link_id_map = None
55
56
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):
60
61             uplink_intf = \
62                 next(intf["virtual-interface"] for intf in interfaces
63                      if intf["name"] == uplink_port)
64             downlink_intf = \
65                 next(intf["virtual-interface"] for intf in interfaces
66                      if intf["name"] == downlink_port)
67
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"]
72
73             rules.add_firewall_script(dst_port0_ip)
74             rules.next_pipeline()
75             rules.add_flow_classification_script()
76             rules.next_pipeline()
77             rules.add_flow_action()
78             rules.next_pipeline()
79             rules.add_flow_action2()
80             rules.next_pipeline()
81             rules.add_route_script(dst_port1_ip, dst_port1_mac)
82             rules.next_pipeline()
83             rules.add_route_script2(dst_port0_ip, dst_port0_mac)
84             rules.next_pipeline(num=4)
85
86         return rules.get_string()
87
88
89 class VpeApproxSetupEnvHelper(DpdkVnfSetupEnvHelper):
90
91     APP_NAME = 'vPE_vnf'
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
96
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
102
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)
110         vpe_vars = {
111             "bin_path": self.ssh_helper.bin_path,
112             "socket": self.socket,
113         }
114         self._build_vnf_ports()
115         vpe_conf = ConfigCreate(self.vnfd_helper, self.socket)
116
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
121         else:
122             with utils.open_relative_file(script_file, task_path) as handle:
123                 vpe_script = handle.read()
124
125         config_basename = posixpath.basename(config_file)
126         script_basename = posixpath.basename(script_file)
127
128         with utils.open_relative_file(action_bulk_file, task_path) as handle:
129             action_bulk = handle.read()
130
131         with utils.open_relative_file(full_tm_profile_file, task_path) as handle:
132             full_tm_profile = handle.read()
133
134         with utils.open_relative_file(config_file, task_path) as handle:
135             vpe_config = handle.read()
136
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))
144
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)
151
152
153 class VpeApproxVnf(SampleVNF):
154     """ This class handles vPE VNF model-driver definitions """
155
156     APP_NAME = 'vPE_vnf'
157     APP_WORD = 'vpe'
158     COLLECT_KPI = VPE_COLLECT_KPI
159     WAIT_TIME = 20
160
161     def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
162                  resource_helper_type=None):
163         if setup_env_helper_type is None:
164             setup_env_helper_type = VpeApproxSetupEnvHelper
165         super(VpeApproxVnf, self).__init__(
166             name, vnfd, task_id, setup_env_helper_type, resource_helper_type)
167
168     def get_stats(self, *args, **kwargs):
169         raise NotImplementedError
170
171     def collect_kpi(self):
172         # we can't get KPIs if the VNF is down
173         check_if_process_failed(self._vnf_process)
174         physical_node = ctx_base.Context.get_physical_node_from_server(
175             self.scenario_helper.nodes[self.name])
176
177         result = {
178             "physical_node": physical_node,
179             'pkt_in_up_stream': 0,
180             'pkt_drop_up_stream': 0,
181             'pkt_in_down_stream': 0,
182             'pkt_drop_down_stream': 0,
183             'collect_stats': self.resource_helper.collect_kpi(),
184         }
185
186         indexes_in = [1]
187         indexes_drop = [2, 3]
188         command = 'p {0} stats port {1} 0'
189         for index, direction in ((5, 'up'), (9, 'down')):
190             key_in = "pkt_in_{0}_stream".format(direction)
191             key_drop = "pkt_drop_{0}_stream".format(direction)
192             for mode in ('in', 'out'):
193                 stats = self.vnf_execute(command.format(index, mode))
194                 match = re.search(self.COLLECT_KPI, stats, re.MULTILINE)
195                 if not match:
196                     continue
197                 result[key_in] += sum(int(match.group(x)) for x in indexes_in)
198                 result[key_drop] += sum(int(match.group(x)) for x in indexes_drop)
199
200         LOG.debug("%s collect KPIs %s", self.APP_NAME, result)
201         return result