コード例 #1
0
    def test_kernel_bound_pci_addresses(self):
        mock_ssh_helper = mock.Mock()
        mock_ssh_helper.execute.return_value = 0, '', ''

        expected = ['a', 'b', 3]

        dpdk_helper = DpdkBindHelper(mock_ssh_helper)
        dpdk_helper.dpdk_status = {
            NETWORK_DPDK: [{
                'vpci': 4
            }, {
                'vpci': 5
            }, {
                'vpci': 'g'
            }],
            NETWORK_KERNEL: [{
                'vpci': 'a'
            }, {
                'vpci': 'b'
            }, {
                'vpci': 3
            }],
            CRYPTO_DPDK: [],
        }

        result = dpdk_helper.kernel_bound_pci_addresses
        self.assertEqual(result, expected)
コード例 #2
0
 def test__dpdk_execute(self):
     conn = mock.Mock()
     conn.execute = mock.Mock(return_value=(0, 'output', 'error'))
     conn.provision_tool = mock.Mock(return_value='tool_path')
     dpdk_bind_helper = DpdkBindHelper(conn)
     self.assertEqual((0, 'output', 'error'),
                      dpdk_bind_helper._dpdk_execute('command'))
コード例 #3
0
    def test_save_real_kernel_drivers(self):
        mock_ssh_helper = mock.Mock()
        mock_ssh_helper.execute.return_value = 0, '', ''

        dpdk_helper = DpdkBindHelper(mock_ssh_helper)
        dpdk_helper.real_kernel_drivers = {
            'abc': '123',
        }
        dpdk_helper.real_kernel_interface_driver_map = {
            'abc': 'AAA',
            'def': 'DDD',
            'abs': 'AAA',
            'ghi': 'GGG',
        }

        # save_used_drivers must be called before save_real_kernel_drivers can be
        with self.assertRaises(AttributeError):
            dpdk_helper.save_real_kernel_drivers()

        dpdk_helper.save_used_drivers()

        expected_used_drivers = {
            'AAA': ['abc', 'abs'],
            'DDD': ['def'],
            'GGG': ['ghi'],
        }
        dpdk_helper.save_real_kernel_drivers()
        self.assertDictEqual(dpdk_helper.used_drivers, expected_used_drivers)
        self.assertDictEqual(dpdk_helper.real_kernel_drivers, {})
コード例 #4
0
 def test__dpdk_execute_failure(self):
     conn = mock.Mock()
     conn.execute = mock.Mock(return_value=(1, 'output', 'error'))
     conn.provision_tool = mock.Mock(return_value='tool_path')
     dpdk_bind_helper = DpdkBindHelper(conn)
     with self.assertRaises(DpdkBindHelperException):
         dpdk_bind_helper._dpdk_execute('command')
コード例 #5
0
 def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
     super(DpdkVnfSetupEnvHelper, self).__init__(vnfd_helper, ssh_helper, scenario_helper)
     self.all_ports = None
     self.bound_pci = None
     self.socket = None
     self.used_drivers = None
     self.dpdk_bind_helper = DpdkBindHelper(ssh_helper)
コード例 #6
0
    def test_find_net_devices_negative(self):
        mock_ssh_helper = mock.Mock()
        mock_ssh_helper.execute.return_value = 1, 'error', 'debug'

        dpdk_helper = DpdkBindHelper(mock_ssh_helper)

        self.assertDictEqual(dpdk_helper.find_net_devices(), {})
コード例 #7
0
    def test_read_status(self):
        conn = mock.Mock()
        conn.execute = mock.Mock(return_value=(0, self.EXAMPLE_OUTPUT, ''))
        conn.provision_tool = mock.Mock(return_value='path_to_tool')

        dpdk_bind_helper = DpdkBindHelper(conn)

        self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.read_status())
コード例 #8
0
    def test_parse_dpdk_status_output(self):
        conn = mock.Mock()

        dpdk_bind_helper = DpdkBindHelper(conn)

        dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)

        self.maxDiff = None
        self.assertEqual(self.PARSED_EXAMPLE, dpdk_bind_helper.dpdk_status)
