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 """
21 from yardstick.network_services.helpers.samplevnf_helper import PortPairs
24 LOG = logging.getLogger(__name__)
27 class QueueFileWrapper(object):
28 """ Class providing file-like API for talking with SSH connection """
30 def __init__(self, q_in, q_out, prompt):
39 """ read chunk from input queue """
40 if self.q_in.qsize() > 0 and size:
41 in_data = self.q_in.get()
44 def write(self, chunk):
45 """ write chunk to output queue """
46 self.buf.append(chunk)
47 # flush on prompt or if we exceed bufsize
49 size = sum(len(c) for c in self.buf)
50 if self.prompt in chunk or size > self.bufsize:
51 out = ''.join(self.buf)
56 """ close multiprocessing queue """
61 while self.q_out.qsize() > 0:
65 class VnfdHelper(dict):
67 def __init__(self, *args, **kwargs):
68 super(VnfdHelper, self).__init__(*args, **kwargs)
69 self.port_pairs = PortPairs(self['vdu'][0]['external-interface'])
70 # port num is not present until binding so we have to memoize
71 self._port_num_map = {}
74 def mgmt_interface(self):
75 return self["mgmt-interface"]
87 return self.vdu0['external-interface']
91 return self['benchmark']['kpi']
93 def find_virtual_interface(self, **kwargs):
94 key, value = next(iter(kwargs.items()))
95 for interface in self.interfaces:
96 virtual_intf = interface["virtual-interface"]
97 if virtual_intf[key] == value:
101 def find_interface(self, **kwargs):
102 key, value = next(iter(kwargs.items()))
103 for interface in self.interfaces:
104 if interface[key] == value:
108 # hide dpdk_port_num key so we can abstract
109 def find_interface_by_port(self, port):
110 for interface in self.interfaces:
111 virtual_intf = interface["virtual-interface"]
112 # we have to convert to int to compare
113 if int(virtual_intf['dpdk_port_num']) == port:
117 def port_num(self, port):
118 # we need interface name -> DPDK port num (PMD ID) -> LINK ID
119 # LINK ID -> PMD ID is governed by the port mask
125 if isinstance(port, dict):
128 intf = self.find_interface(name=port)
129 return self._port_num_map.setdefault(intf["name"],
130 int(intf["virtual-interface"]["dpdk_port_num"]))
132 def port_nums(self, intfs):
133 return [self.port_num(i) for i in intfs]
135 def ports_iter(self):
136 for port_name in self.port_pairs.all_ports:
137 port_num = self.port_num(port_name)
138 yield port_name, port_num
141 class VNFObject(object):
143 # centralize network naming convention
144 UPLINK = PortPairs.UPLINK
145 DOWNLINK = PortPairs.DOWNLINK
147 def __init__(self, name, vnfd):
148 super(VNFObject, self).__init__()
150 self.vnfd_helper = VnfdHelper(vnfd) # fixme: parse this into a structure
153 class GenericVNF(VNFObject):
155 """ Class providing file-like API for generic VNF implementation """
156 def __init__(self, name, vnfd):
157 super(GenericVNF, self).__init__(name, vnfd)
158 # List of statistics we can obtain from this VNF
159 # - ETSI MANO 6.3.1.1 monitoring_parameter
160 self.kpi = self._get_kpi_definition()
161 # Standard dictionary containing params like thread no, buffer size etc
163 self.runs_traffic = False
165 def _get_kpi_definition(self):
166 """ Get list of KPIs defined in VNFD
169 :return: list of KPIs, e.g. ['throughput', 'latency']
171 return self.vnfd_helper.kpi
173 def instantiate(self, scenario_cfg, context_cfg):
174 """ Prepare VNF for operation and start the VNF process/VM
180 raise NotImplementedError()
182 def wait_for_instantiate(self):
183 """ Wait for VNF to start
187 raise NotImplementedError()
190 """ Kill all VNF processes
194 raise NotImplementedError()
196 def scale(self, flavor=""):
202 raise NotImplementedError()
204 def collect_kpi(self):
205 """This method should return a dictionary containing the
206 selected KPI at a given point of time.
208 :return: {"kpi": value, "kpi2": value}
210 raise NotImplementedError()
213 @six.add_metaclass(abc.ABCMeta)
214 class GenericTrafficGen(GenericVNF):
215 """ Class providing file-like API for generic traffic generator """
217 def __init__(self, name, vnfd):
218 super(GenericTrafficGen, self).__init__(name, vnfd)
219 self.runs_traffic = True
220 self.traffic_finished = False
223 def run_traffic(self, traffic_profile):
224 """Generate traffic on the wire according to the given params.
226 This method is non-blocking, returns immediately when traffic process
227 is running. Mandatory.
229 :param traffic_profile:
235 """After this method finishes, all traffic processes should stop.
242 def listen_traffic(self, traffic_profile):
243 """Listen to traffic with the given parameters.
245 Method is non-blocking, returns immediately when traffic process
246 is running. Optional.
248 :param traffic_profile:
253 def verify_traffic(self, traffic_profile):
254 """Verify captured traffic after it has ended.
258 :param traffic_profile:
263 def wait_for_instantiate(self):
264 """Wait for an instance to load.