diff options
author | treyad <treyad@viosoft.com> | 2018-11-20 01:34:19 -0800 |
---|---|---|
committer | treyad <treyad@viosoft.com> | 2019-03-27 11:51:57 -0700 |
commit | 3ca72d0d45f89732a0d64681a5e7a3ce100de815 (patch) | |
tree | 608d2d0a25850a6dd7883cd9a80beb3e1f941e41 | |
parent | faa02f995c7e22bb1bb2ff5cd745c375b3fb3b51 (diff) |
Setup IPSEC tunnel mode for VPP Crypto testing
Update startup config file
Enable logging
Create IPSEC in tunnel mode
JIRA: YARDSTICK-1503
Change-Id: Ifd2b05c063870b31c7f30decb1611a93322bf1e8
Signed-off-by: treyad <treyad@viosoft.com>
4 files changed, 1992 insertions, 41 deletions
diff --git a/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py b/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py index 55313ef41..9aedefec1 100644 --- a/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py @@ -153,6 +153,8 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper): vpp_cfg.add_dpdk_dev_default_rxd(2048) vpp_cfg.add_dpdk_dev_default_txd(2048) + self.apply_config(vpp_cfg, True) + self.update_vpp_interface_data() def setup_vnf_environment(self): resource = super(VipsecApproxSetupEnvHelper, @@ -160,6 +162,8 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper): self.start_vpp_service() self._update_vnfd_helper(self.sys_cores.get_cpu_layout()) + self.update_vpp_interface_data() + self.iface_update_numa() return resource @@ -241,8 +245,43 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper): return result def create_ipsec_tunnels(self): - # TODO Implement later - pass + self.initialize_ipsec() + + # TODO generate the same key + crypto_algorithms = self._get_crypto_algorithms() + if crypto_algorithms == 'aes-gcm': + encr_alg = CryptoAlg.AES_GCM_128 + auth_alg = IntegAlg.AES_GCM_128 + encr_key = 'LNYZXMBQDKESNLREHJMS' + auth_key = 'SWGLDTYZSQKVBZZMPIEV' + elif crypto_algorithms == 'cbc-sha1': + encr_alg = CryptoAlg.AES_CBC_128 + auth_alg = IntegAlg.SHA1_96 + encr_key = 'IFEMSHYLCZIYFUTT' + auth_key = 'PEALEIPSCPTRHYJSDXLY' + + self.execute_script("enable_dpdk_traces.vat", json_out=False) + self.execute_script("enable_vhost_user_traces.vat", json_out=False) + self.execute_script("enable_memif_traces.vat", json_out=False) + + node_name = self.find_encrypted_data_interface()["node_name"] + n_tunnels = self._get_n_tunnels() + n_connections = self._get_n_connections() + flow_dst_start_ip = self._get_flow_dst_start_ip() + if node_name == "vnf__0": + self.vpp_create_ipsec_tunnels( + self.find_encrypted_data_interface()["local_ip"], + self.find_encrypted_data_interface()["peer_intf"]["local_ip"], + self.find_encrypted_data_interface()["ifname"], + n_tunnels, n_connections, encr_alg, encr_key, auth_alg, + auth_key, flow_dst_start_ip) + elif node_name == "vnf__1": + self.vpp_create_ipsec_tunnels( + self.find_encrypted_data_interface()["local_ip"], + self.find_encrypted_data_interface()["peer_intf"]["local_ip"], + self.find_encrypted_data_interface()["ifname"], + n_tunnels, n_connections, encr_alg, encr_key, auth_alg, + auth_key, flow_dst_start_ip, 20000, 10000) def find_raw_data_interface(self): try: @@ -357,6 +396,41 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper): vpp_cfg.add_dpdk_sw_cryptodev(sw_pmd_type, socket_id, thr_count_int) + def initialize_ipsec(self): + flow_src_start_ip = self._get_flow_src_start_ip() + + self.set_interface_state( + self.find_encrypted_data_interface()["ifname"], 'up') + self.set_interface_state(self.find_raw_data_interface()["ifname"], + 'up') + self.vpp_interfaces_ready_wait() + self.vpp_set_interface_mtu( + self.find_encrypted_data_interface()["ifname"]) + self.vpp_set_interface_mtu(self.find_raw_data_interface()["ifname"]) + self.vpp_interfaces_ready_wait() + + self.set_ip(self.find_encrypted_data_interface()["ifname"], + self.find_encrypted_data_interface()["local_ip"], 24) + self.set_ip(self.find_raw_data_interface()["ifname"], + self.find_raw_data_interface()["local_ip"], + 24) + + self.add_arp_on_dut(self.find_encrypted_data_interface()["ifname"], + self.find_encrypted_data_interface()["peer_intf"][ + "local_ip"], + self.find_encrypted_data_interface()["peer_intf"][ + "local_mac"]) + self.add_arp_on_dut(self.find_raw_data_interface()["ifname"], + self.find_raw_data_interface()["peer_intf"][ + "local_ip"], + self.find_raw_data_interface()["peer_intf"][ + "local_mac"]) + + self.vpp_route_add(flow_src_start_ip, 8, + self.find_raw_data_interface()["peer_intf"][ + "local_ip"], + self.find_raw_data_interface()["ifname"]) + class VipsecApproxVnf(SampleVNF): """ This class handles vIPSEC VNF model-driver definitions """ diff --git a/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py b/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py index 1eee537ee..4e67b3c65 100644 --- a/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py @@ -12,10 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import binascii +import ipaddress +import json import logging +import os import re +import tempfile +import time from collections import OrderedDict +from yardstick.common import constants +from yardstick.common import exceptions from yardstick.network_services.helpers.cpu import CpuSysCores from yardstick.network_services.vnf_generic.vnf.sample_vnf import \ DpdkVnfSetupEnvHelper @@ -237,3 +245,449 @@ class VppSetupEnvHelper(DpdkVnfSetupEnvHelper): ifname=interface).get(key) except (KeyError, ValueError): return None + + def vpp_create_ipsec_tunnels(self, if1_ip_addr, if2_ip_addr, if_name, + n_tunnels, n_connections, crypto_alg, + crypto_key, integ_alg, integ_key, addrs_ip, + spi_1=10000, spi_2=20000): + mask_length = 32 + if n_connections <= n_tunnels: + count = 1 + else: + count = int(n_connections / n_tunnels) + addr_ip_i = int(ipaddress.ip_address(str(addrs_ip))) + dst_start_ip = addr_ip_i + + tmp_fd, tmp_path = tempfile.mkstemp() + + vpp_ifname = self.get_value_by_interface_key(if_name, 'vpp_name') + ckey = binascii.hexlify(crypto_key.encode()) + ikey = binascii.hexlify(integ_key.encode()) + + integ = '' + if crypto_alg.alg_name != 'aes-gcm-128': + integ = 'integ_alg {integ_alg} ' \ + 'local_integ_key {local_integ_key} ' \ + 'remote_integ_key {remote_integ_key} ' \ + .format(integ_alg=integ_alg.alg_name, + local_integ_key=ikey, + remote_integ_key=ikey) + create_tunnels_cmds = 'ipsec_tunnel_if_add_del ' \ + 'local_spi {local_spi} ' \ + 'remote_spi {remote_spi} ' \ + 'crypto_alg {crypto_alg} ' \ + 'local_crypto_key {local_crypto_key} ' \ + 'remote_crypto_key {remote_crypto_key} ' \ + '{integ} ' \ + 'local_ip {local_ip} ' \ + 'remote_ip {remote_ip}\n' + start_tunnels_cmds = 'ip_add_del_route {raddr}/{mask} via {addr} ipsec{i}\n' \ + 'exec set interface unnumbered ipsec{i} use {uifc}\n' \ + 'sw_interface_set_flags ipsec{i} admin-up\n' + + with os.fdopen(tmp_fd, 'w') as tmp_file: + for i in range(0, n_tunnels): + create_tunnel = create_tunnels_cmds.format(local_spi=spi_1 + i, + remote_spi=spi_2 + i, + crypto_alg=crypto_alg.alg_name, + local_crypto_key=ckey, + remote_crypto_key=ckey, + integ=integ, + local_ip=if1_ip_addr, + remote_ip=if2_ip_addr) + tmp_file.write(create_tunnel) + self.execute_script(tmp_path, json_out=False, copy_on_execute=True) + os.remove(tmp_path) + + tmp_fd, tmp_path = tempfile.mkstemp() + + with os.fdopen(tmp_fd, 'w') as tmp_file: + for i in range(0, n_tunnels): + if count > 1: + dst_start_ip = addr_ip_i + i * count + dst_end_ip = ipaddress.ip_address(dst_start_ip + count - 1) + ips = [ipaddress.ip_address(ip) for ip in + [str(ipaddress.ip_address(dst_start_ip)), + str(dst_end_ip)]] + lowest_ip, highest_ip = min(ips), max(ips) + mask_length = self.get_prefix_length(int(lowest_ip), + int(highest_ip), + lowest_ip.max_prefixlen) + # TODO check duplicate route for some IPs + elif count == 1: + dst_start_ip = addr_ip_i + i + start_tunnel = start_tunnels_cmds.format( + raddr=str(ipaddress.ip_address(dst_start_ip)), + mask=mask_length, + addr=if2_ip_addr, + i=i, count=count, + uifc=vpp_ifname) + tmp_file.write(start_tunnel) + # TODO add route for remain IPs + + self.execute_script(tmp_path, json_out=False, copy_on_execute=True) + os.remove(tmp_path) + + def apply_config(self, vpp_cfg, restart_vpp=True): + vpp_config = vpp_cfg.dump_config() + ret, _, _ = \ + self.ssh_helper.execute('echo "{config}" | sudo tee {filename}'. + format(config=vpp_config, + filename=self.CFG_CONFIG)) + if ret != 0: + raise RuntimeError('Writing config file failed') + if restart_vpp: + self.start_vpp_service() + + def vpp_route_add(self, network, prefix_len, gateway=None, interface=None, + use_sw_index=True, resolve_attempts=10, + count=1, vrf=None, lookup_vrf=None, multipath=False, + weight=None, local=False): + if interface: + if use_sw_index: + int_cmd = ('sw_if_index {}'.format( + self.get_value_by_interface_key(interface, + 'vpp_sw_index'))) + else: + int_cmd = interface + else: + int_cmd = '' + + rap = 'resolve-attempts {}'.format(resolve_attempts) \ + if resolve_attempts else '' + + via = 'via {}'.format(gateway) if gateway else '' + + cnt = 'count {}'.format(count) \ + if count else '' + + vrf = 'vrf {}'.format(vrf) if vrf else '' + + lookup_vrf = 'lookup-in-vrf {}'.format( + lookup_vrf) if lookup_vrf else '' + + multipath = 'multipath' if multipath else '' + + weight = 'weight {}'.format(weight) if weight else '' + + local = 'local' if local else '' + + with VatTerminal(self.ssh_helper, json_param=False) as vat: + vat.vat_terminal_exec_cmd_from_template('add_route.vat', + network=network, + prefix_length=prefix_len, + via=via, + vrf=vrf, + interface=int_cmd, + resolve_attempts=rap, + count=cnt, + lookup_vrf=lookup_vrf, + multipath=multipath, + weight=weight, + local=local) + + def add_arp_on_dut(self, iface_key, ip_address, mac_address): + with VatTerminal(self.ssh_helper) as vat: + return vat.vat_terminal_exec_cmd_from_template( + 'add_ip_neighbor.vat', + sw_if_index=self.get_value_by_interface_key(iface_key, + 'vpp_sw_index'), + ip_address=ip_address, mac_address=mac_address) + + def set_ip(self, interface, address, prefix_length): + with VatTerminal(self.ssh_helper) as vat: + return vat.vat_terminal_exec_cmd_from_template( + 'add_ip_address.vat', + sw_if_index=self.get_value_by_interface_key(interface, + 'vpp_sw_index'), + address=address, prefix_length=prefix_length) + + def set_interface_state(self, interface, state): + sw_if_index = self.get_value_by_interface_key(interface, + 'vpp_sw_index') + + if state == 'up': + state = 'admin-up link-up' + elif state == 'down': + state = 'admin-down link-down' + else: + raise ValueError('Unexpected interface state: {}'.format(state)) + with VatTerminal(self.ssh_helper) as vat: + return vat.vat_terminal_exec_cmd_from_template( + 'set_if_state.vat', sw_if_index=sw_if_index, state=state) + + def vpp_set_interface_mtu(self, interface, mtu=9200): + sw_if_index = self.get_value_by_interface_key(interface, + 'vpp_sw_index') + if sw_if_index: + with VatTerminal(self.ssh_helper, json_param=False) as vat: + vat.vat_terminal_exec_cmd_from_template( + "hw_interface_set_mtu.vat", sw_if_index=sw_if_index, + mtu=mtu) + + def vpp_interfaces_ready_wait(self, timeout=30): + if_ready = False + not_ready = [] + start = time.time() + while not if_ready: + out = self.vpp_get_interface_data() + if time.time() - start > timeout: + for interface in out: + if interface.get('admin_up_down') == 1: + if interface.get('link_up_down') != 1: + LOG.debug('%s link-down', + interface.get('interface_name')) + raise RuntimeError('timeout, not up {0}'.format(not_ready)) + not_ready = [] + for interface in out: + if interface.get('admin_up_down') == 1: + if interface.get('link_up_down') != 1: + not_ready.append(interface.get('interface_name')) + if not not_ready: + if_ready = True + else: + LOG.debug('Interfaces still in link-down state: %s, ' + 'waiting...', not_ready) + time.sleep(1) + + def vpp_get_interface_data(self, interface=None): + with VatTerminal(self.ssh_helper) as vat: + response = vat.vat_terminal_exec_cmd_from_template( + "interface_dump.vat") + data = response[0] + if interface is not None: + if isinstance(interface, str): + param = "interface_name" + elif isinstance(interface, int): + param = "sw_if_index" + else: + raise TypeError + for data_if in data: + if data_if[param] == interface: + return data_if + return dict() + return data + + def update_vpp_interface_data(self): + data = {} + interface_dump_json = self.execute_script_json_out( + "dump_interfaces.vat") + interface_list = json.loads(interface_dump_json) + for interface in self.vnfd_helper.interfaces: + if_mac = interface['virtual-interface']['local_mac'] + interface_dict = VppSetupEnvHelper.get_vpp_interface_by_mac( + interface_list, if_mac) + if not interface_dict: + LOG.debug('Interface %s not found by MAC %s', interface, + if_mac) + continue + data[interface['virtual-interface']['ifname']] = { + 'vpp_name': interface_dict["interface_name"], + 'vpp_sw_index': interface_dict["sw_if_index"] + } + for iface_key, updated_vnfd in data.items(): + self._update_vnfd_helper(updated_vnfd, iface_key) + + def iface_update_numa(self): + iface_numa = {} + for interface in self.vnfd_helper.interfaces: + cmd = "cat /sys/bus/pci/devices/{}/numa_node".format( + interface["virtual-interface"]["vpci"]) + ret, out, _ = self.ssh_helper.execute(cmd) + if ret == 0: + try: + numa_node = int(out) + if numa_node < 0: + if self.vnfd_helper["cpuinfo"][-1][3] + 1 == 1: + iface_numa[ + interface['virtual-interface']['ifname']] = { + 'numa_node': 0 + } + else: + raise ValueError + else: + iface_numa[ + interface['virtual-interface']['ifname']] = { + 'numa_node': numa_node + } + except ValueError: + LOG.debug( + 'Reading numa location failed for: %s', + interface["virtual-interface"]["vpci"]) + for iface_key, updated_vnfd in iface_numa.items(): + self._update_vnfd_helper(updated_vnfd, iface_key) + + def execute_script(self, vat_name, json_out=True, copy_on_execute=False): + if copy_on_execute: + self.ssh_helper.put_file(vat_name, vat_name) + remote_file_path = vat_name + else: + vat_path = self.ssh_helper.join_bin_path("vpp", "templates") + remote_file_path = '{0}/{1}'.format(vat_path, vat_name) + + cmd = "{vat_bin} {json} in {vat_path} script".format( + vat_bin=self.VAT_BIN_NAME, + json="json" if json_out is True else "", + vat_path=remote_file_path) + + try: + return self.ssh_helper.execute(cmd=cmd) + except Exception: + raise RuntimeError("VAT script execution failed: {0}".format(cmd)) + + def execute_script_json_out(self, vat_name): + vat_path = self.ssh_helper.join_bin_path("vpp", "templates") + remote_file_path = '{0}/{1}'.format(vat_path, vat_name) + + _, stdout, _ = self.execute_script(vat_name, json_out=True) + return self.cleanup_vat_json_output(stdout, vat_file=remote_file_path) + + @staticmethod + def cleanup_vat_json_output(json_output, vat_file=None): + retval = json_output + clutter = ['vat#', 'dump_interface_table error: Misc', + 'dump_interface_table:6019: JSON output supported only ' \ + 'for VPE API calls and dump_stats_table'] + if vat_file: + clutter.append("{0}(2):".format(vat_file)) + for garbage in clutter: + retval = retval.replace(garbage, '') + return retval.strip() + + @staticmethod + def _convert_mac_to_number_list(mac_address): + list_mac = [] + for num in mac_address.split(":"): + list_mac.append(int(num, 16)) + return list_mac + + @staticmethod + def get_vpp_interface_by_mac(interfaces_list, mac_address): + interface_dict = {} + list_mac_address = VppSetupEnvHelper._convert_mac_to_number_list( + mac_address) + LOG.debug("MAC address %s converted to list %s.", mac_address, + list_mac_address) + for interface in interfaces_list: + # TODO: create vat json integrity checking and move there + if "l2_address" not in interface: + raise KeyError( + "key l2_address not found in interface dict." + "Probably input list is not parsed from correct VAT " + "json output.") + if "l2_address_length" not in interface: + raise KeyError( + "key l2_address_length not found in interface " + "dict. Probably input list is not parsed from correct " + "VAT json output.") + mac_from_json = interface["l2_address"][:6] + if mac_from_json == list_mac_address: + if interface["l2_address_length"] != 6: + raise ValueError("l2_address_length value is not 6.") + interface_dict = interface + break + return interface_dict + + @staticmethod + def get_prefix_length(number1, number2, bits): + for i in range(bits): + if number1 >> i == number2 >> i: + return bits - i + return 0 + + +class VatTerminal(object): + + __VAT_PROMPT = ("vat# ",) + __LINUX_PROMPT = (":~# ", ":~$ ", "~]$ ", "~]# ") + + + def __init__(self, ssh_helper, json_param=True): + json_text = ' json' if json_param else '' + self.json = json_param + self.ssh_helper = ssh_helper + EXEC_RETRY = 3 + + try: + self._tty = self.ssh_helper.interactive_terminal_open() + except Exception: + raise RuntimeError("Cannot open interactive terminal") + + for _ in range(EXEC_RETRY): + try: + self.ssh_helper.interactive_terminal_exec_command( + self._tty, + 'sudo -S {0}{1}'.format(VppSetupEnvHelper.VAT_BIN_NAME, + json_text), + self.__VAT_PROMPT) + except exceptions.SSHTimeout: + continue + else: + break + + self._exec_failure = False + self.vat_stdout = None + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.vat_terminal_close() + + def vat_terminal_exec_cmd(self, cmd): + try: + out = self.ssh_helper.interactive_terminal_exec_command(self._tty, + cmd, + self.__VAT_PROMPT) + self.vat_stdout = out + except exceptions.SSHTimeout: + self._exec_failure = True + raise RuntimeError( + "VPP is not running on node. VAT command {0} execution failed". + format(cmd)) + if self.json: + obj_start = out.find('{') + obj_end = out.rfind('}') + array_start = out.find('[') + array_end = out.rfind(']') + + if obj_start == -1 and array_start == -1: + raise RuntimeError( + "VAT command {0}: no JSON data.".format(cmd)) + + if obj_start < array_start or array_start == -1: + start = obj_start + end = obj_end + 1 + else: + start = array_start + end = array_end + 1 + out = out[start:end] + json_out = json.loads(out) + return json_out + else: + return None + + def vat_terminal_close(self): + if not self._exec_failure: + try: + self.ssh_helper.interactive_terminal_exec_command(self._tty, + 'quit', + self.__LINUX_PROMPT) + except exceptions.SSHTimeout: + raise RuntimeError("Failed to close VAT console") + try: + self.ssh_helper.interactive_terminal_close(self._tty) + except Exception: + raise RuntimeError("Cannot close interactive terminal") + + def vat_terminal_exec_cmd_from_template(self, vat_template_file, **args): + file_path = os.path.join(constants.YARDSTICK_ROOT_PATH, + 'yardstick/resources/templates/', + vat_template_file) + with open(file_path, 'r') as template_file: + cmd_template = template_file.readlines() + ret = [] + for line_tmpl in cmd_template: + vat_cmd = line_tmpl.format(**args) + ret.append(self.vat_terminal_exec_cmd(vat_cmd.replace('\n', ''))) + return ret diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py index e94f83f29..8b245b3bf 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py @@ -1241,13 +1241,39 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() self.assertIsNone(ipsec_approx_setup_helper.build_config()) + self.assertEqual(0, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'numa_node')) + self.assertEqual('TenGigabitEthernetff/6/0', + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'vpp_name')) + self.assertEqual(1, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'vpp_sw_index')) + self.assertEqual(0, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'numa_node')) + self.assertEqual('VirtualFunctionEthernetff/7/0', + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'vpp_name')) + self.assertEqual(2, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'vpp_sw_index')) + self.assertGreaterEqual(ssh_helper.execute.call_count, 4) def test_build_config_cbc_algorithms(self): vnfd_helper = VnfdHelper( @@ -1263,13 +1289,39 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() self.assertIsNone(ipsec_approx_setup_helper.build_config()) + self.assertEqual(0, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'numa_node')) + self.assertEqual('TenGigabitEthernetff/6/0', + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'vpp_name')) + self.assertEqual(1, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'vpp_sw_index')) + self.assertEqual(0, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'numa_node')) + self.assertEqual('VirtualFunctionEthernetff/7/0', + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'vpp_name')) + self.assertEqual(2, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'vpp_sw_index')) + self.assertGreaterEqual(ssh_helper.execute.call_count, 4) @mock.patch.object(utils, 'setup_hugepages') def test_setup_vnf_environment(self, *args): @@ -1286,11 +1338,35 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): ssh_helper, scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") self.assertIsInstance( ipsec_approx_setup_helper.setup_vnf_environment(), ResourceProfile) + self.assertEqual(0, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'numa_node')) + self.assertEqual('TenGigabitEthernetff/6/0', + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'vpp_name')) + self.assertEqual(1, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe0', 'vpp_sw_index')) + self.assertEqual(0, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'numa_node')) + self.assertEqual('VirtualFunctionEthernetff/7/0', + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'vpp_name')) + self.assertEqual(2, + ipsec_approx_setup_helper.get_value_by_interface_key( + 'xe1', 'vpp_sw_index')) + self.assertGreaterEqual(ssh_helper.execute.call_count, 4) def test_calculate_frame_size(self): vnfd_helper = VnfdHelper( @@ -1355,16 +1431,73 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): self.assertFalse(ipsec_approx_setup_helper.check_status()) def test_get_vpp_statistics(self): + def execute(cmd): + if 'TenGigabitEthernetff/6/0' in cmd: + return 0, output_xe0, '' + elif 'VirtualFunctionEthernetff/7/0' in cmd: + return 0, output_xe1, '' + return 0, '0', '' + + output_xe0 = \ + ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \ + ' Counter Count \n' \ + 'TenGigabitEthernetff/6/0 1 up 9200/0/0/0 ' \ + 'rx packets 23373568\n' \ + ' ' \ + 'rx bytes 1402414080\n' \ + ' ' \ + 'tx packets 20476416\n' \ + ' ' \ + 'tx bytes 1228584960\n' \ + ' ' \ + 'ip4 23373568\n' \ + ' ' \ + 'rx-miss 27789925' + output_xe1 = \ + ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \ + ' Counter Count \n' \ + 'VirtualFunctionEthernetff/7/0 2 up 9200/0/0/0 ' \ + 'rx packets 23373568\n' \ + ' ' \ + 'rx bytes 1402414080\n' \ + ' ' \ + 'tx packets 20476416\n' \ + ' ' \ + 'tx bytes 1228584960\n' \ + ' ' \ + 'ip4 23373568\n' \ + ' ' \ + 'rx-miss 27789925' + vnfd_helper = VnfdHelper( TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) ssh_helper = mock.Mock() - ssh_helper.execute.return_value = 0, '', '' + ssh_helper.execute = execute scenario_helper = mock.Mock() ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - ipsec_approx_setup_helper.get_vpp_statistics() + with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: + mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") + sys_cores = cpu.CpuSysCores(ssh_helper) + ipsec_approx_setup_helper._update_vnfd_helper( + sys_cores.get_cpu_layout()) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertEqual({'xe0': {'packets_dropped': 27789925, + 'packets_fwd': 20476416, + 'packets_in': 23373568}, + 'xe1': {'packets_dropped': 27789925, + 'packets_fwd': 20476416, + 'packets_in': 23373568}}, + ipsec_approx_setup_helper.get_vpp_statistics()) def test_parser_vpp_stats(self): output = \ @@ -1430,12 +1563,112 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): vnfd_helper = VnfdHelper( TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '0', '' scenario_helper = mock.Mock() + scenario_helper.options = self.OPTIONS + scenario_helper.all_options = self.ALL_OPTIONS ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - ipsec_approx_setup_helper.create_ipsec_tunnels() + + with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out, \ + mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template, \ + mock.patch.object(ipsec_approx_setup_helper, + 'vpp_get_interface_data') as \ + mock_ipsec_approx_setup_helper: + mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") + mock_vat_terminal_exec_cmd_from_template.return_value = self.VPP_INTERFACES_DUMP + mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP + sys_cores = cpu.CpuSysCores(ssh_helper) + ipsec_approx_setup_helper._update_vnfd_helper( + sys_cores.get_cpu_layout()) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.create_ipsec_tunnels()) + self.assertGreaterEqual( + mock_vat_terminal_exec_cmd_from_template.call_count, 9) + + def test_create_ipsec_tunnels_cbc_algorithms(self): + vnfd_helper = VnfdHelper( + TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '0', '' + scenario_helper = mock.Mock() + scenario_helper.options = self.OPTIONS + scenario_helper.all_options = self.ALL_OPTIONS_CBC_ALGORITHMS + + ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper, + ssh_helper, + scenario_helper) + + with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out, \ + mock.patch.object(ipsec_approx_setup_helper, + 'find_encrypted_data_interface') as \ + mock_find_encrypted_data_interface, \ + mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template, \ + mock.patch.object(ipsec_approx_setup_helper, + 'vpp_get_interface_data') as \ + mock_ipsec_approx_setup_helper: + mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") + mock_find_encrypted_data_interface.return_value = { + 'dpdk_port_num': 0, + 'driver': 'igb_uio', + 'dst_ip': '192.168.100.1', + 'dst_mac': '90:e2:ba:7c:30:e8', + 'ifname': 'xe0', + 'local_ip': '192.168.100.2', + 'local_mac': '90:e2:ba:7c:41:a8', + 'netmask': '255.255.255.0', + 'network': {}, + 'node_name': 'vnf__1', + 'numa_node': 0, + 'peer_ifname': 'xe0', + 'peer_intf': {'dpdk_port_num': 0, + 'driver': 'igb_uio', + 'dst_ip': '192.168.100.2', + 'dst_mac': '90:e2:ba:7c:41:a8', + 'ifname': 'xe0', + 'local_ip': '192.168.100.1', + 'local_mac': '90:e2:ba:7c:30:e8', + 'netmask': '255.255.255.0', + 'network': {}, + 'node_name': 'tg__0', + 'peer_ifname': 'xe0', + 'peer_name': 'vnf__0', + 'vld_id': 'uplink_0', + 'vpci': '0000:81:00.0'}, + 'peer_name': 'tg__0', + 'vld_id': 'uplink_0', + 'vpci': '0000:ff:06.0', + 'vpp_name': u'TenGigabitEthernetff/6/0', + 'vpp_sw_index': 1} + mock_vat_terminal_exec_cmd_from_template.return_value = self.VPP_INTERFACES_DUMP + mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP + sys_cores = cpu.CpuSysCores(ssh_helper) + ipsec_approx_setup_helper._update_vnfd_helper( + sys_cores.get_cpu_layout()) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.create_ipsec_tunnels()) + self.assertGreaterEqual( + mock_vat_terminal_exec_cmd_from_template.call_count, 9) def test_find_raw_data_interface(self): expected = {'dpdk_port_num': 0, @@ -1448,6 +1681,7 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): 'netmask': '255.255.255.0', 'network': {}, 'node_name': 'vnf__0', + 'numa_node': 0, 'peer_ifname': 'xe0', 'peer_intf': {'dpdk_port_num': 0, 'driver': 'igb_uio', @@ -1465,7 +1699,9 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): 'vpci': '0000:81:00.0'}, 'peer_name': 'tg__0', 'vld_id': 'uplink_0', - 'vpci': '0000:ff:06.0'} + 'vpci': '0000:ff:06.0', + 'vpp_name': u'TenGigabitEthernetff/6/0', + 'vpp_sw_index': 1} vnfd_helper = VnfdHelper( TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) ssh_helper = mock.Mock() @@ -1500,6 +1736,7 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): 'netmask': '255.255.255.0', 'network': {}, 'node_name': 'vnf__0', + 'numa_node': 0, 'peer_ifname': 'xe1', 'peer_intf': {'driver': 'igb_uio', 'dst_ip': '1.1.1.1', @@ -1516,7 +1753,9 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): 'vpci': '0000:00:07.0'}, 'peer_name': 'vnf__1', 'vld_id': 'ciphertext', - 'vpci': '0000:ff:07.0'} + 'vpci': '0000:ff:07.0', + 'vpp_name': u'VirtualFunctionEthernetff/7/0', + 'vpp_sw_index': 2} vnfd_helper = VnfdHelper( TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) ssh_helper = mock.Mock() @@ -1542,14 +1781,21 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper._update_vnfd_helper( sys_cores.get_cpu_layout()) - self.assertIsInstance( - ipsec_approx_setup_helper.create_startup_configuration_of_vpp(), - vpp_helpers.VppConfigGenerator) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsInstance( + ipsec_approx_setup_helper.create_startup_configuration_of_vpp(), + vpp_helpers.VppConfigGenerator) def test_add_worker_threads_and_rxqueues(self): vnfd_helper = VnfdHelper( @@ -1566,15 +1812,22 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) - self.assertIsNone( - ipsec_approx_setup_helper.add_worker_threads_and_rxqueues( - vpp_config_generator, 1, 1)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone( + ipsec_approx_setup_helper.add_worker_threads_and_rxqueues( + vpp_config_generator, 1, 1)) self.assertEqual( 'cpu\n{\n corelist-workers 2\n main-core 1\n}\ndpdk\n{\n ' \ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n', @@ -1595,15 +1848,22 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_SMT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_SMT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) - self.assertIsNone( - ipsec_approx_setup_helper.add_worker_threads_and_rxqueues( - vpp_config_generator, 1)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone( + ipsec_approx_setup_helper.add_worker_threads_and_rxqueues( + vpp_config_generator, 1)) self.assertEqual( 'cpu\n{\n corelist-workers 2,6\n main-core 1\n}\ndpdk\n{\n ' \ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n', @@ -1624,15 +1884,22 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) - self.assertIsNone( - ipsec_approx_setup_helper.add_worker_threads_and_rxqueues( - vpp_config_generator, 1, 1)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone( + ipsec_approx_setup_helper.add_worker_threads_and_rxqueues( + vpp_config_generator, 1, 1)) self.assertEqual( 'cpu\n{\n corelist-workers 2\n main-core 1\n}\ndpdk\n{\n ' \ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n', @@ -1653,13 +1920,20 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper._update_vnfd_helper( sys_cores.get_cpu_layout()) - self.assertIsNone(ipsec_approx_setup_helper.add_pci_devices( - vpp_config_generator)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.add_pci_devices( + vpp_config_generator)) self.assertEqual( 'dpdk\n{\n dev 0000:ff:06.0 \n dev 0000:ff:07.0 \n}\n', vpp_config_generator.dump_config()) @@ -1679,16 +1953,23 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) - self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev( - vpp_config_generator, 'aesni_gcm', 1)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev( + vpp_config_generator, 'aesni_gcm', 1)) self.assertEqual( - 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=None \n}\n', + 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n', vpp_config_generator.dump_config()) def test_add_dpdk_cryptodev_hw(self): @@ -1706,14 +1987,21 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) - self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev( - vpp_config_generator, 'aesni_gcm', 1)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev( + vpp_config_generator, 'aesni_gcm', 1)) self.assertEqual( 'dpdk\n{\n dev 0000:ff:01.0 \n uio-driver igb_uio\n}\n', vpp_config_generator.dump_config()) @@ -1733,16 +2021,23 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): scenario_helper) with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ - mock_get_cpu_layout: + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out: mock_get_cpu_layout.return_value = self.CPU_SMT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper) ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT ipsec_approx_setup_helper._update_vnfd_helper( ipsec_approx_setup_helper.sys_cores.get_cpu_layout()) - self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev( - vpp_config_generator, 'aesni_gcm', 1)) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev( + vpp_config_generator, 'aesni_gcm', 1)) self.assertEqual( - 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=None \n}\n', + 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n', vpp_config_generator.dump_config()) def test_add_dpdk_cryptodev_smt_used_hw(self): @@ -1771,3 +2066,41 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase): self.assertEqual( 'dpdk\n{\n dev 0000:ff:01.0 \n dev 0000:ff:01.1 \n uio-driver igb_uio\n}\n', vpp_config_generator.dump_config()) + + def test_initialize_ipsec(self): + vnfd_helper = VnfdHelper( + TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '0', '' + scenario_helper = mock.Mock() + scenario_helper.options = self.OPTIONS + scenario_helper.all_options = self.ALL_OPTIONS + + ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper, + ssh_helper, + scenario_helper) + + with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ + mock_get_cpu_layout, \ + mock.patch.object(ipsec_approx_setup_helper, + 'execute_script_json_out') as \ + mock_execute_script_json_out, \ + mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template, \ + mock.patch.object(ipsec_approx_setup_helper, + 'vpp_get_interface_data') as \ + mock_ipsec_approx_setup_helper: + mock_get_cpu_layout.return_value = self.CPU_LAYOUT + mock_execute_script_json_out.return_value = str( + self.VPP_INTERFACES_DUMP).replace("\'", "\"") + mock_vat_terminal_exec_cmd_from_template.return_value = '' + mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP + sys_cores = cpu.CpuSysCores(ssh_helper) + ipsec_approx_setup_helper._update_vnfd_helper( + sys_cores.get_cpu_layout()) + ipsec_approx_setup_helper.update_vpp_interface_data() + ipsec_approx_setup_helper.iface_update_numa() + self.assertIsNone(ipsec_approx_setup_helper.initialize_ipsec()) + self.assertGreaterEqual( + mock_vat_terminal_exec_cmd_from_template.call_count, 9) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py index 52d2c0e15..c3066d7fe 100644 --- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py @@ -11,13 +11,17 @@ # 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. +import ipaddress import unittest import mock +from yardstick.common import exceptions +from yardstick.network_services.helpers import cpu +from yardstick.network_services.vnf_generic.vnf import vpp_helpers from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper from yardstick.network_services.vnf_generic.vnf.vpp_helpers import \ - VppSetupEnvHelper, VppConfigGenerator + VppSetupEnvHelper, VppConfigGenerator, VatTerminal class TestVppConfigGenerator(unittest.TestCase): @@ -312,6 +316,224 @@ class TestVppSetupEnvHelper(unittest.TestCase): ] } + VNFD_1 = { + "benchmark": { + "kpi": [ + "packets_in", + "packets_fwd", + "packets_dropped" + ] + }, + "connection-point": [ + { + "name": "xe0", + "type": "VPORT" + }, + { + "name": "xe1", + "type": "VPORT" + } + ], + "description": "VPP IPsec", + "id": "VipsecApproxVnf", + "mgmt-interface": { + "ip": "10.10.10.101", + "password": "r00t", + "user": "root", + "vdu-id": "ipsecvnf-baremetal" + }, + "name": "IpsecVnf", + "short-name": "IpsecVnf", + "vdu": [ + { + "description": "VPP Ipsec", + "external-interface": [ + { + "name": "xe0", + "virtual-interface": { + "driver": "igb_uio", + "dst_ip": "192.168.100.1", + "dst_mac": "90:e2:ba:7c:30:e8", + "ifname": "xe0", + "local_ip": "192.168.100.2", + "local_mac": "90:e2:ba:7c:41:a8", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "vnf__0", + "peer_ifname": "xe0", + "peer_intf": { + "dpdk_port_num": 0, + "driver": "igb_uio", + "dst_ip": "192.168.100.2", + "dst_mac": "90:e2:ba:7c:41:a8", + "ifname": "xe0", + "local_ip": "192.168.100.1", + "local_mac": "90:e2:ba:7c:30:e8", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "tg__0", + "peer_ifname": "xe0", + "peer_name": "vnf__0", + "vld_id": "uplink_0", + "vpci": "0000:81:00.0" + }, + "peer_name": "tg__0", + "vld_id": "uplink_0", + "vpci": "0000:ff:06.0" + }, + "vnfd-connection-point-ref": "xe0" + }, + { + "name": "xe1", + "virtual-interface": { + "driver": "igb_uio", + "dst_ip": "1.1.1.2", + "dst_mac": "0a:b1:ec:fd:a2:66", + "ifname": "xe1", + "local_ip": "1.1.1.1", + "local_mac": "4e:90:85:d3:c5:13", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "vnf__0", + "peer_ifname": "xe1", + "peer_intf": { + "driver": "igb_uio", + "dst_ip": "1.1.1.1", + "dst_mac": "4e:90:85:d3:c5:13", + "ifname": "xe1", + "local_ip": "1.1.1.2", + "local_mac": "0a:b1:ec:fd:a2:66", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "vnf__1", + "peer_ifname": "xe1", + "peer_name": "vnf__0", + "vld_id": "ciphertext", + "vpci": "0000:00:07.0" + }, + "peer_name": "vnf__1", + "vld_id": "ciphertext", + "vpci": "0000:ff:07.0" + }, + "vnfd-connection-point-ref": "xe1" + } + ], + "id": "ipsecvnf-baremetal", + "name": "ipsecvnf-baremetal", + "routing_table": [] + } + ] + } + + VNFD_2 = { + "benchmark": { + "kpi": [ + "packets_in", + "packets_fwd", + "packets_dropped" + ] + }, + "connection-point": [ + { + "name": "xe0", + "type": "VPORT" + }, + { + "name": "xe1", + "type": "VPORT" + } + ], + "description": "VPP IPsec", + "id": "VipsecApproxVnf", + "mgmt-interface": { + "ip": "10.10.10.101", + "password": "r00t", + "user": "root", + "vdu-id": "ipsecvnf-baremetal" + }, + "name": "IpsecVnf", + "short-name": "IpsecVnf", + "vdu": [ + { + "description": "VPP Ipsec", + "external-interface": [ + { + "name": "xe0", + "virtual-interface": { + "driver": "igb_uio", + "dst_ip": "192.168.100.1", + "dst_mac": "90:e2:ba:7c:30:e8", + "ifname": "xe0", + "local_ip": "192.168.100.2", + "local_mac": "90:e2:ba:7c:41:a8", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "vnf__0", + "peer_ifname": "xe0", + "peer_intf": { + "dpdk_port_num": 0, + "driver": "igb_uio", + "dst_ip": "192.168.100.2", + "dst_mac": "90:e2:ba:7c:41:a8", + "ifname": "xe0", + "local_ip": "192.168.100.1", + "local_mac": "90:e2:ba:7c:30:e8", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "tg__0", + "peer_ifname": "xe0", + "peer_name": "vnf__0", + "vld_id": "uplink_0", + "vpci": "0000:81:00.0" + }, + "peer_name": "tg__0", + "vld_id": "uplink_0", + "vpci": "0000:ff:06.0" + }, + "vnfd-connection-point-ref": "xe0" + }, + { + "name": "xe1", + "virtual-interface": { + "driver": "igb_uio", + "dst_ip": "1.1.1.2", + "dst_mac": "0a:b1:ec:fd:a2:66", + "ifname": "xe1", + "local_ip": "1.1.1.1", + "local_mac": "4e:90:85:d3:c5:13", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "vnf__0", + "peer_ifname": "xe1", + "peer_intf": { + "driver": "igb_uio", + "dst_ip": "1.1.1.1", + "dst_mac": "4e:90:85:d3:c5:13", + "ifname": "xe1", + "local_ip": "1.1.1.2", + "local_mac": "0a:b1:ec:fd:a2:66", + "netmask": "255.255.255.0", + "network": {}, + "node_name": "vnf__1", + "peer_ifname": "xe1", + "peer_name": "vnf__0", + "vld_id": "ciphertext", + "vpci": "0000:00:07.0" + }, + "peer_name": "vnf__1", + "vld_id": "ciphertext", + "vpci": "0000:ff:07.0" + }, + "vnfd-connection-point-ref": "xe1" + } + ], + "id": "ipsecvnf-baremetal", + "name": "ipsecvnf-baremetal", + "routing_table": [] + } + ] + } + VNFD = { 'vnfd:vnfd-catalog': { 'vnfd': [ @@ -398,6 +620,105 @@ class TestVppSetupEnvHelper(unittest.TestCase): } ] + VPP_INTERFACES_DUMP_MAC_ERR = [ + { + "sw_if_index": 0, + "sup_sw_if_index": 0, + "l2_address_length": 0, + "l2_address": [0, 0, 0, 0, 0, 0, 0, 0], + "interface_name": "local0", + "admin_up_down": 0, + "link_up_down": 0, + "link_duplex": 0, + "link_speed": 0, + "mtu": 0, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + }, + { + "sw_if_index": 1, + "sup_sw_if_index": 1, + "l2_address_length": 6, + "l2_address": [144, 226, 186, 124, 65, 169, 0, 0], + "interface_name": "TenGigabitEthernetff/6/0", + "admin_up_down": 0, + "link_up_down": 0, + "link_duplex": 2, + "link_speed": 32, + "mtu": 9202, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + }, + { + "sw_if_index": 2, + "sup_sw_if_index": 2, + "l2_address_length": 6, + "l2_address": [78, 144, 133, 211, 197, 20, 0, 0], + "interface_name": "VirtualFunctionEthernetff/7/0", + "admin_up_down": 0, + "link_up_down": 0, + "link_duplex": 2, + "link_speed": 32, + "mtu": 9206, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + } + ] + + CPU_LAYOUT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 1, 1, 0]]} + CPU_SMT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 1, 1, 0], + [2, 1, 0, 0, 0, 2, 2, 1], + [3, 1, 0, 0, 0, 3, 3, 1], + [4, 2, 0, 0, 0, 4, 4, 2], + [5, 2, 0, 0, 0, 5, 5, 2], + [6, 3, 0, 0, 0, 6, 6, 3], + [7, 3, 0, 0, 0, 7, 7, 3], + [8, 4, 0, 0, 0, 8, 8, 4], + [9, 5, 0, 1, 0, 0, 0, 0], + [10, 6, 0, 1, 0, 1, 1, 0], + [11, 6, 0, 1, 0, 2, 2, 1], + [12, 7, 0, 1, 0, 3, 3, 1], + [13, 7, 0, 1, 0, 4, 4, 2], + [14, 8, 0, 1, 0, 5, 5, 2], + [15, 8, 0, 1, 0, 6, 6, 3], + [16, 9, 0, 1, 0, 7, 7, 3], + [17, 9, 0, 1, 0, 8, 8, 4]]} + def test_kill_vnf(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() @@ -515,3 +836,772 @@ class TestVppSetupEnvHelper(unittest.TestCase): self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key( 'xe2', 'vpp-err')) + + def test_vpp_create_ipsec_tunnels(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + self.assertIsNone( + vpp_setup_env_helper.vpp_create_ipsec_tunnels('10.10.10.2', + '10.10.10.1', 'xe0', + 1, 1, mock.Mock(), + 'crypto_key', + mock.Mock(), + 'integ_key', + '20.20.20.0')) + self.assertGreaterEqual(ssh_helper.execute.call_count, 2) + + def test_vpp_create_ipsec_1000_tunnels(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + self.assertIsNone( + vpp_setup_env_helper.vpp_create_ipsec_tunnels('10.10.10.2', + '10.10.10.1', 'xe0', + 1000, 128000, + mock.Mock(), + 'crypto_key', + mock.Mock(), + 'integ_key', + '20.20.20.0')) + self.assertGreaterEqual(ssh_helper.execute.call_count, 2) + + def test_apply_config(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + self.assertIsNone(vpp_setup_env_helper.apply_config(mock.Mock())) + self.assertGreaterEqual(ssh_helper.execute.call_count, 2) + + def test_apply_config_error(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 1, '', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + with self.assertRaises(RuntimeError) as raised: + vpp_setup_env_helper.apply_config(mock.Mock()) + + self.assertIn('Writing config file failed', str(raised.exception)) + + def test_vpp_route_add(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertIsNone( + vpp_setup_env_helper.vpp_route_add('xe0', '10.10.10.1', 24)) + + def test_vpp_route_add_without_index(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertIsNone( + vpp_setup_env_helper.vpp_route_add('xe0', '10.10.10.1', 24, + interface='xe0', + use_sw_index=False)) + + def test_add_arp_on_dut(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertEqual('', vpp_setup_env_helper.add_arp_on_dut('xe0', + '10.10.10.1', + '00:00:00:00:00:00')) + + def test_set_ip(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertEqual('', + vpp_setup_env_helper.set_ip('xe0', '10.10.10.1', + 24)) + + def test_set_interface_state(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertEqual('', + vpp_setup_env_helper.set_interface_state('xe0', + 'up')) + + def test_set_interface_state_error(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + with self.assertRaises(ValueError) as raised: + vpp_setup_env_helper.set_interface_state('xe0', 'error') + self.assertIn('Unexpected interface state: error', + str(raised.exception)) + + def test_set_interface_down_state(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertEqual('', + vpp_setup_env_helper.set_interface_state('xe0', + 'down')) + + def test_vpp_set_interface_mtu(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = '' + self.assertIsNone( + vpp_setup_env_helper.vpp_set_interface_mtu('xe0', 9200)) + + def test_vpp_interfaces_ready_wait(self): + json_output = [self.VPP_INTERFACES_DUMP] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + self.assertIsNone(vpp_setup_env_helper.vpp_interfaces_ready_wait()) + + def test_vpp_interfaces_ready_wait_timeout(self): + json_output = [[ + { + "sw_if_index": 0, + "sup_sw_if_index": 0, + "l2_address_length": 0, + "l2_address": [0, 0, 0, 0, 0, 0, 0, 0], + "interface_name": "xe0", + "admin_up_down": 1, + "link_up_down": 0, + "link_duplex": 0, + "link_speed": 0, + "mtu": 0, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + }]] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + with self.assertRaises(RuntimeError) as raised: + vpp_setup_env_helper.vpp_interfaces_ready_wait(5) + self.assertIn('timeout, not up [\'xe0\']', str(raised.exception)) + + def test_vpp_get_interface_data(self): + json_output = [self.VPP_INTERFACES_DUMP] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + self.assertEqual(json_output[0], + vpp_setup_env_helper.vpp_get_interface_data()) + + def test_vpp_get_interface_data_ifname(self): + json_output = [self.VPP_INTERFACES_DUMP] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + self.assertEqual(json_output[0][2], + vpp_setup_env_helper.vpp_get_interface_data( + 'VirtualFunctionEthernetff/7/0')) + + def test_vpp_get_interface_data_ifname_error(self): + json_output = [self.VPP_INTERFACES_DUMP] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + self.assertEqual({}, vpp_setup_env_helper.vpp_get_interface_data( + 'error')) + + def test_vpp_get_interface_data_ifindex(self): + json_output = [self.VPP_INTERFACES_DUMP] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + self.assertEqual(json_output[0][1], + vpp_setup_env_helper.vpp_get_interface_data(1)) + + def test_vpp_get_interface_data_error(self): + json_output = [self.VPP_INTERFACES_DUMP] + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + + with mock.patch.object(vpp_helpers.VatTerminal, + 'vat_terminal_exec_cmd_from_template') as \ + mock_vat_terminal_exec_cmd_from_template: + mock_vat_terminal_exec_cmd_from_template.return_value = json_output + with self.assertRaises(TypeError) as raised: + vpp_setup_env_helper.vpp_get_interface_data(1.0) + self.assertEqual('', str(raised.exception)) + + def test_update_vpp_interface_data(self): + output = '{}\n{}'.format(self.VPP_INTERFACES_DUMP, + 'dump_interface_table:6019: JSON output ' \ + 'supported only for VPE API calls and dump_stats_table\n' \ + '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \ + 'dump_interface_table error: Misc') + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, output.replace("\'", "\""), '' + ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + self.assertIsNone(vpp_setup_env_helper.update_vpp_interface_data()) + self.assertGreaterEqual(ssh_helper.execute.call_count, 1) + self.assertEqual('TenGigabitEthernetff/6/0', + vpp_setup_env_helper.get_value_by_interface_key( + 'xe0', 'vpp_name')) + self.assertEqual(1, vpp_setup_env_helper.get_value_by_interface_key( + 'xe0', 'vpp_sw_index')) + self.assertEqual('VirtualFunctionEthernetff/7/0', + vpp_setup_env_helper.get_value_by_interface_key( + 'xe1', 'vpp_name')) + self.assertEqual(2, vpp_setup_env_helper.get_value_by_interface_key( + 'xe1', 'vpp_sw_index')) + + def test_update_vpp_interface_data_error(self): + output = '{}\n{}'.format(self.VPP_INTERFACES_DUMP_MAC_ERR, + 'dump_interface_table:6019: JSON output ' \ + 'supported only for VPE API calls and dump_stats_table\n' \ + '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \ + 'dump_interface_table error: Misc') + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, output.replace("\'", "\""), '' + ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + self.assertIsNone(vpp_setup_env_helper.update_vpp_interface_data()) + self.assertGreaterEqual(ssh_helper.execute.call_count, 1) + + def test_iface_update_numa(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '0', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + self.assertIsNone(vpp_setup_env_helper.iface_update_numa()) + self.assertGreaterEqual(ssh_helper.execute.call_count, 2) + self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key( + 'xe0', 'numa_node')) + self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key( + 'xe1', 'numa_node')) + + def test_iface_update_numa_error(self): + vnfd_helper = VnfdHelper(self.VNFD_1) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '-1', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ + mock_get_cpu_layout: + mock_get_cpu_layout.return_value = self.CPU_LAYOUT + sys_cores = cpu.CpuSysCores(ssh_helper) + vpp_setup_env_helper._update_vnfd_helper( + sys_cores.get_cpu_layout()) + self.assertIsNone(vpp_setup_env_helper.iface_update_numa()) + self.assertGreaterEqual(ssh_helper.execute.call_count, 2) + self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key( + 'xe0', 'numa_node')) + self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key( + 'xe1', 'numa_node')) + + def test_iface_update_without_numa(self): + vnfd_helper = VnfdHelper(self.VNFD_2) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, '-1', '' + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \ + mock_get_cpu_layout: + mock_get_cpu_layout.return_value = self.CPU_SMT + sys_cores = cpu.CpuSysCores(ssh_helper) + vpp_setup_env_helper._update_vnfd_helper( + sys_cores.get_cpu_layout()) + self.assertIsNone(vpp_setup_env_helper.iface_update_numa()) + self.assertGreaterEqual(ssh_helper.execute.call_count, 2) + self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key( + 'xe0', 'numa_node')) + self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key( + 'xe1', 'numa_node')) + + def test_execute_script(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + vpp_setup_env_helper.execute_script('dump_interfaces.vat', True, True) + self.assertGreaterEqual(ssh_helper.put_file.call_count, 1) + self.assertGreaterEqual(ssh_helper.execute.call_count, 1) + + def test_execute_script_error(self): + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.side_effect = Exception + + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + with self.assertRaises(Exception) as raised: + vpp_setup_env_helper.execute_script('dump_interfaces.vat', True, + True) + self.assertIn( + 'VAT script execution failed: vpp_api_test json in dump_interfaces.vat script', + str(raised.exception)) + self.assertGreaterEqual(ssh_helper.put_file.call_count, 1) + + def test_execute_script_json_out(self): + json_output = [ + { + "sw_if_index": 0, + "sup_sw_if_index": 0 + }, + { + "l2_address_length": 6, + "l2_address": [144, 226, 186, 124, 65, 168, 0, 0] + }, + { + "interface_name": "VirtualFunctionEthernetff/7/0", + "admin_up_down": 0 + } + ] + output = '{}\n{}'.format(json_output, + 'dump_interface_table:6019: JSON output ' \ + 'supported only for VPE API calls and dump_stats_table\n' \ + '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \ + 'dump_interface_table error: Misc') + vnfd_helper = VnfdHelper(self.VNFD_0) + ssh_helper = mock.Mock() + ssh_helper.execute.return_value = 0, output, '' + ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates' + scenario_helper = mock.Mock() + vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper, + scenario_helper) + self.assertEqual(str(json_output), + vpp_setup_env_helper.execute_script_json_out( + 'dump_interfaces.vat')) + + def test_self_cleanup_vat_json_output(self): + json_output = [ + { + "sw_if_index": 0, + "sup_sw_if_index": 0 + }, + { + "l2_address_length": 6, + "l2_address": [144, 226, 186, 124, 65, 168, 0, 0] + }, + { + "interface_name": "VirtualFunctionEthernetff/7/0", + "admin_up_down": 0 + } + ] + + output = '{}\n{}'.format(json_output, + 'dump_interface_table:6019: JSON output ' \ + 'supported only for VPE API calls and dump_stats_table\n' \ + '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \ + 'dump_interface_table error: Misc') + self.assertEqual(str(json_output), + VppSetupEnvHelper.cleanup_vat_json_output(output, + '/opt/nsb_bin/vpp/templates/dump_interfaces.vat')) + + def test__convert_mac_to_number_list(self): + self.assertEqual([144, 226, 186, 124, 65, 168], + VppSetupEnvHelper._convert_mac_to_number_list( + '90:e2:ba:7c:41:a8')) + + def test_get_vpp_interface_by_mac(self): + mac_address = '90:e2:ba:7c:41:a8' + self.assertEqual({'admin_up_down': 0, + 'interface_name': 'TenGigabitEthernetff/6/0', + 'l2_address': [144, 226, 186, 124, 65, 168, 0, 0], + 'l2_address_length': 6, + 'link_duplex': 2, + 'link_speed': 32, + 'link_up_down': 0, + 'mtu': 9202, + 'sub_default': 0, + 'sub_dot1ad': 0, + 'sub_exact_match': 0, + 'sub_id': 0, + 'sub_inner_vlan_id': 0, + 'sub_inner_vlan_id_any': 0, + 'sub_number_of_tags': 0, + 'sub_outer_vlan_id': 0, + 'sub_outer_vlan_id_any': 0, + 'sup_sw_if_index': 1, + 'sw_if_index': 1, + 'vtr_op': 0, + 'vtr_push_dot1q': 0, + 'vtr_tag1': 0, + 'vtr_tag2': 0}, + VppSetupEnvHelper.get_vpp_interface_by_mac( + self.VPP_INTERFACES_DUMP, mac_address)) + + def test_get_vpp_interface_by_mac_error(self): + mac_address = '90:e2:ba:7c:41:a9' + with self.assertRaises(ValueError) as raised: + VppSetupEnvHelper.get_vpp_interface_by_mac( + [{ + "sw_if_index": 1, + "sup_sw_if_index": 1, + "l2_address_length": 7, + "l2_address": [144, 226, 186, 124, 65, 169, 0, 0], + "interface_name": "TenGigabitEthernetff/6/0", + "admin_up_down": 0, + "link_up_down": 0, + "link_duplex": 2, + "link_speed": 32, + "mtu": 9202, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + }], mac_address) + + self.assertIn('l2_address_length value is not 6.', + str(raised.exception)) + + def test_get_vpp_interface_by_mac_l2_error(self): + mac_address = '90:e2:ba:7c:41:a7' + with self.assertRaises(KeyError) as raised: + VppSetupEnvHelper.get_vpp_interface_by_mac( + [{ + "sw_if_index": 1, + "sup_sw_if_index": 1, + "l2_address_length": 6, + "l2_address_err": [144, 226, 186, 124, 65, 167, 0, 0], + "interface_name": "TenGigabitEthernetff/6/0", + "admin_up_down": 0, + "link_up_down": 0, + "link_duplex": 2, + "link_speed": 32, + "mtu": 9202, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + }], mac_address) + + self.assertIn( + 'key l2_address not found in interface dict.Probably input list ' \ + 'is not parsed from correct VAT json output.', + str(raised.exception)) + + def test_get_vpp_interface_by_mac_l2_length_error(self): + mac_address = '90:e2:ba:7c:41:a6' + with self.assertRaises(KeyError) as raised: + VppSetupEnvHelper.get_vpp_interface_by_mac( + [{ + "sw_if_index": 1, + "sup_sw_if_index": 1, + "l2_address_length_err": 6, + "l2_address": [144, 226, 186, 124, 65, 166, 0, 0], + "interface_name": "TenGigabitEthernetff/6/0", + "admin_up_down": 0, + "link_up_down": 0, + "link_duplex": 2, + "link_speed": 32, + "mtu": 9202, + "sub_id": 0, + "sub_dot1ad": 0, + "sub_number_of_tags": 0, + "sub_outer_vlan_id": 0, + "sub_inner_vlan_id": 0, + "sub_exact_match": 0, + "sub_default": 0, + "sub_outer_vlan_id_any": 0, + "sub_inner_vlan_id_any": 0, + "vtr_op": 0, + "vtr_push_dot1q": 0, + "vtr_tag1": 0, + "vtr_tag2": 0 + }], mac_address) + + self.assertIn( + 'key l2_address_length not found in interface dict. Probably ' \ + 'input list is not parsed from correct VAT json output.', + str(raised.exception)) + + def test_get_prefix_length(self): + start_ip = '10.10.10.0' + end_ip = '10.10.10.127' + ips = [ipaddress.ip_address(ip) for ip in + [str(ipaddress.ip_address(start_ip)), str(end_ip)]] + lowest_ip, highest_ip = min(ips), max(ips) + + self.assertEqual(25, + VppSetupEnvHelper.get_prefix_length(int(lowest_ip), + int(highest_ip), + lowest_ip.max_prefixlen)) + + def test_get_prefix_length_zero_prefix(self): + start_ip = '10.0.0.0' + end_ip = '10.0.0.0' + ips = [ipaddress.ip_address(ip) for ip in + [str(ipaddress.ip_address(start_ip)), str(end_ip)]] + lowest_ip, highest_ip = min(ips), max(ips) + + self.assertEqual(0, + VppSetupEnvHelper.get_prefix_length(int(lowest_ip), + int(highest_ip), + 0)) + + +class TestVatTerminal(unittest.TestCase): + + def test___init___error(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_open.side_effect = exceptions.SSHTimeout + + with self.assertRaises(RuntimeError) as raised: + VatTerminal(ssh_helper, json_param=True) + self.assertIn('Cannot open interactive terminal', + str(raised.exception)) + + def test___init___exec_error(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout + VatTerminal(ssh_helper, json_param=True) + + def test_vat_terminal_exec_cmd(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.return_value = str( + {'empty': 'value'}).replace("\'", "\"") + vat_terminal = VatTerminal(ssh_helper, json_param=True) + + self.assertEqual({'empty': 'value'}, + vat_terminal.vat_terminal_exec_cmd( + "hw_interface_set_mtu sw_if_index 1 mtu 9200")) + + def test_vat_terminal_exec_cmd_array(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.return_value = str( + [{'empty': 'value'}]).replace("\'", "\"") + vat_terminal = VatTerminal(ssh_helper, json_param=True) + + self.assertEqual([{'empty': 'value'}], + vat_terminal.vat_terminal_exec_cmd( + "hw_interface_set_mtu sw_if_index 1 mtu 9200")) + + def test_vat_terminal_exec_cmd_without_output(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.return_value = str( + {'empty': 'value'}).replace("\'", "\"") + vat_terminal = VatTerminal(ssh_helper, json_param=False) + + self.assertIsNone(vat_terminal.vat_terminal_exec_cmd( + "hw_interface_set_mtu sw_if_index 1 mtu 9200")) + + def test_vat_terminal_exec_cmd_error(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.return_value = str( + {'empty': 'value'}).replace("\'", "\"") + ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout + + vat_terminal = VatTerminal(ssh_helper, json_param=True) + + with self.assertRaises(RuntimeError) as raised: + vat_terminal.vat_terminal_exec_cmd( + "hw_interface_set_mtu sw_if_index 1 mtu 9200") + self.assertIn( + 'VPP is not running on node. VAT command hw_interface_set_mtu ' \ + 'sw_if_index 1 mtu 9200 execution failed', + str(raised.exception)) + + def test_vat_terminal_exec_cmd_output_error(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.return_value = str( + 'empty: value').replace("\'", "\"") + + vat_terminal = VatTerminal(ssh_helper, json_param=True) + + with self.assertRaises(RuntimeError) as raised: + vat_terminal.vat_terminal_exec_cmd( + "hw_interface_set_mtu sw_if_index 1 mtu 9200") + self.assertIn( + 'VAT command hw_interface_set_mtu sw_if_index 1 mtu 9200: no JSON data.', + str(raised.exception)) + + def test_vat_terminal_close(self): + ssh_helper = mock.Mock() + vat_terminal = VatTerminal(ssh_helper, json_param=False) + self.assertIsNone(vat_terminal.vat_terminal_close()) + + def test_vat_terminal_close_error(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout + vat_terminal = VatTerminal(ssh_helper, json_param=False) + with self.assertRaises(RuntimeError) as raised: + vat_terminal.vat_terminal_close() + self.assertIn('Failed to close VAT console', str(raised.exception)) + + def test_vat_terminal_close_vat_error(self): + ssh_helper = mock.Mock() + ssh_helper.interactive_terminal_close.side_effect = exceptions.SSHTimeout + vat_terminal = VatTerminal(ssh_helper, json_param=False) + with self.assertRaises(RuntimeError) as raised: + vat_terminal.vat_terminal_close() + self.assertIn('Cannot close interactive terminal', + str(raised.exception)) + + def test_vat_terminal_exec_cmd_from_template(self): + ssh_helper = mock.Mock() + vat_terminal = VatTerminal(ssh_helper, json_param=False) + + with mock.patch.object(vat_terminal, 'vat_terminal_exec_cmd') as \ + mock_vat_terminal_exec_cmd: + mock_vat_terminal_exec_cmd.return_value = 'empty' + self.assertEqual(['empty'], + vat_terminal.vat_terminal_exec_cmd_from_template( + "hw_interface_set_mtu.vat", sw_if_index=1, + mtu=9200)) |