コード例 #9
0
    def test__addline(self):
        conn = mock.Mock()

        dpdk_bind_helper = DpdkBindHelper(conn)

        dpdk_bind_helper._add_line(NETWORK_KERNEL, self.ONE_INPUT_LINE)

        self.assertIsNotNone(dpdk_bind_helper.dpdk_status)
        self.assertEqual(self.ONE_INPUT_LINE_PARSED,
                         dpdk_bind_helper.dpdk_status[NETWORK_KERNEL])
コード例 #10
0
    def test_save_used_drivers(self):
        conn = mock.Mock()
        dpdk_bind_helper = DpdkBindHelper(conn)
        dpdk_bind_helper.dpdk_status = self.PARSED_EXAMPLE

        dpdk_bind_helper.save_used_drivers()

        expected = {
            'igb_uio': ['0000:00:04.0', '0000:00:05.0'],
            'virtio-pci': ['0000:00:03.0'],
        }

        self.assertDictEqual(expected, dpdk_bind_helper.used_drivers)
コード例 #11
0
    def test_interface_driver_map(self):
        conn = mock.Mock()

        dpdk_bind_helper = DpdkBindHelper(conn)

        dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)

        self.assertEqual(
            {
                '0000:00:04.0': 'igb_uio',
                '0000:00:03.0': 'virtio-pci',
                '0000:00:05.0': 'igb_uio',
            }, dpdk_bind_helper.interface_driver_map)
コード例 #12
0
    def test_bind_single_pci(self):
        conn = mock.Mock()
        conn.execute = mock.Mock(return_value=(0, '', ''))
        conn.join_bin_path.return_value = os.path.join(
            self.bin_path, DpdkBindHelper.DPDK_DEVBIND)

        dpdk_bind_helper = DpdkBindHelper(conn)
        dpdk_bind_helper.read_status = mock.Mock()

        dpdk_bind_helper.bind('0000:00:03.0', 'my_driver')

        conn.execute.assert_called_with(
            'sudo /opt/nsb_bin/dpdk-devbind.py --force '
            '-b my_driver 0000:00:03.0')
        dpdk_bind_helper.read_status.assert_called_once()
コード例 #13
0
    def test_bind_single_pci(self):
        conn = mock.Mock()
        conn.execute = mock.Mock(return_value=(0, '', ''))
        conn.provision_tool = mock.Mock(
            return_value='/opt/nsb_bin/dpdk-devbind.py')

        dpdk_bind_helper = DpdkBindHelper(conn)
        dpdk_bind_helper.read_status = mock.Mock()

        dpdk_bind_helper.bind('0000:00:03.0', 'my_driver')

        conn.execute.assert_called_with(
            'sudo /opt/nsb_bin/dpdk-devbind.py --force '
            '-b my_driver 0000:00:03.0')
        dpdk_bind_helper.read_status.assert_called_once()
コード例 #14
0
    def test_get_real_kernel_driver(self):
        mock_ssh_helper = mock.Mock()
        mock_ssh_helper.execute.side_effect = [
            (0, 'non-matching text', ''),
            (0, 'pre Kernel modules: real_driver1', ''),
            (0, 'before Ethernet middle Virtio network device after', ''),
        ]

        dpdk_helper = DpdkBindHelper(mock_ssh_helper)

        self.assertIsNone(dpdk_helper.get_real_kernel_driver('abc'))
        self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'),
                         'real_driver1')
        self.assertEqual(dpdk_helper.get_real_kernel_driver('abc'),
                         DpdkBindHelper.VIRTIO_DRIVER)
コード例 #15
0
    def test_parse_netdev_info_virtio(self):
        output = """\
/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/ifindex:3
/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/address:fa:de:ad:be:ef:5b
/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/operstate:down
/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/vendor:0x1af4
/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/device/device:0x0001
/sys/devices/pci0000:00/0000:00:04.0/virtio1/net/eth1/driver:virtio_net
"""
        res = DpdkBindHelper.parse_netdev_info(output)
        self.assertDictEqual(res, self.SAMPLE_VM_NETDEVS)
