From: Thomas Monjalon Date: Wed, 20 Jul 2016 13:38:54 +0000 (+0200) Subject: unify tools naming X-Git-Tag: spdx-start~6082 X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=a5d7a3f77ddc;p=dpdk.git unify tools naming The following tools may be installed system-wide. It may be cleaner and more convenient to find them with the same dpdk- prefix (especially for autocompletion). Moreover, the script dpdk_nic_bind.py deserves a new name because it is not restricted to NICs and can be used for e.g. crypto. These files are renamed: pmdinfogen -> dpdk-pmdinfogen pmdinfo.py -> dpdk-pmdinfo.py dpdk_pdump -> dpdk-pdump dpdk_proc_info -> dpdk-procinfo dpdk_nic_bind.py -> dpdk-devbind.py setup.sh -> dpdk-setup.sh The tools pmdinfogen, pmdinfo.py and dpdk_pdump are new in 16.07. The scripts dpdk_nic_bind.py and setup.sh may have been used with previous releases by end users. That's why a symbolic link still provide the old name in the installed tools directory. Signed-off-by: Thomas Monjalon Acked-by: Yuanhan Liu --- diff --git a/MAINTAINERS b/MAINTAINERS index 9c76352955..6a47104371 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -70,7 +70,7 @@ F: scripts/validate-abi.sh Driver information F: buildtools/pmdinfogen/ -F: tools/pmdinfo.py +F: tools/dpdk-pmdinfo.py Environment Abstraction Layer diff --git a/app/pdump/Makefile b/app/pdump/Makefile index d85bb08e31..536198faf0 100644 --- a/app/pdump/Makefile +++ b/app/pdump/Makefile @@ -33,7 +33,7 @@ include $(RTE_SDK)/mk/rte.vars.mk ifeq ($(CONFIG_RTE_LIBRTE_PDUMP),y) -APP = dpdk_pdump +APP = dpdk-pdump CFLAGS += $(WERROR_FLAGS) diff --git a/app/proc_info/Makefile b/app/proc_info/Makefile index 33e058e4f7..e051e03238 100644 --- a/app/proc_info/Makefile +++ b/app/proc_info/Makefile @@ -31,7 +31,7 @@ include $(RTE_SDK)/mk/rte.vars.mk -APP = dpdk_proc_info +APP = dpdk-procinfo CFLAGS += $(WERROR_FLAGS) diff --git a/buildtools/pmdinfogen/Makefile b/buildtools/pmdinfogen/Makefile index 3885d3b396..bd8f9005e6 100644 --- a/buildtools/pmdinfogen/Makefile +++ b/buildtools/pmdinfogen/Makefile @@ -34,7 +34,7 @@ include $(RTE_SDK)/mk/rte.vars.mk # # library name # -HOSTAPP = pmdinfogen +HOSTAPP = dpdk-pmdinfogen # # all sources are stored in SRCS-y diff --git a/doc/guides/faq/faq.rst b/doc/guides/faq/faq.rst index 3228b92cab..8d1ea6cc30 100644 --- a/doc/guides/faq/faq.rst +++ b/doc/guides/faq/faq.rst @@ -50,7 +50,7 @@ When you stop and restart the test application, it looks to see if the pages are If you look in the directory, you will see ``n`` number of 2M pages files. If you specified 1024, you will see 1024 page files. These are then placed in memory segments to get contiguous memory. -If you need to change the number of pages, it is easier to first remove the pages. The tools/setup.sh script provides an option to do this. +If you need to change the number of pages, it is easier to first remove the pages. The tools/dpdk-setup.sh script provides an option to do this. See the "Quick Start Setup Script" section in the :ref:`DPDK Getting Started Guide ` for more information. diff --git a/doc/guides/linux_gsg/build_dpdk.rst b/doc/guides/linux_gsg/build_dpdk.rst index fb2c481df6..f8007b317b 100644 --- a/doc/guides/linux_gsg/build_dpdk.rst +++ b/doc/guides/linux_gsg/build_dpdk.rst @@ -198,7 +198,7 @@ however please consult your distributions documentation to make sure that is the Also, to use VFIO, both kernel and BIOS must support and be configured to use IO virtualization (such as Intel® VT-d). For proper operation of VFIO when running DPDK applications as a non-privileged user, correct permissions should also be set up. -This can be done by using the DPDK setup script (called setup.sh and located in the tools directory). +This can be done by using the DPDK setup script (called dpdk-setup.sh and located in the tools directory). .. _linux_gsg_binding_kernel: @@ -224,7 +224,7 @@ and to bind and unbind those ports from the different kernel modules, including The following are some examples of how the script can be used. A full description of the script and its parameters can be obtained by calling the script with the ``--help`` or ``--usage`` options. Note that the uio or vfio kernel modules to be used, should be loaded into the kernel before -running the ``dpdk_nic_bind.py`` script. +running the ``dpdk-devbind.py`` script. .. warning:: @@ -238,14 +238,14 @@ running the ``dpdk_nic_bind.py`` script. .. warning:: - While any user can run the dpdk_nic_bind.py script to view the status of the network ports, + While any user can run the dpdk-devbind.py script to view the status of the network ports, binding or unbinding network ports requires root privileges. To see the status of all network ports on the system: .. code-block:: console - ./tools/dpdk_nic_bind.py --status + ./tools/dpdk-devbind.py --status Network devices using DPDK-compatible driver ============================================ @@ -267,16 +267,16 @@ To bind device ``eth1``,``04:00.1``, to the ``uio_pci_generic`` driver: .. code-block:: console - ./tools/dpdk_nic_bind.py --bind=uio_pci_generic 04:00.1 + ./tools/dpdk-devbind.py --bind=uio_pci_generic 04:00.1 or, alternatively, .. code-block:: console - ./tools/dpdk_nic_bind.py --bind=uio_pci_generic eth1 + ./tools/dpdk-devbind.py --bind=uio_pci_generic eth1 To restore device ``82:00.0`` to its original kernel binding: .. code-block:: console - ./tools/dpdk_nic_bind.py --bind=ixgbe 82:00.0 + ./tools/dpdk-devbind.py --bind=ixgbe 82:00.0 diff --git a/doc/guides/linux_gsg/nic_perf_intel_platform.rst b/doc/guides/linux_gsg/nic_perf_intel_platform.rst index b433732495..d4a83624e1 100644 --- a/doc/guides/linux_gsg/nic_perf_intel_platform.rst +++ b/doc/guides/linux_gsg/nic_perf_intel_platform.rst @@ -192,12 +192,12 @@ Configurations before running DPDK # Bind ports 82:00.0 and 85:00.0 to dpdk driver - ./dpdk_folder/tools/dpdk_nic_bind.py -b igb_uio 82:00.0 85:00.0 + ./dpdk_folder/tools/dpdk-devbind.py -b igb_uio 82:00.0 85:00.0 # Check the port driver status - ./dpdk_folder/tools/dpdk_nic_bind.py --status + ./dpdk_folder/tools/dpdk-devbind.py --status - See ``dpdk_nic_bind.py --help`` for more details. + See ``dpdk-devbind.py --help`` for more details. More details about DPDK setup and Linux kernel requirements see :ref:`linux_gsg_compiling_dpdk`. diff --git a/doc/guides/linux_gsg/quick_start.rst b/doc/guides/linux_gsg/quick_start.rst index 1e0f8ff356..8789b58884 100644 --- a/doc/guides/linux_gsg/quick_start.rst +++ b/doc/guides/linux_gsg/quick_start.rst @@ -33,7 +33,7 @@ Quick Start Setup Script ======================== -The setup.sh script, found in the tools subdirectory, allows the user to perform the following tasks: +The dpdk-setup.sh script, found in the tools subdirectory, allows the user to perform the following tasks: * Build the DPDK libraries @@ -63,7 +63,7 @@ the user may compile their own application that links in the EAL libraries to cr Script Organization ------------------- -The setup.sh script is logically organized into a series of steps that a user performs in sequence. +The dpdk-setup.sh script is logically organized into a series of steps that a user performs in sequence. Each step provides a number of options that guide the user to completing the desired task. The following is a brief synopsis of each step. @@ -98,17 +98,17 @@ The final step has options for restoring the system to its original state. Use Cases --------- -The following are some example of how to use the setup.sh script. +The following are some example of how to use the dpdk-setup.sh script. The script should be run using the source command. Some options in the script prompt the user for further data before proceeding. .. warning:: - The setup.sh script should be run with root privileges. + The dpdk-setup.sh script should be run with root privileges. .. code-block:: console - source tools/setup.sh + source tools/dpdk-setup.sh ------------------------------------------------------------------------ @@ -269,7 +269,7 @@ The following selection demonstrates the launch of the test application to run o Applications ------------ -Once the user has run the setup.sh script, built one of the EAL targets and set up hugepages (if using one of the Linux EAL targets), +Once the user has run the dpdk-setup.sh script, built one of the EAL targets and set up hugepages (if using one of the Linux EAL targets), the user can then move on to building and running their application or one of the examples provided. The examples in the /examples directory provide a good starting point to gain an understanding of the operation of the DPDK. diff --git a/doc/guides/nics/bnx2x.rst b/doc/guides/nics/bnx2x.rst index df8fb47705..6453168e3a 100644 --- a/doc/guides/nics/bnx2x.rst +++ b/doc/guides/nics/bnx2x.rst @@ -207,7 +207,7 @@ devices managed by ``librte_pmd_bnx2x`` in Linux operating system. #. Bind the QLogic adapters to ``igb_uio`` or ``vfio-pci`` loaded in the previous step:: - ./tools/dpdk_nic_bind.py --bind igb_uio 0000:84:00.0 0000:84:00.1 + ./tools/dpdk-devbind.py --bind igb_uio 0000:84:00.0 0000:84:00.1 or @@ -219,7 +219,7 @@ devices managed by ``librte_pmd_bnx2x`` in Linux operating system. sudo chmod 0666 /dev/vfio/* - ./tools/dpdk_nic_bind.py --bind vfio-pci 0000:84:00.0 0000:84:00.1 + ./tools/dpdk-devbind.py --bind vfio-pci 0000:84:00.0 0000:84:00.1 #. Start ``testpmd`` with basic parameters: diff --git a/doc/guides/nics/cxgbe.rst b/doc/guides/nics/cxgbe.rst index d718f196ce..d8236b08e9 100644 --- a/doc/guides/nics/cxgbe.rst +++ b/doc/guides/nics/cxgbe.rst @@ -285,7 +285,7 @@ devices managed by librte_pmd_cxgbe in Linux operating system. .. code-block:: console - ./tools/dpdk_nic_bind.py --bind igb_uio 0000:02:00.4 + ./tools/dpdk-devbind.py --bind igb_uio 0000:02:00.4 or @@ -297,7 +297,7 @@ devices managed by librte_pmd_cxgbe in Linux operating system. sudo chmod 0666 /dev/vfio/* - ./tools/dpdk_nic_bind.py --bind vfio-pci 0000:02:00.4 + ./tools/dpdk-devbind.py --bind vfio-pci 0000:02:00.4 .. note:: diff --git a/doc/guides/nics/ena.rst b/doc/guides/nics/ena.rst index 9f938486cc..073b35ae2a 100644 --- a/doc/guides/nics/ena.rst +++ b/doc/guides/nics/ena.rst @@ -225,7 +225,7 @@ devices managed by librte_pmd_ena. .. code-block:: console - ./tools/dpdk_nic_bind.py --bind=igb_uio 0000:02:00.1 + ./tools/dpdk-devbind.py --bind=igb_uio 0000:02:00.1 #. Start testpmd with basic parameters: diff --git a/doc/guides/nics/enic.rst b/doc/guides/nics/enic.rst index a81264b5f6..42e781e31f 100644 --- a/doc/guides/nics/enic.rst +++ b/doc/guides/nics/enic.rst @@ -174,13 +174,13 @@ Prerequisites - DPDK suite should be configured based on the user's decision to use VFIO or UIO framework - If the vNIC device(s) to be used is bound to the kernel mode Ethernet driver - (enic), use 'ifconfig' to bring the interface down. The dpdk_nic_bind.py tool + (enic), use 'ifconfig' to bring the interface down. The dpdk-devbind.py tool can then be used to unbind the device's bus id from the enic kernel mode driver. - Bind the intended vNIC to vfio-pci in case the user wants ENIC PMD to use - VFIO framework using dpdk_nic_bind.py. + VFIO framework using dpdk-devbind.py. - Bind the intended vNIC to igb_uio in case the user wants ENIC PMD to use - UIO framework using dpdk_nic_bind.py. + UIO framework using dpdk-devbind.py. At this point the system should be ready to run DPDK applications. Once the application runs to completion, the vNIC can be detached from vfio-pci or diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index da695afd30..4d12b10c54 100644 --- a/doc/guides/nics/i40e.rst +++ b/doc/guides/nics/i40e.rst @@ -164,13 +164,13 @@ devices managed by ``librte_pmd_i40e`` in the Linux operating system. .. code-block:: console - ./tools/dpdk_nic_bind.py --bind igb_uio 0000:83:00.0 + ./tools/dpdk-devbind.py --bind igb_uio 0000:83:00.0 Or setup VFIO permissions for regular users and then bind to ``vfio-pci``: .. code-block:: console - ./tools/dpdk_nic_bind.py --bind vfio-pci 0000:83:00.0 + ./tools/dpdk-devbind.py --bind vfio-pci 0000:83:00.0 #. Start ``testpmd`` with basic parameters: diff --git a/doc/guides/nics/intel_vf.rst b/doc/guides/nics/intel_vf.rst index a68198f882..95a79b599a 100644 --- a/doc/guides/nics/intel_vf.rst +++ b/doc/guides/nics/intel_vf.rst @@ -151,7 +151,7 @@ For example, modprobe uio insmod igb_uio - ./dpdk_nic_bind.py -b igb_uio bb:ss.f + ./dpdk-devbind.py -b igb_uio bb:ss.f echo 2 > /sys/bus/pci/devices/0000\:bb\:ss.f/max_vfs (To enable two VFs on a specific PCI device) Launch the DPDK testpmd/example or your own host daemon application using the DPDK PMD library. @@ -236,7 +236,7 @@ For example, modprobe uio insmod igb_uio - ./dpdk_nic_bind.py -b igb_uio bb:ss.f + ./dpdk-devbind.py -b igb_uio bb:ss.f echo 2 > /sys/bus/pci/devices/0000\:bb\:ss.f/max_vfs (To enable two VFs on a specific PCI device) Launch the DPDK testpmd/example or your own host daemon application using the DPDK PMD library. @@ -285,7 +285,7 @@ For example, .. code-block:: console insmod igb_uio - ./dpdk_nic_bind.py -b igb_uio bb:ss.f + ./dpdk-devbind.py -b igb_uio bb:ss.f echo 2 > /sys/bus/pci/devices/0000\:bb\:ss.f/max_vfs (To enable two VFs on a specific pci device) Launch DPDK testpmd/example or your own host daemon application using the DPDK PMD library. @@ -406,7 +406,7 @@ The setup procedure is as follows: modprobe uio insmod igb_uio - ./dpdk_nic_bind.py -b igb_uio 02:00.0 02:00.1 0e:00.0 0e:00.1 + ./dpdk-devbind.py -b igb_uio 02:00.0 02:00.1 0e:00.0 0e:00.1 echo 2 > /sys/bus/pci/devices/0000\:02\:00.0/max_vfs echo 2 > /sys/bus/pci/devices/0000\:02\:00.1/max_vfs echo 2 > /sys/bus/pci/devices/0000\:0e\:00.0/max_vfs diff --git a/doc/guides/nics/nfp.rst b/doc/guides/nics/nfp.rst index e4ebc712db..4ef6e026c9 100644 --- a/doc/guides/nics/nfp.rst +++ b/doc/guides/nics/nfp.rst @@ -242,9 +242,9 @@ Using the NFP PMD is not different to using other PMDs. Usual steps are: useful for installing the UIO modules and for binding the right device to those modules avoiding doing so manually: - * **setup.sh** - * **dpdk_nic_bind.py** + * **dpdk-setup.sh** + * **dpdk-devbind.py** - Configuration may be performed by running setup.sh which invokes - dpdk_nic_bind.py as needed. Executing setup.sh will display a menu of + Configuration may be performed by running dpdk-setup.sh which invokes + dpdk-devbind.py as needed. Executing dpdk-setup.sh will display a menu of configuration options. diff --git a/doc/guides/nics/qede.rst b/doc/guides/nics/qede.rst index f7ca8eb966..53d749c9b1 100644 --- a/doc/guides/nics/qede.rst +++ b/doc/guides/nics/qede.rst @@ -177,7 +177,7 @@ devices managed by ``librte_pmd_qede`` in Linux operating system. .. code-block:: console - ./tools/dpdk_nic_bind.py --bind igb_uio 0000:84:00.0 0000:84:00.1 \ + ./tools/dpdk-devbind.py --bind igb_uio 0000:84:00.0 0000:84:00.1 \ 0000:84:00.2 0000:84:00.3 #. Start ``testpmd`` with basic parameters: diff --git a/doc/guides/nics/thunderx.rst b/doc/guides/nics/thunderx.rst index e38f260b92..248b1af7bf 100644 --- a/doc/guides/nics/thunderx.rst +++ b/doc/guides/nics/thunderx.rst @@ -146,7 +146,7 @@ managed by ``librte_pmd_thunderx_nicvf`` in the Linux operating system. .. code-block:: console - ./tools/dpdk_nic_bind.py --bind vfio-pci 0002:01:00.2 + ./tools/dpdk-devbind.py --bind vfio-pci 0002:01:00.2 #. Start ``testpmd`` with basic parameters: @@ -246,11 +246,11 @@ This section provides instructions to configure SR-IOV with Linux OS. Unless ``thunder-nicvf`` driver is in use make sure your kernel config includes ``CONFIG_THUNDER_NIC_VF`` setting. -#. Verify PF/VF bind using ``dpdk_nic_bind.py``: +#. Verify PF/VF bind using ``dpdk-devbind.py``: .. code-block:: console - ./tools/dpdk_nic_bind.py --status + ./tools/dpdk-devbind.py --status Example output: @@ -268,18 +268,18 @@ This section provides instructions to configure SR-IOV with Linux OS. modprobe vfio-pci -#. Bind VF devices to ``vfio-pci`` using ``dpdk_nic_bind.py``: +#. Bind VF devices to ``vfio-pci`` using ``dpdk-devbind.py``: .. code-block:: console - ./tools/dpdk_nic_bind.py --bind vfio-pci 0002:01:00.1 - ./tools/dpdk_nic_bind.py --bind vfio-pci 0002:01:00.2 + ./tools/dpdk-devbind.py --bind vfio-pci 0002:01:00.1 + ./tools/dpdk-devbind.py --bind vfio-pci 0002:01:00.2 -#. Verify VF bind using ``dpdk_nic_bind.py``: +#. Verify VF bind using ``dpdk-devbind.py``: .. code-block:: console - ./tools/dpdk_nic_bind.py --status + ./tools/dpdk-devbind.py --status Example output: diff --git a/doc/guides/nics/virtio.rst b/doc/guides/nics/virtio.rst index c6335d405d..5431015795 100644 --- a/doc/guides/nics/virtio.rst +++ b/doc/guides/nics/virtio.rst @@ -172,7 +172,7 @@ Host2VM communication example modprobe uio echo 512 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages modprobe uio_pci_generic - python tools/dpdk_nic_bind.py -b uio_pci_generic 00:03.0 + python tools/dpdk-devbind.py -b uio_pci_generic 00:03.0 We use testpmd as the forwarding application in this example. diff --git a/doc/guides/prog_guide/dev_kit_build_system.rst b/doc/guides/prog_guide/dev_kit_build_system.rst index 18a30104dc..fa2411f7a9 100644 --- a/doc/guides/prog_guide/dev_kit_build_system.rst +++ b/doc/guides/prog_guide/dev_kit_build_system.rst @@ -309,11 +309,11 @@ Misc Internally Generated Build Tools ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``app/pmdinfogen`` +``app/dpdk-pmdinfogen`` -``pmdinfogen`` scans an object (.o) file for various well known symbol names. These -well known symbol names are defined by various macros and used to export +``dpdk-pmdinfogen`` scans an object (.o) file for various well known symbol names. +These well known symbol names are defined by various macros and used to export important information about hardware support and usage for pmd files. For instance the macro: @@ -328,10 +328,10 @@ Creates the following symbol: static char this_pmd_name0[] __attribute__((used)) = ""; -Which pmdinfogen scans for. Using this information other relevant bits of data -can be exported from the object file and used to produce a hardware support -description, that pmdinfogen then encodes into a json formatted string in the -following format: +Which ``dpdk-pmdinfogen`` scans for. Using this information other relevant +bits of data can be exported from the object file and used to produce a +hardware support description, that ``dpdk-pmdinfogen`` then encodes into a +json formatted string in the following format: .. code-block:: c diff --git a/doc/guides/rel_notes/release_16_07.rst b/doc/guides/rel_notes/release_16_07.rst index 5030bb4e7c..d00a6ed59e 100644 --- a/doc/guides/rel_notes/release_16_07.rst +++ b/doc/guides/rel_notes/release_16_07.rst @@ -325,6 +325,9 @@ API Changes * The function ``rte_eth_dev_set_mtu`` adds a new return value ``-EBUSY``, which indicates the operation is forbidden because the port is running. +* The script ``dpdk_nic_bind.py`` is renamed to ``dpdk-devbind.py``. + And the script ``setup.sh`` is renamed to ``dpdk-setup.sh``. + ABI Changes ----------- diff --git a/doc/guides/sample_app_ug/pdump.rst b/doc/guides/sample_app_ug/pdump.rst index ceb038ec0d..ac0e7c9625 100644 --- a/doc/guides/sample_app_ug/pdump.rst +++ b/doc/guides/sample_app_ug/pdump.rst @@ -30,15 +30,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -dpdk_pdump Application +dpdk-pdump Application ====================== -The ``dpdk_pdump`` tool is a Data Plane Development Kit (DPDK) tool that runs as +The ``dpdk-pdump`` tool is a Data Plane Development Kit (DPDK) tool that runs as a DPDK secondary process and is capable of enabling packet capture on dpdk ports. .. Note:: - * The ``dpdk_pdump`` tool depends on libpcap based PMD which is disabled + * The ``dpdk-pdump`` tool depends on libpcap based PMD which is disabled by default in the build configuration files, owing to an external dependency on the libpcap development files which must be installed on the board. @@ -53,7 +53,7 @@ The tool has a number of command line options: .. code-block:: console - ./build/app/dpdk_pdump -- + ./build/app/dpdk-pdump -- --pdump '(port= | device_id=), (queue=), (rx-dev= | @@ -95,10 +95,10 @@ PCI address (or) name of the eth device on which packets should be captured. .. Note:: - * As of now the ``dpdk_pdump`` tool cannot capture the packets of virtual devices + * As of now the ``dpdk-pdump`` tool cannot capture the packets of virtual devices in the primary process due to a bug in the ethdev library. Due to this bug, in a multi process context, when the primary and secondary have different ports set, then the secondary process - (here the ``dpdk_pdump`` tool) overwrites the ``rte_eth_devices[]`` entries of the primary process. + (here the ``dpdk-pdump`` tool) overwrites the ``rte_eth_devices[]`` entries of the primary process. ``queue``: Queue id of the eth device on which packets should be captured. The user can pass a queue value of ``*`` to enable @@ -141,4 +141,4 @@ Example .. code-block:: console - $ sudo ./build/app/dpdk_pdump -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap' + $ sudo ./build/app/dpdk-pdump -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap' diff --git a/doc/guides/sample_app_ug/proc_info.rst b/doc/guides/sample_app_ug/proc_info.rst index 542950b3ad..73f219580e 100644 --- a/doc/guides/sample_app_ug/proc_info.rst +++ b/doc/guides/sample_app_ug/proc_info.rst @@ -30,10 +30,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -dpdk_proc_info Application -========================== +dpdk-procinfo Application +========================= -The dpdk_proc_info application is a Data Plane Development Kit (DPDK) application +The dpdk-procinfo application is a Data Plane Development Kit (DPDK) application that runs as a DPDK secondary process and is capable of retrieving port statistics, resetting port statistics and printing DPDK memory information. This application extends the original functionality that was supported by @@ -45,7 +45,7 @@ The application has a number of command line options: .. code-block:: console - ./$(RTE_TARGET)/app/dpdk_proc_info -- -m | [-p PORTMASK] [--stats | --xstats | + ./$(RTE_TARGET)/app/dpdk-procinfo -- -m | [-p PORTMASK] [--stats | --xstats | --stats-reset | --xstats-reset] Parameters diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst index 30e410dd70..f87e0c29b5 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -999,7 +999,7 @@ For example, to move a pci device using ixgbe under DPDK management: .. code-block:: console # Check the status of the available devices. - ./tools/dpdk_nic_bind.py --status + ./tools/dpdk-devbind.py --status Network devices using DPDK-compatible driver ============================================ @@ -1011,11 +1011,11 @@ For example, to move a pci device using ixgbe under DPDK management: # Bind the device to igb_uio. - sudo ./tools/dpdk_nic_bind.py -b igb_uio 0000:0a:00.0 + sudo ./tools/dpdk-devbind.py -b igb_uio 0000:0a:00.0 # Recheck the status of the devices. - ./tools/dpdk_nic_bind.py --status + ./tools/dpdk-devbind.py --status Network devices using DPDK-compatible driver ============================================ 0000:0a:00.0 '82599ES 10-Gigabit' drv=igb_uio unused= @@ -1118,9 +1118,9 @@ For example, to move a pci device under kernel management: .. code-block:: console - sudo ./tools/dpdk_nic_bind.py -b ixgbe 0000:0a:00.0 + sudo ./tools/dpdk-devbind.py -b ixgbe 0000:0a:00.0 - ./tools/dpdk_nic_bind.py --status + ./tools/dpdk-devbind.py --status Network devices using DPDK-compatible driver ============================================ diff --git a/doc/guides/xen/pkt_switch.rst b/doc/guides/xen/pkt_switch.rst index 3a6fc4708a..00a8f0c115 100644 --- a/doc/guides/xen/pkt_switch.rst +++ b/doc/guides/xen/pkt_switch.rst @@ -323,7 +323,7 @@ Building and Running the Switching Backend .. code-block:: console modprobe uio_pci_generic - python tools/dpdk_nic_bind.py -b uio_pci_generic 0000:09:00:00.0 + python tools/dpdk-devbind.py -b uio_pci_generic 0000:09:00:00.0 In this case, 0000:09:00.0 is the PCI address for the NIC controller. diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index 0a594d7fd9..481c732b18 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -116,9 +116,9 @@ TAILQ_HEAD_INITIALIZER(solib_list); static const char *default_solib_dir = RTE_EAL_PMD_PATH; /* - * Stringified version of solib path used by pmdinfo.py + * Stringified version of solib path used by dpdk-pmdinfo.py * Note: PLEASE DO NOT ALTER THIS without making a corresponding - * change to tools/pmdinfo.py + * change to tools/dpdk-pmdinfo.py */ static const char dpdk_solib_path[] __attribute__((used)) = "DPDK_PLUGIN_PATH=" RTE_EAL_PMD_PATH; diff --git a/mk/internal/rte.compile-pre.mk b/mk/internal/rte.compile-pre.mk index 9c25ff6c25..f740179134 100644 --- a/mk/internal/rte.compile-pre.mk +++ b/mk/internal/rte.compile-pre.mk @@ -84,7 +84,7 @@ C_TO_O = $(CC) -Wp,-MD,$(call obj2dep,$(@)).tmp $(CFLAGS) \ C_TO_O_STR = $(subst ','\'',$(C_TO_O)) #'# fix syntax highlight C_TO_O_DISP = $(if $(V),"$(C_TO_O_STR)"," CC $(@)") endif -PMDINFO_GEN = $(RTE_SDK_BIN)/app/pmdinfogen $@ $@.pmd.c +PMDINFO_GEN = $(RTE_SDK_BIN)/app/dpdk-pmdinfogen $@ $@.pmd.c PMDINFO_CC = $(CC) $(CFLAGS) -c -o $@.pmd.o $@.pmd.c PMDINFO_LD = $(CROSS)ld $(LDFLAGS) -r -o $@.o $@.pmd.o $@ PMDINFO_TO_O = if grep -q 'PMD_REGISTER_DRIVER(.*)' $<; then \ diff --git a/mk/rte.sdkinstall.mk b/mk/rte.sdkinstall.mk index 7cd352c78c..5217063556 100644 --- a/mk/rte.sdkinstall.mk +++ b/mk/rte.sdkinstall.mk @@ -117,18 +117,22 @@ install-runtime: $(Q)cp -a $O/lib/* $(DESTDIR)$(libdir) $(Q)$(call rte_mkdir, $(DESTDIR)$(bindir)) $(Q)tar -cf - -C $O --exclude 'app/*.map' \ - --exclude app/pmdinfogen \ + --exclude app/dpdk-pmdinfogen \ --exclude 'app/cmdline*' --exclude app/test \ --exclude app/testacl --exclude app/testpipeline app | \ tar -xf - -C $(DESTDIR)$(bindir) --strip-components=1 \ --keep-newer-files --warning=no-ignore-newer $(Q)$(call rte_mkdir, $(DESTDIR)$(datadir)) $(Q)cp -a $(RTE_SDK)/tools $(DESTDIR)$(datadir) + $(Q)$(call rte_symlink, $(DESTDIR)$(datadir)/tools/dpdk-setup.sh, \ + $(DESTDIR)$(datadir)/tools/setup.sh) + $(Q)$(call rte_symlink, $(DESTDIR)$(datadir)/tools/dpdk-devbind.py, \ + $(DESTDIR)$(datadir)/tools/dpdk_nic_bind.py) $(Q)$(call rte_mkdir, $(DESTDIR)$(sbindir)) - $(Q)$(call rte_symlink, $(DESTDIR)$(datadir)/tools/dpdk_nic_bind.py, \ - $(DESTDIR)$(sbindir)/dpdk_nic_bind) - $(Q)$(call rte_symlink, $(DESTDIR)$(datadir)/tools/pmdinfo.py, \ - $(DESTDIR)$(bindir)/dpdk_pmdinfo) + $(Q)$(call rte_symlink, $(DESTDIR)$(datadir)/tools/dpdk-devbind.py, \ + $(DESTDIR)$(sbindir)/dpdk-devbind) + $(Q)$(call rte_symlink, $(DESTDIR)$(datadir)/tools/dpdk-pmdinfo.py, \ + $(DESTDIR)$(bindir)/dpdk-pmdinfo) install-kmod: ifneq ($(wildcard $O/kmod/*),) @@ -146,7 +150,7 @@ install-sdk: $(Q)cp -a $(RTE_SDK)/scripts $(DESTDIR)$(sdkdir) $(Q)$(call rte_mkdir, $(DESTDIR)$(targetdir)/app) $(Q)cp -a $O/.config $(DESTDIR)$(targetdir) - $(Q)cp -a $O/app/pmdinfogen $(DESTDIR)$(targetdir)/app + $(Q)cp -a $O/app/dpdk-pmdinfogen $(DESTDIR)$(targetdir)/app $(Q)$(call rte_symlink, $(DESTDIR)$(includedir), $(DESTDIR)$(targetdir)/include) $(Q)$(call rte_symlink, $(DESTDIR)$(libdir), $(DESTDIR)$(targetdir)/lib) diff --git a/mk/rte.sdktest.mk b/mk/rte.sdktest.mk index ff5718196d..ddbbbf6b24 100644 --- a/mk/rte.sdktest.mk +++ b/mk/rte.sdktest.mk @@ -66,7 +66,7 @@ test fast_test perf_test: fi # this is a special target to ease the pain of running coverage tests -# this runs all the autotests, cmdline_test script and dpdk_proc_info +# this runs all the autotests, cmdline_test script and dpdk-procinfo coverage: @mkdir -p $(AUTOTEST_DIR) ; \ cd $(AUTOTEST_DIR) ; \ @@ -78,7 +78,7 @@ coverage: $(RTE_OUTPUT)/app/test \ $(RTE_TARGET) \ $(BLACKLIST) $(WHITELIST) ; \ - $(RTE_OUTPUT)/app/dpdk_proc_info --file-prefix=ring_perf -- -m; \ + $(RTE_OUTPUT)/app/dpdk-procinfo --file-prefix=ring_perf -- -m; \ else \ echo "No test found, please do a 'make build' first, or specify O=" ;\ fi diff --git a/tools/dpdk-devbind.py b/tools/dpdk-devbind.py new file mode 100755 index 0000000000..b69ca2a0db --- /dev/null +++ b/tools/dpdk-devbind.py @@ -0,0 +1,576 @@ +#! /usr/bin/python +# +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import sys +import os +import getopt +import subprocess +from os.path import exists, abspath, dirname, basename + +# The PCI base class for NETWORK devices +NETWORK_BASE_CLASS = "02" + +# global dict ethernet devices present. Dictionary indexed by PCI address. +# Each device within this is itself a dictionary of device properties +devices = {} +# list of supported DPDK drivers +dpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"] + +# command-line arg flags +b_flag = None +status_flag = False +force_flag = False +args = [] + + +def usage(): + '''Print usage information for the program''' + argv0 = basename(sys.argv[0]) + print(""" +Usage: +------ + + %(argv0)s [options] DEVICE1 DEVICE2 .... + +where DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax +or "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may +also be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc. + +Options: + --help, --usage: + Display usage information and quit + + -s, --status: + Print the current status of all known network interfaces. + For each device, it displays the PCI domain, bus, slot and function, + along with a text description of the device. Depending upon whether the + device is being used by a kernel driver, the igb_uio driver, or no + driver, other relevant information will be displayed: + * the Linux interface name e.g. if=eth0 + * the driver being used e.g. drv=igb_uio + * any suitable drivers not currently using that device + e.g. unused=igb_uio + NOTE: if this flag is passed along with a bind/unbind option, the + status display will always occur after the other operations have taken + place. + + -b driver, --bind=driver: + Select the driver to use or \"none\" to unbind the device + + -u, --unbind: + Unbind a device (Equivalent to \"-b none\") + + --force: + By default, devices which are used by Linux - as indicated by having + routes in the routing table - cannot be modified. Using the --force + flag overrides this behavior, allowing active links to be forcibly + unbound. + WARNING: This can lead to loss of network connection and should be used + with caution. + +Examples: +--------- + +To display current device status: + %(argv0)s --status + +To bind eth1 from the current driver and move to use igb_uio + %(argv0)s --bind=igb_uio eth1 + +To unbind 0000:01:00.0 from using any driver + %(argv0)s -u 0000:01:00.0 + +To bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver + %(argv0)s -b ixgbe 02:00.0 02:00.1 + + """ % locals()) # replace items from local variables + + +# This is roughly compatible with check_output function in subprocess module +# which is only available in python 2.7. +def check_output(args, stderr=None): + '''Run a command and capture its output''' + return subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=stderr).communicate()[0] + + +def find_module(mod): + '''find the .ko file for kernel module named mod. + Searches the $RTE_SDK/$RTE_TARGET directory, the kernel + modules directory and finally under the parent directory of + the script ''' + # check $RTE_SDK/$RTE_TARGET directory + if 'RTE_SDK' in os.environ and 'RTE_TARGET' in os.environ: + path = "%s/%s/kmod/%s.ko" % (os.environ['RTE_SDK'], + os.environ['RTE_TARGET'], mod) + if exists(path): + return path + + # check using depmod + try: + depmod_out = check_output(["modinfo", "-n", mod], + stderr=subprocess.STDOUT).lower() + if "error" not in depmod_out: + path = depmod_out.strip() + if exists(path): + return path + except: # if modinfo can't find module, it fails, so continue + pass + + # check for a copy based off current path + tools_dir = dirname(abspath(sys.argv[0])) + if (tools_dir.endswith("tools")): + base_dir = dirname(tools_dir) + find_out = check_output(["find", base_dir, "-name", mod + ".ko"]) + if len(find_out) > 0: # something matched + path = find_out.splitlines()[0] + if exists(path): + return path + + +def check_modules(): + '''Checks that igb_uio is loaded''' + global dpdk_drivers + + # list of supported modules + mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers] + + # first check if module is loaded + try: + # Get list of sysfs modules (both built-in and dynamically loaded) + sysfs_path = '/sys/module/' + + # Get the list of directories in sysfs_path + sysfs_mods = [os.path.join(sysfs_path, o) for o + in os.listdir(sysfs_path) + if os.path.isdir(os.path.join(sysfs_path, o))] + + # Extract the last element of '/sys/module/abc' in the array + sysfs_mods = [a.split('/')[-1] for a in sysfs_mods] + + # special case for vfio_pci (module is named vfio-pci, + # but its .ko is named vfio_pci) + sysfs_mods = map(lambda a: + a if a != 'vfio_pci' else 'vfio-pci', sysfs_mods) + + for mod in mods: + if mod["Name"] in sysfs_mods: + mod["Found"] = True + except: + pass + + # check if we have at least one loaded module + if True not in [mod["Found"] for mod in mods] and b_flag is not None: + if b_flag in dpdk_drivers: + print("Error - no supported modules(DPDK driver) are loaded") + sys.exit(1) + else: + print("Warning - no supported modules(DPDK driver) are loaded") + + # change DPDK driver list to only contain drivers that are loaded + dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] + + +def has_driver(dev_id): + '''return true if a device is assigned to a driver. False otherwise''' + return "Driver_str" in devices[dev_id] + + +def get_pci_device_details(dev_id): + '''This function gets additional details for a PCI device''' + device = {} + + extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() + + # parse lspci details + for line in extra_info: + if len(line) == 0: + continue + name, value = line.decode().split("\t", 1) + name = name.strip(":") + "_str" + device[name] = value + # check for a unix interface name + sys_path = "/sys/bus/pci/devices/%s/net/" % dev_id + if exists(sys_path): + device["Interface"] = ",".join(os.listdir(sys_path)) + else: + device["Interface"] = "" + # check if a port is used for ssh connection + device["Ssh_if"] = False + device["Active"] = "" + + return device + + +def get_nic_details(): + '''This function populates the "devices" dictionary. The keys used are + the pci addresses (domain:bus:slot.func). The values are themselves + dictionaries - one for each NIC.''' + global devices + global dpdk_drivers + + # clear any old data + devices = {} + # first loop through and read details for all devices + # request machine readable format, with numeric IDs + dev = {} + dev_lines = check_output(["lspci", "-Dvmmn"]).splitlines() + for dev_line in dev_lines: + if (len(dev_line) == 0): + if dev["Class"][0:2] == NETWORK_BASE_CLASS: + # convert device and vendor ids to numbers, then add to global + dev["Vendor"] = int(dev["Vendor"], 16) + dev["Device"] = int(dev["Device"], 16) + # use dict to make copy of dev + devices[dev["Slot"]] = dict(dev) + else: + name, value = dev_line.decode().split("\t", 1) + dev[name.rstrip(":")] = value + + # check what is the interface if any for an ssh connection if + # any to this host, so we can mark it later. + ssh_if = [] + route = check_output(["ip", "-o", "route"]) + # filter out all lines for 169.254 routes + route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), + route.decode().splitlines())) + rt_info = route.split() + for i in range(len(rt_info) - 1): + if rt_info[i] == "dev": + ssh_if.append(rt_info[i+1]) + + # based on the basic info, get extended text details + for d in devices.keys(): + # get additional info and add it to existing data + devices[d] = devices[d].copy() + devices[d].update(get_pci_device_details(d).items()) + + for _if in ssh_if: + if _if in devices[d]["Interface"].split(","): + devices[d]["Ssh_if"] = True + devices[d]["Active"] = "*Active*" + break + + # add igb_uio to list of supporting modules if needed + if "Module_str" in devices[d]: + for driver in dpdk_drivers: + if driver not in devices[d]["Module_str"]: + devices[d]["Module_str"] = \ + devices[d]["Module_str"] + ",%s" % driver + else: + devices[d]["Module_str"] = ",".join(dpdk_drivers) + + # make sure the driver and module strings do not have any duplicates + if has_driver(d): + modules = devices[d]["Module_str"].split(",") + if devices[d]["Driver_str"] in modules: + modules.remove(devices[d]["Driver_str"]) + devices[d]["Module_str"] = ",".join(modules) + + +def dev_id_from_dev_name(dev_name): + '''Take a device "name" - a string passed in by user to identify a NIC + device, and determine the device id - i.e. the domain:bus:slot.func - for + it, which can then be used to index into the devices array''' + + # check if it's already a suitable index + if dev_name in devices: + return dev_name + # check if it's an index just missing the domain part + elif "0000:" + dev_name in devices: + return "0000:" + dev_name + else: + # check if it's an interface name, e.g. eth1 + for d in devices.keys(): + if dev_name in devices[d]["Interface"].split(","): + return devices[d]["Slot"] + # if nothing else matches - error + print("Unknown device: %s. " + "Please specify device in \"bus:slot.func\" format" % dev_name) + sys.exit(1) + + +def unbind_one(dev_id, force): + '''Unbind the device identified by "dev_id" from its current driver''' + dev = devices[dev_id] + if not has_driver(dev_id): + print("%s %s %s is not currently managed by any driver\n" % + (dev["Slot"], dev["Device_str"], dev["Interface"])) + return + + # prevent us disconnecting ourselves + if dev["Ssh_if"] and not force: + print("Routing table indicates that interface %s is active. " + "Skipping unbind" % (dev_id)) + return + + # write to /sys to unbind + filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] + try: + f = open(filename, "a") + except: + print("Error: unbind failed for %s - Cannot open %s" + % (dev_id, filename)) + sys.exit(1) + f.write(dev_id) + f.close() + + +def bind_one(dev_id, driver, force): + '''Bind the device given by "dev_id" to the driver "driver". If the device + is already bound to a different driver, it will be unbound first''' + dev = devices[dev_id] + saved_driver = None # used to rollback any unbind in case of failure + + # prevent disconnection of our ssh session + if dev["Ssh_if"] and not force: + print("Routing table indicates that interface %s is active. " + "Not modifying" % (dev_id)) + return + + # unbind any existing drivers we don't want + if has_driver(dev_id): + if dev["Driver_str"] == driver: + print("%s already bound to driver %s, skipping\n" + % (dev_id, driver)) + return + else: + saved_driver = dev["Driver_str"] + unbind_one(dev_id, force) + dev["Driver_str"] = "" # clear driver string + + # if we are binding to one of DPDK drivers, add PCI id's to that driver + if driver in dpdk_drivers: + filename = "/sys/bus/pci/drivers/%s/new_id" % driver + try: + f = open(filename, "w") + except: + print("Error: bind failed for %s - Cannot open %s" + % (dev_id, filename)) + return + try: + f.write("%04x %04x" % (dev["Vendor"], dev["Device"])) + f.close() + except: + print("Error: bind failed for %s - Cannot write new PCI ID to " + "driver %s" % (dev_id, driver)) + return + + # do the bind by writing to /sys + filename = "/sys/bus/pci/drivers/%s/bind" % driver + try: + f = open(filename, "a") + except: + print("Error: bind failed for %s - Cannot open %s" + % (dev_id, filename)) + if saved_driver is not None: # restore any previous driver + bind_one(dev_id, saved_driver, force) + return + try: + f.write(dev_id) + f.close() + except: + # for some reason, closing dev_id after adding a new PCI ID to new_id + # results in IOError. however, if the device was successfully bound, + # we don't care for any errors and can safely ignore IOError + tmp = get_pci_device_details(dev_id) + if "Driver_str" in tmp and tmp["Driver_str"] == driver: + return + print("Error: bind failed for %s - Cannot bind to driver %s" + % (dev_id, driver)) + if saved_driver is not None: # restore any previous driver + bind_one(dev_id, saved_driver, force) + return + + +def unbind_all(dev_list, force=False): + """Unbind method, takes a list of device locations""" + dev_list = map(dev_id_from_dev_name, dev_list) + for d in dev_list: + unbind_one(d, force) + + +def bind_all(dev_list, driver, force=False): + """Bind method, takes a list of device locations""" + global devices + + dev_list = map(dev_id_from_dev_name, dev_list) + + for d in dev_list: + bind_one(d, driver, force) + + # when binding devices to a generic driver (i.e. one that doesn't have a + # PCI ID table), some devices that are not bound to any other driver could + # be bound even if no one has asked them to. hence, we check the list of + # drivers again, and see if some of the previously-unbound devices were + # erroneously bound. + for d in devices.keys(): + # skip devices that were already bound or that we know should be bound + if "Driver_str" in devices[d] or d in dev_list: + continue + + # update information about this device + devices[d] = dict(devices[d].items() + + get_pci_device_details(d).items()) + + # check if updated information indicates that the device was bound + if "Driver_str" in devices[d]: + unbind_one(d, force) + + +def display_devices(title, dev_list, extra_params=None): + '''Displays to the user the details of a list of devices given in + "dev_list". The "extra_params" parameter, if given, should contain a string + with %()s fields in it for replacement by the named fields in each + device's dictionary.''' + strings = [] # this holds the strings to print. We sort before printing + print("\n%s" % title) + print("="*len(title)) + if len(dev_list) == 0: + strings.append("") + else: + for dev in dev_list: + if extra_params is not None: + strings.append("%s '%s' %s" % (dev["Slot"], + dev["Device_str"], extra_params % dev)) + else: + strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) + # sort before printing, so that the entries appear in PCI order + strings.sort() + print("\n".join(strings)) # print one per line + + +def show_status(): + '''Function called when the script is passed the "--status" option. + Displays to the user what devices are bound to the igb_uio driver, the + kernel driver or to no driver''' + global dpdk_drivers + kernel_drv = [] + dpdk_drv = [] + no_drv = [] + + # split our list of devices into the three categories above + for d in devices.keys(): + if not has_driver(d): + no_drv.append(devices[d]) + continue + if devices[d]["Driver_str"] in dpdk_drivers: + dpdk_drv.append(devices[d]) + else: + kernel_drv.append(devices[d]) + + # print each category separately, so we can clearly see what's used by DPDK + display_devices("Network devices using DPDK-compatible driver", dpdk_drv, + "drv=%(Driver_str)s unused=%(Module_str)s") + display_devices("Network devices using kernel driver", kernel_drv, + "if=%(Interface)s drv=%(Driver_str)s " + "unused=%(Module_str)s %(Active)s") + display_devices("Other network devices", no_drv, "unused=%(Module_str)s") + + +def parse_args(): + '''Parses the command-line arguments given by the user and takes the + appropriate action for each''' + global b_flag + global status_flag + global force_flag + global args + if len(sys.argv) <= 1: + usage() + sys.exit(0) + + try: + opts, args = getopt.getopt(sys.argv[1:], "b:us", + ["help", "usage", "status", "force", + "bind=", "unbind"]) + except getopt.GetoptError as error: + print(str(error)) + print("Run '%s --usage' for further information" % sys.argv[0]) + sys.exit(1) + + for opt, arg in opts: + if opt == "--help" or opt == "--usage": + usage() + sys.exit(0) + if opt == "--status" or opt == "-s": + status_flag = True + if opt == "--force": + force_flag = True + if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": + if b_flag is not None: + print("Error - Only one bind or unbind may be specified\n") + sys.exit(1) + if opt == "-u" or opt == "--unbind": + b_flag = "none" + else: + b_flag = arg + + +def do_arg_actions(): + '''do the actual action requested by the user''' + global b_flag + global status_flag + global force_flag + global args + + if b_flag is None and not status_flag: + print("Error: No action specified for devices." + "Please give a -b or -u option") + print("Run '%s --usage' for further information" % sys.argv[0]) + sys.exit(1) + + if b_flag is not None and len(args) == 0: + print("Error: No devices specified.") + print("Run '%s --usage' for further information" % sys.argv[0]) + sys.exit(1) + + if b_flag == "none" or b_flag == "None": + unbind_all(args, force_flag) + elif b_flag is not None: + bind_all(args, b_flag, force_flag) + if status_flag: + if b_flag is not None: + get_nic_details() # refresh if we have changed anything + show_status() + + +def main(): + '''program main function''' + parse_args() + check_modules() + get_nic_details() + do_arg_actions() + +if __name__ == "__main__": + main() diff --git a/tools/dpdk-pmdinfo.py b/tools/dpdk-pmdinfo.py new file mode 100755 index 0000000000..dcc8db864d --- /dev/null +++ b/tools/dpdk-pmdinfo.py @@ -0,0 +1,636 @@ +#!/usr/bin/env python +# ------------------------------------------------------------------------- +# +# Utility to dump PMD_INFO_STRING support from an object file +# +# ------------------------------------------------------------------------- +import os +import sys +from optparse import OptionParser +import string +import json +import platform + +# For running from development directory. It should take precedence over the +# installed pyelftools. +sys.path.insert(0, '.') + + +from elftools import __version__ +from elftools.common.exceptions import ELFError +from elftools.common.py3compat import ( + ifilter, byte2int, bytes2str, itervalues, str2bytes) +from elftools.elf.elffile import ELFFile +from elftools.elf.dynamic import DynamicSection, DynamicSegment +from elftools.elf.enums import ENUM_D_TAG +from elftools.elf.segments import InterpSegment +from elftools.elf.sections import SymbolTableSection +from elftools.elf.gnuversions import ( + GNUVerSymSection, GNUVerDefSection, + GNUVerNeedSection, +) +from elftools.elf.relocation import RelocationSection +from elftools.elf.descriptions import ( + describe_ei_class, describe_ei_data, describe_ei_version, + describe_ei_osabi, describe_e_type, describe_e_machine, + describe_e_version_numeric, describe_p_type, describe_p_flags, + describe_sh_type, describe_sh_flags, + describe_symbol_type, describe_symbol_bind, describe_symbol_visibility, + describe_symbol_shndx, describe_reloc_type, describe_dyn_tag, + describe_ver_flags, +) +from elftools.elf.constants import E_FLAGS +from elftools.dwarf.dwarfinfo import DWARFInfo +from elftools.dwarf.descriptions import ( + describe_reg_name, describe_attr_value, set_global_machine_arch, + describe_CFI_instructions, describe_CFI_register_rule, + describe_CFI_CFA_rule, +) +from elftools.dwarf.constants import ( + DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file) +from elftools.dwarf.callframe import CIE, FDE + +raw_output = False +pcidb = None + +# =========================================== + + +class Vendor: + """ + Class for vendors. This is the top level class + for the devices belong to a specific vendor. + self.devices is the device dictionary + subdevices are in each device. + """ + + def __init__(self, vendorStr): + """ + Class initializes with the raw line from pci.ids + Parsing takes place inside __init__ + """ + self.ID = vendorStr.split()[0] + self.name = vendorStr.replace("%s " % self.ID, "").rstrip() + self.devices = {} + + def addDevice(self, deviceStr): + """ + Adds a device to self.devices + takes the raw line from pci.ids + """ + s = deviceStr.strip() + devID = s.split()[0] + if devID in self.devices: + pass + else: + self.devices[devID] = Device(deviceStr) + + def report(self): + print self.ID, self.name + for id, dev in self.devices.items(): + dev.report() + + def find_device(self, devid): + # convert to a hex string and remove 0x + devid = hex(devid)[2:] + try: + return self.devices[devid] + except: + return Device("%s Unknown Device" % devid) + + +class Device: + + def __init__(self, deviceStr): + """ + Class for each device. + Each vendor has its own devices dictionary. + """ + s = deviceStr.strip() + self.ID = s.split()[0] + self.name = s.replace("%s " % self.ID, "") + self.subdevices = {} + + def report(self): + print "\t%s\t%s" % (self.ID, self.name) + for subID, subdev in self.subdevices.items(): + subdev.report() + + def addSubDevice(self, subDeviceStr): + """ + Adds a subvendor, subdevice to device. + Uses raw line from pci.ids + """ + s = subDeviceStr.strip() + spl = s.split() + subVendorID = spl[0] + subDeviceID = spl[1] + subDeviceName = s.split(" ")[-1] + devID = "%s:%s" % (subVendorID, subDeviceID) + self.subdevices[devID] = SubDevice( + subVendorID, subDeviceID, subDeviceName) + + def find_subid(self, subven, subdev): + subven = hex(subven)[2:] + subdev = hex(subdev)[2:] + devid = "%s:%s" % (subven, subdev) + + try: + return self.subdevices[devid] + except: + if (subven == "ffff" and subdev == "ffff"): + return SubDevice("ffff", "ffff", "(All Subdevices)") + else: + return SubDevice(subven, subdev, "(Unknown Subdevice)") + + +class SubDevice: + """ + Class for subdevices. + """ + + def __init__(self, vendor, device, name): + """ + Class initializes with vendorid, deviceid and name + """ + self.vendorID = vendor + self.deviceID = device + self.name = name + + def report(self): + print "\t\t%s\t%s\t%s" % (self.vendorID, self.deviceID, self.name) + + +class PCIIds: + """ + Top class for all pci.ids entries. + All queries will be asked to this class. + PCIIds.vendors["0e11"].devices["0046"].\ + subdevices["0e11:4091"].name = "Smart Array 6i" + """ + + def __init__(self, filename): + """ + Prepares the directories. + Checks local data file. + Tries to load from local, if not found, downloads from web + """ + self.version = "" + self.date = "" + self.vendors = {} + self.contents = None + self.readLocal(filename) + self.parse() + + def reportVendors(self): + """Reports the vendors + """ + for vid, v in self.vendors.items(): + print v.ID, v.name + + def report(self, vendor=None): + """ + Reports everything for all vendors or a specific vendor + PCIIds.report() reports everything + PCIIDs.report("0e11") reports only "Compaq Computer Corporation" + """ + if vendor is not None: + self.vendors[vendor].report() + else: + for vID, v in self.vendors.items(): + v.report() + + def find_vendor(self, vid): + # convert vid to a hex string and remove the 0x + vid = hex(vid)[2:] + + try: + return self.vendors[vid] + except: + return Vendor("%s Unknown Vendor" % (vid)) + + def findDate(self, content): + for l in content: + if l.find("Date:") > -1: + return l.split()[-2].replace("-", "") + return None + + def parse(self): + if len(self.contents) < 1: + print "data/%s-pci.ids not found" % self.date + else: + vendorID = "" + deviceID = "" + for l in self.contents: + if l[0] == "#": + continue + elif len(l.strip()) == 0: + continue + else: + if l.find("\t\t") == 0: + self.vendors[vendorID].devices[ + deviceID].addSubDevice(l) + elif l.find("\t") == 0: + deviceID = l.strip().split()[0] + self.vendors[vendorID].addDevice(l) + else: + vendorID = l.split()[0] + self.vendors[vendorID] = Vendor(l) + + def readLocal(self, filename): + """ + Reads the local file + """ + self.contents = open(filename).readlines() + self.date = self.findDate(self.contents) + + def loadLocal(self): + """ + Loads database from local. If there is no file, + it creates a new one from web + """ + self.date = idsfile[0].split("/")[1].split("-")[0] + self.readLocal() + + +# ======================================= + +def search_file(filename, search_path): + """ Given a search path, find file with requested name """ + for path in string.split(search_path, ":"): + candidate = os.path.join(path, filename) + if os.path.exists(candidate): + return os.path.abspath(candidate) + return None + + +class ReadElf(object): + """ display_* methods are used to emit output into the output stream + """ + + def __init__(self, file, output): + """ file: + stream object with the ELF file to read + + output: + output stream to write to + """ + self.elffile = ELFFile(file) + self.output = output + + # Lazily initialized if a debug dump is requested + self._dwarfinfo = None + + self._versioninfo = None + + def _section_from_spec(self, spec): + """ Retrieve a section given a "spec" (either number or name). + Return None if no such section exists in the file. + """ + try: + num = int(spec) + if num < self.elffile.num_sections(): + return self.elffile.get_section(num) + else: + return None + except ValueError: + # Not a number. Must be a name then + return self.elffile.get_section_by_name(str2bytes(spec)) + + def pretty_print_pmdinfo(self, pmdinfo): + global pcidb + + for i in pmdinfo["pci_ids"]: + vendor = pcidb.find_vendor(i[0]) + device = vendor.find_device(i[1]) + subdev = device.find_subid(i[2], i[3]) + print("%s (%s) : %s (%s) %s" % + (vendor.name, vendor.ID, device.name, + device.ID, subdev.name)) + + def parse_pmd_info_string(self, mystring): + global raw_output + global pcidb + + optional_pmd_info = [{'id': 'params', 'tag': 'PMD PARAMETERS'}] + + i = mystring.index("=") + mystring = mystring[i + 2:] + pmdinfo = json.loads(mystring) + + if raw_output: + print(pmdinfo) + return + + print("PMD NAME: " + pmdinfo["name"]) + for i in optional_pmd_info: + try: + print("%s: %s" % (i['tag'], pmdinfo[i['id']])) + except KeyError as e: + continue + + if (len(pmdinfo["pci_ids"]) != 0): + print("PMD HW SUPPORT:") + if pcidb is not None: + self.pretty_print_pmdinfo(pmdinfo) + else: + print("VENDOR\t DEVICE\t SUBVENDOR\t SUBDEVICE") + for i in pmdinfo["pci_ids"]: + print("0x%04x\t 0x%04x\t 0x%04x\t\t 0x%04x" % + (i[0], i[1], i[2], i[3])) + + print("") + + def display_pmd_info_strings(self, section_spec): + """ Display a strings dump of a section. section_spec is either a + section number or a name. + """ + section = self._section_from_spec(section_spec) + if section is None: + return + + data = section.data() + dataptr = 0 + + while dataptr < len(data): + while (dataptr < len(data) and + not (32 <= byte2int(data[dataptr]) <= 127)): + dataptr += 1 + + if dataptr >= len(data): + break + + endptr = dataptr + while endptr < len(data) and byte2int(data[endptr]) != 0: + endptr += 1 + + mystring = bytes2str(data[dataptr:endptr]) + rc = mystring.find("PMD_INFO_STRING") + if (rc != -1): + self.parse_pmd_info_string(mystring) + + dataptr = endptr + + def find_librte_eal(self, section): + for tag in section.iter_tags(): + if tag.entry.d_tag == 'DT_NEEDED': + if "librte_eal" in tag.needed: + return tag.needed + return None + + def search_for_autoload_path(self): + scanelf = self + scanfile = None + library = None + + section = self._section_from_spec(".dynamic") + try: + eallib = self.find_librte_eal(section) + if eallib is not None: + ldlibpath = os.environ.get('LD_LIBRARY_PATH') + if ldlibpath is None: + ldlibpath = "" + dtr = self.get_dt_runpath(section) + library = search_file(eallib, + dtr + ":" + ldlibpath + + ":/usr/lib64:/lib64:/usr/lib:/lib") + if library is None: + return (None, None) + if raw_output is False: + print("Scanning for autoload path in %s" % library) + scanfile = open(library, 'rb') + scanelf = ReadElf(scanfile, sys.stdout) + except AttributeError: + # Not a dynamic binary + pass + except ELFError: + scanfile.close() + return (None, None) + + section = scanelf._section_from_spec(".rodata") + if section is None: + if scanfile is not None: + scanfile.close() + return (None, None) + + data = section.data() + dataptr = 0 + + while dataptr < len(data): + while (dataptr < len(data) and + not (32 <= byte2int(data[dataptr]) <= 127)): + dataptr += 1 + + if dataptr >= len(data): + break + + endptr = dataptr + while endptr < len(data) and byte2int(data[endptr]) != 0: + endptr += 1 + + mystring = bytes2str(data[dataptr:endptr]) + rc = mystring.find("DPDK_PLUGIN_PATH") + if (rc != -1): + rc = mystring.find("=") + return (mystring[rc + 1:], library) + + dataptr = endptr + if scanfile is not None: + scanfile.close() + return (None, None) + + def get_dt_runpath(self, dynsec): + for tag in dynsec.iter_tags(): + if tag.entry.d_tag == 'DT_RUNPATH': + return tag.runpath + return "" + + def process_dt_needed_entries(self): + """ Look to see if there are any DT_NEEDED entries in the binary + And process those if there are + """ + global raw_output + runpath = "" + ldlibpath = os.environ.get('LD_LIBRARY_PATH') + if ldlibpath is None: + ldlibpath = "" + + dynsec = self._section_from_spec(".dynamic") + try: + runpath = self.get_dt_runpath(dynsec) + except AttributeError: + # dynsec is None, just return + return + + for tag in dynsec.iter_tags(): + if tag.entry.d_tag == 'DT_NEEDED': + rc = tag.needed.find("librte_pmd") + if (rc != -1): + library = search_file(tag.needed, + runpath + ":" + ldlibpath + + ":/usr/lib64:/lib64:/usr/lib:/lib") + if library is not None: + if raw_output is False: + print("Scanning %s for pmd information" % library) + with open(library, 'rb') as file: + try: + libelf = ReadElf(file, sys.stdout) + except ELFError as e: + print("%s is no an ELF file" % library) + continue + libelf.process_dt_needed_entries() + libelf.display_pmd_info_strings(".rodata") + file.close() + + +def scan_autoload_path(autoload_path): + global raw_output + + if os.path.exists(autoload_path) is False: + return + + try: + dirs = os.listdir(autoload_path) + except OSError as e: + # Couldn't read the directory, give up + return + + for d in dirs: + dpath = os.path.join(autoload_path, d) + if os.path.isdir(dpath): + scan_autoload_path(dpath) + if os.path.isfile(dpath): + try: + file = open(dpath, 'rb') + readelf = ReadElf(file, sys.stdout) + except ELFError as e: + # this is likely not an elf file, skip it + continue + except IOError as e: + # No permission to read the file, skip it + continue + + if raw_output is False: + print("Hw Support for library %s" % d) + readelf.display_pmd_info_strings(".rodata") + file.close() + + +def scan_for_autoload_pmds(dpdk_path): + """ + search the specified application or path for a pmd autoload path + then scan said path for pmds and report hw support + """ + global raw_output + + if (os.path.isfile(dpdk_path) is False): + if raw_output is False: + print("Must specify a file name") + return + + file = open(dpdk_path, 'rb') + try: + readelf = ReadElf(file, sys.stdout) + except ElfError as e: + if raw_output is False: + print("Unable to parse %s" % file) + return + + (autoload_path, scannedfile) = readelf.search_for_autoload_path() + if (autoload_path is None or autoload_path is ""): + if (raw_output is False): + print("No autoload path configured in %s" % dpdk_path) + return + if (raw_output is False): + if (scannedfile is None): + scannedfile = dpdk_path + print("Found autoload path %s in %s" % (autoload_path, scannedfile)) + + file.close() + if (raw_output is False): + print("Discovered Autoload HW Support:") + scan_autoload_path(autoload_path) + return + + +def main(stream=None): + global raw_output + global pcidb + + pcifile_default = "./pci.ids" # for unknown OS's assume local file + if platform.system() == 'Linux': + pcifile_default = "/usr/share/hwdata/pci.ids" + elif platform.system() == 'FreeBSD': + pcifile_default = "/usr/local/share/pciids/pci.ids" + if not os.path.exists(pcifile_default): + pcifile_default = "/usr/share/misc/pci_vendors" + + optparser = OptionParser( + usage='usage: %prog [-hrtp] [-d ', + description="Dump pmd hardware support info", + add_help_option=True) + optparser.add_option('-r', '--raw', + action='store_true', dest='raw_output', + help='Dump raw json strings') + optparser.add_option("-d", "--pcidb", dest="pcifile", + help="specify a pci database " + "to get vendor names from", + default=pcifile_default, metavar="FILE") + optparser.add_option("-t", "--table", dest="tblout", + help="output information on hw support as a hex table", + action='store_true') + optparser.add_option("-p", "--plugindir", dest="pdir", + help="scan dpdk for autoload plugins", + action='store_true') + + options, args = optparser.parse_args() + + if options.raw_output: + raw_output = True + + if options.pcifile: + pcidb = PCIIds(options.pcifile) + if pcidb is None: + print("Pci DB file not found") + exit(1) + + if options.tblout: + options.pcifile = None + pcidb = None + + if (len(args) == 0): + optparser.print_usage() + exit(1) + + if options.pdir is True: + exit(scan_for_autoload_pmds(args[0])) + + ldlibpath = os.environ.get('LD_LIBRARY_PATH') + if (ldlibpath is None): + ldlibpath = "" + + if (os.path.exists(args[0]) is True): + myelffile = args[0] + else: + myelffile = search_file( + args[0], ldlibpath + ":/usr/lib64:/lib64:/usr/lib:/lib") + + if (myelffile is None): + print("File not found") + sys.exit(1) + + with open(myelffile, 'rb') as file: + try: + readelf = ReadElf(file, sys.stdout) + readelf.process_dt_needed_entries() + readelf.display_pmd_info_strings(".rodata") + sys.exit(0) + + except ELFError as ex: + sys.stderr.write('ELF error: %s\n' % ex) + sys.exit(1) + + +# ------------------------------------------------------------------------- +if __name__ == '__main__': + main() diff --git a/tools/dpdk-setup.sh b/tools/dpdk-setup.sh new file mode 100755 index 0000000000..ac81b2e486 --- /dev/null +++ b/tools/dpdk-setup.sh @@ -0,0 +1,634 @@ +#! /bin/bash + +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# +# Run with "source /path/to/dpdk-setup.sh" +# + +# +# Change to DPDK directory ( /.. ), and export it as RTE_SDK +# +cd $(dirname ${BASH_SOURCE[0]})/.. +export RTE_SDK=$PWD +echo "------------------------------------------------------------------------------" +echo " RTE_SDK exported as $RTE_SDK" +echo "------------------------------------------------------------------------------" + +HUGEPGSZ=`cat /proc/meminfo | grep Hugepagesize | cut -d : -f 2 | tr -d ' '` + +# +# Application EAL parameters for setting memory options (amount/channels/ranks). +# +EAL_PARAMS='-n 4' + +# +# Sets QUIT variable so script will finish. +# +quit() +{ + QUIT=$1 +} + +# Shortcut for quit. +q() +{ + quit +} + +# +# Sets up environmental variables for ICC. +# +setup_icc() +{ + DEFAULT_PATH=/opt/intel/bin/iccvars.sh + param=$1 + shpath=`which iccvars.sh 2> /dev/null` + if [ $? -eq 0 ] ; then + echo "Loading iccvars.sh from $shpath for $param" + source $shpath $param + elif [ -f $DEFAULT_PATH ] ; then + echo "Loading iccvars.sh from $DEFAULT_PATH for $param" + source $DEFAULT_PATH $param + else + echo "## ERROR: cannot find 'iccvars.sh' script to set up ICC." + echo "## To fix, please add the directory that contains" + echo "## iccvars.sh to your 'PATH' environment variable." + quit + fi +} + +# +# Sets RTE_TARGET and does a "make install". +# +setup_target() +{ + option=$1 + export RTE_TARGET=${TARGETS[option]} + + compiler=${RTE_TARGET##*-} + if [ "$compiler" == "icc" ] ; then + platform=${RTE_TARGET%%-*} + if [ "$platform" == "x86_64" ] ; then + setup_icc intel64 + else + setup_icc ia32 + fi + fi + if [ "$QUIT" == "0" ] ; then + make install T=${RTE_TARGET} + fi + echo "------------------------------------------------------------------------------" + echo " RTE_TARGET exported as $RTE_TARGET" + echo "------------------------------------------------------------------------------" +} + +# +# Creates hugepage filesystem. +# +create_mnt_huge() +{ + echo "Creating /mnt/huge and mounting as hugetlbfs" + sudo mkdir -p /mnt/huge + + grep -s '/mnt/huge' /proc/mounts > /dev/null + if [ $? -ne 0 ] ; then + sudo mount -t hugetlbfs nodev /mnt/huge + fi +} + +# +# Removes hugepage filesystem. +# +remove_mnt_huge() +{ + echo "Unmounting /mnt/huge and removing directory" + grep -s '/mnt/huge' /proc/mounts > /dev/null + if [ $? -eq 0 ] ; then + sudo umount /mnt/huge + fi + + if [ -d /mnt/huge ] ; then + sudo rm -R /mnt/huge + fi +} + +# +# Unloads igb_uio.ko. +# +remove_igb_uio_module() +{ + echo "Unloading any existing DPDK UIO module" + /sbin/lsmod | grep -s igb_uio > /dev/null + if [ $? -eq 0 ] ; then + sudo /sbin/rmmod igb_uio + fi +} + +# +# Loads new igb_uio.ko (and uio module if needed). +# +load_igb_uio_module() +{ + if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko ];then + echo "## ERROR: Target does not have the DPDK UIO Kernel Module." + echo " To fix, please try to rebuild target." + return + fi + + remove_igb_uio_module + + /sbin/lsmod | grep -s uio > /dev/null + if [ $? -ne 0 ] ; then + modinfo uio > /dev/null + if [ $? -eq 0 ]; then + echo "Loading uio module" + sudo /sbin/modprobe uio + fi + fi + + # UIO may be compiled into kernel, so it may not be an error if it can't + # be loaded. + + echo "Loading DPDK UIO module" + sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko + if [ $? -ne 0 ] ; then + echo "## ERROR: Could not load kmod/igb_uio.ko." + quit + fi +} + +# +# Unloads VFIO modules. +# +remove_vfio_module() +{ + echo "Unloading any existing VFIO module" + /sbin/lsmod | grep -s vfio > /dev/null + if [ $? -eq 0 ] ; then + sudo /sbin/rmmod vfio-pci + sudo /sbin/rmmod vfio_iommu_type1 + sudo /sbin/rmmod vfio + fi +} + +# +# Loads new vfio-pci (and vfio module if needed). +# +load_vfio_module() +{ + remove_vfio_module + + VFIO_PATH="kernel/drivers/vfio/pci/vfio-pci.ko" + + echo "Loading VFIO module" + /sbin/lsmod | grep -s vfio_pci > /dev/null + if [ $? -ne 0 ] ; then + if [ -f /lib/modules/$(uname -r)/$VFIO_PATH ] ; then + sudo /sbin/modprobe vfio-pci + fi + fi + + # make sure regular users can read /dev/vfio + echo "chmod /dev/vfio" + sudo chmod a+x /dev/vfio + if [ $? -ne 0 ] ; then + echo "FAIL" + quit + fi + echo "OK" + + # check if /dev/vfio/vfio exists - that way we + # know we either loaded the module, or it was + # compiled into the kernel + if [ ! -e /dev/vfio/vfio ] ; then + echo "## ERROR: VFIO not found!" + fi +} + +# +# Unloads the rte_kni.ko module. +# +remove_kni_module() +{ + echo "Unloading any existing DPDK KNI module" + /sbin/lsmod | grep -s rte_kni > /dev/null + if [ $? -eq 0 ] ; then + sudo /sbin/rmmod rte_kni + fi +} + +# +# Loads the rte_kni.ko module. +# +load_kni_module() +{ + # Check that the KNI module is already built. + if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/rte_kni.ko ];then + echo "## ERROR: Target does not have the DPDK KNI Module." + echo " To fix, please try to rebuild target." + return + fi + + # Unload existing version if present. + remove_kni_module + + # Now try load the KNI module. + echo "Loading DPDK KNI module" + sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/rte_kni.ko + if [ $? -ne 0 ] ; then + echo "## ERROR: Could not load kmod/rte_kni.ko." + quit + fi +} + +# +# Sets appropriate permissions on /dev/vfio/* files +# +set_vfio_permissions() +{ + # make sure regular users can read /dev/vfio + echo "chmod /dev/vfio" + sudo chmod a+x /dev/vfio + if [ $? -ne 0 ] ; then + echo "FAIL" + quit + fi + echo "OK" + + # make sure regular user can access everything inside /dev/vfio + echo "chmod /dev/vfio/*" + sudo chmod 0666 /dev/vfio/* + if [ $? -ne 0 ] ; then + echo "FAIL" + quit + fi + echo "OK" + + # since permissions are only to be set when running as + # regular user, we only check ulimit here + # + # warn if regular user is only allowed + # to memlock <64M of memory + MEMLOCK_AMNT=`ulimit -l` + + if [ "$MEMLOCK_AMNT" != "unlimited" ] ; then + MEMLOCK_MB=`expr $MEMLOCK_AMNT / 1024` + echo "" + echo "Current user memlock limit: ${MEMLOCK_MB} MB" + echo "" + echo "This is the maximum amount of memory you will be" + echo "able to use with DPDK and VFIO if run as current user." + echo -n "To change this, please adjust limits.conf memlock " + echo "limit for current user." + + if [ $MEMLOCK_AMNT -lt 65536 ] ; then + echo "" + echo "## WARNING: memlock limit is less than 64MB" + echo -n "## DPDK with VFIO may not be able to initialize " + echo "if run as current user." + fi + fi +} + +# +# Removes all reserved hugepages. +# +clear_huge_pages() +{ + echo > .echo_tmp + for d in /sys/devices/system/node/node? ; do + echo "echo 0 > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp + done + echo "Removing currently reserved hugepages" + sudo sh .echo_tmp + rm -f .echo_tmp + + remove_mnt_huge +} + +# +# Creates hugepages. +# +set_non_numa_pages() +{ + clear_huge_pages + + echo "" + echo " Input the number of ${HUGEPGSZ} hugepages" + echo " Example: to have 128MB of hugepages available in a 2MB huge page system," + echo " enter '64' to reserve 64 * 2MB pages" + echo -n "Number of pages: " + read Pages + + echo "echo $Pages > /sys/kernel/mm/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" > .echo_tmp + + echo "Reserving hugepages" + sudo sh .echo_tmp + rm -f .echo_tmp + + create_mnt_huge +} + +# +# Creates hugepages on specific NUMA nodes. +# +set_numa_pages() +{ + clear_huge_pages + + echo "" + echo " Input the number of ${HUGEPGSZ} hugepages for each node" + echo " Example: to have 128MB of hugepages available per node in a 2MB huge page system," + echo " enter '64' to reserve 64 * 2MB pages on each node" + + echo > .echo_tmp + for d in /sys/devices/system/node/node? ; do + node=$(basename $d) + echo -n "Number of pages for $node: " + read Pages + echo "echo $Pages > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp + done + echo "Reserving hugepages" + sudo sh .echo_tmp + rm -f .echo_tmp + + create_mnt_huge +} + +# +# Run unit test application. +# +run_test_app() +{ + echo "" + echo " Enter hex bitmask of cores to execute test app on" + echo " Example: to execute app on cores 0 to 7, enter 0xff" + echo -n "bitmask: " + read Bitmask + echo "Launching app" + sudo ${RTE_TARGET}/app/test -c $Bitmask $EAL_PARAMS +} + +# +# Run unit testpmd application. +# +run_testpmd_app() +{ + echo "" + echo " Enter hex bitmask of cores to execute testpmd app on" + echo " Example: to execute app on cores 0 to 7, enter 0xff" + echo -n "bitmask: " + read Bitmask + echo "Launching app" + sudo ${RTE_TARGET}/app/testpmd -c $Bitmask $EAL_PARAMS -- -i +} + +# +# Print hugepage information. +# +grep_meminfo() +{ + grep -i huge /proc/meminfo +} + +# +# Calls dpdk-devbind.py --status to show the NIC and what they +# are all bound to, in terms of drivers. +# +show_nics() +{ + if [ -d /sys/module/vfio_pci -o -d /sys/module/igb_uio ]; then + ${RTE_SDK}/tools/dpdk-devbind.py --status + else + echo "# Please load the 'igb_uio' or 'vfio-pci' kernel module before " + echo "# querying or adjusting NIC device bindings" + fi +} + +# +# Uses dpdk-devbind.py to move devices to work with vfio-pci +# +bind_nics_to_vfio() +{ + if [ -d /sys/module/vfio_pci ]; then + ${RTE_SDK}/tools/dpdk-devbind.py --status + echo "" + echo -n "Enter PCI address of device to bind to VFIO driver: " + read PCI_PATH + sudo ${RTE_SDK}/tools/dpdk-devbind.py -b vfio-pci $PCI_PATH && + echo "OK" + else + echo "# Please load the 'vfio-pci' kernel module before querying or " + echo "# adjusting NIC device bindings" + fi +} + +# +# Uses dpdk-devbind.py to move devices to work with igb_uio +# +bind_nics_to_igb_uio() +{ + if [ -d /sys/module/igb_uio ]; then + ${RTE_SDK}/tools/dpdk-devbind.py --status + echo "" + echo -n "Enter PCI address of device to bind to IGB UIO driver: " + read PCI_PATH + sudo ${RTE_SDK}/tools/dpdk-devbind.py -b igb_uio $PCI_PATH && echo "OK" + else + echo "# Please load the 'igb_uio' kernel module before querying or " + echo "# adjusting NIC device bindings" + fi +} + +# +# Uses dpdk-devbind.py to move devices to work with kernel drivers again +# +unbind_nics() +{ + ${RTE_SDK}/tools/dpdk-devbind.py --status + echo "" + echo -n "Enter PCI address of device to unbind: " + read PCI_PATH + echo "" + echo -n "Enter name of kernel driver to bind the device to: " + read DRV + sudo ${RTE_SDK}/tools/dpdk-devbind.py -b $DRV $PCI_PATH && echo "OK" +} + +# +# Options for building a target. Note that this step MUST be first as it sets +# up TARGETS[] starting from 1, and this is accessed in setup_target using the +# user entered option. +# +step1_func() +{ + TITLE="Select the DPDK environment to build" + CONFIG_NUM=1 + for cfg in config/defconfig_* ; do + cfg=${cfg/config\/defconfig_/} + TEXT[$CONFIG_NUM]="$cfg" + TARGETS[$CONFIG_NUM]=$cfg + FUNC[$CONFIG_NUM]="setup_target" + let "CONFIG_NUM+=1" + done +} + +# +# Options for setting up environment. +# +step2_func() +{ + TITLE="Setup linuxapp environment" + + TEXT[1]="Insert IGB UIO module" + FUNC[1]="load_igb_uio_module" + + TEXT[2]="Insert VFIO module" + FUNC[2]="load_vfio_module" + + TEXT[3]="Insert KNI module" + FUNC[3]="load_kni_module" + + TEXT[4]="Setup hugepage mappings for non-NUMA systems" + FUNC[4]="set_non_numa_pages" + + TEXT[5]="Setup hugepage mappings for NUMA systems" + FUNC[5]="set_numa_pages" + + TEXT[6]="Display current Ethernet device settings" + FUNC[6]="show_nics" + + TEXT[7]="Bind Ethernet device to IGB UIO module" + FUNC[7]="bind_nics_to_igb_uio" + + TEXT[8]="Bind Ethernet device to VFIO module" + FUNC[8]="bind_nics_to_vfio" + + TEXT[9]="Setup VFIO permissions" + FUNC[9]="set_vfio_permissions" +} + +# +# Options for running applications. +# +step3_func() +{ + TITLE="Run test application for linuxapp environment" + + TEXT[1]="Run test application (\$RTE_TARGET/app/test)" + FUNC[1]="run_test_app" + + TEXT[2]="Run testpmd application in interactive mode (\$RTE_TARGET/app/testpmd)" + FUNC[2]="run_testpmd_app" +} + +# +# Other options +# +step4_func() +{ + TITLE="Other tools" + + TEXT[1]="List hugepage info from /proc/meminfo" + FUNC[1]="grep_meminfo" + +} + +# +# Options for cleaning up the system +# +step5_func() +{ + TITLE="Uninstall and system cleanup" + + TEXT[1]="Unbind NICs from IGB UIO or VFIO driver" + FUNC[1]="unbind_nics" + + TEXT[2]="Remove IGB UIO module" + FUNC[2]="remove_igb_uio_module" + + TEXT[3]="Remove VFIO module" + FUNC[3]="remove_vfio_module" + + TEXT[4]="Remove KNI module" + FUNC[4]="remove_kni_module" + + TEXT[5]="Remove hugepage mappings" + FUNC[5]="clear_huge_pages" +} + +STEPS[1]="step1_func" +STEPS[2]="step2_func" +STEPS[3]="step3_func" +STEPS[4]="step4_func" +STEPS[5]="step5_func" + +QUIT=0 + +while [ "$QUIT" == "0" ]; do + OPTION_NUM=1 + + for s in $(seq ${#STEPS[@]}) ; do + ${STEPS[s]} + + echo "----------------------------------------------------------" + echo " Step $s: ${TITLE}" + echo "----------------------------------------------------------" + + for i in $(seq ${#TEXT[@]}) ; do + echo "[$OPTION_NUM] ${TEXT[i]}" + OPTIONS[$OPTION_NUM]=${FUNC[i]} + let "OPTION_NUM+=1" + done + + # Clear TEXT and FUNC arrays before next step + unset TEXT + unset FUNC + + echo "" + done + + echo "[$OPTION_NUM] Exit Script" + OPTIONS[$OPTION_NUM]="quit" + echo "" + echo -n "Option: " + read our_entry + echo "" + ${OPTIONS[our_entry]} ${our_entry} + + if [ "$QUIT" == "0" ] ; then + echo + echo -n "Press enter to continue ..."; read + fi + +done diff --git a/tools/dpdk_nic_bind.py b/tools/dpdk_nic_bind.py deleted file mode 100755 index b69ca2a0db..0000000000 --- a/tools/dpdk_nic_bind.py +++ /dev/null @@ -1,576 +0,0 @@ -#! /usr/bin/python -# -# BSD LICENSE -# -# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Intel Corporation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -import sys -import os -import getopt -import subprocess -from os.path import exists, abspath, dirname, basename - -# The PCI base class for NETWORK devices -NETWORK_BASE_CLASS = "02" - -# global dict ethernet devices present. Dictionary indexed by PCI address. -# Each device within this is itself a dictionary of device properties -devices = {} -# list of supported DPDK drivers -dpdk_drivers = ["igb_uio", "vfio-pci", "uio_pci_generic"] - -# command-line arg flags -b_flag = None -status_flag = False -force_flag = False -args = [] - - -def usage(): - '''Print usage information for the program''' - argv0 = basename(sys.argv[0]) - print(""" -Usage: ------- - - %(argv0)s [options] DEVICE1 DEVICE2 .... - -where DEVICE1, DEVICE2 etc, are specified via PCI "domain:bus:slot.func" syntax -or "bus:slot.func" syntax. For devices bound to Linux kernel drivers, they may -also be referred to by Linux interface name e.g. eth0, eth1, em0, em1, etc. - -Options: - --help, --usage: - Display usage information and quit - - -s, --status: - Print the current status of all known network interfaces. - For each device, it displays the PCI domain, bus, slot and function, - along with a text description of the device. Depending upon whether the - device is being used by a kernel driver, the igb_uio driver, or no - driver, other relevant information will be displayed: - * the Linux interface name e.g. if=eth0 - * the driver being used e.g. drv=igb_uio - * any suitable drivers not currently using that device - e.g. unused=igb_uio - NOTE: if this flag is passed along with a bind/unbind option, the - status display will always occur after the other operations have taken - place. - - -b driver, --bind=driver: - Select the driver to use or \"none\" to unbind the device - - -u, --unbind: - Unbind a device (Equivalent to \"-b none\") - - --force: - By default, devices which are used by Linux - as indicated by having - routes in the routing table - cannot be modified. Using the --force - flag overrides this behavior, allowing active links to be forcibly - unbound. - WARNING: This can lead to loss of network connection and should be used - with caution. - -Examples: ---------- - -To display current device status: - %(argv0)s --status - -To bind eth1 from the current driver and move to use igb_uio - %(argv0)s --bind=igb_uio eth1 - -To unbind 0000:01:00.0 from using any driver - %(argv0)s -u 0000:01:00.0 - -To bind 0000:02:00.0 and 0000:02:00.1 to the ixgbe kernel driver - %(argv0)s -b ixgbe 02:00.0 02:00.1 - - """ % locals()) # replace items from local variables - - -# This is roughly compatible with check_output function in subprocess module -# which is only available in python 2.7. -def check_output(args, stderr=None): - '''Run a command and capture its output''' - return subprocess.Popen(args, stdout=subprocess.PIPE, - stderr=stderr).communicate()[0] - - -def find_module(mod): - '''find the .ko file for kernel module named mod. - Searches the $RTE_SDK/$RTE_TARGET directory, the kernel - modules directory and finally under the parent directory of - the script ''' - # check $RTE_SDK/$RTE_TARGET directory - if 'RTE_SDK' in os.environ and 'RTE_TARGET' in os.environ: - path = "%s/%s/kmod/%s.ko" % (os.environ['RTE_SDK'], - os.environ['RTE_TARGET'], mod) - if exists(path): - return path - - # check using depmod - try: - depmod_out = check_output(["modinfo", "-n", mod], - stderr=subprocess.STDOUT).lower() - if "error" not in depmod_out: - path = depmod_out.strip() - if exists(path): - return path - except: # if modinfo can't find module, it fails, so continue - pass - - # check for a copy based off current path - tools_dir = dirname(abspath(sys.argv[0])) - if (tools_dir.endswith("tools")): - base_dir = dirname(tools_dir) - find_out = check_output(["find", base_dir, "-name", mod + ".ko"]) - if len(find_out) > 0: # something matched - path = find_out.splitlines()[0] - if exists(path): - return path - - -def check_modules(): - '''Checks that igb_uio is loaded''' - global dpdk_drivers - - # list of supported modules - mods = [{"Name": driver, "Found": False} for driver in dpdk_drivers] - - # first check if module is loaded - try: - # Get list of sysfs modules (both built-in and dynamically loaded) - sysfs_path = '/sys/module/' - - # Get the list of directories in sysfs_path - sysfs_mods = [os.path.join(sysfs_path, o) for o - in os.listdir(sysfs_path) - if os.path.isdir(os.path.join(sysfs_path, o))] - - # Extract the last element of '/sys/module/abc' in the array - sysfs_mods = [a.split('/')[-1] for a in sysfs_mods] - - # special case for vfio_pci (module is named vfio-pci, - # but its .ko is named vfio_pci) - sysfs_mods = map(lambda a: - a if a != 'vfio_pci' else 'vfio-pci', sysfs_mods) - - for mod in mods: - if mod["Name"] in sysfs_mods: - mod["Found"] = True - except: - pass - - # check if we have at least one loaded module - if True not in [mod["Found"] for mod in mods] and b_flag is not None: - if b_flag in dpdk_drivers: - print("Error - no supported modules(DPDK driver) are loaded") - sys.exit(1) - else: - print("Warning - no supported modules(DPDK driver) are loaded") - - # change DPDK driver list to only contain drivers that are loaded - dpdk_drivers = [mod["Name"] for mod in mods if mod["Found"]] - - -def has_driver(dev_id): - '''return true if a device is assigned to a driver. False otherwise''' - return "Driver_str" in devices[dev_id] - - -def get_pci_device_details(dev_id): - '''This function gets additional details for a PCI device''' - device = {} - - extra_info = check_output(["lspci", "-vmmks", dev_id]).splitlines() - - # parse lspci details - for line in extra_info: - if len(line) == 0: - continue - name, value = line.decode().split("\t", 1) - name = name.strip(":") + "_str" - device[name] = value - # check for a unix interface name - sys_path = "/sys/bus/pci/devices/%s/net/" % dev_id - if exists(sys_path): - device["Interface"] = ",".join(os.listdir(sys_path)) - else: - device["Interface"] = "" - # check if a port is used for ssh connection - device["Ssh_if"] = False - device["Active"] = "" - - return device - - -def get_nic_details(): - '''This function populates the "devices" dictionary. The keys used are - the pci addresses (domain:bus:slot.func). The values are themselves - dictionaries - one for each NIC.''' - global devices - global dpdk_drivers - - # clear any old data - devices = {} - # first loop through and read details for all devices - # request machine readable format, with numeric IDs - dev = {} - dev_lines = check_output(["lspci", "-Dvmmn"]).splitlines() - for dev_line in dev_lines: - if (len(dev_line) == 0): - if dev["Class"][0:2] == NETWORK_BASE_CLASS: - # convert device and vendor ids to numbers, then add to global - dev["Vendor"] = int(dev["Vendor"], 16) - dev["Device"] = int(dev["Device"], 16) - # use dict to make copy of dev - devices[dev["Slot"]] = dict(dev) - else: - name, value = dev_line.decode().split("\t", 1) - dev[name.rstrip(":")] = value - - # check what is the interface if any for an ssh connection if - # any to this host, so we can mark it later. - ssh_if = [] - route = check_output(["ip", "-o", "route"]) - # filter out all lines for 169.254 routes - route = "\n".join(filter(lambda ln: not ln.startswith("169.254"), - route.decode().splitlines())) - rt_info = route.split() - for i in range(len(rt_info) - 1): - if rt_info[i] == "dev": - ssh_if.append(rt_info[i+1]) - - # based on the basic info, get extended text details - for d in devices.keys(): - # get additional info and add it to existing data - devices[d] = devices[d].copy() - devices[d].update(get_pci_device_details(d).items()) - - for _if in ssh_if: - if _if in devices[d]["Interface"].split(","): - devices[d]["Ssh_if"] = True - devices[d]["Active"] = "*Active*" - break - - # add igb_uio to list of supporting modules if needed - if "Module_str" in devices[d]: - for driver in dpdk_drivers: - if driver not in devices[d]["Module_str"]: - devices[d]["Module_str"] = \ - devices[d]["Module_str"] + ",%s" % driver - else: - devices[d]["Module_str"] = ",".join(dpdk_drivers) - - # make sure the driver and module strings do not have any duplicates - if has_driver(d): - modules = devices[d]["Module_str"].split(",") - if devices[d]["Driver_str"] in modules: - modules.remove(devices[d]["Driver_str"]) - devices[d]["Module_str"] = ",".join(modules) - - -def dev_id_from_dev_name(dev_name): - '''Take a device "name" - a string passed in by user to identify a NIC - device, and determine the device id - i.e. the domain:bus:slot.func - for - it, which can then be used to index into the devices array''' - - # check if it's already a suitable index - if dev_name in devices: - return dev_name - # check if it's an index just missing the domain part - elif "0000:" + dev_name in devices: - return "0000:" + dev_name - else: - # check if it's an interface name, e.g. eth1 - for d in devices.keys(): - if dev_name in devices[d]["Interface"].split(","): - return devices[d]["Slot"] - # if nothing else matches - error - print("Unknown device: %s. " - "Please specify device in \"bus:slot.func\" format" % dev_name) - sys.exit(1) - - -def unbind_one(dev_id, force): - '''Unbind the device identified by "dev_id" from its current driver''' - dev = devices[dev_id] - if not has_driver(dev_id): - print("%s %s %s is not currently managed by any driver\n" % - (dev["Slot"], dev["Device_str"], dev["Interface"])) - return - - # prevent us disconnecting ourselves - if dev["Ssh_if"] and not force: - print("Routing table indicates that interface %s is active. " - "Skipping unbind" % (dev_id)) - return - - # write to /sys to unbind - filename = "/sys/bus/pci/drivers/%s/unbind" % dev["Driver_str"] - try: - f = open(filename, "a") - except: - print("Error: unbind failed for %s - Cannot open %s" - % (dev_id, filename)) - sys.exit(1) - f.write(dev_id) - f.close() - - -def bind_one(dev_id, driver, force): - '''Bind the device given by "dev_id" to the driver "driver". If the device - is already bound to a different driver, it will be unbound first''' - dev = devices[dev_id] - saved_driver = None # used to rollback any unbind in case of failure - - # prevent disconnection of our ssh session - if dev["Ssh_if"] and not force: - print("Routing table indicates that interface %s is active. " - "Not modifying" % (dev_id)) - return - - # unbind any existing drivers we don't want - if has_driver(dev_id): - if dev["Driver_str"] == driver: - print("%s already bound to driver %s, skipping\n" - % (dev_id, driver)) - return - else: - saved_driver = dev["Driver_str"] - unbind_one(dev_id, force) - dev["Driver_str"] = "" # clear driver string - - # if we are binding to one of DPDK drivers, add PCI id's to that driver - if driver in dpdk_drivers: - filename = "/sys/bus/pci/drivers/%s/new_id" % driver - try: - f = open(filename, "w") - except: - print("Error: bind failed for %s - Cannot open %s" - % (dev_id, filename)) - return - try: - f.write("%04x %04x" % (dev["Vendor"], dev["Device"])) - f.close() - except: - print("Error: bind failed for %s - Cannot write new PCI ID to " - "driver %s" % (dev_id, driver)) - return - - # do the bind by writing to /sys - filename = "/sys/bus/pci/drivers/%s/bind" % driver - try: - f = open(filename, "a") - except: - print("Error: bind failed for %s - Cannot open %s" - % (dev_id, filename)) - if saved_driver is not None: # restore any previous driver - bind_one(dev_id, saved_driver, force) - return - try: - f.write(dev_id) - f.close() - except: - # for some reason, closing dev_id after adding a new PCI ID to new_id - # results in IOError. however, if the device was successfully bound, - # we don't care for any errors and can safely ignore IOError - tmp = get_pci_device_details(dev_id) - if "Driver_str" in tmp and tmp["Driver_str"] == driver: - return - print("Error: bind failed for %s - Cannot bind to driver %s" - % (dev_id, driver)) - if saved_driver is not None: # restore any previous driver - bind_one(dev_id, saved_driver, force) - return - - -def unbind_all(dev_list, force=False): - """Unbind method, takes a list of device locations""" - dev_list = map(dev_id_from_dev_name, dev_list) - for d in dev_list: - unbind_one(d, force) - - -def bind_all(dev_list, driver, force=False): - """Bind method, takes a list of device locations""" - global devices - - dev_list = map(dev_id_from_dev_name, dev_list) - - for d in dev_list: - bind_one(d, driver, force) - - # when binding devices to a generic driver (i.e. one that doesn't have a - # PCI ID table), some devices that are not bound to any other driver could - # be bound even if no one has asked them to. hence, we check the list of - # drivers again, and see if some of the previously-unbound devices were - # erroneously bound. - for d in devices.keys(): - # skip devices that were already bound or that we know should be bound - if "Driver_str" in devices[d] or d in dev_list: - continue - - # update information about this device - devices[d] = dict(devices[d].items() + - get_pci_device_details(d).items()) - - # check if updated information indicates that the device was bound - if "Driver_str" in devices[d]: - unbind_one(d, force) - - -def display_devices(title, dev_list, extra_params=None): - '''Displays to the user the details of a list of devices given in - "dev_list". The "extra_params" parameter, if given, should contain a string - with %()s fields in it for replacement by the named fields in each - device's dictionary.''' - strings = [] # this holds the strings to print. We sort before printing - print("\n%s" % title) - print("="*len(title)) - if len(dev_list) == 0: - strings.append("") - else: - for dev in dev_list: - if extra_params is not None: - strings.append("%s '%s' %s" % (dev["Slot"], - dev["Device_str"], extra_params % dev)) - else: - strings.append("%s '%s'" % (dev["Slot"], dev["Device_str"])) - # sort before printing, so that the entries appear in PCI order - strings.sort() - print("\n".join(strings)) # print one per line - - -def show_status(): - '''Function called when the script is passed the "--status" option. - Displays to the user what devices are bound to the igb_uio driver, the - kernel driver or to no driver''' - global dpdk_drivers - kernel_drv = [] - dpdk_drv = [] - no_drv = [] - - # split our list of devices into the three categories above - for d in devices.keys(): - if not has_driver(d): - no_drv.append(devices[d]) - continue - if devices[d]["Driver_str"] in dpdk_drivers: - dpdk_drv.append(devices[d]) - else: - kernel_drv.append(devices[d]) - - # print each category separately, so we can clearly see what's used by DPDK - display_devices("Network devices using DPDK-compatible driver", dpdk_drv, - "drv=%(Driver_str)s unused=%(Module_str)s") - display_devices("Network devices using kernel driver", kernel_drv, - "if=%(Interface)s drv=%(Driver_str)s " - "unused=%(Module_str)s %(Active)s") - display_devices("Other network devices", no_drv, "unused=%(Module_str)s") - - -def parse_args(): - '''Parses the command-line arguments given by the user and takes the - appropriate action for each''' - global b_flag - global status_flag - global force_flag - global args - if len(sys.argv) <= 1: - usage() - sys.exit(0) - - try: - opts, args = getopt.getopt(sys.argv[1:], "b:us", - ["help", "usage", "status", "force", - "bind=", "unbind"]) - except getopt.GetoptError as error: - print(str(error)) - print("Run '%s --usage' for further information" % sys.argv[0]) - sys.exit(1) - - for opt, arg in opts: - if opt == "--help" or opt == "--usage": - usage() - sys.exit(0) - if opt == "--status" or opt == "-s": - status_flag = True - if opt == "--force": - force_flag = True - if opt == "-b" or opt == "-u" or opt == "--bind" or opt == "--unbind": - if b_flag is not None: - print("Error - Only one bind or unbind may be specified\n") - sys.exit(1) - if opt == "-u" or opt == "--unbind": - b_flag = "none" - else: - b_flag = arg - - -def do_arg_actions(): - '''do the actual action requested by the user''' - global b_flag - global status_flag - global force_flag - global args - - if b_flag is None and not status_flag: - print("Error: No action specified for devices." - "Please give a -b or -u option") - print("Run '%s --usage' for further information" % sys.argv[0]) - sys.exit(1) - - if b_flag is not None and len(args) == 0: - print("Error: No devices specified.") - print("Run '%s --usage' for further information" % sys.argv[0]) - sys.exit(1) - - if b_flag == "none" or b_flag == "None": - unbind_all(args, force_flag) - elif b_flag is not None: - bind_all(args, b_flag, force_flag) - if status_flag: - if b_flag is not None: - get_nic_details() # refresh if we have changed anything - show_status() - - -def main(): - '''program main function''' - parse_args() - check_modules() - get_nic_details() - do_arg_actions() - -if __name__ == "__main__": - main() diff --git a/tools/pmdinfo.py b/tools/pmdinfo.py deleted file mode 100755 index 662034af6f..0000000000 --- a/tools/pmdinfo.py +++ /dev/null @@ -1,638 +0,0 @@ -#!/usr/bin/env python -# ------------------------------------------------------------------------- -# scripts/pmdinfo.py -# -# Utility to dump PMD_INFO_STRING support from an object file -# -# ------------------------------------------------------------------------- -import os -import sys -from optparse import OptionParser -import string -import json -import platform - -# For running from development directory. It should take precedence over the -# installed pyelftools. -sys.path.insert(0, '.') - - -from elftools import __version__ -from elftools.common.exceptions import ELFError -from elftools.common.py3compat import ( - ifilter, byte2int, bytes2str, itervalues, str2bytes) -from elftools.elf.elffile import ELFFile -from elftools.elf.dynamic import DynamicSection, DynamicSegment -from elftools.elf.enums import ENUM_D_TAG -from elftools.elf.segments import InterpSegment -from elftools.elf.sections import SymbolTableSection -from elftools.elf.gnuversions import ( - GNUVerSymSection, GNUVerDefSection, - GNUVerNeedSection, -) -from elftools.elf.relocation import RelocationSection -from elftools.elf.descriptions import ( - describe_ei_class, describe_ei_data, describe_ei_version, - describe_ei_osabi, describe_e_type, describe_e_machine, - describe_e_version_numeric, describe_p_type, describe_p_flags, - describe_sh_type, describe_sh_flags, - describe_symbol_type, describe_symbol_bind, describe_symbol_visibility, - describe_symbol_shndx, describe_reloc_type, describe_dyn_tag, - describe_ver_flags, -) -from elftools.elf.constants import E_FLAGS -from elftools.dwarf.dwarfinfo import DWARFInfo -from elftools.dwarf.descriptions import ( - describe_reg_name, describe_attr_value, set_global_machine_arch, - describe_CFI_instructions, describe_CFI_register_rule, - describe_CFI_CFA_rule, -) -from elftools.dwarf.constants import ( - DW_LNS_copy, DW_LNS_set_file, DW_LNE_define_file) -from elftools.dwarf.callframe import CIE, FDE - -raw_output = False -pcidb = None - -# =========================================== - - -class Vendor: - """ - Class for vendors. This is the top level class - for the devices belong to a specific vendor. - self.devices is the device dictionary - subdevices are in each device. - """ - - def __init__(self, vendorStr): - """ - Class initializes with the raw line from pci.ids - Parsing takes place inside __init__ - """ - self.ID = vendorStr.split()[0] - self.name = vendorStr.replace("%s " % self.ID, "").rstrip() - self.devices = {} - - def addDevice(self, deviceStr): - """ - Adds a device to self.devices - takes the raw line from pci.ids - """ - s = deviceStr.strip() - devID = s.split()[0] - if devID in self.devices: - pass - else: - self.devices[devID] = Device(deviceStr) - - def report(self): - print self.ID, self.name - for id, dev in self.devices.items(): - dev.report() - - def find_device(self, devid): - # convert to a hex string and remove 0x - devid = hex(devid)[2:] - try: - return self.devices[devid] - except: - return Device("%s Unknown Device" % devid) - - -class Device: - - def __init__(self, deviceStr): - """ - Class for each device. - Each vendor has its own devices dictionary. - """ - s = deviceStr.strip() - self.ID = s.split()[0] - self.name = s.replace("%s " % self.ID, "") - self.subdevices = {} - - def report(self): - print "\t%s\t%s" % (self.ID, self.name) - for subID, subdev in self.subdevices.items(): - subdev.report() - - def addSubDevice(self, subDeviceStr): - """ - Adds a subvendor, subdevice to device. - Uses raw line from pci.ids - """ - s = subDeviceStr.strip() - spl = s.split() - subVendorID = spl[0] - subDeviceID = spl[1] - subDeviceName = s.split(" ")[-1] - devID = "%s:%s" % (subVendorID, subDeviceID) - self.subdevices[devID] = SubDevice( - subVendorID, subDeviceID, subDeviceName) - - def find_subid(self, subven, subdev): - subven = hex(subven)[2:] - subdev = hex(subdev)[2:] - devid = "%s:%s" % (subven, subdev) - - try: - return self.subdevices[devid] - except: - if (subven == "ffff" and subdev == "ffff"): - return SubDevice("ffff", "ffff", "(All Subdevices)") - else: - return SubDevice(subven, subdev, "(Unknown Subdevice)") - - -class SubDevice: - """ - Class for subdevices. - """ - - def __init__(self, vendor, device, name): - """ - Class initializes with vendorid, deviceid and name - """ - self.vendorID = vendor - self.deviceID = device - self.name = name - - def report(self): - print "\t\t%s\t%s\t%s" % (self.vendorID, self.deviceID, self.name) - - -class PCIIds: - """ - Top class for all pci.ids entries. - All queries will be asked to this class. - PCIIds.vendors["0e11"].devices["0046"].\ - subdevices["0e11:4091"].name = "Smart Array 6i" - """ - - def __init__(self, filename): - """ - Prepares the directories. - Checks local data file. - Tries to load from local, if not found, downloads from web - """ - self.version = "" - self.date = "" - self.vendors = {} - self.contents = None - self.readLocal(filename) - self.parse() - - def reportVendors(self): - """Reports the vendors - """ - for vid, v in self.vendors.items(): - print v.ID, v.name - - def report(self, vendor=None): - """ - Reports everything for all vendors or a specific vendor - PCIIds.report() reports everything - PCIIDs.report("0e11") reports only "Compaq Computer Corporation" - """ - if vendor is not None: - self.vendors[vendor].report() - else: - for vID, v in self.vendors.items(): - v.report() - - def find_vendor(self, vid): - # convert vid to a hex string and remove the 0x - vid = hex(vid)[2:] - - try: - return self.vendors[vid] - except: - return Vendor("%s Unknown Vendor" % (vid)) - - def findDate(self, content): - for l in content: - if l.find("Date:") > -1: - return l.split()[-2].replace("-", "") - return None - - def parse(self): - if len(self.contents) < 1: - print "data/%s-pci.ids not found" % self.date - else: - vendorID = "" - deviceID = "" - for l in self.contents: - if l[0] == "#": - continue - elif len(l.strip()) == 0: - continue - else: - if l.find("\t\t") == 0: - self.vendors[vendorID].devices[ - deviceID].addSubDevice(l) - elif l.find("\t") == 0: - deviceID = l.strip().split()[0] - self.vendors[vendorID].addDevice(l) - else: - vendorID = l.split()[0] - self.vendors[vendorID] = Vendor(l) - - def readLocal(self, filename): - """ - Reads the local file - """ - self.contents = open(filename).readlines() - self.date = self.findDate(self.contents) - - def loadLocal(self): - """ - Loads database from local. If there is no file, - it creates a new one from web - """ - self.date = idsfile[0].split("/")[1].split("-")[0] - self.readLocal() - - -# ======================================= - -def search_file(filename, search_path): - """ Given a search path, find file with requested name """ - for path in string.split(search_path, ":"): - candidate = os.path.join(path, filename) - if os.path.exists(candidate): - return os.path.abspath(candidate) - return None - - -class ReadElf(object): - """ display_* methods are used to emit output into the output stream - """ - - def __init__(self, file, output): - """ file: - stream object with the ELF file to read - - output: - output stream to write to - """ - self.elffile = ELFFile(file) - self.output = output - - # Lazily initialized if a debug dump is requested - self._dwarfinfo = None - - self._versioninfo = None - - def _section_from_spec(self, spec): - """ Retrieve a section given a "spec" (either number or name). - Return None if no such section exists in the file. - """ - try: - num = int(spec) - if num < self.elffile.num_sections(): - return self.elffile.get_section(num) - else: - return None - except ValueError: - # Not a number. Must be a name then - return self.elffile.get_section_by_name(str2bytes(spec)) - - def pretty_print_pmdinfo(self, pmdinfo): - global pcidb - - for i in pmdinfo["pci_ids"]: - vendor = pcidb.find_vendor(i[0]) - device = vendor.find_device(i[1]) - subdev = device.find_subid(i[2], i[3]) - print("%s (%s) : %s (%s) %s" % - (vendor.name, vendor.ID, device.name, - device.ID, subdev.name)) - - def parse_pmd_info_string(self, mystring): - global raw_output - global pcidb - - optional_pmd_info = [{'id': 'params', 'tag': 'PMD PARAMETERS'}] - - i = mystring.index("=") - mystring = mystring[i + 2:] - pmdinfo = json.loads(mystring) - - if raw_output: - print(pmdinfo) - return - - print("PMD NAME: " + pmdinfo["name"]) - for i in optional_pmd_info: - try: - print("%s: %s" % (i['tag'], pmdinfo[i['id']])) - except KeyError as e: - continue - - if (len(pmdinfo["pci_ids"]) != 0): - print("PMD HW SUPPORT:") - if pcidb is not None: - self.pretty_print_pmdinfo(pmdinfo) - else: - print("VENDOR\t DEVICE\t SUBVENDOR\t SUBDEVICE") - for i in pmdinfo["pci_ids"]: - print("0x%04x\t 0x%04x\t 0x%04x\t\t 0x%04x" % - (i[0], i[1], i[2], i[3])) - - print("") - - def display_pmd_info_strings(self, section_spec): - """ Display a strings dump of a section. section_spec is either a - section number or a name. - """ - section = self._section_from_spec(section_spec) - if section is None: - return - - data = section.data() - dataptr = 0 - - while dataptr < len(data): - while (dataptr < len(data) and - not (32 <= byte2int(data[dataptr]) <= 127)): - dataptr += 1 - - if dataptr >= len(data): - break - - endptr = dataptr - while endptr < len(data) and byte2int(data[endptr]) != 0: - endptr += 1 - - mystring = bytes2str(data[dataptr:endptr]) - rc = mystring.find("PMD_INFO_STRING") - if (rc != -1): - self.parse_pmd_info_string(mystring) - - dataptr = endptr - - def find_librte_eal(self, section): - for tag in section.iter_tags(): - if tag.entry.d_tag == 'DT_NEEDED': - if "librte_eal" in tag.needed: - return tag.needed - return None - - def search_for_autoload_path(self): - scanelf = self - scanfile = None - library = None - - section = self._section_from_spec(".dynamic") - try: - eallib = self.find_librte_eal(section) - if eallib is not None: - ldlibpath = os.environ.get('LD_LIBRARY_PATH') - if ldlibpath is None: - ldlibpath = "" - dtr = self.get_dt_runpath(section) - library = search_file(eallib, - dtr + ":" + ldlibpath + - ":/usr/lib64:/lib64:/usr/lib:/lib") - if library is None: - return (None, None) - if raw_output is False: - print("Scanning for autoload path in %s" % library) - scanfile = open(library, 'rb') - scanelf = ReadElf(scanfile, sys.stdout) - except AttributeError: - # Not a dynamic binary - pass - except ELFError: - scanfile.close() - return (None, None) - - section = scanelf._section_from_spec(".rodata") - if section is None: - if scanfile is not None: - scanfile.close() - return (None, None) - - data = section.data() - dataptr = 0 - - while dataptr < len(data): - while (dataptr < len(data) and - not (32 <= byte2int(data[dataptr]) <= 127)): - dataptr += 1 - - if dataptr >= len(data): - break - - endptr = dataptr - while endptr < len(data) and byte2int(data[endptr]) != 0: - endptr += 1 - - mystring = bytes2str(data[dataptr:endptr]) - rc = mystring.find("DPDK_PLUGIN_PATH") - if (rc != -1): - rc = mystring.find("=") - return (mystring[rc + 1:], library) - - dataptr = endptr - if scanfile is not None: - scanfile.close() - return (None, None) - - def get_dt_runpath(self, dynsec): - for tag in dynsec.iter_tags(): - if tag.entry.d_tag == 'DT_RUNPATH': - return tag.runpath - return "" - - def process_dt_needed_entries(self): - """ Look to see if there are any DT_NEEDED entries in the binary - And process those if there are - """ - global raw_output - runpath = "" - ldlibpath = os.environ.get('LD_LIBRARY_PATH') - if ldlibpath is None: - ldlibpath = "" - - dynsec = self._section_from_spec(".dynamic") - try: - runpath = self.get_dt_runpath(dynsec) - except AttributeError: - # dynsec is None, just return - return - - for tag in dynsec.iter_tags(): - if tag.entry.d_tag == 'DT_NEEDED': - rc = tag.needed.find("librte_pmd") - if (rc != -1): - library = search_file(tag.needed, - runpath + ":" + ldlibpath + - ":/usr/lib64:/lib64:/usr/lib:/lib") - if library is not None: - if raw_output is False: - print("Scanning %s for pmd information" % library) - with open(library, 'rb') as file: - try: - libelf = ReadElf(file, sys.stdout) - except ELFError as e: - print("%s is no an ELF file" % library) - continue - libelf.process_dt_needed_entries() - libelf.display_pmd_info_strings(".rodata") - file.close() - - -def scan_autoload_path(autoload_path): - global raw_output - - if os.path.exists(autoload_path) is False: - return - - try: - dirs = os.listdir(autoload_path) - except OSError as e: - # Couldn't read the directory, give up - return - - for d in dirs: - dpath = os.path.join(autoload_path, d) - if os.path.isdir(dpath): - scan_autoload_path(dpath) - if os.path.isfile(dpath): - try: - file = open(dpath, 'rb') - readelf = ReadElf(file, sys.stdout) - except ELFError as e: - # this is likely not an elf file, skip it - continue - except IOError as e: - # No permission to read the file, skip it - continue - - if raw_output is False: - print("Hw Support for library %s" % d) - readelf.display_pmd_info_strings(".rodata") - file.close() - - -def scan_for_autoload_pmds(dpdk_path): - """ - search the specified application or path for a pmd autoload path - then scan said path for pmds and report hw support - """ - global raw_output - - if (os.path.isfile(dpdk_path) is False): - if raw_output is False: - print("Must specify a file name") - return - - file = open(dpdk_path, 'rb') - try: - readelf = ReadElf(file, sys.stdout) - except ElfError as e: - if raw_output is False: - print("Unable to parse %s" % file) - return - - (autoload_path, scannedfile) = readelf.search_for_autoload_path() - if (autoload_path is None or autoload_path is ""): - if (raw_output is False): - print("No autoload path configured in %s" % dpdk_path) - return - if (raw_output is False): - if (scannedfile is None): - scannedfile = dpdk_path - print("Found autoload path %s in %s" % (autoload_path, scannedfile)) - - file.close() - if (raw_output is False): - print("Discovered Autoload HW Support:") - scan_autoload_path(autoload_path) - return - - -def main(stream=None): - global raw_output - global pcidb - - pcifile_default = "./pci.ids" # for unknown OS's assume local file - if platform.system() == 'Linux': - pcifile_default = "/usr/share/hwdata/pci.ids" - elif platform.system() == 'FreeBSD': - pcifile_default = "/usr/local/share/pciids/pci.ids" - if not os.path.exists(pcifile_default): - pcifile_default = "/usr/share/misc/pci_vendors" - - optparser = OptionParser( - usage='usage: %prog [-hrtp] [-d ', - description="Dump pmd hardware support info", - add_help_option=True, - prog='pmdinfo.py') - optparser.add_option('-r', '--raw', - action='store_true', dest='raw_output', - help='Dump raw json strings') - optparser.add_option("-d", "--pcidb", dest="pcifile", - help="specify a pci database " - "to get vendor names from", - default=pcifile_default, metavar="FILE") - optparser.add_option("-t", "--table", dest="tblout", - help="output information on hw support as a hex table", - action='store_true') - optparser.add_option("-p", "--plugindir", dest="pdir", - help="scan dpdk for autoload plugins", - action='store_true') - - options, args = optparser.parse_args() - - if options.raw_output: - raw_output = True - - if options.pcifile: - pcidb = PCIIds(options.pcifile) - if pcidb is None: - print("Pci DB file not found") - exit(1) - - if options.tblout: - options.pcifile = None - pcidb = None - - if (len(args) == 0): - optparser.print_usage() - exit(1) - - if options.pdir is True: - exit(scan_for_autoload_pmds(args[0])) - - ldlibpath = os.environ.get('LD_LIBRARY_PATH') - if (ldlibpath is None): - ldlibpath = "" - - if (os.path.exists(args[0]) is True): - myelffile = args[0] - else: - myelffile = search_file( - args[0], ldlibpath + ":/usr/lib64:/lib64:/usr/lib:/lib") - - if (myelffile is None): - print("File not found") - sys.exit(1) - - with open(myelffile, 'rb') as file: - try: - readelf = ReadElf(file, sys.stdout) - readelf.process_dt_needed_entries() - readelf.display_pmd_info_strings(".rodata") - sys.exit(0) - - except ELFError as ex: - sys.stderr.write('ELF error: %s\n' % ex) - sys.exit(1) - - -# ------------------------------------------------------------------------- -if __name__ == '__main__': - main() diff --git a/tools/setup.sh b/tools/setup.sh deleted file mode 100755 index 6097ab7bfd..0000000000 --- a/tools/setup.sh +++ /dev/null @@ -1,634 +0,0 @@ -#! /bin/bash - -# BSD LICENSE -# -# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Intel Corporation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# -# Run with "source /path/to/setup.sh" -# - -# -# Change to DPDK directory ( /.. ), and export it as RTE_SDK -# -cd $(dirname ${BASH_SOURCE[0]})/.. -export RTE_SDK=$PWD -echo "------------------------------------------------------------------------------" -echo " RTE_SDK exported as $RTE_SDK" -echo "------------------------------------------------------------------------------" - -HUGEPGSZ=`cat /proc/meminfo | grep Hugepagesize | cut -d : -f 2 | tr -d ' '` - -# -# Application EAL parameters for setting memory options (amount/channels/ranks). -# -EAL_PARAMS='-n 4' - -# -# Sets QUIT variable so script will finish. -# -quit() -{ - QUIT=$1 -} - -# Shortcut for quit. -q() -{ - quit -} - -# -# Sets up environmental variables for ICC. -# -setup_icc() -{ - DEFAULT_PATH=/opt/intel/bin/iccvars.sh - param=$1 - shpath=`which iccvars.sh 2> /dev/null` - if [ $? -eq 0 ] ; then - echo "Loading iccvars.sh from $shpath for $param" - source $shpath $param - elif [ -f $DEFAULT_PATH ] ; then - echo "Loading iccvars.sh from $DEFAULT_PATH for $param" - source $DEFAULT_PATH $param - else - echo "## ERROR: cannot find 'iccvars.sh' script to set up ICC." - echo "## To fix, please add the directory that contains" - echo "## iccvars.sh to your 'PATH' environment variable." - quit - fi -} - -# -# Sets RTE_TARGET and does a "make install". -# -setup_target() -{ - option=$1 - export RTE_TARGET=${TARGETS[option]} - - compiler=${RTE_TARGET##*-} - if [ "$compiler" == "icc" ] ; then - platform=${RTE_TARGET%%-*} - if [ "$platform" == "x86_64" ] ; then - setup_icc intel64 - else - setup_icc ia32 - fi - fi - if [ "$QUIT" == "0" ] ; then - make install T=${RTE_TARGET} - fi - echo "------------------------------------------------------------------------------" - echo " RTE_TARGET exported as $RTE_TARGET" - echo "------------------------------------------------------------------------------" -} - -# -# Creates hugepage filesystem. -# -create_mnt_huge() -{ - echo "Creating /mnt/huge and mounting as hugetlbfs" - sudo mkdir -p /mnt/huge - - grep -s '/mnt/huge' /proc/mounts > /dev/null - if [ $? -ne 0 ] ; then - sudo mount -t hugetlbfs nodev /mnt/huge - fi -} - -# -# Removes hugepage filesystem. -# -remove_mnt_huge() -{ - echo "Unmounting /mnt/huge and removing directory" - grep -s '/mnt/huge' /proc/mounts > /dev/null - if [ $? -eq 0 ] ; then - sudo umount /mnt/huge - fi - - if [ -d /mnt/huge ] ; then - sudo rm -R /mnt/huge - fi -} - -# -# Unloads igb_uio.ko. -# -remove_igb_uio_module() -{ - echo "Unloading any existing DPDK UIO module" - /sbin/lsmod | grep -s igb_uio > /dev/null - if [ $? -eq 0 ] ; then - sudo /sbin/rmmod igb_uio - fi -} - -# -# Loads new igb_uio.ko (and uio module if needed). -# -load_igb_uio_module() -{ - if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko ];then - echo "## ERROR: Target does not have the DPDK UIO Kernel Module." - echo " To fix, please try to rebuild target." - return - fi - - remove_igb_uio_module - - /sbin/lsmod | grep -s uio > /dev/null - if [ $? -ne 0 ] ; then - modinfo uio > /dev/null - if [ $? -eq 0 ]; then - echo "Loading uio module" - sudo /sbin/modprobe uio - fi - fi - - # UIO may be compiled into kernel, so it may not be an error if it can't - # be loaded. - - echo "Loading DPDK UIO module" - sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko - if [ $? -ne 0 ] ; then - echo "## ERROR: Could not load kmod/igb_uio.ko." - quit - fi -} - -# -# Unloads VFIO modules. -# -remove_vfio_module() -{ - echo "Unloading any existing VFIO module" - /sbin/lsmod | grep -s vfio > /dev/null - if [ $? -eq 0 ] ; then - sudo /sbin/rmmod vfio-pci - sudo /sbin/rmmod vfio_iommu_type1 - sudo /sbin/rmmod vfio - fi -} - -# -# Loads new vfio-pci (and vfio module if needed). -# -load_vfio_module() -{ - remove_vfio_module - - VFIO_PATH="kernel/drivers/vfio/pci/vfio-pci.ko" - - echo "Loading VFIO module" - /sbin/lsmod | grep -s vfio_pci > /dev/null - if [ $? -ne 0 ] ; then - if [ -f /lib/modules/$(uname -r)/$VFIO_PATH ] ; then - sudo /sbin/modprobe vfio-pci - fi - fi - - # make sure regular users can read /dev/vfio - echo "chmod /dev/vfio" - sudo chmod a+x /dev/vfio - if [ $? -ne 0 ] ; then - echo "FAIL" - quit - fi - echo "OK" - - # check if /dev/vfio/vfio exists - that way we - # know we either loaded the module, or it was - # compiled into the kernel - if [ ! -e /dev/vfio/vfio ] ; then - echo "## ERROR: VFIO not found!" - fi -} - -# -# Unloads the rte_kni.ko module. -# -remove_kni_module() -{ - echo "Unloading any existing DPDK KNI module" - /sbin/lsmod | grep -s rte_kni > /dev/null - if [ $? -eq 0 ] ; then - sudo /sbin/rmmod rte_kni - fi -} - -# -# Loads the rte_kni.ko module. -# -load_kni_module() -{ - # Check that the KNI module is already built. - if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/rte_kni.ko ];then - echo "## ERROR: Target does not have the DPDK KNI Module." - echo " To fix, please try to rebuild target." - return - fi - - # Unload existing version if present. - remove_kni_module - - # Now try load the KNI module. - echo "Loading DPDK KNI module" - sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/rte_kni.ko - if [ $? -ne 0 ] ; then - echo "## ERROR: Could not load kmod/rte_kni.ko." - quit - fi -} - -# -# Sets appropriate permissions on /dev/vfio/* files -# -set_vfio_permissions() -{ - # make sure regular users can read /dev/vfio - echo "chmod /dev/vfio" - sudo chmod a+x /dev/vfio - if [ $? -ne 0 ] ; then - echo "FAIL" - quit - fi - echo "OK" - - # make sure regular user can access everything inside /dev/vfio - echo "chmod /dev/vfio/*" - sudo chmod 0666 /dev/vfio/* - if [ $? -ne 0 ] ; then - echo "FAIL" - quit - fi - echo "OK" - - # since permissions are only to be set when running as - # regular user, we only check ulimit here - # - # warn if regular user is only allowed - # to memlock <64M of memory - MEMLOCK_AMNT=`ulimit -l` - - if [ "$MEMLOCK_AMNT" != "unlimited" ] ; then - MEMLOCK_MB=`expr $MEMLOCK_AMNT / 1024` - echo "" - echo "Current user memlock limit: ${MEMLOCK_MB} MB" - echo "" - echo "This is the maximum amount of memory you will be" - echo "able to use with DPDK and VFIO if run as current user." - echo -n "To change this, please adjust limits.conf memlock " - echo "limit for current user." - - if [ $MEMLOCK_AMNT -lt 65536 ] ; then - echo "" - echo "## WARNING: memlock limit is less than 64MB" - echo -n "## DPDK with VFIO may not be able to initialize " - echo "if run as current user." - fi - fi -} - -# -# Removes all reserved hugepages. -# -clear_huge_pages() -{ - echo > .echo_tmp - for d in /sys/devices/system/node/node? ; do - echo "echo 0 > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp - done - echo "Removing currently reserved hugepages" - sudo sh .echo_tmp - rm -f .echo_tmp - - remove_mnt_huge -} - -# -# Creates hugepages. -# -set_non_numa_pages() -{ - clear_huge_pages - - echo "" - echo " Input the number of ${HUGEPGSZ} hugepages" - echo " Example: to have 128MB of hugepages available in a 2MB huge page system," - echo " enter '64' to reserve 64 * 2MB pages" - echo -n "Number of pages: " - read Pages - - echo "echo $Pages > /sys/kernel/mm/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" > .echo_tmp - - echo "Reserving hugepages" - sudo sh .echo_tmp - rm -f .echo_tmp - - create_mnt_huge -} - -# -# Creates hugepages on specific NUMA nodes. -# -set_numa_pages() -{ - clear_huge_pages - - echo "" - echo " Input the number of ${HUGEPGSZ} hugepages for each node" - echo " Example: to have 128MB of hugepages available per node in a 2MB huge page system," - echo " enter '64' to reserve 64 * 2MB pages on each node" - - echo > .echo_tmp - for d in /sys/devices/system/node/node? ; do - node=$(basename $d) - echo -n "Number of pages for $node: " - read Pages - echo "echo $Pages > $d/hugepages/hugepages-${HUGEPGSZ}/nr_hugepages" >> .echo_tmp - done - echo "Reserving hugepages" - sudo sh .echo_tmp - rm -f .echo_tmp - - create_mnt_huge -} - -# -# Run unit test application. -# -run_test_app() -{ - echo "" - echo " Enter hex bitmask of cores to execute test app on" - echo " Example: to execute app on cores 0 to 7, enter 0xff" - echo -n "bitmask: " - read Bitmask - echo "Launching app" - sudo ${RTE_TARGET}/app/test -c $Bitmask $EAL_PARAMS -} - -# -# Run unit testpmd application. -# -run_testpmd_app() -{ - echo "" - echo " Enter hex bitmask of cores to execute testpmd app on" - echo " Example: to execute app on cores 0 to 7, enter 0xff" - echo -n "bitmask: " - read Bitmask - echo "Launching app" - sudo ${RTE_TARGET}/app/testpmd -c $Bitmask $EAL_PARAMS -- -i -} - -# -# Print hugepage information. -# -grep_meminfo() -{ - grep -i huge /proc/meminfo -} - -# -# Calls dpdk_nic_bind.py --status to show the NIC and what they -# are all bound to, in terms of drivers. -# -show_nics() -{ - if [ -d /sys/module/vfio_pci -o -d /sys/module/igb_uio ]; then - ${RTE_SDK}/tools/dpdk_nic_bind.py --status - else - echo "# Please load the 'igb_uio' or 'vfio-pci' kernel module before " - echo "# querying or adjusting NIC device bindings" - fi -} - -# -# Uses dpdk_nic_bind.py to move devices to work with vfio-pci -# -bind_nics_to_vfio() -{ - if [ -d /sys/module/vfio_pci ]; then - ${RTE_SDK}/tools/dpdk_nic_bind.py --status - echo "" - echo -n "Enter PCI address of device to bind to VFIO driver: " - read PCI_PATH - sudo ${RTE_SDK}/tools/dpdk_nic_bind.py -b vfio-pci $PCI_PATH && - echo "OK" - else - echo "# Please load the 'vfio-pci' kernel module before querying or " - echo "# adjusting NIC device bindings" - fi -} - -# -# Uses dpdk_nic_bind.py to move devices to work with igb_uio -# -bind_nics_to_igb_uio() -{ - if [ -d /sys/module/igb_uio ]; then - ${RTE_SDK}/tools/dpdk_nic_bind.py --status - echo "" - echo -n "Enter PCI address of device to bind to IGB UIO driver: " - read PCI_PATH - sudo ${RTE_SDK}/tools/dpdk_nic_bind.py -b igb_uio $PCI_PATH && echo "OK" - else - echo "# Please load the 'igb_uio' kernel module before querying or " - echo "# adjusting NIC device bindings" - fi -} - -# -# Uses dpdk_nic_bind.py to move devices to work with kernel drivers again -# -unbind_nics() -{ - ${RTE_SDK}/tools/dpdk_nic_bind.py --status - echo "" - echo -n "Enter PCI address of device to unbind: " - read PCI_PATH - echo "" - echo -n "Enter name of kernel driver to bind the device to: " - read DRV - sudo ${RTE_SDK}/tools/dpdk_nic_bind.py -b $DRV $PCI_PATH && echo "OK" -} - -# -# Options for building a target. Note that this step MUST be first as it sets -# up TARGETS[] starting from 1, and this is accessed in setup_target using the -# user entered option. -# -step1_func() -{ - TITLE="Select the DPDK environment to build" - CONFIG_NUM=1 - for cfg in config/defconfig_* ; do - cfg=${cfg/config\/defconfig_/} - TEXT[$CONFIG_NUM]="$cfg" - TARGETS[$CONFIG_NUM]=$cfg - FUNC[$CONFIG_NUM]="setup_target" - let "CONFIG_NUM+=1" - done -} - -# -# Options for setting up environment. -# -step2_func() -{ - TITLE="Setup linuxapp environment" - - TEXT[1]="Insert IGB UIO module" - FUNC[1]="load_igb_uio_module" - - TEXT[2]="Insert VFIO module" - FUNC[2]="load_vfio_module" - - TEXT[3]="Insert KNI module" - FUNC[3]="load_kni_module" - - TEXT[4]="Setup hugepage mappings for non-NUMA systems" - FUNC[4]="set_non_numa_pages" - - TEXT[5]="Setup hugepage mappings for NUMA systems" - FUNC[5]="set_numa_pages" - - TEXT[6]="Display current Ethernet device settings" - FUNC[6]="show_nics" - - TEXT[7]="Bind Ethernet device to IGB UIO module" - FUNC[7]="bind_nics_to_igb_uio" - - TEXT[8]="Bind Ethernet device to VFIO module" - FUNC[8]="bind_nics_to_vfio" - - TEXT[9]="Setup VFIO permissions" - FUNC[9]="set_vfio_permissions" -} - -# -# Options for running applications. -# -step3_func() -{ - TITLE="Run test application for linuxapp environment" - - TEXT[1]="Run test application (\$RTE_TARGET/app/test)" - FUNC[1]="run_test_app" - - TEXT[2]="Run testpmd application in interactive mode (\$RTE_TARGET/app/testpmd)" - FUNC[2]="run_testpmd_app" -} - -# -# Other options -# -step4_func() -{ - TITLE="Other tools" - - TEXT[1]="List hugepage info from /proc/meminfo" - FUNC[1]="grep_meminfo" - -} - -# -# Options for cleaning up the system -# -step5_func() -{ - TITLE="Uninstall and system cleanup" - - TEXT[1]="Unbind NICs from IGB UIO or VFIO driver" - FUNC[1]="unbind_nics" - - TEXT[2]="Remove IGB UIO module" - FUNC[2]="remove_igb_uio_module" - - TEXT[3]="Remove VFIO module" - FUNC[3]="remove_vfio_module" - - TEXT[4]="Remove KNI module" - FUNC[4]="remove_kni_module" - - TEXT[5]="Remove hugepage mappings" - FUNC[5]="clear_huge_pages" -} - -STEPS[1]="step1_func" -STEPS[2]="step2_func" -STEPS[3]="step3_func" -STEPS[4]="step4_func" -STEPS[5]="step5_func" - -QUIT=0 - -while [ "$QUIT" == "0" ]; do - OPTION_NUM=1 - - for s in $(seq ${#STEPS[@]}) ; do - ${STEPS[s]} - - echo "----------------------------------------------------------" - echo " Step $s: ${TITLE}" - echo "----------------------------------------------------------" - - for i in $(seq ${#TEXT[@]}) ; do - echo "[$OPTION_NUM] ${TEXT[i]}" - OPTIONS[$OPTION_NUM]=${FUNC[i]} - let "OPTION_NUM+=1" - done - - # Clear TEXT and FUNC arrays before next step - unset TEXT - unset FUNC - - echo "" - done - - echo "[$OPTION_NUM] Exit Script" - OPTIONS[$OPTION_NUM]="quit" - echo "" - echo -n "Option: " - read our_entry - echo "" - ${OPTIONS[our_entry]} ${our_entry} - - if [ "$QUIT" == "0" ] ; then - echo - echo -n "Press enter to continue ..."; read - fi - -done