An AMD server and an Allied Telesis switch

I recently bought some old networking equipment and decided to test it (raw throughput, NAT, firewall). One of the best tools for this is Cisco TRex, an open source L3-7 traffic generator. TRex uses DPDK as its primary backend, so before getting started with the traffic generator, DPDK must be installed.

In this post, I will show you how to compile and install DPDK from scratch on an Ubuntu 24.04 LTS server.

This post is divided into 4 steps:

  1. Enabling IOMMU (recommended for full throughput)
  2. Reserving hugepages (recommended for optimal performance)
  3. Compiling and installing DPDK
    1. Installing dependencies
    2. Obtaining DPDK source code
    3. Compiling DPDK
  4. Configuring DPDK

The final section of this post provides some useful commands.

IOMMU configuration

On most systems, IOMMU is enabled by default, especially on AMD based machines.

To check the IOMMU status on an Intel based machine, use:

dmesg | grep -i dmar

On an AMD based machine, use:

dmesg | grep -i amd-vi

You can also use these commands to check the number of IOMMU groups and verify if they are enabled in the kernel boot parameters:

ls /sys/kernel/iommu_groups/
cat /proc/cmdline

The screenshot below shows the IOMMU status on my machine: Linux terminal output showing IOMMU status

I am using an AMD based machine, which does not require additional kernel parameters: Linux kernel boot parameters (AMD)

If the (dmesg) commands above return nothing, you may need to enable IOMMU, particularly if you are using an Intel, ARM, or RISC-V processor.

To explicitly enable IOMMU on an Intel processor, modify your kernel boot parameters. Open your GRUB configuration file:

nano /etc/default/grub

Find the GRUB_CMDLINE_LINUX_DEFAULT line and add intel_iommu=on inside the quotes: Linux kernel boot parameters (Intel)

Update the GRUB configuration:

update-grub

Restart the system:

systemctl reboot

After enabling IOMMU on an HP server with Intel processors, the boot log looks like this: Linux kernel boot, IOMMU, dmar in the boot log

If you can’t enable IOMMU or your system does not support it, you can still use DPDK, but performance will be degraded and it’s generally considered less secure.

Reserving hugepages (HugeTLB Pages)

Using hugepages is optional but highly recommended, as it allows a large, reserved chunk of memory to be managed entirely by DPDK.

First, check if your CPU supports hugepages:

cat /proc/cpuinfo | grep "pse"
cat /proc/cpuinfo | grep "pdpe1gb"

Here, pse indicates 2MB hugepage support, and pdpe1gb indicates 1GB support.

On my system, pse and pdpe1gb pages are supported: Terminal output, checking CPU hugepages status

You can find additional information about hugepages in /proc/meminfo:

