Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion main/dpdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <rte_errno.h>
#include <rte_log.h>
#include <rte_mempool.h>
#include <rte_pdump.h>
#include <rte_version.h>
#include <rte_vfio.h>

Expand Down Expand Up @@ -165,7 +166,7 @@ int dpdk_init(void) {
else
gr_vec_add(eal_args, "2048");
}
} else {
} else if (!gr_config.pdump) {
gr_vec_add(eal_args, "--in-memory");
}

Expand All @@ -186,6 +187,16 @@ int dpdk_init(void) {
goto end;
}

if (gr_config.pdump) {
ret = rte_pdump_init();
if (ret < 0) {
ret = -ret;
LOG(ERR, "rte_pdump_init: %s", rte_strerror(ret));
goto end;
}
LOG(NOTICE, "pdump enabled, secondary processes can attach for packet capture");
}
Comment on lines +190 to +198

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

DPDK rte_pdump_init return value and rte_errno

💡 Result:

The DPDK function rte_pdump_init returns an int value: 0 on success. It returns -1 on failure, in which case rte_errno is set accordingly to indicate the specific error condition. This follows the standard DPDK API convention for functions returning int, as seen in related APIs like rte_pdump_enable and older documentation explicitly stating "Returns: 0 on success, -1 on error, rte_errno is set accordingly." (e.g., DPDK 17.11 docs). No specific error codes unique to rte_pdump_init are documented; rte_errno provides DPDK-specific or system error details (e.g., E_RTE_SECONDARY if called from secondary process). Official DPDK documentation and manpages confirm the signature int rte_pdump_init(void) and usage in primary processes like testpmd for initializing the packet capture framework.

Citations:


Incorrect error code extraction from rte_pdump_init().

rte_pdump_init() returns -1 on failure with the actual error code stored in rte_errno. The current code negates the return value (yielding 1), which loses the real error information.