コード例 #16
0
    def test___init__(self):
        conn = mock.Mock()
        conn.provision_tool = mock.Mock(return_value='path_to_tool')

        dpdk_bind_helper = DpdkBindHelper(conn)

        self.assertEquals(conn, dpdk_bind_helper.ssh_helper)
        self.assertEquals(self.CLEAN_STATUS, dpdk_bind_helper.dpdk_status)
        self.assertIsNone(dpdk_bind_helper.status_nic_row_re)
        self.assertIsNone(dpdk_bind_helper._dpdk_nic_bind_attr)
        self.assertIsNone(dpdk_bind_helper._status_cmd_attr)
コード例 #17
0
    def test___init__(self):
        conn = mock.Mock()
        conn.provision_tool = mock.Mock(return_value='path_to_tool')
        conn.join_bin_path.return_value = os.path.join(
            self.bin_path, DpdkBindHelper.DPDK_DEVBIND)

        dpdk_bind_helper = DpdkBindHelper(conn)

        self.assertEqual(conn, dpdk_bind_helper.ssh_helper)
        self.assertEqual(self.CLEAN_STATUS, dpdk_bind_helper.dpdk_status)
        self.assertIsNone(dpdk_bind_helper.status_nic_row_re)
        self.assertEqual(
            dpdk_bind_helper.dpdk_devbind,
            os.path.join(self.bin_path, dpdk_bind_helper.DPDK_DEVBIND))
        self.assertIsNone(dpdk_bind_helper._status_cmd_attr)
コード例 #18
0
    def test_force_dpdk_rebind(self):
        mock_ssh_helper = mock.Mock()
        mock_ssh_helper.execute.return_value = 0, '', ''

        dpdk_helper = DpdkBindHelper(mock_ssh_helper, 'driver2')
        dpdk_helper.dpdk_status = {
            NETWORK_DPDK: [
                {
                    'vpci': 'pci1',
                },
                {
                    'vpci': 'pci3',
                },
                {
                    'vpci': 'pci6',
                },
                {
                    'vpci': 'pci3',
                },
            ]
        }
        dpdk_helper.real_kernel_interface_driver_map = {
            'pci1': 'real_driver1',
            'pci2': 'real_driver2',
            'pci3': 'real_driver1',
            'pci4': 'real_driver4',
            'pci6': 'real_driver6',
        }
        dpdk_helper.load_dpdk_driver = mock.Mock()
        dpdk_helper.read_status = mock.Mock()
        dpdk_helper.save_real_kernel_interface_driver_map = mock.Mock()
        dpdk_helper.save_used_drivers = mock.Mock()
        dpdk_helper.bind = mock_bind = mock.Mock()

        dpdk_helper.force_dpdk_rebind()
        self.assertEqual(mock_bind.call_count, 2)
コード例 #19
0
    def test__get_bound_pci_addresses(self):
        conn = mock.Mock()

        dpdk_bind_helper = DpdkBindHelper(conn)

        dpdk_bind_helper._parse_dpdk_status_output(self.EXAMPLE_OUTPUT)

        self.assertEqual(
            ['0000:00:04.0', '0000:00:05.0'],
            dpdk_bind_helper._get_bound_pci_addresses(NETWORK_DPDK))
        self.assertEqual(
            ['0000:00:03.0'],
            dpdk_bind_helper._get_bound_pci_addresses(NETWORK_KERNEL))
コード例 #20
0
    def test_rebind_drivers(self):
        conn = mock.Mock()

        dpdk_bind_helper = DpdkBindHelper(conn)

        dpdk_bind_helper.bind = mock.Mock()
        dpdk_bind_helper.used_drivers = {
            'd1': ['0000:05:00.0'],
            'd3': ['0000:05:01.0', '0000:05:02.0'],
        }

        dpdk_bind_helper.rebind_drivers()

        dpdk_bind_helper.bind.assert_any_call(['0000:05:00.0'], 'd1', True)
        dpdk_bind_helper.bind.assert_any_call(['0000:05:01.0', '0000:05:02.0'],
                                              'd3', True)
