From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH v23 24/24] test: add comprehensive test suite for pcap PMD
Date: Wed, 15 Apr 2026 07:46:13 -0700 [thread overview]
Message-ID: <20260415144717.226161-25-stephen@networkplumber.org> (raw)
In-Reply-To: <20260415144717.226161-1-stephen@networkplumber.org>
Add unit tests for the pcap PMD covering file and interface modes.
Tests include:
- basic TX to file and RX from file
- varied packet sizes and jumbo frames
- infinite RX mode
- TX drop mode
- statistics (ipackets, opackets, ibytes, obytes)
- interface (iface=) pass-through mode
- asymmetric rx_iface/tx_iface mode
- rx_iface_in direction filtering
- link status reporting for file and iface modes
- link status change (LSC) with interface toggle
- EOF notification via LSC
- RX timestamps and timestamp with infinite RX
- multiple TX/RX queues
- snapshot length (snaplen) and truncation
- scatter RX and oversized packet drop
- per-queue start/stop
- imissed statistic (pcap_stats kernel drops)
The LSC link toggle test requires a pre-created dummy interface
(Linux: dummy0, FreeBSD: disc0) and is skipped if unavailable.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/meson.build | 2 +
app/test/test_pmd_pcap.c | 3452 ++++++++++++++++++++++++
doc/guides/rel_notes/release_26_07.rst | 1 +
3 files changed, 3455 insertions(+)
create mode 100644 app/test/test_pmd_pcap.c
diff --git a/app/test/meson.build b/app/test/meson.build
index 7d458f9c07..7a4daeb0c7 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -141,6 +141,7 @@ source_file_deps = {
'test_per_lcore.c': [],
'test_pflock.c': [],
'test_pie.c': ['sched'],
+ 'test_pmd_pcap.c': ['net_pcap', 'ethdev', 'bus_vdev'] + packet_burst_generator_deps,
'test_pmd_perf.c': ['ethdev', 'net'] + packet_burst_generator_deps,
'test_pmd_ring.c': ['net_ring', 'ethdev', 'bus_vdev'],
'test_pmd_ring_perf.c': ['ethdev', 'net_ring', 'bus_vdev'],
@@ -217,6 +218,7 @@ source_file_deps = {
source_file_ext_deps = {
'test_compressdev.c': ['zlib'],
'test_pcapng.c': ['pcap'],
+ 'test_pmd_pcap.c': ['pcap'],
}
# the NULL ethdev is used by a number of tests, in some cases as an optional dependency.
diff --git a/app/test/test_pmd_pcap.c b/app/test/test_pmd_pcap.c
new file mode 100644
index 0000000000..1b8952a157
--- /dev/null
+++ b/app/test/test_pmd_pcap.c
@@ -0,0 +1,3452 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Stephen Hemminger
+ */
+
+#include "test.h"
+
+#include "packet_burst_generator.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <unistd.h>
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+#include <windows.h>
+#else
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#endif
+
+#include <pcap/pcap.h>
+
+#include <rte_ethdev.h>
+#include <rte_bus_vdev.h>
+#include <rte_mbuf.h>
+#include <rte_mbuf_dyn.h>
+#include <rte_mempool.h>
+#include <rte_ether.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+#define SOCKET0 0
+#define RING_SIZE 256
+#define NB_MBUF 1024
+#define NUM_PACKETS 64
+#define MAX_PKT_BURST 32
+#define PCAP_SNAPLEN 65535
+
+/* Packet sizes to test */
+#define PKT_SIZE_MIN 60
+#define PKT_SIZE_SMALL 128
+#define PKT_SIZE_MEDIUM 512
+#define PKT_SIZE_LARGE 1024
+#define PKT_SIZE_MTU 1500
+#define PKT_SIZE_JUMBO 9000
+
+static struct rte_mempool *mp;
+
+/* Timestamp dynamic field access */
+static int timestamp_dynfield_offset = -1;
+static uint64_t timestamp_rx_dynflag;
+
+/* Temporary file paths shared between tests */
+static char tx_pcap_path[PATH_MAX]; /* test_tx_to_file -> test_rx_from_file */
+
+/* Constants for multi-queue tests */
+#define MULTI_QUEUE_NUM_QUEUES 4U
+#define MULTI_QUEUE_NUM_PACKETS 100U
+#define MULTI_QUEUE_BURST_SIZE 32U
+
+/* MAC addresses for packet generation */
+static struct rte_ether_addr src_mac;
+static struct rte_ether_addr dst_mac = {
+ .addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+};
+
+/* Sample Ethernet/IPv4/UDP packet for testing */
+static const uint8_t test_packet[] = {
+ /* Ethernet header */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst MAC (broadcast) */
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, /* src MAC */
+ 0x08, 0x00, /* EtherType: IPv4 */
+ /* IPv4 header */
+ 0x45, 0x00, 0x00, 0x2e, /* ver, ihl, tos, len */
+ 0x00, 0x01, 0x00, 0x00, /* id, flags, frag */
+ 0x40, 0x11, 0x00, 0x00, /* ttl, proto(UDP), csum */
+ 0x0a, 0x00, 0x00, 0x01, /* src: 10.0.0.1 */
+ 0x0a, 0x00, 0x00, 0x02, /* dst: 10.0.0.2 */
+ /* UDP header */
+ 0x04, 0xd2, 0x04, 0xd2, /* sport, dport (1234) */
+ 0x00, 0x1a, 0x00, 0x00, /* len, csum */
+ /* Payload: "Test packet!" */
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x70,
+ 0x61, 0x63, 0x6b, 0x65, 0x74, 0x21
+};
+
+/* Helper: Get timestamp from mbuf using dynamic field */
+static inline rte_mbuf_timestamp_t
+mbuf_timestamp_get(const struct rte_mbuf *mbuf)
+{
+ return *RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset, rte_mbuf_timestamp_t *);
+}
+
+/* Helper: Check if mbuf has valid timestamp */
+static inline int
+mbuf_has_timestamp(const struct rte_mbuf *mbuf)
+{
+ return (mbuf->ol_flags & timestamp_rx_dynflag) != 0;
+}
+
+/* Helper: Initialize timestamp dynamic field access */
+static int
+timestamp_init(void)
+{
+ int offset;
+
+ offset = rte_mbuf_dynfield_lookup(RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, NULL);
+ if (offset < 0) {
+ printf("Timestamp dynfield not registered\n");
+ return -1;
+ }
+ timestamp_dynfield_offset = offset;
+
+ offset = rte_mbuf_dynflag_lookup(RTE_MBUF_DYNFLAG_RX_TIMESTAMP_NAME, NULL);
+ if (offset < 0) {
+ printf("Timestamp dynflag not registered\n");
+ return -1;
+ }
+ timestamp_rx_dynflag = RTE_BIT64(offset);
+ return 0;
+}
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+
+/*
+ * Helper: Create a unique temporary file path (Windows version)
+ */
+static int
+create_temp_path(char *buf, size_t buflen, const char *prefix)
+{
+ char temp_dir[MAX_PATH];
+ char temp_file[MAX_PATH];
+ DWORD ret;
+
+ ret = GetTempPathA(sizeof(temp_dir), temp_dir);
+ if (ret == 0 || ret > sizeof(temp_dir))
+ return -1;
+
+ if (GetTempFileNameA(temp_dir, prefix, 0, temp_file) == 0)
+ return -1;
+
+ ret = snprintf(buf, buflen, "%s.pcap", temp_file);
+ if (ret >= buflen) {
+ DeleteFileA(temp_file);
+ return -1;
+ }
+
+ if (MoveFileA(temp_file, buf) == 0) {
+ DeleteFileA(temp_file);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Helper: Remove temporary file (Windows version)
+ */
+static inline void
+remove_temp_file(const char *path)
+{
+ if (path[0] != '\0')
+ DeleteFileA(path);
+}
+
+#else /* POSIX */
+
+/*
+ * Helper: Create a unique temporary file path (POSIX version)
+ */
+static int
+create_temp_path(char *buf, size_t buflen, const char *prefix)
+{
+ int fd;
+
+ snprintf(buf, buflen, "/tmp/%s_XXXXXX.pcap", prefix);
+ fd = mkstemps(buf, 5); /* 5 = strlen(".pcap") */
+ if (fd < 0)
+ return -1;
+ close(fd);
+ return 0;
+}
+
+/*
+ * Helper: Remove temporary file (POSIX version)
+ */
+static inline void
+remove_temp_file(const char *path)
+{
+ if (path[0] != '\0')
+ unlink(path);
+}
+
+#endif /* RTE_EXEC_ENV_WINDOWS */
+
+/*
+ * Helper: Create a pcap file with test packets using libpcap
+ */
+static int
+create_test_pcap(const char *path, unsigned int num_pkts)
+{
+ pcap_t *pd;
+ pcap_dumper_t *dumper;
+ struct pcap_pkthdr hdr;
+ unsigned int i;
+
+ pd = pcap_open_dead(DLT_EN10MB, PCAP_SNAPLEN);
+ if (pd == NULL) {
+ printf("pcap_open_dead failed\n");
+ return -1;
+ }
+
+ dumper = pcap_dump_open(pd, path);
+ if (dumper == NULL) {
+ printf("pcap_dump_open failed: %s\n", pcap_geterr(pd));
+ pcap_close(pd);
+ return -1;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.caplen = sizeof(test_packet);
+ hdr.len = sizeof(test_packet);
+
+ for (i = 0; i < num_pkts; i++) {
+ hdr.ts.tv_sec = i;
+ hdr.ts.tv_usec = 0;
+ pcap_dump((u_char *)dumper, &hdr, test_packet);
+ }
+
+ pcap_dump_close(dumper);
+ pcap_close(pd);
+ return 0;
+}
+
+/*
+ * Helper: Create pcap file with packets of specified size
+ */
+static int
+create_sized_pcap(const char *path, unsigned int num_pkts, uint16_t pkt_size)
+{
+ pcap_t *pd;
+ pcap_dumper_t *dumper;
+ struct pcap_pkthdr hdr;
+ uint8_t *pkt_data;
+ unsigned int i;
+
+ /* Minimum valid ethernet frame */
+ if (pkt_size < 60)
+ pkt_size = 60;
+
+ pkt_data = calloc(1, pkt_size);
+ if (pkt_data == NULL)
+ return -1;
+
+ /* Build ethernet header */
+ struct rte_ether_hdr *eth_hdr = (struct rte_ether_hdr *)pkt_data;
+ rte_ether_addr_copy(&src_mac, ð_hdr->src_addr);
+ rte_ether_addr_copy(&dst_mac, ð_hdr->dst_addr);
+ eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+
+ /* Build IP header */
+ struct rte_ipv4_hdr *ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
+ uint16_t ip_len = pkt_size - sizeof(struct rte_ether_hdr);
+ ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
+ ip_hdr->total_length = rte_cpu_to_be_16(ip_len);
+ ip_hdr->time_to_live = 64;
+ ip_hdr->next_proto_id = IPPROTO_UDP;
+ ip_hdr->src_addr = rte_cpu_to_be_32(IPV4_ADDR(10, 0, 0, 1));
+ ip_hdr->dst_addr = rte_cpu_to_be_32(IPV4_ADDR(10, 0, 0, 2));
+ ip_hdr->hdr_checksum = 0;
+ ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr);
+
+ /* Build UDP header */
+ struct rte_udp_hdr *udp_hdr = (struct rte_udp_hdr *)(ip_hdr + 1);
+ uint16_t udp_len = ip_len - sizeof(struct rte_ipv4_hdr);
+ udp_hdr->src_port = rte_cpu_to_be_16(1234);
+ udp_hdr->dst_port = rte_cpu_to_be_16(1234);
+ udp_hdr->dgram_len = rte_cpu_to_be_16(udp_len);
+ udp_hdr->dgram_cksum = 0;
+
+ /* Fill payload with pattern */
+ uint8_t *payload = (uint8_t *)(udp_hdr + 1);
+ uint16_t payload_len = udp_len - sizeof(struct rte_udp_hdr);
+ for (uint16_t j = 0; j < payload_len; j++)
+ payload[j] = (uint8_t)(j & 0xFF);
+
+ pd = pcap_open_dead(DLT_EN10MB, PCAP_SNAPLEN);
+ if (pd == NULL) {
+ free(pkt_data);
+ return -1;
+ }
+
+ dumper = pcap_dump_open(pd, path);
+ if (dumper == NULL) {
+ pcap_close(pd);
+ free(pkt_data);
+ return -1;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.caplen = pkt_size;
+ hdr.len = pkt_size;
+
+ for (i = 0; i < num_pkts; i++) {
+ hdr.ts.tv_sec = i;
+ hdr.ts.tv_usec = 0;
+ /* Vary sequence byte in payload */
+ payload[0] = (uint8_t)(i & 0xFF);
+ pcap_dump((u_char *)dumper, &hdr, pkt_data);
+ }
+
+ pcap_dump_close(dumper);
+ pcap_close(pd);
+ free(pkt_data);
+ return 0;
+}
+
+/*
+ * Helper: Create pcap file with varied packet sizes
+ */
+static int
+create_varied_pcap(const char *path, unsigned int num_pkts)
+{
+ static const uint16_t sizes[] = {
+ PKT_SIZE_MIN, PKT_SIZE_SMALL, PKT_SIZE_MEDIUM,
+ PKT_SIZE_LARGE, PKT_SIZE_MTU
+ };
+ pcap_t *pd;
+ pcap_dumper_t *dumper;
+ struct pcap_pkthdr hdr;
+ uint8_t *pkt_data;
+ unsigned int i;
+
+ pkt_data = calloc(1, PKT_SIZE_MTU);
+ if (pkt_data == NULL)
+ return -1;
+
+ pd = pcap_open_dead(DLT_EN10MB, PCAP_SNAPLEN);
+ if (pd == NULL) {
+ free(pkt_data);
+ return -1;
+ }
+
+ dumper = pcap_dump_open(pd, path);
+ if (dumper == NULL) {
+ pcap_close(pd);
+ free(pkt_data);
+ return -1;
+ }
+
+ for (i = 0; i < num_pkts; i++) {
+ uint16_t pkt_size = sizes[i % RTE_DIM(sizes)];
+
+ memset(pkt_data, 0, pkt_size);
+
+ /* Build ethernet header */
+ struct rte_ether_hdr *eth_hdr = (struct rte_ether_hdr *)pkt_data;
+ rte_ether_addr_copy(&src_mac, ð_hdr->src_addr);
+ rte_ether_addr_copy(&dst_mac, ð_hdr->dst_addr);
+ eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+
+ /* Build IP header */
+ struct rte_ipv4_hdr *ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
+ uint16_t ip_len = pkt_size - sizeof(struct rte_ether_hdr);
+ ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
+ ip_hdr->total_length = rte_cpu_to_be_16(ip_len);
+ ip_hdr->time_to_live = 64;
+ ip_hdr->next_proto_id = IPPROTO_UDP;
+ ip_hdr->src_addr = rte_cpu_to_be_32(IPV4_ADDR(10, 0, 0, 1));
+ ip_hdr->dst_addr = rte_cpu_to_be_32(IPV4_ADDR(10, 0, 0, 2));
+ ip_hdr->hdr_checksum = 0;
+ ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr);
+
+ /* Build UDP header */
+ struct rte_udp_hdr *udp_hdr = (struct rte_udp_hdr *)(ip_hdr + 1);
+ uint16_t udp_len = ip_len - sizeof(struct rte_ipv4_hdr);
+ udp_hdr->src_port = rte_cpu_to_be_16(1234);
+ udp_hdr->dst_port = rte_cpu_to_be_16(1234);
+ udp_hdr->dgram_len = rte_cpu_to_be_16(udp_len);
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.ts.tv_sec = i;
+ hdr.caplen = pkt_size;
+ hdr.len = pkt_size;
+
+ pcap_dump((u_char *)dumper, &hdr, pkt_data);
+ }
+
+ pcap_dump_close(dumper);
+ pcap_close(pd);
+ free(pkt_data);
+ return 0;
+}
+
+/*
+ * Helper: Create pcap file with specific timestamps for testing
+ */
+static int
+create_timestamped_pcap(const char *path, unsigned int num_pkts,
+ uint32_t base_sec, uint32_t usec_increment)
+{
+ pcap_t *pd;
+ pcap_dumper_t *dumper;
+ struct pcap_pkthdr hdr;
+ unsigned int i;
+
+ pd = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, PCAP_SNAPLEN,
+ PCAP_TSTAMP_PRECISION_MICRO);
+ if (pd == NULL)
+ return -1;
+
+ dumper = pcap_dump_open(pd, path);
+ if (dumper == NULL) {
+ pcap_close(pd);
+ return -1;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.caplen = sizeof(test_packet);
+ hdr.len = sizeof(test_packet);
+
+ for (i = 0; i < num_pkts; i++) {
+ uint64_t total_usec = (uint64_t)i * usec_increment;
+ hdr.ts.tv_sec = base_sec + total_usec / 1000000;
+ hdr.ts.tv_usec = total_usec % 1000000;
+ pcap_dump((u_char *)dumper, &hdr, test_packet);
+ }
+
+ pcap_dump_close(dumper);
+ pcap_close(pd);
+ return 0;
+}
+
+/*
+ * Helper: Count packets in a pcap file using libpcap
+ */
+static int
+count_pcap_packets(const char *path)
+{
+ pcap_t *pd;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ struct pcap_pkthdr *hdr;
+ const u_char *data;
+ int count = 0;
+
+ pd = pcap_open_offline(path, errbuf);
+ if (pd == NULL)
+ return -1;
+
+ while (pcap_next_ex(pd, &hdr, &data) == 1)
+ count++;
+
+ pcap_close(pd);
+ return count;
+}
+
+/*
+ * Helper: Get packet sizes from pcap file
+ */
+static int
+get_pcap_packet_sizes(const char *path, uint16_t *sizes, unsigned int max_pkts)
+{
+ pcap_t *pd;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ struct pcap_pkthdr *hdr;
+ const u_char *data;
+ unsigned int count = 0;
+
+ pd = pcap_open_offline(path, errbuf);
+ if (pd == NULL)
+ return -1;
+
+ while (pcap_next_ex(pd, &hdr, &data) == 1 && count < max_pkts) {
+ sizes[count] = hdr->caplen;
+ count++;
+ }
+
+ pcap_close(pd);
+ return count;
+}
+
+/*
+ * Helper: Verify packets in pcap file are truncated correctly
+ * Returns 0 if all packets have caplen == expected_caplen and len == expected_len
+ */
+static int
+verify_pcap_truncation(const char *path, uint32_t expected_caplen,
+ uint32_t expected_len, unsigned int *pkt_count)
+{
+ pcap_t *pd;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ struct pcap_pkthdr *hdr;
+ const u_char *data;
+ unsigned int count = 0;
+
+ pd = pcap_open_offline(path, errbuf);
+ if (pd == NULL)
+ return -1;
+
+ while (pcap_next_ex(pd, &hdr, &data) == 1) {
+ if (hdr->caplen != expected_caplen || hdr->len != expected_len) {
+ printf("Packet %u: caplen=%u (expected %u), len=%u (expected %u)\n",
+ count, hdr->caplen, expected_caplen,
+ hdr->len, expected_len);
+ pcap_close(pd);
+ return -1;
+ }
+ count++;
+ }
+
+ pcap_close(pd);
+ if (pkt_count)
+ *pkt_count = count;
+ return 0;
+}
+
+/*
+ * Helper: Configure and start a pcap ethdev port with custom config
+ */
+static int
+setup_pcap_port_conf(uint16_t port, const struct rte_eth_conf *conf)
+{
+ int ret;
+
+ ret = rte_eth_dev_configure(port, 1, 1, conf);
+ TEST_ASSERT(ret == 0, "Failed to configure port %u: %s",
+ port, rte_strerror(-ret));
+
+ ret = rte_eth_rx_queue_setup(port, 0, RING_SIZE, SOCKET0, NULL, mp);
+ TEST_ASSERT(ret == 0, "Failed to setup RX queue on port %u: %s",
+ port, rte_strerror(-ret));
+
+ ret = rte_eth_tx_queue_setup(port, 0, RING_SIZE, SOCKET0, NULL);
+ TEST_ASSERT(ret == 0, "Failed to setup TX queue on port %u: %s",
+ port, rte_strerror(-ret));
+
+ ret = rte_eth_dev_start(port);
+ TEST_ASSERT(ret == 0, "Failed to start port %u: %s",
+ port, rte_strerror(-ret));
+
+ return 0;
+}
+
+/*
+ * Helper: Configure and start a pcap ethdev port (default: timestamp offload)
+ */
+static int
+setup_pcap_port(uint16_t port)
+{
+ struct rte_eth_conf port_conf = {
+ .rxmode.offloads = RTE_ETH_RX_OFFLOAD_TIMESTAMP,
+ };
+
+ return setup_pcap_port_conf(port, &port_conf);
+}
+
+/*
+ * Helper: Create a pcap vdev and return its port ID
+ */
+static int
+create_pcap_vdev(const char *name, const char *devargs, uint16_t *port_id)
+{
+ int ret;
+
+ ret = rte_vdev_init(name, devargs);
+ TEST_ASSERT(ret == 0, "Failed to create vdev %s: %s",
+ name, rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name(name, port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID for %s", name);
+
+ return 0;
+}
+
+/*
+ * Helper: Cleanup a pcap vdev
+ */
+static void
+cleanup_pcap_vdev(const char *name, uint16_t port_id)
+{
+ rte_eth_dev_stop(port_id);
+ rte_vdev_uninit(name);
+}
+
+/*
+ * Helper: Generate test packets using packet_burst_generator
+ */
+static int
+generate_test_packets(struct rte_mempool *pool, struct rte_mbuf **mbufs,
+ unsigned int count, uint16_t pkt_len)
+{
+ struct rte_ether_hdr eth_hdr;
+ struct rte_ipv4_hdr ip_hdr;
+ struct rte_udp_hdr udp_hdr;
+ uint16_t ip_pkt_data_len;
+ int nb_pkt;
+
+ /* Initialize ethernet header */
+ initialize_eth_header(ð_hdr, &src_mac, &dst_mac,
+ RTE_ETHER_TYPE_IPV4, 0, 0);
+
+ /* Calculate IP payload length (total - eth - ip headers) */
+ ip_pkt_data_len = pkt_len - sizeof(struct rte_ether_hdr) -
+ sizeof(struct rte_ipv4_hdr);
+
+ /* Initialize UDP header */
+ initialize_udp_header(&udp_hdr, 1234, 1234,
+ ip_pkt_data_len - sizeof(struct rte_udp_hdr));
+
+ /* Initialize IPv4 header */
+ initialize_ipv4_header(&ip_hdr, IPV4_ADDR(10, 0, 0, 1),
+ IPV4_ADDR(10, 0, 0, 2), ip_pkt_data_len);
+
+ /* Generate packet burst */
+ nb_pkt = generate_packet_burst(pool, mbufs, ð_hdr, 0,
+ &ip_hdr, 1, &udp_hdr,
+ count, pkt_len, 1);
+
+ return nb_pkt;
+}
+
+/*
+ * Helper: Allocate mbufs and fill with test packet data (legacy method)
+ */
+static int
+alloc_test_mbufs(struct rte_mbuf **mbufs, unsigned int count)
+{
+ unsigned int i;
+ int ret;
+
+ ret = rte_pktmbuf_alloc_bulk(mp, mbufs, count);
+ if (ret != 0)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ memcpy(rte_pktmbuf_mtod(mbufs[i], void *),
+ test_packet, sizeof(test_packet));
+ mbufs[i]->data_len = sizeof(test_packet);
+ mbufs[i]->pkt_len = sizeof(test_packet);
+ }
+ return 0;
+}
+
+/*
+ * Helper: Allocate a multi-segment mbuf for jumbo frames
+ * Returns the head mbuf with chained segments, or NULL on failure
+ */
+static struct rte_mbuf *
+alloc_jumbo_mbuf(uint32_t pkt_len, uint8_t fill_byte)
+{
+ struct rte_mbuf *head = NULL;
+ struct rte_mbuf **prev = &head;
+ uint32_t remaining = pkt_len;
+ uint16_t nb_segs = 0;
+
+ while (remaining > 0) {
+ struct rte_mbuf *seg = rte_pktmbuf_alloc(mp);
+ uint16_t seg_size;
+
+ if (seg == NULL) {
+ rte_pktmbuf_free(head);
+ return NULL;
+ }
+
+ seg_size = RTE_MIN(remaining, rte_pktmbuf_tailroom(seg));
+ seg->data_len = seg_size;
+
+ /* Fill segment with pattern */
+ memset(rte_pktmbuf_mtod(seg, void *), fill_byte, seg_size);
+
+ *prev = seg;
+ prev = &seg->next;
+ remaining -= seg_size;
+ nb_segs++;
+ }
+
+ if (head != NULL) {
+ head->pkt_len = pkt_len;
+ head->nb_segs = nb_segs;
+ }
+
+ return head;
+}
+
+/*
+ * Helper: Allocate a multi-segment mbuf with controlled segment size.
+ *
+ * Unlike alloc_jumbo_mbuf which fills segments to tailroom capacity,
+ * this limits each segment to seg_size bytes, guaranteeing that the
+ * resulting mbuf chain has multiple segments even for moderate pkt_len.
+ */
+static struct rte_mbuf *
+alloc_multiseg_mbuf(uint32_t pkt_len, uint16_t seg_size, uint8_t fill_byte)
+{
+ struct rte_mbuf *head = NULL;
+ struct rte_mbuf **prev = &head;
+ uint32_t remaining = pkt_len;
+ uint16_t nb_segs = 0;
+
+ while (remaining > 0) {
+ struct rte_mbuf *seg = rte_pktmbuf_alloc(mp);
+ uint16_t this_len;
+
+ if (seg == NULL) {
+ rte_pktmbuf_free(head);
+ return NULL;
+ }
+
+ this_len = RTE_MIN(remaining, seg_size);
+ this_len = RTE_MIN(this_len, rte_pktmbuf_tailroom(seg));
+ seg->data_len = this_len;
+
+ memset(rte_pktmbuf_mtod(seg, void *), fill_byte, this_len);
+
+ *prev = seg;
+ prev = &seg->next;
+ remaining -= this_len;
+ nb_segs++;
+ }
+
+ if (head != NULL) {
+ head->pkt_len = pkt_len;
+ head->nb_segs = nb_segs;
+ }
+
+ return head;
+}
+
+/*
+ * Helper: Receive packets from port (no retry needed for file-based RX)
+ */
+static int
+receive_packets(uint16_t port, struct rte_mbuf **mbufs,
+ unsigned int max_pkts, unsigned int *received)
+{
+ unsigned int total = 0;
+
+ while (total < max_pkts) {
+ uint16_t nb_rx = rte_eth_rx_burst(port, 0, &mbufs[total], max_pkts - total);
+ if (nb_rx == 0)
+ break;
+ total += nb_rx;
+ }
+ *received = total;
+ return 0;
+}
+
+/*
+ * Helper: Verify mbuf contains expected test packet
+ */
+static int
+verify_packet(struct rte_mbuf *mbuf)
+{
+ TEST_ASSERT_EQUAL(rte_pktmbuf_data_len(mbuf), sizeof(test_packet),
+ "Packet length mismatch");
+ TEST_ASSERT_BUFFERS_ARE_EQUAL(rte_pktmbuf_mtod(mbuf, void *),
+ test_packet, sizeof(test_packet),
+ "Packet data mismatch");
+ return 0;
+}
+
+/*
+ * Helper: Check if interface supports Ethernet (DLT_EN10MB)
+ *
+ * The pcap PMD only works with Ethernet interfaces. On FreeBSD/macOS,
+ * the loopback interface uses DLT_NULL which is incompatible.
+ */
+static int
+iface_is_ethernet(const char *name)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pcap;
+ int datalink;
+
+ pcap = pcap_open_live(name, 256, 0, 0, errbuf);
+ if (pcap == NULL)
+ return 0;
+
+ datalink = pcap_datalink(pcap);
+ pcap_close(pcap);
+
+ return datalink == DLT_EN10MB;
+}
+
+/*
+ * Helper: Find a usable test interface using pcap_findalldevs
+ *
+ * Uses libpcap's portable interface enumeration which works on
+ * Linux, FreeBSD, macOS, and Windows.
+ *
+ * Only selects interfaces that support Ethernet link type (DLT_EN10MB).
+ * This excludes loopback on FreeBSD/macOS which uses DLT_NULL.
+ *
+ * Preference order:
+ * 1. Loopback interface (if Ethernet - Linux only)
+ * 2. Any interface that is UP and RUNNING
+ * 3. Any available Ethernet interface
+ *
+ * Returns static buffer with interface name, or NULL if none found.
+ */
+static const char *
+find_test_iface(void)
+{
+ static char iface_name[256];
+ pcap_if_t *alldevs, *dev;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ const char *loopback = NULL;
+ const char *any_up = NULL;
+ const char *any_ether = NULL;
+
+ if (pcap_findalldevs(&alldevs, errbuf) != 0) {
+ printf("pcap_findalldevs failed: %s\n", errbuf);
+ return NULL;
+ }
+
+ if (alldevs == NULL) {
+ printf("No interfaces found\n");
+ return NULL;
+ }
+
+ for (dev = alldevs; dev != NULL; dev = dev->next) {
+ if (dev->name == NULL)
+ continue;
+
+ /* Only consider Ethernet interfaces */
+ if (!iface_is_ethernet(dev->name))
+ continue;
+
+ if (any_ether == NULL)
+ any_ether = dev->name;
+
+ /* Prefer loopback for safety (Linux lo supports DLT_EN10MB) */
+ if ((dev->flags & PCAP_IF_LOOPBACK) && loopback == NULL) {
+ loopback = dev->name;
+ continue;
+ }
+
+#ifdef PCAP_IF_UP
+ if ((dev->flags & PCAP_IF_UP) &&
+ (dev->flags & PCAP_IF_RUNNING) &&
+ any_up == NULL)
+ any_up = dev->name;
+#else
+ if (any_up == NULL)
+ any_up = dev->name;
+#endif
+ }
+
+ /* Select best available interface */
+ const char *selected = NULL;
+ if (loopback != NULL)
+ selected = loopback;
+ else if (any_up != NULL)
+ selected = any_up;
+ else if (any_ether != NULL)
+ selected = any_ether;
+
+ if (selected != NULL)
+ strlcpy(iface_name, selected, sizeof(iface_name));
+
+ pcap_freealldevs(alldevs);
+ return selected ? iface_name : NULL;
+}
+
+/*
+ * Test: Transmit packets to pcap file
+ */
+static int
+test_tx_to_file(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ char devargs[256];
+ uint16_t port_id;
+ int nb_tx, pkt_count;
+ int ret;
+
+ printf("Testing TX to pcap file\n");
+
+ TEST_ASSERT(create_temp_path(tx_pcap_path, sizeof(tx_pcap_path),
+ "pcap_tx") == 0,
+ "Failed to create temp file path");
+
+ ret = snprintf(devargs, sizeof(devargs), "tx_pcap=%s", tx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_tx", devargs, &port_id) == 0,
+ "Failed to create TX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup TX port");
+ TEST_ASSERT(alloc_test_mbufs(mbufs, NUM_PACKETS) == 0,
+ "Failed to allocate mbufs");
+
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, NUM_PACKETS);
+ TEST_ASSERT_EQUAL(nb_tx, NUM_PACKETS,
+ "TX burst failed: sent %d/%d", nb_tx, NUM_PACKETS);
+
+ cleanup_pcap_vdev("net_pcap_tx", port_id);
+
+ pkt_count = count_pcap_packets(tx_pcap_path);
+ TEST_ASSERT_EQUAL(pkt_count, NUM_PACKETS,
+ "Pcap file has %d packets, expected %d",
+ pkt_count, NUM_PACKETS);
+
+ printf("TX to file PASSED: %d packets written\n", NUM_PACKETS);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Receive packets from pcap file
+ * Uses output from TX test as input
+ */
+static int
+test_rx_from_file(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int received, i;
+ int ret;
+
+ printf("Testing RX from pcap file\n");
+
+ /* Create input file if TX test didn't run */
+ if (access(tx_pcap_path, F_OK) != 0) {
+ TEST_ASSERT(create_temp_path(tx_pcap_path, sizeof(tx_pcap_path),
+ "pcap_rx_input") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_test_pcap(tx_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create input pcap");
+ }
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", tx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_rx", devargs, &port_id) == 0,
+ "Failed to create RX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup RX port");
+
+ receive_packets(port_id, mbufs, RTE_DIM(mbufs), &received);
+ TEST_ASSERT_EQUAL(received, RTE_DIM(mbufs),
+ "Received %u packets, expected %lu",
+ received, RTE_DIM(mbufs));
+
+ for (i = 0; i < received; i++) {
+ TEST_ASSERT(verify_packet(mbufs[i]) == 0,
+ "Packet %u verification failed", i);
+ }
+ rte_pktmbuf_free_bulk(mbufs, received);
+
+ cleanup_pcap_vdev("net_pcap_rx", port_id);
+
+ printf("RX from file PASSED: %u packets verified\n", received);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: TX with varied packet sizes using packet_burst_generator
+ */
+static int
+test_tx_varied_sizes(void)
+{
+ static const uint16_t test_sizes[] = {
+ PKT_SIZE_MIN, PKT_SIZE_SMALL, 200
+ };
+ char tx_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int i;
+ int ret;
+
+ printf("Testing TX with varied packet sizes\n");
+
+ TEST_ASSERT(create_temp_path(tx_path, sizeof(tx_path),
+ "pcap_tx_varied") == 0,
+ "Failed to create temp file path");
+
+ ret = snprintf(devargs, sizeof(devargs), "tx_pcap=%s", tx_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_tx_var", devargs, &port_id) == 0,
+ "Failed to create TX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup TX port");
+
+ unsigned int total_tx = 0;
+
+ for (i = 0; i < RTE_DIM(test_sizes); i++) {
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ int nb_pkt, nb_tx;
+
+ nb_pkt = generate_test_packets(mp, mbufs, MAX_PKT_BURST,
+ test_sizes[i]);
+ TEST_ASSERT(nb_pkt > 0,
+ "Failed to generate packets of size %u",
+ test_sizes[i]);
+
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, nb_pkt);
+ if (nb_tx < nb_pkt)
+ rte_pktmbuf_free_bulk(&mbufs[nb_tx], nb_pkt - nb_tx);
+
+ printf(" Size %u: generated %d, transmitted %d\n",
+ test_sizes[i], nb_pkt, nb_tx);
+ TEST_ASSERT(nb_tx > 0, "Failed to TX packets of size %u",
+ test_sizes[i]);
+ total_tx += nb_tx;
+ }
+
+ cleanup_pcap_vdev("net_pcap_tx_var", port_id);
+
+ /* Read back pcap file and verify packet sizes match what was sent */
+ {
+ uint16_t sizes[MAX_PKT_BURST * RTE_DIM(test_sizes)];
+ int pkt_count;
+ unsigned int idx = 0;
+
+ pkt_count = get_pcap_packet_sizes(tx_path, sizes,
+ RTE_DIM(sizes));
+ TEST_ASSERT_EQUAL((unsigned int)pkt_count, total_tx,
+ "Pcap has %d packets, expected %u",
+ pkt_count, total_tx);
+
+ for (i = 0; i < RTE_DIM(test_sizes); i++) {
+ unsigned int j;
+ /* Each size produced MAX_PKT_BURST (or fewer) packets */
+ for (j = 0; j < MAX_PKT_BURST && idx < (unsigned int)pkt_count; j++, idx++) {
+ TEST_ASSERT_EQUAL(sizes[idx], test_sizes[i],
+ "Packet %u: size %u, expected %u",
+ idx, sizes[idx], test_sizes[i]);
+ }
+ }
+ }
+
+ remove_temp_file(tx_path);
+
+ printf("TX varied sizes PASSED: %u packets verified\n", total_tx);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: RX with varied packet sizes
+ */
+static int
+test_rx_varied_sizes(void)
+{
+ static const uint16_t expected_sizes[] = {
+ PKT_SIZE_MIN, PKT_SIZE_SMALL, PKT_SIZE_MEDIUM,
+ PKT_SIZE_LARGE, PKT_SIZE_MTU
+ };
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ uint16_t rx_sizes[NUM_PACKETS];
+ char varied_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int received, i;
+ int ret;
+
+ printf("Testing RX with varied packet sizes\n");
+
+ TEST_ASSERT(create_temp_path(varied_pcap_path, sizeof(varied_pcap_path),
+ "pcap_varied") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_varied_pcap(varied_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create varied pcap");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", varied_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_var", devargs, &port_id) == 0,
+ "Failed to create varied RX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup varied RX port");
+
+ receive_packets(port_id, mbufs, RTE_DIM(mbufs), &received);
+ TEST_ASSERT_EQUAL(received, RTE_DIM(mbufs),
+ "Received %u packets, expected %lu",
+ received, RTE_DIM(mbufs));
+
+ /* Verify packet sizes match expected pattern */
+ for (i = 0; i < received; i++) {
+ uint16_t expected = expected_sizes[i % RTE_DIM(expected_sizes)];
+ rx_sizes[i] = rte_pktmbuf_pkt_len(mbufs[i]);
+ TEST_ASSERT_EQUAL(rx_sizes[i], expected,
+ "Packet %u: size %u, expected %u",
+ i, rx_sizes[i], expected);
+ }
+
+ rte_pktmbuf_free_bulk(mbufs, received);
+ cleanup_pcap_vdev("net_pcap_var", port_id);
+ remove_temp_file(varied_pcap_path);
+
+ printf("RX varied sizes PASSED: %u packets with correct sizes\n", received);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Infinite RX mode - loops through pcap file continuously
+ */
+static int
+test_infinite_rx(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ char infinite_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int total_rx = 0;
+ int iter, attempts;
+ int ret;
+
+ printf("Testing infinite RX mode\n");
+
+ TEST_ASSERT(create_temp_path(infinite_pcap_path, sizeof(infinite_pcap_path),
+ "pcap_inf") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_test_pcap(infinite_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create input pcap");
+
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_pcap=%s,infinite_rx=1", infinite_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_inf", devargs, &port_id) == 0,
+ "Failed to create infinite RX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup infinite RX port");
+
+ /* Read more packets than file contains to verify looping */
+ for (iter = 0; iter < 3 && total_rx < NUM_PACKETS * 2; iter++) {
+ for (attempts = 0; attempts < 100 && total_rx < NUM_PACKETS * 2;
+ attempts++) {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0, mbufs,
+ MAX_PKT_BURST);
+ if (nb_rx > 0)
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ total_rx += nb_rx;
+ if (nb_rx == 0)
+ rte_delay_us_sleep(100);
+ }
+ }
+
+ cleanup_pcap_vdev("net_pcap_inf", port_id);
+ remove_temp_file(infinite_pcap_path);
+
+ TEST_ASSERT(total_rx >= NUM_PACKETS * 2,
+ "Infinite RX: got %u packets, need >= %d",
+ total_rx, NUM_PACKETS * 2);
+
+ printf("Infinite RX PASSED: %u packets (file has %d)\n",
+ total_rx, NUM_PACKETS);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: TX drop mode - packets dropped when no tx_pcap specified
+ */
+static int
+test_tx_drop(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ struct rte_eth_stats stats;
+ char rx_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ int nb_tx;
+ int ret;
+
+ printf("Testing TX drop mode\n");
+
+ TEST_ASSERT(create_temp_path(rx_pcap_path, sizeof(rx_pcap_path), "pcap_drop") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_test_pcap(rx_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create input pcap");
+
+ /* Only rx_pcap - TX should silently drop */
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", rx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_drop", devargs, &port_id) == 0,
+ "Failed to create drop vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup drop port");
+ TEST_ASSERT(alloc_test_mbufs(mbufs, RTE_DIM(mbufs)) == 0,
+ "Failed to allocate mbufs");
+
+ TEST_ASSERT(rte_eth_stats_reset(port_id) == 0,
+ "Failed to reset stats");
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, RTE_DIM(mbufs));
+
+ /* Packets should be accepted even in drop mode */
+ TEST_ASSERT_EQUAL(nb_tx, RTE_DIM(mbufs),
+ "Drop mode TX: %d/%lu accepted",
+ nb_tx, RTE_DIM(mbufs));
+
+ TEST_ASSERT(rte_eth_stats_get(port_id, &stats) == 0,
+ "Failed to get stats");
+ cleanup_pcap_vdev("net_pcap_drop", port_id);
+ remove_temp_file(rx_pcap_path);
+
+ printf("TX drop PASSED: %d packets dropped, opackets=%" PRIu64"\n",
+ nb_tx, stats.opackets);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Statistics accuracy and reset
+ */
+static int
+test_stats(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ struct rte_eth_stats stats;
+ char rx_pcap_path[PATH_MAX];
+ char devargs[256];
+ char stats_tx_path[PATH_MAX];
+ uint16_t port_id;
+ unsigned int received;
+ int nb_tx;
+ int ret;
+
+ printf("Testing statistics accuracy\n");
+
+ TEST_ASSERT(create_temp_path(rx_pcap_path, sizeof(rx_pcap_path), "pcap_stats_rx") == 0,
+ "Failed to create RX temp path");
+ TEST_ASSERT(create_temp_path(stats_tx_path, sizeof(stats_tx_path), "pcap_stats_tx") == 0,
+ "Failed to create TX temp path");
+ TEST_ASSERT(create_test_pcap(rx_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create input pcap");
+
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_pcap=%s,tx_pcap=%s", rx_pcap_path, stats_tx_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_stats", devargs, &port_id) == 0,
+ "Failed to create stats vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup stats port");
+
+ /* Verify stats start at zero */
+ TEST_ASSERT(rte_eth_stats_reset(port_id) == 0,
+ "Failed to reset stats");
+ TEST_ASSERT(rte_eth_stats_get(port_id, &stats) == 0,
+ "Failed to get stats");
+ TEST_ASSERT(stats.ipackets == 0 && stats.opackets == 0 &&
+ stats.ibytes == 0 && stats.obytes == 0,
+ "Initial stats not zero");
+
+ /* RX and verify stats */
+ receive_packets(port_id, mbufs, RTE_DIM(mbufs), &received);
+ TEST_ASSERT(rte_eth_stats_get(port_id, &stats) == 0,
+ "Failed to get stats after RX");
+ TEST_ASSERT_EQUAL(stats.ipackets, received,
+ "RX stats: ipackets=%"PRIu64", received=%u",
+ stats.ipackets, received);
+ TEST_ASSERT(stats.ibytes > 0,
+ "RX stats: ibytes should be > 0");
+ TEST_ASSERT_EQUAL(stats.ibytes, (uint64_t)received * sizeof(test_packet),
+ "RX stats: ibytes=%"PRIu64", expected=%"PRIu64,
+ stats.ibytes,
+ (uint64_t)received * sizeof(test_packet));
+
+ /* TX and verify stats */
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, received);
+ TEST_ASSERT(rte_eth_stats_get(port_id, &stats) == 0,
+ "Failed to get stats after TX");
+ TEST_ASSERT_EQUAL(stats.opackets, (uint64_t)nb_tx,
+ "TX stats: opackets=%"PRIu64", sent=%u",
+ stats.opackets, nb_tx);
+ TEST_ASSERT(stats.obytes > 0,
+ "TX stats: obytes should be > 0");
+ TEST_ASSERT_EQUAL(stats.obytes, (uint64_t)nb_tx * sizeof(test_packet),
+ "TX stats: obytes=%"PRIu64", expected=%"PRIu64,
+ stats.obytes,
+ (uint64_t)nb_tx * sizeof(test_packet));
+
+ /* Verify stats reset */
+ TEST_ASSERT(rte_eth_stats_reset(port_id) == 0,
+ "Failed to reset stats");
+ TEST_ASSERT(rte_eth_stats_get(port_id, &stats) == 0,
+ "Failed to get stats after reset");
+ TEST_ASSERT(stats.ipackets == 0 && stats.opackets == 0,
+ "Stats not reset to zero");
+
+ cleanup_pcap_vdev("net_pcap_stats", port_id);
+ remove_temp_file(rx_pcap_path);
+ remove_temp_file(stats_tx_path);
+
+ printf("Statistics PASSED: RX=%u, TX=%d\n", received, nb_tx);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Jumbo frame RX (multi-segment mbufs)
+ */
+static int
+test_jumbo_rx(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ char jumbo_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int received, i;
+ int ret;
+ const unsigned int num_jumbo = 16;
+
+ printf("Testing jumbo frame RX (%u byte packets, multi-segment)\n",
+ PKT_SIZE_JUMBO);
+
+ TEST_ASSERT(create_temp_path(jumbo_pcap_path, sizeof(jumbo_pcap_path), "pcap_jumbo") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_sized_pcap(jumbo_pcap_path, num_jumbo,
+ PKT_SIZE_JUMBO) == 0,
+ "Failed to create jumbo pcap");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", jumbo_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_jumbo", devargs, &port_id) == 0,
+ "Failed to create jumbo RX vdev");
+
+ /* Jumbo frames require scatter to receive into multi-segment mbufs */
+ struct rte_eth_conf jumbo_conf = {
+ .rxmode.offloads = RTE_ETH_RX_OFFLOAD_SCATTER |
+ RTE_ETH_RX_OFFLOAD_TIMESTAMP,
+ };
+ TEST_ASSERT(setup_pcap_port_conf(port_id, &jumbo_conf) == 0,
+ "Failed to setup jumbo RX port");
+
+ receive_packets(port_id, mbufs, num_jumbo, &received);
+ TEST_ASSERT_EQUAL(received, num_jumbo,
+ "Received %u packets, expected %u", received, num_jumbo);
+
+ /* Verify all packets are jumbo size (may be multi-segment) */
+ for (i = 0; i < received; i++) {
+ uint32_t pkt_len = rte_pktmbuf_pkt_len(mbufs[i]);
+ uint16_t nb_segs = mbufs[i]->nb_segs;
+
+ TEST_ASSERT_EQUAL(pkt_len, PKT_SIZE_JUMBO,
+ "Packet %u: size %u, expected %u",
+ i, pkt_len, PKT_SIZE_JUMBO);
+
+ /* Jumbo frames should use multiple segments */
+ if (nb_segs > 1)
+ printf(" Packet %u: %u segments\n", i, nb_segs);
+ }
+
+ rte_pktmbuf_free_bulk(mbufs, received);
+ cleanup_pcap_vdev("net_pcap_jumbo", port_id);
+ remove_temp_file(jumbo_pcap_path);
+
+ printf("Jumbo RX PASSED: %u jumbo packets received\n", received);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Jumbo frame TX (multi-segment mbufs)
+ */
+static int
+test_jumbo_tx(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ char tx_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ uint16_t sizes[MAX_PKT_BURST];
+ int nb_tx, pkt_count;
+ unsigned int i;
+ int ret;
+ const unsigned int num_jumbo = 8;
+
+ printf("Testing jumbo frame TX (multi-segment mbufs)\n");
+
+ TEST_ASSERT(create_temp_path(tx_path, sizeof(tx_path),
+ "pcap_jumbo_tx") == 0,
+ "Failed to create temp file path");
+
+ ret = snprintf(devargs, sizeof(devargs), "tx_pcap=%s", tx_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_jumbo_tx", devargs, &port_id) == 0,
+ "Failed to create TX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup TX port");
+
+ /* Allocate multi-segment mbufs for jumbo frames */
+ for (i = 0; i < num_jumbo; i++) {
+ mbufs[i] = alloc_jumbo_mbuf(PKT_SIZE_JUMBO, (uint8_t)(i & 0xFF));
+ if (mbufs[i] == NULL) {
+ /* Free already allocated mbufs */
+ while (i > 0)
+ rte_pktmbuf_free(mbufs[--i]);
+ cleanup_pcap_vdev("net_pcap_jumbo_tx", port_id);
+ remove_temp_file(tx_path);
+ return TEST_FAILED;
+ }
+ printf(" Packet %u: %u segments for %u bytes\n",
+ i, mbufs[i]->nb_segs, PKT_SIZE_JUMBO);
+ }
+
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, num_jumbo);
+ /* Free any unsent mbufs */
+ for (i = nb_tx; i < num_jumbo; i++)
+ rte_pktmbuf_free(mbufs[i]);
+
+ TEST_ASSERT_EQUAL(nb_tx, (int)num_jumbo,
+ "TX burst failed: sent %d/%u", nb_tx, num_jumbo);
+
+ cleanup_pcap_vdev("net_pcap_jumbo_tx", port_id);
+
+ /* Verify pcap file has correct packet count and sizes */
+ pkt_count = get_pcap_packet_sizes(tx_path, sizes, MAX_PKT_BURST);
+ TEST_ASSERT_EQUAL(pkt_count, (int)num_jumbo,
+ "Pcap file has %d packets, expected %u",
+ pkt_count, num_jumbo);
+
+ for (i = 0; i < (unsigned int)pkt_count; i++) {
+ TEST_ASSERT_EQUAL(sizes[i], PKT_SIZE_JUMBO,
+ "Packet %u: size %u, expected %u",
+ i, sizes[i], PKT_SIZE_JUMBO);
+ }
+
+ remove_temp_file(tx_path);
+
+ printf("Jumbo TX PASSED: %d jumbo packets written\n", nb_tx);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Layering on Linux network interface
+ */
+static int
+test_iface(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ struct rte_eth_dev_info dev_info;
+ char devargs[256];
+ uint16_t port_id;
+ const char *iface;
+ int ret, nb_tx, nb_pkt;
+
+ printf("Testing pcap on network interface\n");
+
+ iface = find_test_iface();
+ if (iface == NULL) {
+ printf("No suitable interface, skipping\n");
+ return TEST_SKIPPED;
+ }
+ printf("Using interface: %s\n", iface);
+
+ ret = snprintf(devargs, sizeof(devargs), "iface=%s", iface);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ if (rte_vdev_init("net_pcap_iface", devargs) < 0) {
+ printf("Cannot create iface vdev (needs root?), skipping\n");
+ return TEST_SKIPPED;
+ }
+
+ TEST_ASSERT(rte_eth_dev_get_port_by_name("net_pcap_iface",
+ &port_id) == 0,
+ "Failed to get iface port ID");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup iface port");
+
+ ret = rte_eth_dev_info_get(port_id, &dev_info);
+ TEST_ASSERT(ret == 0, "Failed to get dev info: %s", rte_strerror(-ret));
+
+ printf("Driver: %s, max_rx_queues=%u, max_tx_queues=%u\n",
+ dev_info.driver_name, dev_info.max_rx_queues,
+ dev_info.max_tx_queues);
+
+ /* Use packet_burst_generator for interface test */
+ nb_pkt = generate_test_packets(mp, mbufs, MAX_PKT_BURST,
+ PACKET_BURST_GEN_PKT_LEN);
+ TEST_ASSERT(nb_pkt > 0, "Failed to generate packets");
+
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, nb_pkt);
+ if (nb_tx < nb_pkt)
+ rte_pktmbuf_free_bulk(&mbufs[nb_tx], nb_pkt - nb_tx);
+
+ cleanup_pcap_vdev("net_pcap_iface", port_id);
+
+ printf("Interface test PASSED: sent %d packets\n", nb_tx);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Link status and speed reporting
+ *
+ * This test verifies that:
+ * 1. In interface (pass-through) mode, link state reflects the real interface
+ * 2. In file mode, link status follows device started/stopped state
+ * 3. Link speed values are properly reported
+ */
+static int
+test_link_status(void)
+{
+ struct rte_eth_link link;
+ char rx_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ const char *iface;
+ int ret;
+
+ printf("Testing link status reporting\n");
+
+ /*
+ * Test 1: Interface (pass-through) mode
+ * Link state should reflect the underlying interface
+ */
+ iface = find_test_iface();
+ if (iface != NULL) {
+ printf(" Testing interface mode with: %s\n", iface);
+
+ ret = snprintf(devargs, sizeof(devargs), "iface=%s", iface);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ if (rte_vdev_init("net_pcap_link_iface", devargs) == 0) {
+ ret = rte_eth_dev_get_port_by_name("net_pcap_link_iface", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+
+ ret = setup_pcap_port(port_id);
+ TEST_ASSERT(ret == 0, "Failed to setup port");
+
+ /* Get link status */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link: %s", rte_strerror(-ret));
+
+ printf(" Link status: %s\n",
+ link.link_status ? "UP" : "DOWN");
+ printf(" Link speed: %u Mbps\n", link.link_speed);
+ printf(" Link duplex: %s\n",
+ link.link_duplex ? "full" : "half");
+ printf(" Link autoneg: %s\n",
+ link.link_autoneg ? "enabled" : "disabled");
+
+ /*
+ * For loopback interface, link should be up.
+ * Speed may be 0 or undefined for virtual interfaces.
+ */
+ if (strcmp(iface, "lo") == 0) {
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_UP,
+ "Loopback should report link UP");
+ }
+
+ /*
+ * Verify link_get returns consistent results
+ */
+ struct rte_eth_link link2;
+ ret = rte_eth_link_get(port_id, &link2);
+ TEST_ASSERT(ret == 0, "Second link_get failed");
+ TEST_ASSERT(link.link_status == link2.link_status,
+ "Link status inconsistent between calls");
+
+ cleanup_pcap_vdev("net_pcap_link_iface", port_id);
+ printf(" Interface mode link test PASSED\n");
+ } else {
+ printf(" Cannot create iface vdev (needs root?), skipping iface test\n");
+ }
+ } else {
+ printf(" No suitable interface found, skipping iface test\n");
+ }
+
+ /*
+ * Test 2: File mode
+ * Link status should be DOWN before start, UP after start
+ */
+ printf(" Testing file mode link status\n");
+
+ /* Create a simple pcap file for testing */
+ TEST_ASSERT(create_temp_path(rx_pcap_path, sizeof(rx_pcap_path), "pcap_link") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_test_pcap(rx_pcap_path, 1) == 0,
+ "Failed to create test pcap");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", rx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_link_file", devargs, &port_id) == 0,
+ "Failed to create file vdev");
+
+ /* Before starting: configure but don't start */
+ struct rte_eth_conf port_conf = { 0 };
+ ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
+ TEST_ASSERT(ret == 0, "Failed to configure port");
+
+ ret = rte_eth_rx_queue_setup(port_id, 0, RING_SIZE, SOCKET0, NULL, mp);
+ TEST_ASSERT(ret == 0, "Failed to setup RX queue");
+
+ ret = rte_eth_tx_queue_setup(port_id, 0, RING_SIZE, SOCKET0, NULL);
+ TEST_ASSERT(ret == 0, "Failed to setup TX queue");
+
+ /* Check link before start - should be DOWN */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link before start");
+ printf(" Before start: link %s, speed %u Mbps\n",
+ link.link_status ? "UP" : "DOWN", link.link_speed);
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_DOWN,
+ "Link should be DOWN before start");
+
+ /* Start the port */
+ ret = rte_eth_dev_start(port_id);
+ TEST_ASSERT(ret == 0, "Failed to start port");
+
+ /* Check link after start - should be UP */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link after start");
+ printf(" After start: link %s, speed %u Mbps\n",
+ link.link_status ? "UP" : "DOWN", link.link_speed);
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_UP,
+ "Link should be UP after start");
+
+ /* Stop the port */
+ ret = rte_eth_dev_stop(port_id);
+ TEST_ASSERT(ret == 0, "Failed to stop port");
+
+ /* Check link after stop - should be DOWN again */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link after stop");
+ printf(" After stop: link %s\n",
+ link.link_status ? "UP" : "DOWN");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_DOWN,
+ "Link should be DOWN after stop");
+
+ rte_vdev_uninit("net_pcap_link_file");
+ remove_temp_file(rx_pcap_path);
+
+ printf("Link status test PASSED\n");
+ return TEST_SUCCESS;
+}
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static int
+test_lsc_iface(void)
+{
+ printf(" Link toggle test not supported on Windows, skipping\n");
+ return TEST_SKIPPED;
+}
+#else
+/*
+ * Test: Link Status Change (LSC) interrupt support
+ *
+ * Verifies that:
+ * 1. LSC capability is NOT advertised for file mode
+ * 2. LSC capability IS advertised for iface mode
+ * 3. LSC callback fires when the underlying interface goes down/up
+ *
+ * Requires a toggleable Ethernet interface created before running:
+ * Linux: ip link add dummy0 type dummy && ip link set dummy0 up
+ * FreeBSD: ifconfig disc0 create && ifconfig disc0 up
+ *
+ * Skipped if no suitable interface is found or on Windows.
+ */
+
+/* Callback counter for LSC test */
+static volatile int lsc_callback_count;
+
+static int
+test_lsc_callback(uint16_t port_id __rte_unused,
+ enum rte_eth_event_type event __rte_unused,
+ void *cb_arg __rte_unused, void *ret_param __rte_unused)
+{
+ lsc_callback_count++;
+ return 0;
+}
+
+/*
+ * Helper: Set interface link up or down via ioctl.
+ * Returns 0 on success, -errno on failure.
+ */
+static int
+set_iface_up_down(const char *ifname, int up)
+{
+ struct ifreq ifr;
+ int fd, ret;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -errno;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ ret = ioctl(fd, SIOCGIFFLAGS, &ifr);
+ if (ret < 0) {
+ ret = -errno;
+ close(fd);
+ return ret;
+ }
+
+ if (up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
+ if (ret < 0)
+ ret = -errno;
+ else
+ ret = 0;
+
+ close(fd);
+ return ret;
+}
+
+/*
+ * Helper: Find a toggleable test interface for LSC testing.
+ *
+ * Looks for well-known interfaces that are safe to bring up/down:
+ * Linux: dummy0 (ip link add dummy0 type dummy)
+ * FreeBSD: disc0 (ifconfig disc0 create)
+ *
+ * Returns interface name or NULL if none found.
+ */
+static const char *
+find_lsc_test_iface(void)
+{
+ static const char * const candidates[] = { "dummy0", "disc0" };
+ unsigned int i;
+
+ for (i = 0; i < RTE_DIM(candidates); i++) {
+ if (iface_is_ethernet(candidates[i]))
+ return candidates[i];
+ }
+ return NULL;
+}
+
+static int
+test_lsc_iface(void)
+{
+ struct rte_eth_dev_info dev_info;
+ char devargs[256];
+ int ret;
+
+ printf("Testing Link Status Change (LSC) support\n");
+
+ /*
+ * Test 1: Verify LSC is NOT advertised for file mode
+ */
+ printf(" Testing file mode does not advertise LSC\n");
+ {
+ char lsc_pcap_path[PATH_MAX];
+ uint16_t file_port_id;
+
+ TEST_ASSERT(create_temp_path(lsc_pcap_path, sizeof(lsc_pcap_path),
+ "pcap_lsc") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_test_pcap(lsc_pcap_path, 1) == 0,
+ "Failed to create test pcap");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", lsc_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_lsc_file", devargs,
+ &file_port_id) == 0,
+ "Failed to create file vdev");
+
+ ret = rte_eth_dev_info_get(file_port_id, &dev_info);
+ TEST_ASSERT(ret == 0, "Failed to get dev info");
+
+ TEST_ASSERT((*dev_info.dev_flags & RTE_ETH_DEV_INTR_LSC) == 0,
+ "File mode should NOT advertise LSC capability");
+
+ rte_vdev_uninit("net_pcap_lsc_file");
+ remove_temp_file(lsc_pcap_path);
+ printf(" File mode LSC check PASSED\n");
+ }
+
+ struct rte_eth_link link;
+ struct rte_eth_conf port_conf = {
+ .intr_conf.lsc = 1,
+ };
+ uint16_t port_id;
+
+ /*
+ * Test 2: Use a toggleable interface to test link change events.
+ * Skip if not present.
+ */
+ const char *lsc_iface = find_lsc_test_iface();
+ if (lsc_iface == NULL) {
+ printf(" No toggleable interface found, skipping link change test\n");
+ printf(" Linux: ip link add dummy0 type dummy && ip link set dummy0 up\n");
+ printf(" FreeBSD: ifconfig disc0 create && ifconfig disc0 up\n");
+ return TEST_SKIPPED;
+ }
+
+ printf(" Testing iface mode LSC with: %s\n", lsc_iface);
+
+ /* Ensure interface is up before we start */
+ ret = set_iface_up_down(lsc_iface, 1);
+ if (ret != 0) {
+ printf(" Cannot set %s up (%s), skipping\n",
+ lsc_iface, strerror(-ret));
+ return TEST_SKIPPED;
+ }
+
+ ret = snprintf(devargs, sizeof(devargs), "iface=%s", lsc_iface);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ ret = rte_vdev_init("net_pcap_lsc", devargs);
+ if (ret < 0) {
+ printf(" Cannot create iface vdev for %s, skipping\n", lsc_iface);
+ return TEST_SKIPPED;
+ }
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_lsc", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+
+ /* Verify LSC capability is advertised */
+ ret = rte_eth_dev_info_get(port_id, &dev_info);
+ TEST_ASSERT(ret == 0, "Failed to get dev info");
+ TEST_ASSERT(*dev_info.dev_flags & RTE_ETH_DEV_INTR_LSC,
+ "Iface mode should advertise LSC capability");
+ printf(" LSC capability advertised: yes\n");
+
+ /* Register LSC callback */
+ lsc_callback_count = 0;
+ ret = rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC,
+ test_lsc_callback, NULL);
+ TEST_ASSERT(ret == 0, "Failed to register LSC callback");
+
+ /* Configure with LSC enabled and start */
+ TEST_ASSERT(setup_pcap_port_conf(port_id, &port_conf) == 0,
+ "Failed to setup port with LSC");
+
+ /* Verify link is up initially */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link status");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_UP,
+ "Link should be UP after start");
+ printf(" Link after start: UP\n");
+
+ /* Bring interface down - should trigger LSC */
+ lsc_callback_count = 0;
+ ret = set_iface_up_down(lsc_iface, 0);
+ TEST_ASSERT(ret == 0, "Failed to set %s down: %s",
+ lsc_iface, strerror(-ret));
+
+ /* Poll for link state change (1 second poll interval in driver) */
+ {
+ int poll;
+ for (poll = 0; poll < 30; poll++) {
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ if (ret == 0 && link.link_status == RTE_ETH_LINK_DOWN &&
+ lsc_callback_count >= 1)
+ break;
+ rte_delay_us_sleep(100 * 1000);
+ }
+ }
+
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link after down");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_DOWN,
+ "Link should be DOWN after interface down");
+ TEST_ASSERT(lsc_callback_count >= 1,
+ "LSC callback should have fired, count=%d",
+ lsc_callback_count);
+ printf(" Interface down: link DOWN, callbacks=%d\n",
+ lsc_callback_count);
+
+ /* Bring it back up - should trigger another LSC */
+ lsc_callback_count = 0;
+ ret = set_iface_up_down(lsc_iface, 1);
+ TEST_ASSERT(ret == 0, "Failed to set %s up: %s",
+ lsc_iface, strerror(-ret));
+
+ /* Poll for link state change back to UP */
+ {
+ int poll;
+ for (poll = 0; poll < 30; poll++) {
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ if (ret == 0 && link.link_status == RTE_ETH_LINK_UP &&
+ lsc_callback_count >= 1)
+ break;
+ rte_delay_us_sleep(100 * 1000);
+ }
+ }
+
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link after up");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_UP,
+ "Link should be UP after interface up");
+ TEST_ASSERT(lsc_callback_count >= 1,
+ "LSC callback should have fired on link restore, count=%d",
+ lsc_callback_count);
+ printf(" Interface up: link UP, callbacks=%d\n",
+ lsc_callback_count);
+
+ /* Cleanup */
+ rte_eth_dev_stop(port_id);
+ rte_eth_dev_callback_unregister(port_id, RTE_ETH_EVENT_INTR_LSC,
+ test_lsc_callback, NULL);
+ rte_vdev_uninit("net_pcap_lsc");
+
+ printf("LSC test PASSED\n");
+ return TEST_SUCCESS;
+}
+#endif /* RTE_EXEC_ENV_WINDOWS */
+
+/*
+ * Test: EOF notification via link status change
+ *
+ * Verifies that:
+ * 1. The eof devarg causes link down + LSC event at end of pcap file
+ * 2. link_get reports DOWN after EOF
+ * 3. Stop/start resets the EOF state and replays the file
+ * 4. The eof and infinite_rx options are mutually exclusive
+ */
+
+static volatile int eof_callback_count;
+
+static int
+test_eof_callback(uint16_t port_id __rte_unused,
+ enum rte_eth_event_type event __rte_unused,
+ void *cb_arg __rte_unused, void *ret_param __rte_unused)
+{
+ eof_callback_count++;
+ return 0;
+}
+
+static int
+test_eof_rx(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ struct rte_eth_conf port_conf = {
+ .intr_conf.lsc = 1,
+ };
+ struct rte_eth_link link;
+ char eof_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int total_rx;
+ int ret;
+
+ printf("Testing EOF notification via link status change\n");
+
+ /* Create pcap file with known number of packets */
+ TEST_ASSERT(create_temp_path(eof_pcap_path, sizeof(eof_pcap_path),
+ "pcap_eof") == 0,
+ "Failed to create temp file path");
+ TEST_ASSERT(create_test_pcap(eof_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create test pcap file");
+
+ /*
+ * Test 1: EOF triggers link down and LSC callback
+ */
+ printf(" Testing EOF triggers link down and LSC event\n");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s,eof=1",
+ eof_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ ret = rte_vdev_init("net_pcap_eof", devargs);
+ TEST_ASSERT(ret == 0, "Failed to create eof vdev: %s",
+ rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_eof", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+
+ /* Verify LSC capability is advertised */
+ struct rte_eth_dev_info dev_info;
+ ret = rte_eth_dev_info_get(port_id, &dev_info);
+ TEST_ASSERT(ret == 0, "Failed to get dev info");
+ TEST_ASSERT(*dev_info.dev_flags & RTE_ETH_DEV_INTR_LSC,
+ "EOF mode should advertise LSC capability");
+
+ /* Register LSC callback */
+ eof_callback_count = 0;
+ ret = rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC,
+ test_eof_callback, NULL);
+ TEST_ASSERT(ret == 0, "Failed to register LSC callback");
+
+ /* Configure with LSC enabled and start */
+ TEST_ASSERT(setup_pcap_port_conf(port_id, &port_conf) == 0,
+ "Failed to setup port with LSC");
+
+ /* Verify link is up initially */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_UP,
+ "Link should be UP after start");
+
+ /* Drain all packets from the pcap file */
+ total_rx = 0;
+ for (int attempts = 0; attempts < 200; attempts++) {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0, mbufs,
+ MAX_PKT_BURST);
+ if (nb_rx > 0) {
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ total_rx += nb_rx;
+ } else if (total_rx >= NUM_PACKETS) {
+ /* Got all packets and rx returned 0 — EOF hit */
+ break;
+ }
+ }
+
+ printf(" Received %u packets (expected %d)\n", total_rx, NUM_PACKETS);
+ TEST_ASSERT_EQUAL(total_rx, NUM_PACKETS,
+ "Should receive exactly %d packets", NUM_PACKETS);
+
+ /* Verify link went down */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link after EOF");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_DOWN,
+ "Link should be DOWN after EOF");
+
+ /* Poll for the deferred EOF alarm to fire on the interrupt thread */
+ {
+ int poll;
+ for (poll = 0; poll < 20; poll++) {
+ if (eof_callback_count >= 1)
+ break;
+ rte_delay_us_sleep(100 * 1000);
+ }
+ }
+
+ /* Verify callback fired exactly once */
+ TEST_ASSERT_EQUAL(eof_callback_count, 1,
+ "LSC callback should fire once, fired %d times",
+ eof_callback_count);
+ printf(" EOF signaled: link DOWN, callback fired\n");
+
+ /*
+ * Test 2: Stop/start resets EOF and replays the file
+ */
+ printf(" Testing restart replays pcap file\n");
+
+ ret = rte_eth_dev_stop(port_id);
+ TEST_ASSERT(ret == 0, "Failed to stop port");
+
+ eof_callback_count = 0;
+
+ ret = rte_eth_dev_start(port_id);
+ TEST_ASSERT(ret == 0, "Failed to restart port");
+
+ /* Verify link is up again */
+ ret = rte_eth_link_get_nowait(port_id, &link);
+ TEST_ASSERT(ret == 0, "Failed to get link after restart");
+ TEST_ASSERT(link.link_status == RTE_ETH_LINK_UP,
+ "Link should be UP after restart");
+
+ /* Read packets again */
+ total_rx = 0;
+ for (int attempts = 0; attempts < 200; attempts++) {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0, mbufs,
+ MAX_PKT_BURST);
+ if (nb_rx > 0) {
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ total_rx += nb_rx;
+ } else if (total_rx >= NUM_PACKETS) {
+ break;
+ }
+ }
+
+ TEST_ASSERT_EQUAL(total_rx, NUM_PACKETS,
+ "Restart: should receive %d packets, got %u",
+ NUM_PACKETS, total_rx);
+
+ /* Poll for the deferred EOF alarm to fire on the interrupt thread */
+ {
+ int poll;
+ for (poll = 0; poll < 20; poll++) {
+ if (eof_callback_count >= 1)
+ break;
+ rte_delay_us_sleep(100 * 1000);
+ }
+ }
+
+ TEST_ASSERT_EQUAL(eof_callback_count, 1,
+ "Restart: callback should fire once, fired %d times",
+ eof_callback_count);
+ printf(" Restart replay: %u packets, EOF signaled again\n", total_rx);
+
+ /* Cleanup */
+ rte_eth_dev_callback_unregister(port_id, RTE_ETH_EVENT_INTR_LSC,
+ test_eof_callback, NULL);
+ rte_eth_dev_stop(port_id);
+ rte_vdev_uninit("net_pcap_eof");
+
+ /*
+ * Test 3: eof + infinite_rx is rejected
+ */
+ printf(" Testing eof + infinite_rx mutual exclusion\n");
+
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_pcap=%s,eof=1,infinite_rx=1", eof_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ ret = rte_vdev_init("net_pcap_eof_bad", devargs);
+ TEST_ASSERT(ret != 0, "eof + infinite_rx should be rejected");
+ printf(" Mutual exclusion check PASSED\n");
+
+ remove_temp_file(eof_pcap_path);
+
+ printf("EOF test PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Verify receive timestamps from pcap file
+ */
+static int
+test_rx_timestamp(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ char timestamp_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int received, i;
+ int ret;
+ const uint32_t base_sec = 1000;
+ const uint32_t usec_increment = 10000; /* 10ms between packets */
+ rte_mbuf_timestamp_t prev_ts = 0;
+
+ printf("Testing RX timestamp accuracy\n");
+
+ TEST_ASSERT(create_temp_path(timestamp_pcap_path, sizeof(timestamp_pcap_path),
+ "pcap_ts") == 0,
+ "Failed to create temp path");
+ TEST_ASSERT(create_timestamped_pcap(timestamp_pcap_path, NUM_PACKETS,
+ base_sec, usec_increment) == 0,
+ "Failed to create timestamped pcap");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", timestamp_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_ts", devargs, &port_id) == 0,
+ "Failed to create timestamp vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup timestamp port");
+
+ /* Try to initialize timestamp dynamic field access */
+ TEST_ASSERT(timestamp_init() == 0, "Timestamp dynfield not available");
+
+ receive_packets(port_id, mbufs, RTE_DIM(mbufs), &received);
+ TEST_ASSERT_EQUAL(received, RTE_DIM(mbufs),
+ "Received %u packets, expected %u",
+ received, RTE_DIM(mbufs));
+
+ /* Check if first packet has timestamp flag set */
+ if (!mbuf_has_timestamp(mbufs[0])) {
+ printf("Timestamps not enabled in mbufs, skipping validation\n");
+ rte_pktmbuf_free_bulk(mbufs, received);
+ cleanup_pcap_vdev("net_pcap_ts", port_id);
+ return TEST_SKIPPED;
+ }
+
+ for (i = 0; i < received; i++) {
+ struct rte_mbuf *m = mbufs[i];
+
+ TEST_ASSERT(mbuf_has_timestamp(m),
+ "Packet %u missing timestamp flag", i);
+
+ /* PCAP PMD stores timestamp in nanoseconds */
+ rte_mbuf_timestamp_t ts = mbuf_timestamp_get(mbufs[i]);
+ uint64_t expected = (uint64_t)base_sec * NS_PER_S
+ + (uint64_t)i * usec_increment * 1000;
+
+ TEST_ASSERT_EQUAL(ts, expected,
+ "Packet %u: timestamp mismatch, expected=%"PRIu64
+ " actual=%"PRIu64, i, expected, ts);
+
+ /* Verify monotonically increasing timestamps */
+ if (i > 0) {
+ TEST_ASSERT(ts >= prev_ts,
+ "Packet %u: timestamp not monotonic %"PRIu64" > %"PRIu64,
+ i, prev_ts, ts);
+ }
+ prev_ts = ts;
+ }
+
+ rte_pktmbuf_free_bulk(mbufs, received);
+ cleanup_pcap_vdev("net_pcap_ts", port_id);
+ remove_temp_file(timestamp_pcap_path);
+
+ printf("RX timestamp PASSED: %u packets with valid timestamps\n", received);
+ return TEST_SUCCESS;
+}
+
+/* Helper: Generate packets for multi-queue tests */
+static int
+generate_mq_test_packets(struct rte_mbuf **pkts, unsigned int nb_pkts, uint16_t queue_id)
+{
+ struct rte_ether_hdr eth_hdr;
+ struct rte_ipv4_hdr ip_hdr;
+ struct rte_udp_hdr udp_hdr;
+ uint16_t pkt_data_len;
+ unsigned int i;
+
+ initialize_eth_header(ð_hdr, &src_mac, &dst_mac, RTE_ETHER_TYPE_IPV4, 0, 0);
+ pkt_data_len = sizeof(struct rte_udp_hdr);
+ initialize_udp_header(&udp_hdr, 1234, 1234, pkt_data_len);
+ initialize_ipv4_header(&ip_hdr, IPV4_ADDR(192, 168, 1, 1), IPV4_ADDR(192, 168, 1, 2),
+ pkt_data_len + sizeof(struct rte_udp_hdr));
+
+ for (i = 0; i < nb_pkts; i++) {
+ pkts[i] = rte_pktmbuf_alloc(mp);
+ if (pkts[i] == NULL) {
+ printf("Failed to allocate mbuf\n");
+ while (i > 0)
+ rte_pktmbuf_free(pkts[--i]);
+ return -1;
+ }
+
+ char *pkt_data = rte_pktmbuf_append(pkts[i], PACKET_BURST_GEN_PKT_LEN);
+ if (pkt_data == NULL) {
+ printf("Failed to append data to mbuf\n");
+ rte_pktmbuf_free(pkts[i]);
+ while (i > 0)
+ rte_pktmbuf_free(pkts[--i]);
+ return -1;
+ }
+
+ size_t offset = 0;
+ memcpy(pkt_data + offset, ð_hdr, sizeof(eth_hdr));
+ offset += sizeof(eth_hdr);
+
+ /* Mark packet with queue ID in IP packet_id field for tracing */
+ ip_hdr.packet_id = rte_cpu_to_be_16((queue_id << 8) | (i & 0xFF));
+ ip_hdr.hdr_checksum = 0;
+ ip_hdr.hdr_checksum = rte_ipv4_cksum(&ip_hdr);
+
+ memcpy(pkt_data + offset, &ip_hdr, sizeof(ip_hdr));
+ offset += sizeof(ip_hdr);
+ memcpy(pkt_data + offset, &udp_hdr, sizeof(udp_hdr));
+ }
+ return (int)nb_pkts;
+}
+
+/* Helper: Validate pcap file structure using libpcap */
+static int
+validate_pcap_file(const char *filename)
+{
+ pcap_t *pcap;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ pcap = pcap_open_offline(filename, errbuf);
+ if (pcap == NULL) {
+ printf("Failed to validate pcap file %s: %s\n", filename, errbuf);
+ return -1;
+ }
+ if (pcap_datalink(pcap) != DLT_EN10MB) {
+ printf("Unexpected datalink type: %d\n", pcap_datalink(pcap));
+ pcap_close(pcap);
+ return -1;
+ }
+ pcap_close(pcap);
+ return 0;
+}
+
+/*
+ * Test: Multiple TX queues writing to separate pcap files
+ *
+ * This test creates a pcap PMD with multiple TX queues, each configured
+ * to write to its own output file. We verify that:
+ * 1. All packets from all queues are written
+ * 2. Each resulting pcap file is valid
+ * 3. Each file has the expected packet count
+ */
+static int
+test_multi_tx_queue(void)
+{
+ char multi_tx_pcap_paths[MULTI_QUEUE_NUM_QUEUES][PATH_MAX];
+ char devargs[512];
+ uint16_t port_id;
+ struct rte_eth_conf port_conf;
+ struct rte_eth_txconf tx_conf;
+ struct rte_mbuf *pkts[MULTI_QUEUE_BURST_SIZE];
+ uint16_t q;
+ int ret;
+ unsigned int total_tx = 0;
+ unsigned int tx_per_queue[MULTI_QUEUE_NUM_QUEUES] = {0};
+
+ printf("Testing multiple TX queues to separate files\n");
+
+ /* Create temp paths for each TX queue */
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ char prefix[32];
+ snprintf(prefix, sizeof(prefix), "pcap_multi_tx%u", q);
+ TEST_ASSERT(create_temp_path(multi_tx_pcap_paths[q],
+ sizeof(multi_tx_pcap_paths[q]), prefix) == 0,
+ "Failed to create temp path for queue %u", q);
+ }
+
+ /* Create the pcap PMD with multiple TX queues to separate files */
+ ret = snprintf(devargs, sizeof(devargs), "tx_pcap=%s,tx_pcap=%s,tx_pcap=%s,tx_pcap=%s",
+ multi_tx_pcap_paths[0], multi_tx_pcap_paths[1],
+ multi_tx_pcap_paths[2], multi_tx_pcap_paths[3]);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+
+ ret = rte_vdev_init("net_pcap_multi_tx", devargs);
+ TEST_ASSERT_SUCCESS(ret, "Failed to create pcap PMD: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_multi_tx", &port_id);
+ TEST_ASSERT_SUCCESS(ret, "Cannot find added pcap device");
+
+ memset(&port_conf, 0, sizeof(port_conf));
+ ret = rte_eth_dev_configure(port_id, 0, MULTI_QUEUE_NUM_QUEUES, &port_conf);
+ TEST_ASSERT_SUCCESS(ret, "Failed to configure device: %s", rte_strerror(-ret));
+
+ memset(&tx_conf, 0, sizeof(tx_conf));
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ ret = rte_eth_tx_queue_setup(port_id, q, RING_SIZE,
+ rte_eth_dev_socket_id(port_id), &tx_conf);
+ TEST_ASSERT_SUCCESS(ret, "Failed to setup TX queue %u: %s", q, rte_strerror(-ret));
+ }
+
+ ret = rte_eth_dev_start(port_id);
+ TEST_ASSERT_SUCCESS(ret, "Failed to start device: %s", rte_strerror(-ret));
+
+ /* Transmit packets from each queue */
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ unsigned int pkts_to_send = MULTI_QUEUE_NUM_PACKETS / MULTI_QUEUE_NUM_QUEUES;
+
+ while (tx_per_queue[q] < pkts_to_send) {
+ unsigned int burst = RTE_MIN(MULTI_QUEUE_BURST_SIZE,
+ pkts_to_send - tx_per_queue[q]);
+
+ ret = generate_mq_test_packets(pkts, burst, q);
+ TEST_ASSERT(ret >= 0, "Failed to generate packets for queue %u", q);
+
+ uint16_t nb_tx = rte_eth_tx_burst(port_id, q, pkts, burst);
+ for (unsigned int i = nb_tx; i < burst; i++)
+ rte_pktmbuf_free(pkts[i]);
+
+ tx_per_queue[q] += nb_tx;
+ total_tx += nb_tx;
+
+ if (nb_tx == 0) {
+ printf("TX stall on queue %u\n", q);
+ break;
+ }
+ }
+ printf(" Queue %u: transmitted %u packets\n", q, tx_per_queue[q]);
+ }
+
+ rte_eth_dev_stop(port_id);
+ rte_vdev_uninit("net_pcap_multi_tx");
+ rte_delay_ms(100);
+
+ /* Validate each pcap file */
+ unsigned int total_in_files = 0;
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ ret = validate_pcap_file(multi_tx_pcap_paths[q]);
+ TEST_ASSERT_SUCCESS(ret, "pcap file for queue %u is invalid", q);
+
+ int pkt_count = count_pcap_packets(multi_tx_pcap_paths[q]);
+ TEST_ASSERT(pkt_count >= 0, "Could not count packets in pcap file for queue %u", q);
+
+ printf(" Queue %u file: %d packets\n", q, pkt_count);
+ TEST_ASSERT_EQUAL((unsigned int)pkt_count, tx_per_queue[q],
+ "Queue %u: file has %d packets, expected %u",
+ q, pkt_count, tx_per_queue[q]);
+ total_in_files += pkt_count;
+ }
+
+ printf(" Total packets transmitted: %u\n", total_tx);
+ printf(" Total packets in all files: %u\n", total_in_files);
+
+ TEST_ASSERT_EQUAL(total_in_files, total_tx,
+ "Total packet count mismatch: expected %u, got %u",
+ total_tx, total_in_files);
+
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++)
+ remove_temp_file(multi_tx_pcap_paths[q]);
+
+ printf("Multi-TX queue PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Multiple RX queues reading from the same pcap file
+ *
+ * This test creates a pcap PMD with multiple RX queues all configured
+ * to read from the same input file. We verify that:
+ * 1. Each queue can read packets
+ * 2. The total packets read equals the file content (or expected behavior)
+ */
+static int
+test_multi_rx_queue_same_file(void)
+{
+ char multi_rx_pcap_path[PATH_MAX];
+ char devargs[512];
+ uint16_t port_id;
+ struct rte_eth_conf port_conf;
+ struct rte_eth_rxconf rx_conf;
+ struct rte_mbuf *pkts[MULTI_QUEUE_BURST_SIZE];
+ uint16_t q;
+ int ret;
+ unsigned int total_rx = 0;
+ unsigned int rx_per_queue[MULTI_QUEUE_NUM_QUEUES] = {0};
+ unsigned int seed_packets = MULTI_QUEUE_NUM_PACKETS;
+ unsigned int expected_total;
+
+ printf("Testing multiple RX queues from same file\n");
+
+ TEST_ASSERT(create_temp_path(multi_rx_pcap_path, sizeof(multi_rx_pcap_path),
+ "pcap_multi_rx") == 0,
+ "Failed to create temp path");
+
+ ret = create_test_pcap(multi_rx_pcap_path, seed_packets);
+ TEST_ASSERT_SUCCESS(ret, "Failed to create seed pcap file");
+ printf(" Created seed pcap file with %u packets\n", seed_packets);
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s,rx_pcap=%s,rx_pcap=%s,rx_pcap=%s",
+ multi_rx_pcap_path, multi_rx_pcap_path, multi_rx_pcap_path, multi_rx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+
+ ret = rte_vdev_init("net_pcap_multi_rx", devargs);
+ TEST_ASSERT_SUCCESS(ret, "Failed to create pcap PMD: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_multi_rx", &port_id);
+ TEST_ASSERT_SUCCESS(ret, "Cannot find added pcap device");
+
+ memset(&port_conf, 0, sizeof(port_conf));
+ ret = rte_eth_dev_configure(port_id, MULTI_QUEUE_NUM_QUEUES, 0, &port_conf);
+ TEST_ASSERT_SUCCESS(ret, "Failed to configure device: %s", rte_strerror(-ret));
+
+ memset(&rx_conf, 0, sizeof(rx_conf));
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ ret = rte_eth_rx_queue_setup(port_id, q, RING_SIZE,
+ rte_eth_dev_socket_id(port_id), &rx_conf, mp);
+ TEST_ASSERT_SUCCESS(ret, "Failed to setup RX queue %u: %s", q, rte_strerror(-ret));
+ }
+
+ ret = rte_eth_dev_start(port_id);
+ TEST_ASSERT_SUCCESS(ret, "Failed to start device: %s", rte_strerror(-ret));
+
+ /* Receive packets from all queues. Each queue has its own file handle. */
+ int empty_rounds = 0;
+ while (empty_rounds < 10) {
+ int received_this_round = 0;
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, q, pkts, MULTI_QUEUE_BURST_SIZE);
+ if (nb_rx > 0) {
+ rx_per_queue[q] += nb_rx;
+ total_rx += nb_rx;
+ received_this_round += nb_rx;
+ rte_pktmbuf_free_bulk(pkts, nb_rx);
+ }
+ }
+ if (received_this_round == 0)
+ empty_rounds++;
+ else
+ empty_rounds = 0;
+ }
+
+ printf(" RX Results:\n");
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++)
+ printf(" Queue %u: received %u packets\n", q, rx_per_queue[q]);
+ printf(" Total received: %u packets\n", total_rx);
+
+ /* Each RX queue opens its own file handle, so each reads all packets */
+ expected_total = seed_packets * MULTI_QUEUE_NUM_QUEUES;
+ printf(" Expected total (each queue reads all): %u packets\n", expected_total);
+
+ rte_eth_dev_stop(port_id);
+ rte_vdev_uninit("net_pcap_multi_rx");
+
+ TEST_ASSERT(total_rx > 0, "No packets received at all");
+ for (q = 0; q < MULTI_QUEUE_NUM_QUEUES; q++) {
+ TEST_ASSERT(rx_per_queue[q] > 0, "Queue %u received no packets", q);
+ TEST_ASSERT_EQUAL(rx_per_queue[q], seed_packets,
+ "Queue %u received %u packets, expected %u",
+ q, rx_per_queue[q], seed_packets);
+ }
+ TEST_ASSERT_EQUAL(total_rx, expected_total,
+ "Total RX mismatch: expected %u, got %u", expected_total, total_rx);
+
+ remove_temp_file(multi_rx_pcap_path);
+
+ printf("Multi-RX queue PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Device info reports correct queue counts and MTU limits
+ *
+ * This test verifies that rte_eth_dev_info_get() returns correct values:
+ * 1. max_rx_queues matches the number of rx_pcap files passed
+ * 2. max_tx_queues matches the number of tx_pcap files passed
+ * 3. max_rx_pktlen and max_mtu are based on default snapshot length
+ */
+static int
+test_dev_info(void)
+{
+ struct rte_eth_dev_info dev_info;
+ char devargs[512];
+ char rx_paths[3][PATH_MAX];
+ char tx_paths[2][PATH_MAX];
+ uint16_t port_id;
+ int ret;
+ unsigned int i;
+ /* Default snapshot length is 65535 */
+ const uint32_t default_snaplen = 65535;
+ const uint32_t expected_max_mtu = default_snaplen - RTE_ETHER_HDR_LEN;
+
+ printf("Testing device info reporting\n");
+
+ /* Create temp RX pcap files (3 queues) */
+ for (i = 0; i < 3; i++) {
+ char prefix[32];
+ snprintf(prefix, sizeof(prefix), "pcap_devinfo_rx%u", i);
+ TEST_ASSERT(create_temp_path(rx_paths[i], sizeof(rx_paths[i]), prefix) == 0,
+ "Failed to create RX temp path %u", i);
+ TEST_ASSERT(create_test_pcap(rx_paths[i], 1) == 0,
+ "Failed to create RX pcap %u", i);
+ }
+
+ /* Create temp TX pcap files (2 queues) */
+ for (i = 0; i < 2; i++) {
+ char prefix[32];
+ snprintf(prefix, sizeof(prefix), "pcap_devinfo_tx%u", i);
+ TEST_ASSERT(create_temp_path(tx_paths[i], sizeof(tx_paths[i]), prefix) == 0,
+ "Failed to create TX temp path %u", i);
+ }
+
+ /* Create device with 3 RX queues and 2 TX queues */
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_pcap=%s,rx_pcap=%s,rx_pcap=%s,tx_pcap=%s,tx_pcap=%s",
+ rx_paths[0], rx_paths[1], rx_paths[2], tx_paths[0], tx_paths[1]);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+
+ ret = rte_vdev_init("net_pcap_devinfo", devargs);
+ TEST_ASSERT_SUCCESS(ret, "Failed to create pcap PMD: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_devinfo", &port_id);
+ TEST_ASSERT_SUCCESS(ret, "Cannot find added pcap device");
+
+ ret = rte_eth_dev_info_get(port_id, &dev_info);
+ TEST_ASSERT_SUCCESS(ret, "Failed to get device info: %s", rte_strerror(-ret));
+
+ printf(" Device info:\n");
+ printf(" driver_name: %s\n", dev_info.driver_name);
+ printf(" max_rx_queues: %u (expected: 3)\n", dev_info.max_rx_queues);
+ printf(" max_tx_queues: %u (expected: 2)\n", dev_info.max_tx_queues);
+ printf(" max_rx_pktlen: %u (expected: %u)\n", dev_info.max_rx_pktlen, default_snaplen);
+ printf(" max_mtu: %u (expected: %u)\n", dev_info.max_mtu, expected_max_mtu);
+
+ /* Verify queue counts match number of pcap files */
+ TEST_ASSERT_EQUAL(dev_info.max_rx_queues, 3U,
+ "max_rx_queues mismatch: expected 3, got %u", dev_info.max_rx_queues);
+ TEST_ASSERT_EQUAL(dev_info.max_tx_queues, 2U,
+ "max_tx_queues mismatch: expected 2, got %u", dev_info.max_tx_queues);
+
+ /* Verify max_rx_pktlen equals default snapshot length */
+ TEST_ASSERT_EQUAL(dev_info.max_rx_pktlen, default_snaplen,
+ "max_rx_pktlen mismatch: expected %u, got %u",
+ default_snaplen, dev_info.max_rx_pktlen);
+
+ /* Verify max_mtu is snapshot_len minus ethernet header */
+ TEST_ASSERT_EQUAL(dev_info.max_mtu, expected_max_mtu,
+ "max_mtu mismatch: expected %u, got %u",
+ expected_max_mtu, dev_info.max_mtu);
+
+ rte_vdev_uninit("net_pcap_devinfo");
+
+ /* Cleanup temp files */
+ for (i = 0; i < 3; i++)
+ remove_temp_file(rx_paths[i]);
+ for (i = 0; i < 2; i++)
+ remove_temp_file(tx_paths[i]);
+
+ printf("Device info PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Custom snapshot length (snaplen) parameter
+ *
+ * This test verifies that the snaplen devarg works correctly:
+ * 1. max_rx_pktlen reflects the custom snapshot length
+ * 2. max_mtu is calculated as snaplen - ethernet header
+ */
+static int
+test_snaplen(void)
+{
+ struct rte_eth_dev_info dev_info;
+ char devargs[512];
+ char rx_path[PATH_MAX];
+ char tx_path[PATH_MAX];
+ uint16_t port_id;
+ int ret;
+ const uint32_t custom_snaplen = 9000;
+ const uint32_t expected_max_mtu = custom_snaplen - RTE_ETHER_HDR_LEN;
+
+ printf("Testing custom snapshot length parameter\n");
+
+ /* Create temp files */
+ TEST_ASSERT(create_temp_path(rx_path, sizeof(rx_path), "pcap_snaplen_rx") == 0,
+ "Failed to create RX temp path");
+ TEST_ASSERT(create_test_pcap(rx_path, 1) == 0,
+ "Failed to create RX pcap");
+ TEST_ASSERT(create_temp_path(tx_path, sizeof(tx_path), "pcap_snaplen_tx") == 0,
+ "Failed to create TX temp path");
+
+ /* Create device with custom snaplen */
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s,tx_pcap=%s,snaplen=%u",
+ rx_path, tx_path, custom_snaplen);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+
+ ret = rte_vdev_init("net_pcap_snaplen", devargs);
+ TEST_ASSERT_SUCCESS(ret, "Failed to create pcap PMD: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_snaplen", &port_id);
+ TEST_ASSERT_SUCCESS(ret, "Cannot find added pcap device");
+
+ ret = rte_eth_dev_info_get(port_id, &dev_info);
+ TEST_ASSERT_SUCCESS(ret, "Failed to get device info: %s", rte_strerror(-ret));
+
+ printf(" Custom snaplen: %u\n", custom_snaplen);
+ printf(" max_rx_pktlen: %u (expected: %u)\n", dev_info.max_rx_pktlen, custom_snaplen);
+ printf(" max_mtu: %u (expected: %u)\n", dev_info.max_mtu, expected_max_mtu);
+
+ /* Verify max_rx_pktlen equals custom snapshot length */
+ TEST_ASSERT_EQUAL(dev_info.max_rx_pktlen, custom_snaplen,
+ "max_rx_pktlen mismatch: expected %u, got %u",
+ custom_snaplen, dev_info.max_rx_pktlen);
+
+ /* Verify max_mtu is snaplen minus ethernet header */
+ TEST_ASSERT_EQUAL(dev_info.max_mtu, expected_max_mtu,
+ "max_mtu mismatch: expected %u, got %u",
+ expected_max_mtu, dev_info.max_mtu);
+
+ rte_vdev_uninit("net_pcap_snaplen");
+
+ /* Cleanup temp files */
+ remove_temp_file(rx_path);
+ remove_temp_file(tx_path);
+
+ printf("Snapshot length test PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Snapshot length truncation behavior
+ *
+ * This test verifies that packets larger than snaplen are properly truncated
+ * when written to pcap files:
+ * 1. caplen in pcap header is limited to snaplen
+ * 2. len in pcap header preserves original packet length
+ * 3. Only snaplen bytes of data are written
+ */
+static int
+test_snaplen_truncation(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ char devargs[512];
+ char tx_path[PATH_MAX];
+ uint16_t port_id;
+ int ret, nb_tx, nb_gen;
+ unsigned int pkt_count;
+ const uint32_t test_snaplen = 100;
+ const uint8_t pkt_size = 200;
+
+ printf("Testing snaplen truncation behavior\n");
+
+ /* Create temp TX file */
+ TEST_ASSERT(create_temp_path(tx_path, sizeof(tx_path), "pcap_trunc_tx") == 0,
+ "Failed to create TX temp path");
+
+ /* Create device with small snaplen */
+ ret = snprintf(devargs, sizeof(devargs), "tx_pcap=%s,snaplen=%u",
+ tx_path, test_snaplen);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+
+ ret = rte_vdev_init("net_pcap_trunc", devargs);
+ TEST_ASSERT_SUCCESS(ret, "Failed to create pcap PMD: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_trunc", &port_id);
+ TEST_ASSERT_SUCCESS(ret, "Cannot find added pcap device");
+
+ TEST_ASSERT(setup_pcap_port(port_id) == 0, "Failed to setup port");
+
+ /* Generate packets larger than snaplen */
+ nb_gen = generate_test_packets(mp, mbufs, NUM_PACKETS, pkt_size);
+ TEST_ASSERT_EQUAL(nb_gen, NUM_PACKETS,
+ "Failed to generate packets: got %d, expected %d",
+ nb_gen, NUM_PACKETS);
+
+ printf(" Sending %d packets of size %u with snaplen=%u\n",
+ NUM_PACKETS, pkt_size, test_snaplen);
+
+ /* Transmit packets */
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, NUM_PACKETS);
+ TEST_ASSERT_EQUAL(nb_tx, NUM_PACKETS,
+ "TX burst failed: sent %d/%d", nb_tx, NUM_PACKETS);
+
+ cleanup_pcap_vdev("net_pcap_trunc", port_id);
+
+ /* Verify truncation in output file */
+ ret = verify_pcap_truncation(tx_path, test_snaplen, pkt_size, &pkt_count);
+ TEST_ASSERT_SUCCESS(ret, "Truncation verification failed");
+ TEST_ASSERT_EQUAL(pkt_count, (unsigned int)NUM_PACKETS,
+ "Packet count mismatch: got %u, expected %d",
+ pkt_count, NUM_PACKETS);
+
+ printf(" Verified %u packets: caplen=%u, len=%u\n",
+ pkt_count, test_snaplen, pkt_size);
+
+ /* Cleanup */
+ remove_temp_file(tx_path);
+
+ printf("Snaplen truncation test PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Snapshot length truncation with multi-segment mbufs
+ *
+ * This test verifies that the dumper path correctly truncates
+ * non-contiguous (multi-segment) mbufs when the total packet length
+ * exceeds the configured snaplen. It exercises the RTE_MIN(len, snaplen)
+ * cap in the TX dumper by ensuring:
+ *
+ * 1. caplen in the pcap header equals snaplen (not pkt_len)
+ * 2. len in the pcap header preserves the original packet length
+ * 3. Truncation works when the snaplen boundary falls mid-chain
+ */
+static int
+test_snaplen_truncation_multiseg(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ char devargs[512];
+ char tx_path[PATH_MAX];
+ uint16_t port_id;
+ int ret, nb_tx;
+ unsigned int i, pkt_count;
+ const uint32_t test_snaplen = 100;
+ const uint32_t pkt_size = 300;
+ const uint16_t seg_size = 64;
+ const unsigned int num_pkts = 8;
+
+ printf("Testing snaplen truncation with multi-segment mbufs\n");
+
+ /* Create temp TX file */
+ TEST_ASSERT(create_temp_path(tx_path, sizeof(tx_path),
+ "pcap_trunc_ms") == 0,
+ "Failed to create TX temp path");
+
+ /* Create device with small snaplen */
+ ret = snprintf(devargs, sizeof(devargs), "tx_pcap=%s,snaplen=%u",
+ tx_path, test_snaplen);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+
+ TEST_ASSERT(create_pcap_vdev("net_pcap_trunc_ms", devargs,
+ &port_id) == 0,
+ "Failed to create TX vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0, "Failed to setup port");
+
+ /*
+ * Allocate multi-segment mbufs. With seg_size=64 and pkt_size=300,
+ * each mbuf will have 5 segments (4×64 + 1×44). The snaplen of 100
+ * falls partway through the second segment, forcing the dumper to
+ * stop writing in the middle of the chain.
+ */
+ for (i = 0; i < num_pkts; i++) {
+ mbufs[i] = alloc_multiseg_mbuf(pkt_size, seg_size,
+ (uint8_t)(0xA0 + i));
+ if (mbufs[i] == NULL) {
+ while (i > 0)
+ rte_pktmbuf_free(mbufs[--i]);
+ cleanup_pcap_vdev("net_pcap_trunc_ms", port_id);
+ remove_temp_file(tx_path);
+ return TEST_FAILED;
+ }
+ }
+
+ printf(" Sending %u packets: pkt_len=%u, seg_size=%u (%u segs), snaplen=%u\n",
+ num_pkts, pkt_size, seg_size, mbufs[0]->nb_segs, test_snaplen);
+
+ /* Verify mbufs are actually multi-segment */
+ TEST_ASSERT(mbufs[0]->nb_segs > 1,
+ "Expected multi-segment mbufs, got %u segment(s)",
+ mbufs[0]->nb_segs);
+
+ /* Transmit packets */
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, num_pkts);
+
+ /* Free any unsent mbufs */
+ for (i = nb_tx; i < num_pkts; i++)
+ rte_pktmbuf_free(mbufs[i]);
+
+ TEST_ASSERT_EQUAL(nb_tx, (int)num_pkts,
+ "TX burst failed: sent %d/%u", nb_tx, num_pkts);
+
+ cleanup_pcap_vdev("net_pcap_trunc_ms", port_id);
+
+ /* Verify truncation in output file */
+ ret = verify_pcap_truncation(tx_path, test_snaplen, pkt_size,
+ &pkt_count);
+ TEST_ASSERT_SUCCESS(ret, "Truncation verification failed");
+ TEST_ASSERT_EQUAL(pkt_count, num_pkts,
+ "Packet count mismatch: got %u, expected %u",
+ pkt_count, num_pkts);
+
+ printf(" Verified %u packets: caplen=%u, len=%u\n",
+ pkt_count, test_snaplen, pkt_size);
+
+ remove_temp_file(tx_path);
+
+ printf("Snaplen truncation multi-segment test PASSED\n");
+ return TEST_SUCCESS;
+}
+
+
+/*
+ * Test: Timestamps in infinite RX mode
+ *
+ * This test verifies that timestamp offload works correctly when combined
+ * with infinite_rx mode. Since infinite_rx generates packets on-the-fly,
+ * timestamps should reflect the current time rather than pcap file timestamps.
+ */
+static int
+test_timestamp_infinite_rx(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ struct rte_eth_conf port_conf = {
+ .rxmode.offloads = RTE_ETH_RX_OFFLOAD_TIMESTAMP,
+ };
+ char ts_inf_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int total_rx = 0;
+ unsigned int ts_count = 0;
+ int iter, attempts, ret;
+ rte_mbuf_timestamp_t first_ts = 0;
+ rte_mbuf_timestamp_t last_ts = 0;
+
+ printf("Testing timestamps with infinite RX mode\n");
+
+ /* Initialize timestamp dynamic field access */
+ if (timestamp_dynfield_offset < 0) {
+ ret = timestamp_init();
+ if (ret != 0) {
+ printf("Timestamp dynfield not available, skipping\n");
+ return TEST_SKIPPED;
+ }
+ }
+
+ /* Create simple pcap file */
+ TEST_ASSERT(create_temp_path(ts_inf_pcap_path, sizeof(ts_inf_pcap_path),
+ "pcap_ts_inf") == 0,
+ "Failed to create temp file path");
+
+ TEST_ASSERT(create_test_pcap(ts_inf_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create test pcap file");
+
+ /* Create vdev with infinite_rx enabled */
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s,infinite_rx=1", ts_inf_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ ret = rte_vdev_init("net_pcap_ts_inf", devargs);
+ TEST_ASSERT(ret == 0, "Failed to create infinite RX vdev: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_ts_inf", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+
+ /* Configure with timestamp offload enabled and start */
+ TEST_ASSERT(setup_pcap_port_conf(port_id, &port_conf) == 0,
+ "Failed to setup port with timestamps");
+
+ /* Read packets */
+ for (iter = 0; iter < 3 && total_rx < NUM_PACKETS * 2; iter++) {
+ for (attempts = 0; attempts < 100 && total_rx < NUM_PACKETS * 2; attempts++) {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0, mbufs, MAX_PKT_BURST);
+
+ for (uint16_t i = 0; i < nb_rx; i++) {
+ if (mbuf_has_timestamp(mbufs[i])) {
+ rte_mbuf_timestamp_t ts = mbuf_timestamp_get(mbufs[i]);
+
+ if (ts_count == 0)
+ first_ts = ts;
+ last_ts = ts;
+ ts_count++;
+ }
+ }
+
+ if (nb_rx > 0)
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ total_rx += nb_rx;
+
+ if (nb_rx == 0)
+ rte_delay_us_sleep(100);
+ }
+ }
+
+ rte_eth_dev_stop(port_id);
+ rte_vdev_uninit("net_pcap_ts_inf");
+ remove_temp_file(ts_inf_pcap_path);
+
+ TEST_ASSERT(total_rx >= NUM_PACKETS * 2,
+ "Infinite RX: got %u packets, need >= %d", total_rx, NUM_PACKETS * 2);
+
+ TEST_ASSERT_EQUAL(ts_count, total_rx,
+ "Timestamp missing: only %u/%u packets have timestamps",
+ ts_count, total_rx);
+
+ /* Timestamps should be monotonically increasing (current time) */
+ TEST_ASSERT(last_ts >= first_ts,
+ "Timestamps not monotonic: first=%" PRIu64 " last=%" PRIu64,
+ first_ts, last_ts);
+
+ printf("Timestamp infinite RX PASSED: %u packets with valid timestamps\n", total_rx);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test suite setup
+ */
+static int
+test_setup(void)
+{
+ /* Generate random source MAC address */
+ rte_eth_random_addr(src_mac.addr_bytes);
+
+ mp = rte_pktmbuf_pool_create("pcap_test_pool", NB_MBUF, 32, 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE,
+ rte_socket_id());
+ TEST_ASSERT_NOT_NULL(mp, "Failed to create mempool");
+
+ return 0;
+}
+
+
+/*
+ * Test: Oversized packets are dropped when scatter is disabled
+ *
+ * Use the default mempool (buf_size ~2048) without scatter enabled.
+ * Read a pcap file containing packets larger than the mbuf data room.
+ * Verify that oversized packets are dropped and counted as errors.
+ */
+static int
+test_scatter_drop_oversized(void)
+{
+ struct rte_eth_conf port_conf;
+ struct rte_eth_stats stats;
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ char rx_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int received;
+ int ret;
+ const unsigned int num_pkts = 16;
+
+ printf("Testing scatter: oversized packets dropped without scatter\n");
+
+ TEST_ASSERT(create_temp_path(rx_pcap_path, sizeof(rx_pcap_path),
+ "pcap_scat_drop") == 0,
+ "Failed to create temp file path");
+
+ /*
+ * Create pcap with jumbo packets (9000 bytes) that exceed the
+ * default mbuf data room (~2048 bytes). Without scatter enabled,
+ * these should be dropped at receive time.
+ */
+ TEST_ASSERT(create_sized_pcap(rx_pcap_path, num_pkts,
+ PKT_SIZE_JUMBO) == 0,
+ "Failed to create jumbo pcap file");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", rx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ ret = rte_vdev_init("net_pcap_scat_drop", devargs);
+ TEST_ASSERT(ret == 0, "Failed to create vdev: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_scat_drop", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+
+ /* Configure without scatter - MTU check passes (1514 < 2048) */
+ memset(&port_conf, 0, sizeof(port_conf));
+ ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
+ TEST_ASSERT(ret == 0, "Failed to configure port: %s", rte_strerror(-ret));
+
+ ret = rte_eth_rx_queue_setup(port_id, 0, RING_SIZE, SOCKET0, NULL, mp);
+ TEST_ASSERT(ret == 0, "rx_queue_setup failed: %s", rte_strerror(-ret));
+
+ ret = rte_eth_tx_queue_setup(port_id, 0, RING_SIZE, SOCKET0, NULL);
+ TEST_ASSERT(ret == 0, "tx_queue_setup failed: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_start(port_id);
+ TEST_ASSERT(ret == 0, "Failed to start port: %s", rte_strerror(-ret));
+
+ ret = rte_eth_stats_reset(port_id);
+ TEST_ASSERT(ret == 0, "Failed to reset stats");
+
+ /*
+ * Read all packets. The pcap file has 9000-byte packets but
+ * scatter is not enabled. They should all be dropped.
+ */
+ receive_packets(port_id, mbufs, num_pkts, &received);
+ rte_pktmbuf_free_bulk(mbufs, received);
+
+ ret = rte_eth_stats_get(port_id, &stats);
+ TEST_ASSERT(ret == 0, "Failed to get stats");
+
+ printf(" Received %u packets, errors=%" PRIu64 "\n",
+ received, stats.ierrors);
+
+ TEST_ASSERT_EQUAL(received, 0U,
+ "Expected 0 received packets without scatter, got %u",
+ received);
+ TEST_ASSERT_EQUAL(stats.ierrors, (uint64_t)num_pkts,
+ "Expected %u errors for oversized packets, got %" PRIu64,
+ num_pkts, stats.ierrors);
+
+ cleanup_pcap_vdev("net_pcap_scat_drop", port_id);
+ remove_temp_file(rx_pcap_path);
+
+ printf("Scatter drop oversized PASSED: %" PRIu64 " packets dropped\n",
+ stats.ierrors);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Jumbo packets are scattered when scatter is enabled
+ *
+ * With scatter enabled and a normal mempool, read jumbo-sized packets
+ * from a pcap file. Verify they arrive as multi-segment mbufs with
+ * correct total length.
+ */
+static int
+test_scatter_jumbo_rx(void)
+{
+ struct rte_mbuf *mbufs[NUM_PACKETS];
+ struct rte_eth_conf port_conf;
+ char rx_pcap_path[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ unsigned int received, i;
+ unsigned int multiseg_count = 0;
+ int ret;
+ const unsigned int num_pkts = 16;
+
+ printf("Testing scatter: jumbo RX with scatter enabled\n");
+
+ TEST_ASSERT(create_temp_path(rx_pcap_path, sizeof(rx_pcap_path),
+ "pcap_scat_jumbo") == 0,
+ "Failed to create temp file path");
+ TEST_ASSERT(create_sized_pcap(rx_pcap_path, num_pkts,
+ PKT_SIZE_JUMBO) == 0,
+ "Failed to create jumbo pcap file");
+
+ ret = snprintf(devargs, sizeof(devargs), "rx_pcap=%s", rx_pcap_path);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ ret = rte_vdev_init("net_pcap_scat_jumbo", devargs);
+ TEST_ASSERT(ret == 0, "Failed to create vdev: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_scat_jumbo", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+
+ /* Configure WITH scatter enabled */
+ memset(&port_conf, 0, sizeof(port_conf));
+ port_conf.rxmode.offloads = RTE_ETH_RX_OFFLOAD_SCATTER;
+ ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
+ TEST_ASSERT(ret == 0, "Failed to configure port: %s", rte_strerror(-ret));
+
+ ret = rte_eth_rx_queue_setup(port_id, 0, RING_SIZE, SOCKET0, NULL, mp);
+ TEST_ASSERT(ret == 0, "rx_queue_setup failed: %s", rte_strerror(-ret));
+
+ ret = rte_eth_tx_queue_setup(port_id, 0, RING_SIZE, SOCKET0, NULL);
+ TEST_ASSERT(ret == 0, "tx_queue_setup failed: %s", rte_strerror(-ret));
+
+ ret = rte_eth_dev_start(port_id);
+ TEST_ASSERT(ret == 0, "Failed to start port: %s", rte_strerror(-ret));
+
+ receive_packets(port_id, mbufs, num_pkts, &received);
+ TEST_ASSERT_EQUAL(received, num_pkts,
+ "Received %u packets, expected %u", received, num_pkts);
+
+ for (i = 0; i < received; i++) {
+ uint32_t pkt_len = rte_pktmbuf_pkt_len(mbufs[i]);
+ uint16_t nb_segs = mbufs[i]->nb_segs;
+
+ TEST_ASSERT_EQUAL(pkt_len, PKT_SIZE_JUMBO,
+ "Packet %u: size %u, expected %u",
+ i, pkt_len, PKT_SIZE_JUMBO);
+
+ if (nb_segs > 1)
+ multiseg_count++;
+ }
+
+ rte_pktmbuf_free_bulk(mbufs, received);
+ cleanup_pcap_vdev("net_pcap_scat_jumbo", port_id);
+ remove_temp_file(rx_pcap_path);
+
+ /* Jumbo packets should require multiple segments */
+ TEST_ASSERT(multiseg_count > 0,
+ "Expected multi-segment mbufs for jumbo packets");
+
+ printf("Scatter jumbo RX PASSED: %u/%u packets were multi-segment\n",
+ multiseg_count, received);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Asymmetric rx_iface/tx_iface mode
+ *
+ * Verifies that the rx_iface= and tx_iface= devargs work when
+ * specified separately, which exercises a distinct code path from
+ * the symmetric iface= mode.
+ */
+static int
+test_rx_tx_iface(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ char devargs[256];
+ uint16_t port_id;
+ const char *iface;
+ int ret, nb_tx, nb_pkt;
+
+ printf("Testing asymmetric rx_iface/tx_iface mode\n");
+
+ iface = find_test_iface();
+ if (iface == NULL) {
+ printf("No suitable interface, skipping\n");
+ return TEST_SKIPPED;
+ }
+ printf("Using interface: %s\n", iface);
+
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_iface=%s,tx_iface=%s", iface, iface);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ if (rte_vdev_init("net_pcap_rxtx_iface", devargs) < 0) {
+ printf("Cannot create rx_iface/tx_iface vdev (needs root?), skipping\n");
+ return TEST_SKIPPED;
+ }
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_rxtx_iface", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup port");
+
+ /* Transmit some packets to verify TX path works */
+ nb_pkt = generate_test_packets(mp, mbufs, MAX_PKT_BURST,
+ PACKET_BURST_GEN_PKT_LEN);
+ TEST_ASSERT(nb_pkt > 0, "Failed to generate packets");
+
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, nb_pkt);
+ if (nb_tx < nb_pkt)
+ rte_pktmbuf_free_bulk(&mbufs[nb_tx], nb_pkt - nb_tx);
+
+ /* RX burst to exercise the receive path (may or may not get packets) */
+ {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0, mbufs, MAX_PKT_BURST);
+ if (nb_rx > 0)
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ }
+
+ cleanup_pcap_vdev("net_pcap_rxtx_iface", port_id);
+
+ printf("rx_iface/tx_iface PASSED: sent %d packets\n", nb_tx);
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: rx_iface_in direction filtering
+ *
+ * Verifies that rx_iface_in= sets pcap direction to PCAP_D_IN,
+ * which filters out outgoing packets. This exercises the
+ * set_iface_direction() code path and PCAP_D_IN filtering.
+ */
+static int
+test_rx_iface_in(void)
+{
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ char devargs[256];
+ uint16_t port_id;
+ const char *iface;
+ int ret, nb_pkt, nb_tx;
+
+ printf("Testing rx_iface_in direction filtering\n");
+
+ iface = find_test_iface();
+ if (iface == NULL) {
+ printf("No suitable interface, skipping\n");
+ return TEST_SKIPPED;
+ }
+ printf("Using interface: %s\n", iface);
+
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_iface_in=%s,tx_iface=%s", iface, iface);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ if (rte_vdev_init("net_pcap_iface_in", devargs) < 0) {
+ printf("Cannot create rx_iface_in vdev (needs root?), skipping\n");
+ return TEST_SKIPPED;
+ }
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_iface_in", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup port");
+
+ /*
+ * Send packets on the TX side. With rx_iface_in (PCAP_D_IN),
+ * our own transmitted packets should NOT appear on the RX side
+ * because they are outgoing, not incoming.
+ */
+ nb_pkt = generate_test_packets(mp, mbufs, MAX_PKT_BURST,
+ PACKET_BURST_GEN_PKT_LEN);
+ TEST_ASSERT(nb_pkt > 0, "Failed to generate packets");
+
+ nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, nb_pkt);
+ if (nb_tx < nb_pkt)
+ rte_pktmbuf_free_bulk(&mbufs[nb_tx], nb_pkt - nb_tx);
+
+ /* Small delay then try to receive - should get 0 (our own TX filtered) */
+ rte_delay_us_sleep(50 * 1000);
+ {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0, mbufs, MAX_PKT_BURST);
+ if (nb_rx > 0) {
+ printf(" Note: received %u packets (external traffic present)\n",
+ nb_rx);
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ } else {
+ printf(" No packets received (TX correctly filtered by PCAP_D_IN)\n");
+ }
+ }
+
+ cleanup_pcap_vdev("net_pcap_iface_in", port_id);
+
+ printf("rx_iface_in PASSED: direction filtering exercised\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: Per-queue start and stop
+ *
+ * Verifies that rx_queue_start/stop and tx_queue_start/stop API calls
+ * succeed and return correct status. Note: the pcap PMD burst functions
+ * do not check queue state in the fast path, so this test validates
+ * the API plumbing rather than burst-level gating.
+ */
+static int
+test_queue_start_stop(void)
+{
+ char rx_pcap_path[PATH_MAX];
+ char tx_pcap_path_local[PATH_MAX];
+ char devargs[256];
+ uint16_t port_id;
+ int ret;
+
+ printf("Testing per-queue start/stop\n");
+
+ TEST_ASSERT(create_temp_path(rx_pcap_path, sizeof(rx_pcap_path),
+ "pcap_qss_rx") == 0,
+ "Failed to create RX temp path");
+ TEST_ASSERT(create_temp_path(tx_pcap_path_local, sizeof(tx_pcap_path_local),
+ "pcap_qss_tx") == 0,
+ "Failed to create TX temp path");
+ TEST_ASSERT(create_test_pcap(rx_pcap_path, NUM_PACKETS) == 0,
+ "Failed to create test pcap");
+
+ ret = snprintf(devargs, sizeof(devargs),
+ "rx_pcap=%s,tx_pcap=%s", rx_pcap_path, tx_pcap_path_local);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ TEST_ASSERT(create_pcap_vdev("net_pcap_qss", devargs, &port_id) == 0,
+ "Failed to create vdev");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup port");
+
+ /* Stop RX queue */
+ ret = rte_eth_dev_rx_queue_stop(port_id, 0);
+ TEST_ASSERT(ret == 0, "Failed to stop RX queue: %s", rte_strerror(-ret));
+
+ /* Restart RX queue */
+ ret = rte_eth_dev_rx_queue_start(port_id, 0);
+ TEST_ASSERT(ret == 0, "Failed to start RX queue: %s", rte_strerror(-ret));
+
+ /* Stop TX queue */
+ ret = rte_eth_dev_tx_queue_stop(port_id, 0);
+ TEST_ASSERT(ret == 0, "Failed to stop TX queue: %s", rte_strerror(-ret));
+
+ /* Restart TX queue */
+ ret = rte_eth_dev_tx_queue_start(port_id, 0);
+ TEST_ASSERT(ret == 0, "Failed to start TX queue: %s", rte_strerror(-ret));
+
+ /* Verify burst still works after stop/start cycle */
+ {
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ unsigned int received;
+
+ receive_packets(port_id, mbufs, RTE_DIM(mbufs), &received);
+ TEST_ASSERT(received > 0,
+ "Expected packets after queue stop/start cycle, got 0");
+ rte_pktmbuf_free_bulk(mbufs, received);
+ }
+
+ {
+ struct rte_mbuf *mbufs[1];
+
+ TEST_ASSERT(alloc_test_mbufs(mbufs, 1) == 0,
+ "Failed to allocate mbufs");
+ int nb_tx = rte_eth_tx_burst(port_id, 0, mbufs, 1);
+ TEST_ASSERT_EQUAL(nb_tx, 1,
+ "TX after queue stop/start cycle failed: sent %d/1",
+ nb_tx);
+ }
+
+ cleanup_pcap_vdev("net_pcap_qss", port_id);
+ remove_temp_file(rx_pcap_path);
+ remove_temp_file(tx_pcap_path_local);
+
+ printf("Per-queue start/stop PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test: imissed statistic in interface mode
+ *
+ * Verifies that the imissed counter (based on pcap_stats kernel drops)
+ * is accessible and starts at zero after stats reset. Kernel-level
+ * drops are hard to trigger deterministically, so this test validates
+ * the counter plumbing rather than forcing drops.
+ */
+static int
+test_imissed_stat(void)
+{
+ struct rte_eth_stats stats;
+ char devargs[256];
+ uint16_t port_id;
+ const char *iface;
+ int ret;
+
+ printf("Testing imissed statistic\n");
+
+ iface = find_test_iface();
+ if (iface == NULL) {
+ printf("No suitable interface, skipping\n");
+ return TEST_SKIPPED;
+ }
+ printf("Using interface: %s\n", iface);
+
+ ret = snprintf(devargs, sizeof(devargs), "iface=%s", iface);
+ TEST_ASSERT(ret > 0 && ret < (int)sizeof(devargs),
+ "devargs string truncated");
+ if (rte_vdev_init("net_pcap_imissed", devargs) < 0) {
+ printf("Cannot create iface vdev (needs root?), skipping\n");
+ return TEST_SKIPPED;
+ }
+
+ ret = rte_eth_dev_get_port_by_name("net_pcap_imissed", &port_id);
+ TEST_ASSERT(ret == 0, "Failed to get port ID");
+ TEST_ASSERT(setup_pcap_port(port_id) == 0,
+ "Failed to setup port");
+
+ /* Reset stats and verify imissed starts at zero */
+ ret = rte_eth_stats_reset(port_id);
+ TEST_ASSERT(ret == 0, "Failed to reset stats");
+
+ ret = rte_eth_stats_get(port_id, &stats);
+ TEST_ASSERT(ret == 0, "Failed to get stats");
+
+ TEST_ASSERT_EQUAL(stats.imissed, 0U,
+ "imissed should be 0 after reset, got %"PRIu64,
+ stats.imissed);
+
+ /* Do some RX bursts to exercise the pcap_stats path */
+ {
+ struct rte_mbuf *mbufs[MAX_PKT_BURST];
+ int attempts;
+
+ for (attempts = 0; attempts < 5; attempts++) {
+ uint16_t nb_rx = rte_eth_rx_burst(port_id, 0,
+ mbufs, MAX_PKT_BURST);
+ if (nb_rx > 0)
+ rte_pktmbuf_free_bulk(mbufs, nb_rx);
+ }
+ }
+
+ /* Query stats again - imissed should still be queryable */
+ ret = rte_eth_stats_get(port_id, &stats);
+ TEST_ASSERT(ret == 0, "Failed to get stats after RX");
+ printf(" imissed=%"PRIu64" (kernel drops via pcap_stats)\n",
+ stats.imissed);
+
+ cleanup_pcap_vdev("net_pcap_imissed", port_id);
+
+ printf("imissed stat PASSED\n");
+ return TEST_SUCCESS;
+}
+
+/*
+ * Test suite teardown
+ */
+static void
+test_teardown(void)
+{
+ /* Cleanup shared temp files */
+ remove_temp_file(tx_pcap_path);
+
+ rte_mempool_free(mp);
+ mp = NULL;
+}
+
+static struct unit_test_suite test_pmd_pcap_suite = {
+ .setup = test_setup,
+ .teardown = test_teardown,
+ .suite_name = "PCAP PMD Unit Test Suite",
+ .unit_test_cases = {
+ TEST_CASE(test_dev_info),
+ TEST_CASE(test_tx_to_file),
+ TEST_CASE(test_rx_from_file),
+ TEST_CASE(test_tx_varied_sizes),
+ TEST_CASE(test_rx_varied_sizes),
+ TEST_CASE(test_jumbo_rx),
+ TEST_CASE(test_jumbo_tx),
+ TEST_CASE(test_infinite_rx),
+ TEST_CASE(test_tx_drop),
+ TEST_CASE(test_stats),
+ TEST_CASE(test_iface),
+ TEST_CASE(test_link_status),
+ TEST_CASE(test_lsc_iface),
+ TEST_CASE(test_eof_rx),
+ TEST_CASE(test_rx_timestamp),
+ TEST_CASE(test_multi_tx_queue),
+ TEST_CASE(test_multi_rx_queue_same_file),
+ TEST_CASE(test_timestamp_infinite_rx),
+ TEST_CASE(test_snaplen),
+ TEST_CASE(test_snaplen_truncation),
+ TEST_CASE(test_snaplen_truncation_multiseg),
+ TEST_CASE(test_scatter_drop_oversized),
+ TEST_CASE(test_scatter_jumbo_rx),
+ TEST_CASE(test_rx_tx_iface),
+ TEST_CASE(test_rx_iface_in),
+ TEST_CASE(test_queue_start_stop),
+ TEST_CASE(test_imissed_stat),
+
+ TEST_CASES_END()
+ }
+};
+
+static int
+test_pmd_pcap(void)
+{
+ return unit_test_suite_runner(&test_pmd_pcap_suite);
+}
+
+REGISTER_FAST_TEST(pcap_pmd_autotest, NOHUGE_OK, ASAN_OK, test_pmd_pcap);
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 4f1ab1b113..1b012c4776 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -72,6 +72,7 @@ New Features
* Added support for Link State interrupt in ``iface`` mode.
* Added ``eof`` devarg to use link state to signal end of receive
file input.
+ * Added unit test suite.
--
2.53.0
next prev parent reply other threads:[~2026-04-15 14:50 UTC|newest]
Thread overview: 543+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-06 18:26 [PATCH 00/12] net/pcap: cleanups and test Stephen Hemminger
2026-01-06 18:26 ` [PATCH 01/12] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-06 18:26 ` [PATCH 02/12] net/pcap: support MTU set Stephen Hemminger
2026-01-06 18:26 ` [PATCH 03/12] net/pcap: use bool for flags Stephen Hemminger
2026-01-07 10:28 ` Marat Khalili
2026-01-09 0:23 ` Stephen Hemminger
2026-01-06 18:26 ` [PATCH 04/12] net/pcap: support Tx offloads Stephen Hemminger
2026-01-06 18:26 ` [PATCH 05/12] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-06 18:26 ` [PATCH 06/12] net/pcap: remove global variables Stephen Hemminger
2026-01-07 9:48 ` Marat Khalili
2026-01-06 18:26 ` [PATCH 07/12] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-07 10:31 ` Marat Khalili
2026-01-06 18:26 ` [PATCH 08/12] net/pcap: optimize calculation of receive timestamp Stephen Hemminger
2026-01-07 10:58 ` Marat Khalili
2026-01-06 18:26 ` [PATCH 09/12] net/pcap: report receive clock Stephen Hemminger
2026-01-06 18:26 ` [PATCH 10/12] net/pcap: cleanup MAC address handling Stephen Hemminger
2026-01-06 18:26 ` [PATCH 11/12] net/pcap: support MAC address set Stephen Hemminger
2026-01-06 18:26 ` [PATCH 12/12] test: add test for pcap PMD Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 0/9] pcap: cleanup pcap PMD and add test Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 1/9] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 2/9] net/pcap: support MTU set Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 3/9] net/pcap: use bool for flags Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 4/9] net/pcap: support Tx offloads Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 5/9] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 6/9] net/pcap: remove global variables Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 7/9] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 8/9] net/pcap: support MAC address set Stephen Hemminger
2026-01-09 1:16 ` [PATCH v2 9/9] test: add test for pcap PMD Stephen Hemminger
2026-01-12 0:50 ` [PATCH v2 0/9] pcap: cleanup pcap PMD and add test Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 0/9] net/pcap: improvements and test coverage Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 1/9] doc: update features for PCAP PMD Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 2/9] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 3/9] net/pcap: support MTU set Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 4/9] net/pcap: use bool for flags Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 5/9] net/pcap: support Tx offloads Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 6/9] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 7/9] net/pcap: remove global variables Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 8/9] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-13 19:23 ` [PATCH v3 9/9] test: add test for pcap PMD Stephen Hemminger
2026-01-17 21:56 ` [PATCH v4 00/11] PCAP PMD improvements Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 01/11] doc: update features for PCAP PMD Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 02/11] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 03/11] net/pcap: cleanup transmit of multi segment Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 04/11] net/pcap: support setting MTU Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 05/11] net/pcap: use bool for flags Stephen Hemminger
2026-01-19 12:43 ` Marat Khalili
2026-01-17 21:57 ` [PATCH v4 06/11] net/pcap: support VLAN offloads Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 07/11] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 08/11] net/pcap: remove global variables Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 09/11] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 10/11] test: add test for pcap PMD Stephen Hemminger
2026-01-17 21:57 ` [PATCH v4 11/11] net/pcap: add release note Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 00/11] PCAP PMD improvements Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 01/11] doc: update features for PCAP PMD Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 02/11] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 03/11] net/pcap: cleanup transmit of multi segment Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 04/11] net/pcap: support setting MTU Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 05/11] net/pcap: use bool for flags Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 06/11] net/pcap: support VLAN offloads Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 07/11] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 08/11] net/pcap: remove global variables Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 09/11] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 10/11] test: add test for pcap PMD Stephen Hemminger
2026-01-18 16:58 ` [PATCH v5 11/11] net/pcap: add release note Stephen Hemminger
2026-01-25 19:19 ` [PATCH v6 00/13] net/pcap: improvements and new features Stephen Hemminger
2026-01-25 19:19 ` [PATCH v6 01/13] maintainers: update for pcap driver Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 02/13] doc: update features for PCAP PMD Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 03/13] net/pcap: include used headers Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 04/13] net/pcap: remove unnecessary casts Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 05/13] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 06/13] net/pcap: improve multi-segment transmit handling Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 07/13] net/pcap: support MTU configuration in single interface mode Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 08/13] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 09/13] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 10/13] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 11/13] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 12/13] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-25 19:20 ` [PATCH v6 13/13] test: add test for pcap PMD Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 00/13] net/pcap: improvements and test suite Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 01/13] maintainers: update for pcap driver Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 02/13] doc: update features for PCAP PMD Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 03/13] net/pcap: include used headers Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 04/13] net/pcap: remove unnecessary casts Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 05/13] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 06/13] net/pcap: improve multi-segment transmit handling Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 07/13] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 08/13] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 09/13] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 10/13] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 11/13] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 12/13] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-26 18:06 ` [PATCH v7 13/13] test: add test for pcap PMD Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 00/14] net/pcap: improvements and test suite Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 01/14] maintainers: update for pcap driver Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 02/14] doc: update features for PCAP PMD Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 03/14] net/pcap: include used headers Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 04/14] net/pcap: remove unnecessary casts Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 05/14] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 06/14] net/pcap: improve multi-segment transmit handling Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 07/14] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 08/14] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 09/14] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 10/14] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 11/14] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 12/14] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 13/14] net/pcap: clarify maximum received packet Stephen Hemminger
2026-01-27 17:18 ` [PATCH v8 14/14] test: add test for pcap PMD Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 00/15] net/pcap: improvements and test suite Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 01/15] maintainers: update for pcap driver Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 02/15] doc: update features for PCAP PMD Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 03/15] net/pcap: include used headers Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 04/15] net/pcap: remove unnecessary casts Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 05/15] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 06/15] net/pcap: improve multi-segment transmit handling Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 07/15] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 08/15] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 09/15] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 10/15] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 11/15] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 12/15] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 13/15] net/pcap: clarify maximum received packet Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 14/15] test: add test for pcap PMD Stephen Hemminger
2026-01-28 18:40 ` [PATCH v9 15/15] net/pcap: add snapshot length devarg Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 00/19] net/pcap: improvements and test suite Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 01/19] maintainers: update for pcap driver Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 02/19] doc: update features for PCAP PMD Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 03/19] net/pcap: include used headers Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 04/19] net/pcap: remove unnecessary casts Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 05/19] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 06/19] net/pcap: use bulk free Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 07/19] net/pcap: allocate Tx bounce buffer Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 08/19] net/pcap: cleanup transmit buffer handling Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 09/19] net/pcap: report multi-segment transmit capability Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 10/19] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 11/19] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 12/19] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 13/19] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 14/19] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 15/19] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 16/19] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 17/19] net/pcap: clarify maximum received packet Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 18/19] net/pcap: add snapshot length devarg Stephen Hemminger
2026-01-30 1:12 ` [PATCH v10 19/19] test: add test for pcap PMD Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 00/19] net/pcap: improvements and test suite Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 01/19] maintainers: update for pcap driver Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 02/19] doc: update features for PCAP PMD Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 03/19] net/pcap: include used headers Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 04/19] net/pcap: remove unnecessary casts Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 05/19] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 06/19] net/pcap: use bulk free Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 07/19] net/pcap: allocate Tx bounce buffer Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 08/19] net/pcap: cleanup transmit buffer handling Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 09/19] net/pcap: report multi-segment transmit capability Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 10/19] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 11/19] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 12/19] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 13/19] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 14/19] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 15/19] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 16/19] net/pcap: avoid use of volatile Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 17/19] net/pcap: clarify maximum received packet Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 18/19] net/pcap: add snapshot length devarg Stephen Hemminger
2026-01-30 17:33 ` [PATCH v11 19/19] test: add test for pcap PMD Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 00/19] net/pcap: improvements and test suite Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 01/19] maintainers: update for pcap driver Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 02/19] doc: update features for PCAP PMD Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 03/19] net/pcap: include used headers Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 04/19] net/pcap: remove unnecessary casts Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 05/19] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 06/19] net/pcap: use bulk free Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 07/19] net/pcap: allocate Tx bounce buffer Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 08/19] net/pcap: cleanup transmit buffer handling Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 09/19] net/pcap: report multi-segment transmit capability Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 10/19] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 11/19] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 12/19] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 13/19] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 14/19] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 15/19] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 16/19] net/pcap: avoid use of volatile Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 17/19] net/pcap: clarify maximum received packet Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 18/19] net/pcap: add snapshot length devarg Stephen Hemminger
2026-02-02 23:09 ` [PATCH v12 19/19] test: add test for pcap PMD Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 00/16] net/pcap: improvements and test suite Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 01/16] maintainers: update for pcap driver Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 02/16] doc: update features for PCAP PMD Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 03/16] net/pcap: include used headers Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 04/16] net/pcap: remove unnecessary casts Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 05/16] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 06/16] net/pcap: cleanup transmit burst logic Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 07/16] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 08/16] net/pcap: support VLAN insert and strip Stephen Hemminger
2026-02-23 11:34 ` David Marchand
2026-02-10 0:00 ` [PATCH v13 09/16] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 10/16] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 11/16] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 12/16] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 13/16] net/pcap: avoid use of volatile Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 14/16] net/pcap: clarify maximum received packet Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 15/16] net/pcap: add snapshot length devarg Stephen Hemminger
2026-02-10 0:00 ` [PATCH v13 16/16] test: add test for pcap PMD Stephen Hemminger
2026-04-29 15:27 ` David Marchand
2026-02-11 21:09 ` [PATCH v14 00/18] net/pcap: improvements and test suite Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 01/18] maintainers: update for pcap driver Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 02/18] doc: update features for PCAP PMD Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 03/18] net/pcap: include used headers Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 04/18] net/pcap: remove unnecessary casts Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 05/18] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 06/18] net/pcap: rework transmit burst handling Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 07/18] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 08/18] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 09/18] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 10/18] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 11/18] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 12/18] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 13/18] net/pcap: avoid use of volatile Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 14/18] net/pcap: clarify maximum received packet Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 15/18] net/pcap: add snapshot length devarg Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 16/18] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 17/18] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-02-11 21:09 ` [PATCH v14 18/18] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 00/18] net/pcap: improvements and test suite Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 01/18] maintainers: update for pcap driver Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 02/18] doc: update features for PCAP PMD Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 03/18] net/pcap: include used headers Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 04/18] net/pcap: remove unnecessary casts Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 05/18] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 06/18] net/pcap: rework transmit burst handling Stephen Hemminger
2026-02-16 10:02 ` David Marchand
2026-02-13 17:01 ` [PATCH v15 07/18] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 08/18] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 09/18] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 10/18] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 11/18] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 12/18] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 13/18] net/pcap: avoid use of volatile Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 14/18] net/pcap: clarify maximum received packet Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 15/18] net/pcap: add snapshot length devarg Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 16/18] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 17/18] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-02-13 17:01 ` [PATCH v15 18/18] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-02-16 18:11 ` [PATCH v16 00/21] net/pcap: improvements and test suite Stephen Hemminger
2026-02-16 18:11 ` [PATCH v16 01/21] maintainers: update for pcap driver Stephen Hemminger
2026-02-16 18:11 ` [PATCH v16 02/21] doc: update features for PCAP PMD Stephen Hemminger
2026-02-16 18:11 ` [PATCH v16 03/21] net/pcap: include used headers Stephen Hemminger
2026-02-16 18:11 ` [PATCH v16 04/21] net/pcap: remove unnecessary casts Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 05/21] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 06/21] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 07/21] net/pcap: replace stack bounce buffer with per-queue allocation Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 08/21] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 09/21] net/pcap: add datapath debug logging Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 10/21] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 11/21] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 12/21] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 13/21] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 14/21] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 15/21] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 16/21] net/pcap: avoid use of volatile Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 17/21] net/pcap: clarify maximum received packet Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 18/21] net/pcap: add snapshot length devarg Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 19/21] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 20/21] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-02-16 18:12 ` [PATCH v16 21/21] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 00/23] net/pcap: fixes, test, and ehancements Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 01/23] maintainers: update for pcap driver Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 02/23] net/pcap: fix build on Windows Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 03/23] doc: update features for PCAP PMD Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 04/23] net/pcap: include used headers Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 05/23] net/pcap: remove unnecessary casts Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 06/23] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 07/23] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 08/23] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 09/23] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 10/23] net/pcap: add datapath debug logging Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 11/23] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 12/23] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 13/23] net/pcap: add link state and speed for interface mode Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 14/23] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 15/23] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 16/23] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 17/23] net/pcap: avoid use of volatile Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 18/23] net/pcap: clarify maximum received packet Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 19/23] eal/windows: add wrapper for access function Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 20/23] net/pcap: add snapshot length devarg Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 21/23] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 22/23] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-02-20 5:45 ` [PATCH v17 23/23] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 00/23] net/pcap: fixes, test, and enhancements Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 01/23] maintainers: update for pcap driver Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 02/23] net/pcap: fix build on Windows Stephen Hemminger
2026-03-02 3:28 ` fengchengwen
2026-03-02 8:03 ` David Marchand
2026-03-01 2:05 ` [PATCH v18 03/23] doc: update features for PCAP PMD Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 04/23] net/pcap: include used headers Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 05/23] net/pcap: remove unnecessary casts Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 06/23] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 07/23] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 08/23] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 09/23] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 10/23] net/pcap: add datapath debug logging Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 11/23] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 12/23] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 13/23] net/pcap: add link status for interface mode Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 14/23] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 15/23] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 16/23] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 17/23] net/pcap: avoid use of volatile Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 18/23] net/pcap: clarify maximum received packet Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 19/23] eal/windows: add wrapper for access function Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 20/23] net/pcap: add snapshot length devarg Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 21/23] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 22/23] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-03-01 2:05 ` [PATCH v18 23/23] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 00/24] net/pcap: fixes, test, and enhancements Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 01/25] maintainers: update for pcap driver Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 02/25] net/pcap: fix build on Windows Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 03/25] doc: update features for PCAP PMD Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 04/25] net/pcap: include used headers Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 05/25] net/pcap: remove unnecessary casts Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 06/25] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 07/25] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 08/25] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 09/25] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 10/25] net/pcap: add datapath debug logging Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 11/25] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 12/25] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 13/25] net/pcap: add link status for interface mode Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 14/25] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 15/25] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 16/25] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 17/25] net/pcap: avoid use of volatile Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 18/25] net/pcap: clarify maximum received packet Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 19/25] eal/windows: add wrapper for access function Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 20/25] net/pcap: add snapshot length devarg Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 21/25] net/pcap: add Rx scatter offload Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 22/25] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 23/25] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-03-10 2:47 ` [PATCH v19 24/25] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-03-10 2:48 ` [PATCH v19 25/25] check patch warn in test Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 00/25] net/pcap: fixes, test, and enhancements Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 01/25] maintainers: update for pcap driver Stephen Hemminger
2026-03-16 11:07 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 02/25] net/pcap: fix build on Windows Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 03/25] doc: update features for PCAP PMD Stephen Hemminger
2026-03-16 11:16 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 04/25] net/pcap: include used headers Stephen Hemminger
2026-03-16 11:21 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 05/25] net/pcap: remove unnecessary casts Stephen Hemminger
2026-03-16 11:27 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 06/25] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-03-16 11:38 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 07/25] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-03-16 11:39 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 08/25] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-03-16 11:47 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 09/25] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-03-16 12:24 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 10/25] net/pcap: add datapath debug logging Stephen Hemminger
2026-03-16 13:50 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 11/25] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-03-16 14:00 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 12/25] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-03-16 14:04 ` Bruce Richardson
2026-03-24 16:47 ` Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 13/25] net/pcap: add link status for interface mode Stephen Hemminger
2026-03-16 14:11 ` Bruce Richardson
2026-03-24 16:48 ` Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 14/25] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-03-16 14:16 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 15/25] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 16/25] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-03-16 14:20 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 17/25] net/pcap: avoid use of volatile Stephen Hemminger
2026-03-16 14:31 ` Bruce Richardson
2026-03-16 15:23 ` Stephen Hemminger
2026-03-10 16:09 ` [PATCH v20 18/25] net/pcap: clarify maximum received packet Stephen Hemminger
2026-03-16 14:32 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 19/25] eal/windows: add wrapper for access function Stephen Hemminger
2026-03-16 14:34 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 20/25] net/pcap: add snapshot length devarg Stephen Hemminger
2026-03-16 14:37 ` Bruce Richardson
2026-03-10 16:09 ` [PATCH v20 21/25] net/pcap: add Rx scatter offload Stephen Hemminger
2026-03-16 15:01 ` Bruce Richardson
2026-03-10 16:10 ` [PATCH v20 22/25] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-03-16 15:02 ` Bruce Richardson
2026-03-10 16:10 ` [PATCH v20 23/25] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-03-16 15:05 ` Bruce Richardson
2026-03-10 16:10 ` [PATCH v20 24/25] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-03-16 15:31 ` Bruce Richardson
2026-03-10 16:10 ` [PATCH v20 25/25] app/pdump: preserve VLAN tags in captured packets Stephen Hemminger
2026-03-16 15:33 ` Bruce Richardson
2026-03-16 15:55 ` Morten Brørup
2026-03-16 16:05 ` Bruce Richardson
2026-03-16 16:15 ` Morten Brørup
2026-03-24 17:12 ` Stephen Hemminger
2026-03-25 7:41 ` Morten Brørup
2026-03-25 9:12 ` Bruce Richardson
2026-03-25 9:36 ` Morten Brørup
2026-03-25 9:42 ` Bruce Richardson
2026-03-25 16:19 ` Stephen Hemminger
2026-03-25 16:22 ` Bruce Richardson
2026-03-25 16:52 ` Stephen Hemminger
2026-03-25 17:09 ` Bruce Richardson
2026-03-25 17:33 ` Stephen Hemminger
2026-03-25 17:00 ` Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 00/25] net/pcap: fixes, test, and enhancements Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 01/25] maintainers: update for pcap driver Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 02/25] net/pcap: fix build on Windows Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 03/25] doc: update features for PCAP PMD Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 04/25] net/pcap: include used headers Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 05/25] net/pcap: remove unnecessary casts Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 06/25] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 07/25] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 08/25] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 09/25] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 10/25] net/pcap: clean up TX dumper return value and types Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 11/25] net/pcap: add datapath debug logging Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 12/25] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 13/25] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 14/25] app/pdump: preserve VLAN tags in captured packets Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 15/25] net/pcap: add link status for interface mode Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 16/25] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 17/25] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 18/25] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 19/25] net/pcap: clarify maximum received packet Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 20/25] eal/windows: add wrapper for access function Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 21/25] net/pcap: add snapshot length devarg Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 22/25] net/pcap: add Rx scatter offload Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 23/25] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 24/25] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-03-25 2:37 ` [PATCH v21 25/25] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 00/24] net/pcap: fixes, test and enhancements Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 01/24] maintainers: update for pcap driver Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 02/24] net/pcap: fix build on Windows Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 03/24] doc: update features for PCAP PMD Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 04/24] net/pcap: include used headers Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 05/24] net/pcap: remove unnecessary casts Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 06/24] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 07/24] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-04-14 16:07 ` [PATCH v22 08/24] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 09/24] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 10/24] net/pcap: clean up TX dumper return value and types Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 11/24] net/pcap: add datapath debug logging Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 12/24] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 13/24] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 14/24] net/pcap: add link status for interface mode Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 15/24] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 16/24] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 17/24] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 18/24] net/pcap: clarify maximum received packet Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 19/24] eal/windows: add wrapper for access function Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 20/24] net/pcap: add snapshot length devarg Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 21/24] net/pcap: add Rx scatter offload Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 22/24] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 23/24] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-04-14 16:08 ` [PATCH v22 24/24] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 00/24] net/pcap: fixes, test and enhancements Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 01/24] maintainers: update for pcap driver Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 02/24] net/pcap: fix build on Windows Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 03/24] doc: update features for PCAP PMD Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 04/24] net/pcap: include used headers Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 05/24] net/pcap: remove unnecessary casts Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 06/24] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 07/24] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 08/24] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 09/24] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-04-15 14:45 ` [PATCH v23 10/24] net/pcap: clean up TX dumper return value and types Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 11/24] net/pcap: add datapath debug logging Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 12/24] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 13/24] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 14/24] net/pcap: add link status for interface mode Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 15/24] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 16/24] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 17/24] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 18/24] net/pcap: clarify maximum received packet Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 19/24] eal/windows: add wrapper for access function Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 20/24] net/pcap: add snapshot length devarg Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 21/24] net/pcap: add Rx scatter offload Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 22/24] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-04-15 14:46 ` [PATCH v23 23/24] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-04-15 14:46 ` Stephen Hemminger [this message]
2026-04-16 18:45 ` [PATCH v24 00/24] net/pcap: fixes, test and enhancements Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 01/24] maintainers: update for pcap driver Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 02/24] net/pcap: fix build on Windows Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 03/24] doc: update features for PCAP PMD Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 04/24] net/pcap: include used headers Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 05/24] net/pcap: remove unnecessary casts Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 06/24] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 07/24] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 08/24] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 09/24] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-04-16 18:45 ` [PATCH v24 10/24] net/pcap: clean up TX dumper return value and types Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 00/24] net/pcap: bug fixes and new features Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 01/24] maintainers: update for pcap driver Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 02/24] net/pcap: fix build on Windows Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 03/24] doc: update features for PCAP PMD Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 04/24] net/pcap: include used headers Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 05/24] net/pcap: remove unnecessary casts Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 06/24] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 07/24] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 08/24] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 09/24] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 10/24] net/pcap: clean up TX dumper return value and types Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 11/24] net/pcap: add datapath debug logging Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 12/24] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 13/24] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 14/24] net/pcap: add link status for interface mode Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 15/24] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 16/24] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 17/24] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 18/24] net/pcap: clarify maximum received packet Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 19/24] eal/windows: add wrapper for access function Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 20/24] net/pcap: add snapshot length devarg Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 21/24] net/pcap: add Rx scatter offload Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 22/24] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 23/24] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-04-16 18:48 ` [PATCH v24 24/24] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 00/24] net/pcap: bug fixes and new features Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 01/24] maintainers: update for pcap driver Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 02/24] net/pcap: fix build on Windows Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 03/24] doc: update features for PCAP PMD Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 04/24] net/pcap: include used headers Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 05/24] net/pcap: remove unnecessary casts Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 06/24] net/pcap: avoid using rte_malloc and rte_memcpy Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 07/24] net/pcap: advertise Tx multi segment Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 08/24] net/pcap: replace stack bounce buffer Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 09/24] net/pcap: fix error accounting and backpressure on transmit Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 10/24] net/pcap: clean up TX dumper return value and types Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 11/24] net/pcap: add datapath debug logging Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 12/24] net/pcap: consolidate boolean flag handling Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 13/24] net/pcap: support VLAN strip and insert offloads Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 14/24] net/pcap: add link status for interface mode Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 15/24] net/pcap: support nanosecond timestamp precision Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 16/24] net/pcap: reject non-Ethernet interfaces Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 17/24] net/pcap: reduce scope of file-level variables Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 18/24] net/pcap: clarify maximum received packet Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 19/24] eal/windows: add wrapper for access function Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 20/24] net/pcap: add snapshot length devarg Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 21/24] net/pcap: add Rx scatter offload Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 22/24] net/pcap: add link status change support for iface mode Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 23/24] net/pcap: add EOF notification via link status change Stephen Hemminger
2026-04-19 16:09 ` [PATCH v25 24/24] test: add comprehensive test suite for pcap PMD Stephen Hemminger
2026-04-30 17:10 ` [PATCH v25 00/24] net/pcap: bug fixes and new features Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260415144717.226161-25-stephen@networkplumber.org \
--to=stephen@networkplumber.org \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.