X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=yardstick%2Fnetwork_services%2Fvnf_generic%2Fvnf%2Fprox_helpers.py;h=29f9c7bba43b89e0a1710d235141792994c101ea;hb=de8ce9889cfc9e9d62e26e53b5f27b2f4cd9ff06;hp=ac5abfbcb547b5e9509054d751a45f77b80f62a1;hpb=b346b40f67feb1a38226be12f0d57a6bf6f8a2fe;p=yardstick.git diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index ac5abfbcb..29f9c7bba 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import import array import io @@ -31,7 +30,6 @@ import six from six.moves import cStringIO from six.moves import zip, StringIO -from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file from yardstick.common import utils from yardstick.common.utils import SocketTopology, join_non_strings, try_int from yardstick.network_services.helpers.iniparser import ConfigParser @@ -363,9 +361,9 @@ class ProxSocketHelper(object): """ send data to the remote instance """ LOG.debug("Sending data to socket: [%s]", to_send.rstrip('\n')) try: - # TODO: sendall will block, we need a timeout + # NOTE: sendall will block, we need a timeout self._sock.sendall(to_send.encode('utf-8')) - except: + except: # pylint: disable=bare-except pass def get_packet_dump(self): @@ -509,11 +507,6 @@ class ProxSocketHelper(object): def hz(self): return self.get_all_tot_stats()[3] - # Deprecated - # TODO: remove - def rx_stats(self, cores, task=0): - return self.core_stats(cores, task) - def core_stats(self, cores, task=0): """Get the receive statistics from the remote system""" rx = tx = drop = tsc = 0 @@ -544,7 +537,7 @@ class ProxSocketHelper(object): finally: container['end_tot'] = end = self.get_all_tot_stats() - container['delta'] = TotStatsTuple(end - start for start, end in zip(start, end)) + container['delta'] = TotStatsTuple(e - s for s, e in zip(start, end)) def tot_stats(self): """Get the total statistics from the remote system""" @@ -642,13 +635,6 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): raise KeyError(template.format(section_key, section_name)) return result - def _build_pipeline_kwargs(self): - tool_path = self.ssh_helper.provision_tool(tool_file=self.APP_NAME) - self.pipeline_kwargs = { - 'tool_path': tool_path, - 'tool_dir': os.path.dirname(tool_path), - } - def copy_to_target(self, config_file_path, prox_file): remote_path = os.path.join("/tmp", prox_file) self.ssh_helper.put(config_file_path, remote_path) @@ -690,14 +676,13 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): if port_section_name != section_name: continue - for index, section_data in enumerate(section): + for section_data in section: if section_data[0] == "mac": section_data[1] = "hardware" # search for dst mac for _, section in sections: - # for index, (item_key, item_val) in enumerate(section): - for index, section_data in enumerate(section): + for section_data in section: item_key, item_val = section_data if item_val.startswith("@@dst_mac"): tx_port_iter = re.finditer(r'\d+', item_val) @@ -718,14 +703,14 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): return sections for section_name, section in sections: - for index, section_data in enumerate(section): + for section_data in section: try: if section_data[0].startswith("dofile"): section_data[0] = self._insert_additional_file(section_data[0]) if section_data[1].startswith("dofile"): section_data[1] = self._insert_additional_file(section_data[1]) - except: + except: # pylint: disable=bare-except pass return sections @@ -758,9 +743,9 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): a custom method """ out = [] - for i, (section_name, section) in enumerate(prox_config): + for (section_name, section) in prox_config: out.append("[{}]".format(section_name)) - for index, item in enumerate(section): + for item in section: key, value = item if key == "__name__": continue @@ -812,7 +797,7 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): options = self.scenario_helper.options config_path = options['prox_config'] config_file = os.path.basename(config_path) - config_path = find_relative_file(config_path, task_path) + config_path = utils.find_relative_file(config_path, task_path) self.additional_files = {} try: @@ -821,7 +806,7 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): self.lua = self.generate_prox_lua_file() if len(self.lua) > 0: self.upload_prox_lua("parameters.lua", self.lua) - except: + except: # pylint: disable=bare-except pass prox_files = options.get('prox_files', []) @@ -829,7 +814,7 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): prox_files = [prox_files] for key_prox_file in prox_files: base_prox_file = os.path.basename(key_prox_file) - key_prox_path = find_relative_file(key_prox_file, task_path) + key_prox_path = utils.find_relative_file(key_prox_file, task_path) remote_prox_file = self.copy_to_target(key_prox_path, base_prox_file) self.additional_files[base_prox_file] = remote_prox_file @@ -842,17 +827,20 @@ class ProxDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): self.build_config_file() options = self.scenario_helper.options - prox_args = options['prox_args'] - LOG.info("Provision and start the %s", self.APP_NAME) - self._build_pipeline_kwargs() - self.pipeline_kwargs["args"] = " ".join( - " ".join([k, v if v else ""]) for k, v in prox_args.items()) - self.pipeline_kwargs["cfg_file"] = self.remote_path + tool_path = self.ssh_helper.join_bin_path(self.APP_NAME) + + self.pipeline_kwargs = { + 'tool_path': tool_path, + 'tool_dir': os.path.dirname(tool_path), + 'cfg_file': self.remote_path, + 'args': ' '.join(' '.join([str(k), str(v) if v else '']) + for k, v in prox_args.items()) + } - cmd_template = "sudo bash -c 'cd {tool_dir}; {tool_path} -o cli {args} -f {cfg_file} '" - prox_cmd = cmd_template.format(**self.pipeline_kwargs) - return prox_cmd + cmd_template = ("sudo bash -c 'cd {tool_dir}; {tool_path} -o cli " + "{args} -f {cfg_file} '") + return cmd_template.format(**self.pipeline_kwargs) # this might be bad, sometimes we want regular ResourceHelper methods, like collect_kpi @@ -940,6 +928,7 @@ class ProxResourceHelper(ClientResourceHelper): func = getattr(self.sut, cmd, None) if func: return func(*args, **kwargs) + return None def _connect(self, client=None): """Run and connect to prox on the remote system """ @@ -1016,11 +1005,18 @@ class ProxDataHelper(object): def samples(self): samples = {} for port_name, port_num in self.vnfd_helper.ports_iter(): - port_rx_total, port_tx_total = self.sut.port_stats([port_num])[6:8] - samples[port_name] = { - "in_packets": port_rx_total, - "out_packets": port_tx_total, - } + try: + port_rx_total, port_tx_total = self.sut.port_stats([port_num])[6:8] + samples[port_name] = { + "in_packets": port_rx_total, + "out_packets": port_tx_total, + } + except (KeyError, TypeError, NameError, MemoryError, ValueError, + SystemError, BufferError): + samples[port_name] = { + "in_packets": 0, + "out_packets": 0, + } return samples def __enter__(self): @@ -1062,7 +1058,7 @@ class ProxDataHelper(object): self.tsc_hz = float(self.sut.hz()) def line_rate_to_pps(self): - # FIXME Don't hardcode 10Gb/s + # NOTE: to fix, don't hardcode 10Gb/s return self.port_count * TEN_GIGABIT / BITS_PER_BYTE / (self.pkt_size + 20) @@ -1138,7 +1134,7 @@ class ProxProfileHelper(object): for key, value in section: if key == "mode" and value == mode: core_tuple = CoreSocketTuple(section_name) - core = core_tuple.find_in_topology(self.cpu_topology) + core = core_tuple.core_id cores.append(core) return cores @@ -1160,6 +1156,10 @@ class ProxProfileHelper(object): :return: return lat_min, lat_max, lat_avg :rtype: list """ + + if not self._latency_cores: + self._latency_cores = self.get_cores(self.PROX_CORE_LAT_MODE) + if self._latency_cores: return self.sut.lat_stats(self._latency_cores) return [] @@ -1209,12 +1209,12 @@ class ProxMplsProfileHelper(ProxProfileHelper): if item_value.startswith("tag"): core_tuple = CoreSocketTuple(section_name) - core_tag = core_tuple.find_in_topology(self.cpu_topology) + core_tag = core_tuple.core_id cores_tagged.append(core_tag) elif item_value.startswith("udp"): core_tuple = CoreSocketTuple(section_name) - core_udp = core_tuple.find_in_topology(self.cpu_topology) + core_udp = core_tuple.core_id cores_plain.append(core_udp) return cores_tagged, cores_plain @@ -1287,23 +1287,23 @@ class ProxBngProfileHelper(ProxProfileHelper): if item_value.startswith("cpe"): core_tuple = CoreSocketTuple(section_name) - cpe_core = core_tuple.find_in_topology(self.cpu_topology) + cpe_core = core_tuple.core_id cpe_cores.append(cpe_core) elif item_value.startswith("inet"): core_tuple = CoreSocketTuple(section_name) - inet_core = core_tuple.find_in_topology(self.cpu_topology) + inet_core = core_tuple.core_id inet_cores.append(inet_core) elif item_value.startswith("arp"): core_tuple = CoreSocketTuple(section_name) - arp_core = core_tuple.find_in_topology(self.cpu_topology) + arp_core = core_tuple.core_id arp_cores.append(arp_core) # We check the tasks/core separately if item_value.startswith("arp_task"): core_tuple = CoreSocketTuple(section_name) - arp_task_core = core_tuple.find_in_topology(self.cpu_topology) + arp_task_core = core_tuple.core_id arp_tasks_core.append(arp_task_core) return cpe_cores, inet_cores, arp_cores, arp_tasks_core @@ -1466,12 +1466,12 @@ class ProxVpeProfileHelper(ProxProfileHelper): if item_value.startswith("cpe"): core_tuple = CoreSocketTuple(section_name) - core_tag = core_tuple.find_in_topology(self.cpu_topology) + core_tag = core_tuple.core_id cpe_cores.append(core_tag) elif item_value.startswith("inet"): core_tuple = CoreSocketTuple(section_name) - inet_core = core_tuple.find_in_topology(self.cpu_topology) + inet_core = core_tuple.core_id inet_cores.append(inet_core) return cpe_cores, inet_cores @@ -1490,7 +1490,6 @@ class ProxVpeProfileHelper(ProxProfileHelper): if item_key != 'name': continue - for item_key, item_value in section: if item_value.startswith("cpe"): cpe_ports.append(tx_port_no) @@ -1595,3 +1594,192 @@ class ProxVpeProfileHelper(ProxProfileHelper): data_helper.latency = self.get_latency() return data_helper.result_tuple, data_helper.samples + + +class ProxlwAFTRProfileHelper(ProxProfileHelper): + + __prox_profile_type__ = "lwAFTR gen" + + def __init__(self, resource_helper): + super(ProxlwAFTRProfileHelper, self).__init__(resource_helper) + self._cores_tuple = None + self._ports_tuple = None + self.step_delta = 5 + self.step_time = 0.5 + + @property + def _lwaftr_cores(self): + if not self._cores_tuple: + self._cores_tuple = self._get_cores_gen_lwaftr() + return self._cores_tuple + + @property + def tun_cores(self): + return self._lwaftr_cores[0] + + @property + def inet_cores(self): + return self._lwaftr_cores[1] + + @property + def _lwaftr_ports(self): + if not self._ports_tuple: + self._ports_tuple = self._get_ports_gen_lw_aftr() + return self._ports_tuple + + @property + def tun_ports(self): + return self._lwaftr_ports[0] + + @property + def inet_ports(self): + return self._lwaftr_ports[1] + + @property + def all_rx_cores(self): + return self.latency_cores + + def _get_cores_gen_lwaftr(self): + tun_cores = [] + inet_cores = [] + for section_name, section in self.resource_helper.setup_helper.prox_config_data: + if not section_name.startswith("core"): + continue + + if all(key != "mode" or value != self.PROX_CORE_GEN_MODE for key, value in section): + continue + + core_tuple = CoreSocketTuple(section_name) + core_tag = core_tuple.core_id + for item_value in (v for k, v in section if k == 'name'): + if item_value.startswith('tun'): + tun_cores.append(core_tag) + elif item_value.startswith('inet'): + inet_cores.append(core_tag) + + return tun_cores, inet_cores + + def _get_ports_gen_lw_aftr(self): + tun_ports = [] + inet_ports = [] + + re_port = re.compile(r'port (\d+)') + for section_name, section in self.resource_helper.setup_helper.prox_config_data: + match = re_port.search(section_name) + if not match: + continue + + tx_port_no = int(match.group(1)) + for item_value in (v for k, v in section if k == 'name'): + if item_value.startswith('lwB4'): + tun_ports.append(tx_port_no) + elif item_value.startswith('inet'): + inet_ports.append(tx_port_no) + + return tun_ports, inet_ports + + @staticmethod + def _resize(len1, len2): + if len1 == len2: + return 1.0 + return 1.0 * len1 / len2 + + @contextmanager + def traffic_context(self, pkt_size, value): + # Tester is sending packets at the required speed already after + # setup_test(). Just get the current statistics, sleep the required + # amount of time and calculate packet loss. + tun_pkt_size = pkt_size + inet_pkt_size = pkt_size - 40 + ratio = 1.0 * (tun_pkt_size + 20) / (inet_pkt_size + 20) + + curr_up_speed = curr_down_speed = 0 + max_up_speed = max_down_speed = value + + max_up_speed = value / ratio + + # Adjust speed when multiple cores per port are used to generate traffic + if len(self.tun_ports) != len(self.tun_cores): + max_down_speed *= self._resize(len(self.tun_ports), len(self.tun_cores)) + if len(self.inet_ports) != len(self.inet_cores): + max_up_speed *= self._resize(len(self.inet_ports), len(self.inet_cores)) + + # Initialize cores + self.sut.stop_all() + time.sleep(0.5) + + # Flush any packets in the NIC RX buffers, otherwise the stats will be + # wrong. + self.sut.start(self.all_rx_cores) + time.sleep(0.5) + self.sut.stop(self.all_rx_cores) + time.sleep(0.5) + self.sut.reset_stats() + + self.sut.set_pkt_size(self.inet_cores, inet_pkt_size) + self.sut.set_pkt_size(self.tun_cores, tun_pkt_size) + + self.sut.reset_values(self.tun_cores) + self.sut.reset_values(self.inet_cores) + + # Set correct IP and UDP lengths in packet headers + # tun + # IPv6 length (byte 18): 58 for MAC(12), EthType(2), IPv6(40) , CRC(4) + self.sut.set_value(self.tun_cores, 18, tun_pkt_size - 58, 2) + # IP length (byte 56): 58 for MAC(12), EthType(2), CRC(4) + self.sut.set_value(self.tun_cores, 56, tun_pkt_size - 58, 2) + # UDP length (byte 78): 78 for MAC(12), EthType(2), IP(20), UDP(8), CRC(4) + self.sut.set_value(self.tun_cores, 78, tun_pkt_size - 78, 2) + + # INET + # IP length (byte 20): 22 for MAC(12), EthType(2), CRC(4) + self.sut.set_value(self.inet_cores, 16, inet_pkt_size - 18, 2) + # UDP length (byte 42): 42 for MAC(12), EthType(2), IP(20), UPD(8), CRC(4) + self.sut.set_value(self.inet_cores, 38, inet_pkt_size - 38, 2) + + LOG.info("Initializing SUT: sending lwAFTR packets") + self.sut.set_speed(self.inet_cores, curr_up_speed) + self.sut.set_speed(self.tun_cores, curr_down_speed) + time.sleep(4) + + # Ramp up the transmission speed. First go to the common speed, then + # increase steps for the faster one. + self.sut.start(self.tun_cores + self.inet_cores + self.latency_cores) + + LOG.info("Ramping up speed to %s up, %s down", max_up_speed, max_down_speed) + + while (curr_up_speed < max_up_speed) or (curr_down_speed < max_down_speed): + # The min(..., ...) takes care of 1) floating point rounding errors + # that could make curr_*_speed to be slightly greater than + # max_*_speed and 2) max_*_speed not being an exact multiple of + # self._step_delta. + if curr_up_speed < max_up_speed: + curr_up_speed = min(curr_up_speed + self.step_delta, max_up_speed) + if curr_down_speed < max_down_speed: + curr_down_speed = min(curr_down_speed + self.step_delta, max_down_speed) + + self.sut.set_speed(self.inet_cores, curr_up_speed) + self.sut.set_speed(self.tun_cores, curr_down_speed) + time.sleep(self.step_time) + + LOG.info("Target speeds reached. Starting real test.") + + yield + + self.sut.stop(self.tun_cores + self.inet_cores) + LOG.info("Test ended. Flushing NIC buffers") + self.sut.start(self.all_rx_cores) + time.sleep(3) + self.sut.stop(self.all_rx_cores) + + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + + with data_helper, self.traffic_context(pkt_size, value): + with data_helper.measure_tot_stats(): + time.sleep(duration) + # Getting statistics to calculate PPS at right speed.... + data_helper.capture_tsc_hz() + data_helper.latency = self.get_latency() + + return data_helper.result_tuple, data_helper.samples