コード例 #21
0
    def test_parse_netdev_info(self):
        output = """\
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/ifindex:2
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/address:0a:de:ad:be:ef:f5
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/operstate:down
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/vendor:0x8086
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/device:0x1533
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_vendor:0x15d9
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/device/subsystem_device:0x1533
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/driver:igb
/sys/devices/pci0000:00/0000:00:1c.3/0000:0b:00.0/net/enp11s0/pci_bus_id:0000:0b:00.0
/sys/devices/pci0000:00/0000:00:19.0/net/lan/ifindex:3
/sys/devices/pci0000:00/0000:00:19.0/net/lan/address:0a:de:ad:be:ef:f4
/sys/devices/pci0000:00/0000:00:19.0/net/lan/operstate:up
/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/vendor:0x8086
/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/device:0x153a
/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_vendor:0x15d9
/sys/devices/pci0000:00/0000:00:19.0/net/lan/device/subsystem_device:0x153a
/sys/devices/pci0000:00/0000:00:19.0/net/lan/driver:e1000e
/sys/devices/pci0000:00/0000:00:19.0/net/lan/pci_bus_id:0000:00:19.0
"""
        res = DpdkBindHelper.parse_netdev_info(output)
        self.assertDictEqual(res, self.SAMPLE_NETDEVS)
