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):
99 ip_to_convert = ip_addr.split(".")
101 if self.get_ip_version(ip_addr) == 4:
102 ip_to_convert = ip_addr.split(".")
103 ip_octect = [int(octect) for octect in ip_to_convert]
104 ip_x = "{0[0]:02X}{0[1]:02X}{0[2]:02X}{0[3]:02X}".format(ip_octect)
107 def _get_dpdk_port_num(self, name):
108 for intf in self.vnfd['vdu'][0]['external-interface']:
109 if name == intf['name']:
110 return intf['virtual-interface']['dpdk_port_num']
112 def _append_routes(self, ip_pipeline_cfg):
113 if 'routing_table' in self.vnfd['vdu'][0]:
114 routing_table = self.vnfd['vdu'][0]['routing_table']
116 where = ip_pipeline_cfg.find("arp_route_tbl")
117 link = ip_pipeline_cfg[:where]
118 route_add = ip_pipeline_cfg[where:]
120 tmp = route_add.find('\n')
121 route_add = route_add[tmp:]
123 cmds = "arp_route_tbl ="
125 for route in routing_table:
126 net = self._ip_to_hex(route['network'])
127 net_nm = self._ip_to_hex(route['netmask'])
128 net_gw = self._ip_to_hex(route['gateway'])
129 port = self._get_dpdk_port_num(route['if'])
131 " ({port0_local_ip_hex},{port0_netmask_hex},{dpdk_port},"\
132 "{port1_local_ip_hex})".format(port0_local_ip_hex=net,
133 port0_netmask_hex=net_nm,
135 port1_local_ip_hex=net_gw)
139 ip_pipeline_cfg = link + cmds + route_add
141 return ip_pipeline_cfg
143 def _append_nd_routes(self, ip_pipeline_cfg):
144 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
145 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
147 where = ip_pipeline_cfg.find("nd_route_tbl")
148 link = ip_pipeline_cfg[:where]
149 route_nd = ip_pipeline_cfg[where:]
151 tmp = route_nd.find('\n')
152 route_nd = route_nd[tmp:]
154 cmds = "nd_route_tbl ="
156 for route in routing_table:
157 net = route['network']
158 net_nm = route['netmask']
159 net_gw = route['gateway']
160 port = self._get_dpdk_port_num(route['if'])
162 " ({port0_local_ip_hex},{port0_netmask_hex},{dpdk_port},"\
163 "{port1_local_ip_hex})".format(port0_local_ip_hex=net,
164 port0_netmask_hex=net_nm,
166 port1_local_ip_hex=net_gw)
170 ip_pipeline_cfg = link + cmds + route_nd
172 return ip_pipeline_cfg
174 def _get_port0localip6(self):
176 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
177 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
180 for route in routing_table:
183 return_value = route['network']
184 LOG.info("_get_port0localip6 : %s", return_value)
187 def _get_port1localip6(self):
189 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
190 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
193 for route in routing_table:
196 return_value = route['network']
197 LOG.info("_get_port1localip6 : %s", return_value)
200 def _get_port0prefixlen6(self):
202 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
203 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
206 for route in routing_table:
209 return_value = route['netmask']
210 LOG.info("_get_port0prefixlen6 : %s", return_value)
213 def _get_port1prefixlen6(self):
215 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
216 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
219 for route in routing_table:
222 return_value = route['netmask']
223 LOG.info("_get_port1prefixlen6 : %s", return_value)
226 def _get_port0gateway6(self):
228 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
229 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
232 for route in routing_table:
235 return_value = route['network']
236 LOG.info("_get_port0gateway6 : %s", return_value)
239 def _get_port1gateway6(self):
241 if 'nd_route_tbl' in self.vnfd['vdu'][0]:
242 routing_table = self.vnfd['vdu'][0]['nd_route_tbl']
245 for route in routing_table:
248 return_value = route['network']
249 LOG.info("_get_port1gateway6 : %s", return_value)
252 def instantiate(self, scenario_cfg, context_cfg):
253 """ Prepare VNF for operation and start the VNF process/VM
259 raise NotImplementedError()
262 """ Kill all VNF processes
266 raise NotImplementedError()
268 def scale(self, flavor=""):
274 raise NotImplementedError()
276 def collect_kpi(self):
277 """This method should return a dictionary containing the
278 selected KPI at a given point of time.
280 :return: {"kpi": value, "kpi2": value}
282 raise NotImplementedError()
285 class GenericTrafficGen(GenericVNF):
286 """ Class providing file-like API for generic traffic generator """
288 def __init__(self, vnfd):
289 super(GenericTrafficGen, self).__init__(vnfd)
290 self.runs_traffic = True
291 self.traffic_finished = False
292 self.name = "tgen__1" # name in topology file
294 def run_traffic(self, traffic_profile):
295 """ Generate traffic on the wire according to the given params.
296 Method is non-blocking, returns immediately when traffic process
297 is running. Mandatory.
299 :param traffic_profile:
302 raise NotImplementedError()
304 def listen_traffic(self, traffic_profile):
305 """ Listen to traffic with the given parameters.
306 Method is non-blocking, returns immediately when traffic process
307 is running. Optional.
309 :param traffic_profile:
314 def verify_traffic(self, traffic_profile):
315 """ Verify captured traffic after it has ended. Optional.
317 :param traffic_profile:
323 """ After this method finishes, all traffic processes should stop. Mandatory.
327 raise NotImplementedError()