Proposed fix
 	if (gr_config.pdump) {
 		ret = rte_pdump_init();
 		if (ret < 0) {
-			ret = -ret;
+			ret = rte_errno;
 			LOG(ERR, "rte_pdump_init: %s", rte_strerror(ret));
 			goto end;
 		}
 		LOG(NOTICE, "pdump enabled, secondary processes can attach for packet capture");
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main/dpdk.c` around lines 190 - 198, The check for rte_pdump_init()
incorrectly negates its return value (which is -1) and loses the real error in
rte_errno; change the failure branch so that when rte_pdump_init() < 0 you read
the actual error code from rte_errno (e.g. int err = rte_errno), log
rte_strerror(err) via LOG(...), and set ret to -err (to preserve the negative
return convention) before jumping to end; update the block around
gr_config.pdump / rte_pdump_init to use rte_errno for both logging and the
returned error value.


char affinity[BUFSIZ];
cpuset_format(affinity, sizeof(affinity), &gr_config.control_cpus);
LOG(INFO, "running control plane on CPU %s", affinity);
Expand Down
1 change: 1 addition & 0 deletions main/gr_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct gr_config {
bool poll_mode;
bool log_syslog;
bool log_packets;
bool pdump;
gr_vec char **eal_extra_args;
cpu_set_t control_cpus; // control plane threads allowed CPUs
cpu_set_t datapath_cpus; // datapath threads allowed CPUs
Expand Down
8 changes: 7 additions & 1 deletion main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ static void usage(void) {
printf(" [-m PERMISSIONS]");
printf(" [-o USER:GROUP]");
printf("\n ");
printf(" [-P]");
printf(" [-p]");
printf(" [-s PATH]");
printf(" [-t]");
Expand All @@ -63,6 +64,7 @@ static void usage(void) {
puts(" -h, --help Display this help message and exit.");
puts(" -m, --socket-mode PERMISSIONS API socket file permissions (Default: 0660).");
puts(" -o, --socket-owner USER:GROUP API socket file ownership");
puts(" -P, --pdump Enable pdump (shared hugepages for tcpdump).");
puts(" -p, --poll-mode Disable automatic micro-sleep.");
puts(" -s, --socket PATH Path the control plane API socket.");
puts(" Default: GROUT_SOCK_PATH from env or");
Expand Down Expand Up @@ -176,11 +178,12 @@ static int parse_sock_owner(char *user_group_str) {
static int parse_args(int argc, char **argv) {
int c;

#define FLAGS ":M:Vhm:o:pSs:tu:vx"
#define FLAGS ":M:VhPm:o:pSs:tu:vx"
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"max-mtu", required_argument, NULL, 'u'},
{"metrics", required_argument, NULL, 'M'},
{"pdump", no_argument, NULL, 'P'},
{"poll-mode", no_argument, NULL, 'p'},
{"socket", required_argument, NULL, 's'},
{"socket-mode", required_argument, NULL, 'm'},
Expand Down Expand Up @@ -221,6 +224,9 @@ static int parse_args(int argc, char **argv) {
if (parse_sock_owner(optarg) < 0)
return errno_set(EINVAL);
break;
case 'P':
gr_config.pdump = true;
break;
case 'p':
gr_config.poll_mode = true;
break;
Expand Down
38 changes: 37 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ dpdk_dep = dependency(
'werror=false',
'tests=false',
'enable_drivers=net/virtio,net/vhost,net/i40e,net/ice,net/iavf,net/ixgbe,net/null,net/tap,common/mlx5,net/mlx5,bus/auxiliary,net/vmxnet3',
'enable_libs=graph,hash,fib,rib,pcapng,gso,vhost,cryptodev,dmadev,security',
'enable_libs=graph,hash,fib,rib,pcapng,pdump,bpf,gso,vhost,cryptodev,dmadev,security',
'disable_apps=*',
'enable_docs=false',
'developer_mode=disabled',
Expand Down Expand Up @@ -156,6 +156,42 @@ pkg.generate(
install_dir: get_option('datadir') / 'pkgconfig',
)

# libpcap with DPDK pdump support (for tcpdump packet capture against grout).
# Builds libpcap.so with grout:N device support. Stock tcpdump picks it up
# via LD_LIBRARY_PATH or system install — no tcpdump recompilation needed.
libpcap_srcdir = meson.current_source_dir() / 'subprojects' / 'libpcap'
libpcap_builddir = meson.current_build_dir() / 'libpcap-build'

dpdk_pkgconfig_path = meson.global_build_root() / 'meson-uninstalled'
dpdk_pc_path = meson.global_build_root() / 'meson-private'

libpcap_build = custom_target(
'libpcap',
output: '.libpcap-stamp',
command: [
'sh', '-c',
'mkdir -p "' + libpcap_builddir + '" && ' +
'cd "' + libpcap_builddir + '" && ' +
'export PKG_CONFIG_PATH="' + dpdk_pkgconfig_path + ':' + dpdk_pc_path + ':$PKG_CONFIG_PATH" && ' +
'DPDK_LIBDIR="' + meson.global_build_root() + '/subprojects/dpdk/lib" && ' +
'DPDK_DRVDIR="' + meson.global_build_root() + '/subprojects/dpdk/drivers" && ' +
'cmake "' + libpcap_srcdir + '" ' +
'-DDISABLE_DPDK:BOOL=OFF ' +
'-DHAVE_RTE_ETH_DEV_COUNT_AVAIL:BOOL=ON ' +
'-DHAVE_STRUCT_RTE_ETHER_ADDR:BOOL=ON ' +
'-DDISABLE_DBUS:BOOL=ON ' +
'-DDISABLE_RDMA:BOOL=ON ' +
'-DDISABLE_BLUETOOTH:BOOL=ON ' +
'-DDISABLE_NETMAP:BOOL=ON ' +
'-DBUILD_SHARED_LIBS:BOOL=ON ' +
'"-DCMAKE_SHARED_LINKER_FLAGS=-L$DPDK_LIBDIR -L$DPDK_DRVDIR -Wl,-rpath,$DPDK_LIBDIR:$DPDK_DRVDIR" ' +
'&& make -j pcap && ' +
'ln -sf libpcap.so.1 libpcap.so.0.8 && ' +
'touch "@OUTPUT@"',
],
build_by_default: true,
)
Comment on lines +168 to +193

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing build dependency on DPDK could cause parallel build failures.

The custom_target for libpcap relies on DPDK libraries and pkg-config files existing at configure/build time, but doesn't declare a dependency on the DPDK build. In a parallel build (ninja -j$(nproc)), cmake may run before DPDK artifacts are available.

Proposed fix
 libpcap_build = custom_target(
   'libpcap',
   output: '.libpcap-stamp',
+  depends: dpdk_dep.type_name() == 'internal' ? subproject('dpdk').get_variable('dpdk_lib') : [],
   command: [

Alternatively, if dpdk_lib isn't exposed, you could depend on the grout executable or another target that already depends on DPDK:

 libpcap_build = custom_target(
   'libpcap',
   output: '.libpcap-stamp',
+  depends: [grout_exe],
   command: [
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@meson.build` around lines 168 - 193, The custom_target libpcap_build runs
cmake/make against libpcap but doesn't declare a build dependency on the DPDK
build, causing races in parallel builds; update the libpcap_build target to add
a depends entry referencing the DPDK build target (for example the dpdk library
target from the dpdk subproject or an existing executable like grout that
already depends on DPDK) so the DPDK artifacts and pkg-config files are
guaranteed to exist before running the cmake command; keep the dependency as the
dpdk build target name already present in your meson project (or grout) so cmake
runs only after DPDK is built.


cmocka_dep = dependency('cmocka', required: get_option('tests'))
if cmocka_dep.found()
fs = import('fs')
Expand Down
6 changes: 6 additions & 0 deletions subprojects/libpcap.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[wrap-git]
url = https://github.com/vjardin/libpcap
revision = vj_add_dpdk_grout
depth = 1

[provide]
37 changes: 37 additions & 0 deletions subprojects/packagefiles/libpcap/grout-tcpdump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2026 Vincent Jardin, Free Mobile, Iliad
#
# Wrapper to run system tcpdump with grout's libpcap (DPDK pdump support).
#
# This is a temporary workaround until libpcap merges the DPDK pdump
# capture module upstream and Linux distributions enable it at compile
# time. Track progress at:
# https://github.com/the-tcpdump-group/libpcap/pull/1656
#
# Once distributions ship a libpcap with PCAP_SUPPORT_DPDK_PDUMP,
# this script is no longer needed — tcpdump will natively support
# "grout:N" devices.
#
# Usage: sudo ./subprojects/packagefiles/libpcap/grout-tcpdump.sh -i grout:0 -n

SCRIPT="$(readlink -f "$0")"
BASEDIR="$(dirname "$SCRIPT")/../../.."
LIBPCAP_DIR="$BASEDIR/build/libpcap-build"
DPDK_LIBDIR="$BASEDIR/build/subprojects/dpdk/lib"
DPDK_DRVDIR="$BASEDIR/build/subprojects/dpdk/drivers"

if [ ! -f "$LIBPCAP_DIR/libpcap.so" ]; then
echo "error: $LIBPCAP_DIR/libpcap.so not found, build grout first" >&2
exit 1
fi

# Our libpcap.so.0.8 symlink is found before the system one.
export LD_LIBRARY_PATH="$LIBPCAP_DIR:$DPDK_LIBDIR:$DPDK_DRVDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"

# Tell the DPDK secondary process where to find PMD drivers.
# The compiled-in path (RTE_EAL_PMD_PATH) points to an install prefix
# that doesn't exist in a development build tree.
export DPDK_CFG="--proc-type=secondary -l0 --no-telemetry --log-level=critical -d $DPDK_DRVDIR"

exec tcpdump "$@"
Loading