コード例 #22
0
class DpdkVnfSetupEnvHelper(SetupEnvHelper):

    APP_NAME = 'DpdkVnf'
    FIND_NET_CMD = "find /sys/class/net -lname '*{}*' -printf '%f'"
    NR_HUGEPAGES_PATH = '/proc/sys/vm/nr_hugepages'

    @staticmethod
    def _update_packet_type(ip_pipeline_cfg, traffic_options):
        match_str = 'pkt_type = ipv4'
        replace_str = 'pkt_type = {0}'.format(traffic_options['pkt_type'])
        pipeline_config_str = ip_pipeline_cfg.replace(match_str, replace_str)
        return pipeline_config_str

    @classmethod
    def _update_traffic_type(cls, ip_pipeline_cfg, traffic_options):
        traffic_type = traffic_options['traffic_type']

        if traffic_options['vnf_type'] is not cls.APP_NAME:
            match_str = 'traffic_type = 4'
            replace_str = 'traffic_type = {0}'.format(traffic_type)

        elif traffic_type == 4:
            match_str = 'pkt_type = ipv4'
            replace_str = 'pkt_type = ipv4'

        else:
            match_str = 'pkt_type = ipv4'
            replace_str = 'pkt_type = ipv6'

        pipeline_config_str = ip_pipeline_cfg.replace(match_str, replace_str)
        return pipeline_config_str

    def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
        super(DpdkVnfSetupEnvHelper, self).__init__(vnfd_helper, ssh_helper, scenario_helper)
        self.all_ports = None
        self.bound_pci = None
        self.socket = None
        self.used_drivers = None
        self.dpdk_bind_helper = DpdkBindHelper(ssh_helper)

    def _setup_hugepages(self):
        meminfo = utils.read_meminfo(self.ssh_helper)
        hp_size_kb = int(meminfo['Hugepagesize'])
        hugepages_gb = self.scenario_helper.all_options.get('hugepages_gb', 16)
        nr_hugepages = int(abs(hugepages_gb * 1024 * 1024 / hp_size_kb))
        self.ssh_helper.execute('echo %s | sudo tee %s' %
                                (nr_hugepages, self.NR_HUGEPAGES_PATH))
        hp = six.BytesIO()
        self.ssh_helper.get_file_obj(self.NR_HUGEPAGES_PATH, hp)
        nr_hugepages_set = int(hp.getvalue().decode('utf-8').splitlines()[0])
        LOG.info('Hugepages size (kB): %s, number claimed: %s, number set: %s',
                 hp_size_kb, nr_hugepages, nr_hugepages_set)

    def build_config(self):
        vnf_cfg = self.scenario_helper.vnf_cfg
        task_path = self.scenario_helper.task_path

        config_file = vnf_cfg.get('file')
        lb_count = vnf_cfg.get('lb_count', 3)
        lb_config = vnf_cfg.get('lb_config', 'SW')
        worker_config = vnf_cfg.get('worker_config', '1C/1T')
        worker_threads = vnf_cfg.get('worker_threads', 3)

        traffic_type = self.scenario_helper.all_options.get('traffic_type', 4)
        traffic_options = {
            'traffic_type': traffic_type,
            'pkt_type': 'ipv%s' % traffic_type,
            'vnf_type': self.VNF_TYPE,
        }

        # read actions/rules from file
        acl_options = None
        acl_file_name = self.scenario_helper.options.get('rules')
        if acl_file_name:
            with utils.open_relative_file(acl_file_name, task_path) as infile:
                acl_options = yaml_loader.yaml_load(infile)

        config_tpl_cfg = utils.find_relative_file(self.DEFAULT_CONFIG_TPL_CFG,
                                                  task_path)
        config_basename = posixpath.basename(self.CFG_CONFIG)
        script_basename = posixpath.basename(self.CFG_SCRIPT)
        multiport = MultiPortConfig(self.scenario_helper.topology,
                                    config_tpl_cfg,
                                    config_basename,
                                    self.vnfd_helper,
                                    self.VNF_TYPE,
                                    lb_count,
                                    worker_threads,
                                    worker_config,
                                    lb_config,
                                    self.socket)

        multiport.generate_config()
        if config_file:
            with utils.open_relative_file(config_file, task_path) as infile:
                new_config = ['[EAL]']
                vpci = []
                for port in self.vnfd_helper.port_pairs.all_ports:
                    interface = self.vnfd_helper.find_interface(name=port)
                    vpci.append(interface['virtual-interface']["vpci"])
                new_config.extend('w = {0}'.format(item) for item in vpci)
                new_config = '\n'.join(new_config) + '\n' + infile.read()
        else:
            with open(self.CFG_CONFIG) as handle:
                new_config = handle.read()
            new_config = self._update_traffic_type(new_config, traffic_options)
            new_config = self._update_packet_type(new_config, traffic_options)
        self.ssh_helper.upload_config_file(config_basename, new_config)
        self.ssh_helper.upload_config_file(script_basename,
            multiport.generate_script(self.vnfd_helper,
                                      self.get_flows_config(acl_options)))

        LOG.info("Provision and start the %s", self.APP_NAME)
        self._build_pipeline_kwargs()
        return self.PIPELINE_COMMAND.format(**self.pipeline_kwargs)

    def get_flows_config(self, options=None): # pylint: disable=unused-argument
        """No actions/rules (flows) by default"""
        return None

    def _build_pipeline_kwargs(self):
        tool_path = self.ssh_helper.provision_tool(tool_file=self.APP_NAME)
        # count the number of actual ports in the list of pairs
        # remove duplicate ports
        # this is really a mapping from LINK ID to DPDK PMD ID
        # e.g. 0x110 maps LINK0 -> PMD_ID_1, LINK1 -> PMD_ID_2
        #      0x1010 maps LINK0 -> PMD_ID_1, LINK1 -> PMD_ID_3
        ports = self.vnfd_helper.port_pairs.all_ports
        port_nums = self.vnfd_helper.port_nums(ports)
        # create mask from all the dpdk port numbers
        ports_mask_hex = hex(sum(2 ** num for num in port_nums))

        vnf_cfg = self.scenario_helper.vnf_cfg
        lb_config = vnf_cfg.get('lb_config', 'SW')
        worker_threads = vnf_cfg.get('worker_threads', 3)
        hwlb = ''
        if lb_config == 'HW':
            hwlb = ' --hwlb %s' % worker_threads

        self.pipeline_kwargs = {
            'cfg_file': self.CFG_CONFIG,
            'script': self.CFG_SCRIPT,
            'port_mask_hex': ports_mask_hex,
            'tool_path': tool_path,
            'hwlb': hwlb,
        }

    def setup_vnf_environment(self):
        self._setup_dpdk()
        self.kill_vnf()
        # bind before _setup_resources so we can use dpdk_port_num
        self._detect_and_bind_drivers()
        resource = self._setup_resources()
        return resource

    def kill_vnf(self):
        # pkill is not matching, debug with pgrep
        self.ssh_helper.execute("sudo pgrep -lax  %s" % self.APP_NAME)
        self.ssh_helper.execute("sudo ps aux | grep -i %s" % self.APP_NAME)
        # have to use exact match
        # try using killall to match
        self.ssh_helper.execute("sudo killall %s" % self.APP_NAME)

    def _setup_dpdk(self):
        """Setup DPDK environment needed for VNF to run"""
        self._setup_hugepages()
        self.dpdk_bind_helper.load_dpdk_driver()

        exit_status = self.dpdk_bind_helper.check_dpdk_driver()
        if exit_status == 0:
            return

    def _setup_resources(self):
        # what is this magic?  how do we know which socket is for which port?
        # what about quad-socket?
        if any(v[5] == "0" for v in self.bound_pci):
            self.socket = 0
        else:
            self.socket = 1

        # implicit ordering, presumably by DPDK port num, so pre-sort by port_num
        # this won't work because we don't have DPDK port numbers yet
        ports = sorted(self.vnfd_helper.interfaces, key=self.vnfd_helper.port_num)
        port_names = (intf["name"] for intf in ports)
        plugins = self.collectd_options.get("plugins", {})
        interval = self.collectd_options.get("interval")
        # we must set timeout to be the same as the VNF otherwise KPIs will die before VNF
        return ResourceProfile(self.vnfd_helper.mgmt_interface, port_names=port_names,
                               plugins=plugins, interval=interval,
                               timeout=self.scenario_helper.timeout)

    def _check_interface_fields(self):
        num_nodes = len(self.scenario_helper.nodes)
        # OpenStack instance creation time is probably proportional to the number
        # of instances
        timeout = 120 * num_nodes
        dpdk_node = DpdkNode(self.scenario_helper.name, self.vnfd_helper.interfaces,
                             self.ssh_helper, timeout)
        dpdk_node.check()

    def _detect_and_bind_drivers(self):
        interfaces = self.vnfd_helper.interfaces

        self._check_interface_fields()
        # check for bound after probe
        self.bound_pci = [v['virtual-interface']["vpci"] for v in interfaces]

        self.dpdk_bind_helper.read_status()
        self.dpdk_bind_helper.save_used_drivers()

        self.dpdk_bind_helper.bind(self.bound_pci, 'igb_uio')

        sorted_dpdk_pci_addresses = sorted(self.dpdk_bind_helper.dpdk_bound_pci_addresses)
        for dpdk_port_num, vpci in enumerate(sorted_dpdk_pci_addresses):
            try:
                intf = next(v for v in interfaces
                            if vpci == v['virtual-interface']['vpci'])
                # force to int
                intf['virtual-interface']['dpdk_port_num'] = int(dpdk_port_num)
            except:  # pylint: disable=bare-except
                pass
        time.sleep(2)

    def get_local_iface_name_by_vpci(self, vpci):
        find_net_cmd = self.FIND_NET_CMD.format(vpci)
        exit_status, stdout, _ = self.ssh_helper.execute(find_net_cmd)
        if exit_status == 0:
            return stdout
        return None

    def tear_down(self):
        self.dpdk_bind_helper.rebind_drivers()
