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 """ Base class implementation for generic vnf implementation """
16 from __future__ import absolute_import
21 from yardstick.network_services.utils import get_nsb_option
23 LOG = logging.getLogger(__name__)
26 class QueueFileWrapper(object):
27 """ Class providing file-like API for talking with SSH connection """
29 def __init__(self, q_in, q_out, prompt):
38 """ read chunk from input queue """
39 if self.q_in.qsize() > 0 and size:
40 in_data = self.q_in.get()
43 def write(self, chunk):
44 """ write chunk to output queue """
45 self.buf.append(chunk)
46 # flush on prompt or if we exceed bufsize
48 size = sum(len(c) for c in self.buf)
49 if self.prompt in chunk or size > self.bufsize:
50 out = ''.join(self.buf)
55 """ close multiprocessing queue """
60 while self.q_out.qsize() > 0:
64 class GenericVNF(object):
65 """ Class providing file-like API for generic VNF implementation """
66 def __init__(self, vnfd):
67 super(GenericVNF, self).__init__()
68 self.vnfd = vnfd # fixme: parse this into a structure
69 # List of statistics we can obtain from this VNF
70 # - ETSI MANO 6.3.1.1 monitoring_parameter
71 self.kpi = self._get_kpi_definition(vnfd)
72 # Standard dictionary containing params like thread no, buffer size etc
74 self.runs_traffic = False
75 self.name = "vnf__1" # name in topology file
76 self.bin_path = get_nsb_option("bin_path", "")
79 def _get_kpi_definition(cls, vnfd):
80 """ Get list of KPIs defined in VNFD
83 :return: list of KPIs, e.g. ['throughput', 'latency']
85 return vnfd['benchmark']['kpi']
88 def get_ip_version(cls, ip_addr):
89 """ get ip address version v6 or v4 """
91 address = ipaddress.ip_address(six.text_type(ip_addr))
93 LOG.error(ip_addr, " is not valid")
96 return address.version
98 def _ip_to_hex(self, ip_addr):
100 if self.get_ip_version(ip_addr) == 4:
101 ip_to_convert = ip_addr.split(".")
102 ip_octect = [int(octect) for octect in ip_to_convert]
103 ip_x = "{0[0]:02X}{0[1]:02X}{0[2]:02X}{0[3]:02X}".format(ip_octect)
106 def _get_dpdk_port_num(self, name):
107 for intf in self.vnfd['vdu'][0]['external-interface']:
108 if name == intf['name']:
109 return intf['virtual-interface']['dpdk_port_num']
111 def _append_routes(self, ip_pipeline_cfg):
112 if 'routing_table' in self.vnfd['vdu'][0]:
113 routing_table = self.vnfd['vdu'][0]['routing_table']
115 where = ip_pipeline_cfg.find("arp_route_tbl")
116 link = ip_pipeline_cfg[:where]
117 route_add = ip_pipeline_cfg[where:]
119 tmp = route_add.find('\n')
120 route_add = route_add[tmp:]
122 cmds = "arp_route_tbl ="
124 for route in routing_table:
125 net = self._ip_to_hex(route['network'])
126 net_nm = self._ip_to_hex(route['netmask'])
127 net_gw = self._ip_to_hex(route['gateway'])
128 port = self._get_dpdk_port_num(route['if'])
130 " ({port0_local_ip_hex},{port0_netmask_hex},{dpdk_port},"\
131 "{port1_local_ip_hex})".format(port0_local_ip_hex=net,
132 port0_netmask_hex=net_nm,
134 port1_local_ip_hex=net_gw)
138 ip_pipeline_cfg = link + cmds + route_add
140 return ip_pipeline_cfg
142 def _append_nd_routes(self, ip_pipeline_cfg):
143 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
144 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
146 where = ip_pipeline_cfg.find("nd_route_tbl")
147 link = ip_pipeline_cfg[:where]
148 route_nd = ip_pipeline_cfg[where:]
150 tmp = route_nd.find('\n')
151 route_nd = route_nd[tmp:]
153 cmds = "nd_route_tbl ="
155 for route in routing_table:
156 net = route['network']
157 net_nm = route['netmask']
158 net_gw = route['gateway']
159 port = self._get_dpdk_port_num(route['if'])
161 " ({port0_local_ip_hex},{port0_netmask_hex},{dpdk_port},"\
162 "{port1_local_ip_hex})".format(port0_local_ip_hex=net,
163 port0_netmask_hex=net_nm,
165 port1_local_ip_hex=net_gw)
169 ip_pipeline_cfg = link + cmds + route_nd
171 return ip_pipeline_cfg
173 def _get_port0localip6(self):
175 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
176 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
179 for route in routing_table:
182 return_value = route['network']
183 LOG.info("_get_port0localip6 : %s", return_value)
186 def _get_port1localip6(self):
188 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
189 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
192 for route in routing_table:
195 return_value = route['network']
196 LOG.info("_get_port1localip6 : %s", return_value)
199 def _get_port0prefixlen6(self):
201 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
202 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
205 for route in routing_table:
208 return_value = route['netmask']
209 LOG.info("_get_port0prefixlen6 : %s", return_value)
212 def _get_port1prefixlen6(self):
214 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
215 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
218 for route in routing_table:
221 return_value = route['netmask']
222 LOG.info("_get_port1prefixlen6 : %s", return_value)
225 def _get_port0gateway6(self):
227 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
228 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
231 for route in routing_table:
234 return_value = route['network']
235 LOG.info("_get_port0gateway6 : %s", return_value)
238 def _get_port1gateway6(self):
240 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
241 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
244 for route in routing_table:
247 return_value = route['network']
248 LOG.info("_get_port1gateway6 : %s", return_value)
251 def instantiate(self, scenario_cfg, context_cfg):
252 """ Prepare VNF for operation and start the VNF process/VM
258 raise NotImplementedError()
261 """ Kill all VNF processes
265 raise NotImplementedError()
267 def scale(self, flavor=""):
273 raise NotImplementedError()
275 def collect_kpi(self):
276 """This method should return a dictionary containing the
277 selected KPI at a given point of time.
279 :return: {"kpi": value, "kpi2": value}
281 raise NotImplementedError()
284 class GenericTrafficGen(GenericVNF):
285 """ Class providing file-like API for generic traffic generator """
287 def __init__(self, vnfd):
288 super(GenericTrafficGen, self).__init__(vnfd)
289 self.runs_traffic = True
290 self.traffic_finished = False
291 self.name = "tgen__1" # name in topology file
293 def run_traffic(self, traffic_profile):
294 """ Generate traffic on the wire according to the given params.
295 Method is non-blocking, returns immediately when traffic process
296 is running. Mandatory.
298 :param traffic_profile:
301 raise NotImplementedError()
303 def listen_traffic(self, traffic_profile):
304 """ Listen to traffic with the given parameters.
305 Method is non-blocking, returns immediately when traffic process
306 is running. Optional.
308 :param traffic_profile:
313 def verify_traffic(self, traffic_profile):
314 """ Verify captured traffic after it has ended. Optional.
316 :param traffic_profile:
322 """ After this method finishes, all traffic processes should stop. Mandatory.
326 raise NotImplementedError()