cat /proc/meminfo | grep Huge`

Before reserving hugepages, the meminfo may look like this: Terminal output, checking meminfo hugepages status (before changes)

There are several ways to reserve hugepages. In this section, I will do so using kernel boot parameters.

Open the GRUB configuration file again:

nano /etc/default/grub

Add default_hugepagesz=2M hugepagesz=2M hugepages=512 to the GRUB_CMDLINE_LINUX_DEFAULT line: Editing Linux kernel boot parameters (grub)

Here, hugepages=512 defines the number of hugepages, default_hugepagesz=2M sets the default hugepage size, and hugepagesz=2M specifies the hugepage size to allocate.

For example, on my Intel server, I reserved 4 pages 1GB each (default_hugepagesz=1G hugepagesz=1G hugepages=4): Editing Linux kernel boot parameters (grub) Intel server

Update the GRUB configuration:

update-grub

Restart the system:

systemctl reboot

Verify the reserved pages:

cat /proc/meminfo | grep Huge

Here is how reserved pages look on my system: Terminal output, checking meminfo hugepages status (after changes)

Installing dependencies

DPDK can be compiled with GCC or Clang. To keep things simple, I will use GCC, which is provided by the build-essential package.

Install the required dependencies:

apt install build-essential meson ninja-build python3-pyelftools libnuma-dev

Here is a brief description of the packages:

  • build-essential - general development tools (GCC, make).
  • meson ninja-build - build systems.
  • python3-pyelftools - parsing and analyzing ELF.
  • libnuma-dev - library for handling NUMA.

Here is the APT output showing the packages and dependencies that will be downloaded and installed: Terminal output of APT about the packages and dependencies that will be downloaded and installed

All packages have been installed: Terminal output, all packages have been installed

Obtaining DPDK source code

Next, you need to obtain the DPDK source code.

You can just download the archive and unpack it:

tar xJf dpdk-<version>.tar.xz
cd dpdk-<version>

While you can download a tarball, I prefer cloning the repository directly from git to ensure I am on the latest stable version. At the time of writing this post, the latest version is v26.03. Using git, download the source code and switch to the stable tag:

git clone --branch v26.03 --recursive https://github.com/DPDK/dpdk.git

The repository is being cloned: DPDK repository with the source code is being cloned

Enter the directory:

cd dpdk

Check that you’re on the stable tag:

git describe --tags --exact-match

The repository is on the v26.03 tag right now: DPDK repository, git, stable tag

Compiling DPDK

Right now you should be in the directory containing the DPDK source code.

Check the possible configuration options:

meson configure

There are many configuration options: DPDK meson configuration

You don’t have to change anything, but if you need to customize the build, use the following command:

meson setup <options> build

Build the project:

meson setup build

You’ll have to wait a moment while meson configures the project and generates the ninja build scripts.

It’s also a great idea to check which drivers will be compiled: DPDK meson configuration - enabled drivers

Switch to the build directory:

cd build

Finally, compile DPDK:

ninja

You can see that DPDK has been compiled: Compiling DPDK - ninja output

Install DPDK:

meson install

DPDK has been installed: DPDK meson - DPDK has been installed

Update the linker run time bindings:

ldconfig

Check that DPDK has been successfully installed:

dpdk-devbind.py --status

You can see that DPDK is working properly: DPDK is working

Configuring DPDK

After completing the steps above, your DPDK environment should be ready. In this optional section, I’ll show you how you can interact with DPDK.

Allocate hugepages for DPDK:

dpdk-hugepages.py --setup 1G

Load the VFIO driver:

modprobe vfio-pci

Check DPDK devices:

dpdk-devbind.py --status

After loading the VFIO driver, you can see that vfio-pci appeared in the unused= section: DPDK devices, vfio-pci is available

At this step, it may be a good idea to obtain the devices’ MAC addresses, because after binding an interface to DPDK, it won’t be that simple to find out its MAC address:

ip addr

Bind NICs to the VFIO driver:

dpdk-devbind.py -b vfio-pci 0000:09:00.0 0000:09:00.1

Here, 0000:09:00.0 and 0000:09:00.1 are the NICs I’m binding to DPDK.

Check DPDK devices again to see that the NICs have been successfully bound to DPDK:

dpdk-devbind.py --status

Network devices are using a DPDK-compatible driver: Network devices are using a DPDK-compatible driver

In dmesg, you can see that the VFIO driver was successfully loaded and the NICs were detached from the Intel igb driver: dmesg VFIO and igb removed NICs

On my Intel HP server with multiple NICs, you can see that e1000e devices now use vfio-pci: Intel HP server - e1000e

That’s basically it. You’ve successfully compiled, configured, and installed DPDK from scratch!

In the future, I will demonstrate how to use DPDK with Cisco TRex. Thanks to the DPDK architecture, the initial configuration is now complete, and we can focus on the integration.

How to reserve hugepages right away (without rebooting)

On a single node system:

echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

Here, 1024 represents the number of 2048kB pages. The example above reserves 2GB (1024 * 2048kB) of memory.

On a NUMA system:

echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages

Here you can see that hugepages are reserved for each NUMA node (node0, node1).

See HugeTLB Pages for more information.

How to reserve hugepages via DPDK (dpdk-hugepages.py)

DPDK provides a script for working with hugepages (dpdk-hugepages.py). This script can reserve pages:

dpdk-hugepages.py --reserve=2G

See dpdk-hugepages Application for more information.

How to reserve hugepages via kernel boot parameters on a NUMA architecture

Just specify NUMA nodes in the kernel boot settings of the hugepages parameter:

hugepages=0:1,1:2

Here, 0 stands for NUMA node0, and 1 for NUMA node1.

So, on node0 a single page will be allocated, and on node1 two pages will be allocated.

See HugeTLB Pages for more information.

See also



Categories: linux