コード例 #23
0
class DpdkVnfSetupEnvHelper(SetupEnvHelper):

    APP_NAME = 'DpdkVnf'
    FIND_NET_CMD = "find /sys/class/net -lname '*{}*' -printf '%f'"

    @staticmethod
    def _update_packet_type(ip_pipeline_cfg, traffic_options):
        match_str = 'pkt_type = ipv4'
        replace_str = 'pkt_type = {0}'.format(traffic_options['pkt_type'])
        pipeline_config_str = ip_pipeline_cfg.replace(match_str, replace_str)
        return pipeline_config_str

    @classmethod
    def _update_traffic_type(cls, ip_pipeline_cfg, traffic_options):
        traffic_type = traffic_options['traffic_type']

        if traffic_options['vnf_type'] is not cls.APP_NAME:
            match_str = 'traffic_type = 4'
            replace_str = 'traffic_type = {0}'.format(traffic_type)

        elif traffic_type == 4:
            match_str = 'pkt_type = ipv4'
            replace_str = 'pkt_type = ipv4'

        else:
            match_str = 'pkt_type = ipv4'
            replace_str = 'pkt_type = ipv6'

        pipeline_config_str = ip_pipeline_cfg.replace(match_str, replace_str)
        return pipeline_config_str

    def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
        super(DpdkVnfSetupEnvHelper, self).__init__(vnfd_helper, ssh_helper,
                                                    scenario_helper)
        self.all_ports = None
        self.bound_pci = None
        self.socket = None
        self.used_drivers = None
        self.dpdk_bind_helper = DpdkBindHelper(ssh_helper)

    def _setup_hugepages(self):
        cmd = "awk '/Hugepagesize/ { print $2$3 }' < /proc/meminfo"
        hugepages = self.ssh_helper.execute(cmd)[1].rstrip()

        memory_path = \
            '/sys/kernel/mm/hugepages/hugepages-%s/nr_hugepages' % hugepages
        self.ssh_helper.execute("awk -F: '{ print $1 }' < %s" % memory_path)

        if hugepages == "2048kB":
            pages = 8192
        else:
            pages = 16

        self.ssh_helper.execute("echo %s | sudo tee %s" % (pages, memory_path))

    def build_config(self):
        vnf_cfg = self.scenario_helper.vnf_cfg
        task_path = self.scenario_helper.task_path

        lb_count = vnf_cfg.get('lb_count', 3)
        lb_config = vnf_cfg.get('lb_config', 'SW')
        worker_config = vnf_cfg.get('worker_config', '1C/1T')
        worker_threads = vnf_cfg.get('worker_threads', 3)

        traffic_type = self.scenario_helper.all_options.get('traffic_type', 4)
        traffic_options = {
            'traffic_type': traffic_type,
            'pkt_type': 'ipv%s' % traffic_type,
            'vnf_type': self.VNF_TYPE,
        }

        config_tpl_cfg = find_relative_file(self.DEFAULT_CONFIG_TPL_CFG,
                                            task_path)
        config_basename = posixpath.basename(self.CFG_CONFIG)
        script_basename = posixpath.basename(self.CFG_SCRIPT)
        multiport = MultiPortConfig(self.scenario_helper.topology,
                                    config_tpl_cfg, config_basename,
                                    self.vnfd_helper, self.VNF_TYPE, lb_count,
                                    worker_threads, worker_config, lb_config,
                                    self.socket)

        multiport.generate_config()
        with open(self.CFG_CONFIG) as handle:
            new_config = handle.read()

        new_config = self._update_traffic_type(new_config, traffic_options)
        new_config = self._update_packet_type(new_config, traffic_options)

        self.ssh_helper.upload_config_file(config_basename, new_config)
        self.ssh_helper.upload_config_file(
            script_basename, multiport.generate_script(self.vnfd_helper))

        LOG.info("Provision and start the %s", self.APP_NAME)
        self._build_pipeline_kwargs()
        return self.PIPELINE_COMMAND.format(**self.pipeline_kwargs)

    def _build_pipeline_kwargs(self):
        tool_path = self.ssh_helper.provision_tool(tool_file=self.APP_NAME)
        # count the number of actual ports in the list of pairs
        # remove duplicate ports
        # this is really a mapping from LINK ID to DPDK PMD ID
        # e.g. 0x110 maps LINK0 -> PMD_ID_1, LINK1 -> PMD_ID_2
        #      0x1010 maps LINK0 -> PMD_ID_1, LINK1 -> PMD_ID_3
        ports = self.vnfd_helper.port_pairs.all_ports
        port_nums = self.vnfd_helper.port_nums(ports)
        # create mask from all the dpdk port numbers
        ports_mask_hex = hex(sum(2**num for num in port_nums))
        self.pipeline_kwargs = {
            'cfg_file': self.CFG_CONFIG,
            'script': self.CFG_SCRIPT,
            'port_mask_hex': ports_mask_hex,
            'tool_path': tool_path,
        }

    def setup_vnf_environment(self):
        self._setup_dpdk()
        self.bound_pci = [
            v['virtual-interface']["vpci"] for v in self.vnfd_helper.interfaces
        ]
        self.kill_vnf()
        # bind before _setup_resources so we can use dpdk_port_num
        self._detect_and_bind_drivers()
        resource = self._setup_resources()
        return resource

    def kill_vnf(self):
        # pkill is not matching, debug with pgrep
        self.ssh_helper.execute("sudo pgrep -lax  %s" % self.APP_NAME)
        self.ssh_helper.execute("sudo ps aux | grep -i %s" % self.APP_NAME)
        # have to use exact match
        # try using killall to match
        self.ssh_helper.execute("sudo killall %s" % self.APP_NAME)

    def _setup_dpdk(self):
        """ setup dpdk environment needed for vnf to run """

        self._setup_hugepages()
        self.ssh_helper.execute("sudo modprobe uio && sudo modprobe igb_uio")

        exit_status = self.ssh_helper.execute("lsmod | grep -i igb_uio")[0]
        if exit_status == 0:
            return

        dpdk = self.ssh_helper.join_bin_path(DPDK_VERSION)
        dpdk_setup = self.ssh_helper.provision_tool(tool_file="nsb_setup.sh")
        exit_status = self.ssh_helper.execute(
            "which {} >/dev/null 2>&1".format(dpdk))[0]
        if exit_status != 0:
            self.ssh_helper.execute("bash %s dpdk >/dev/null 2>&1" %
                                    dpdk_setup)

    def get_collectd_options(self):
        options = self.scenario_helper.all_options.get("collectd", {})
        # override with specific node settings
        options.update(self.scenario_helper.options.get("collectd", {}))
        return options

    def _setup_resources(self):
        # what is this magic?  how do we know which socket is for which port?
        # what about quad-socket?
        if any(v[5] == "0" for v in self.bound_pci):
            self.socket = 0
        else:
            self.socket = 1

        # implicit ordering, presumably by DPDK port num, so pre-sort by port_num
        # this won't work because we don't have DPDK port numbers yet
        ports = sorted(self.vnfd_helper.interfaces,
                       key=self.vnfd_helper.port_num)
        port_names = (intf["name"] for intf in ports)
        collectd_options = self.get_collectd_options()
        plugins = collectd_options.get("plugins", {})
        # we must set timeout to be the same as the VNF otherwise KPIs will die before VNF
        return ResourceProfile(self.vnfd_helper.mgmt_interface,
                               port_names=port_names,
                               plugins=plugins,
                               interval=collectd_options.get("interval"),
                               timeout=self.scenario_helper.timeout)

    def _detect_and_bind_drivers(self):
        interfaces = self.vnfd_helper.interfaces

        self.dpdk_bind_helper.read_status()
        self.dpdk_bind_helper.save_used_drivers()

        self.dpdk_bind_helper.bind(self.bound_pci, 'igb_uio')

        sorted_dpdk_pci_addresses = sorted(
            self.dpdk_bind_helper.dpdk_bound_pci_addresses)
        for dpdk_port_num, vpci in enumerate(sorted_dpdk_pci_addresses):
            try:
                intf = next(v for v in interfaces
                            if vpci == v['virtual-interface']['vpci'])
                # force to int
                intf['virtual-interface']['dpdk_port_num'] = int(dpdk_port_num)
            except:
                pass
        time.sleep(2)

    def get_local_iface_name_by_vpci(self, vpci):
        find_net_cmd = self.FIND_NET_CMD.format(vpci)
        exit_status, stdout, _ = self.ssh_helper.execute(find_net_cmd)
        if exit_status == 0:
            return stdout
        return None

    def tear_down(self):
        self.dpdk_bind_helper.rebind_drivers()
コード例 #24
0
 def test__switch_active_dict_by_header(self):
     line = "Crypto devices using DPDK-compatible driver"
     olddict = 'olddict'
     self.assertEqual(CRYPTO_DPDK,
                      DpdkBindHelper._switch_active_dict(line, olddict))
コード例 #25
0
 def test__switch_active_dict_by_header_empty(self):
     line = "<none>"
     olddict = 'olddict'
     self.assertEqual(olddict,
                      DpdkBindHelper._switch_active_dict(line, olddict))