Skip to content

feat(dpdk-stdlib-tcp): real-NIC engine driver so DPDK TCP DUTs actually run - #99

Merged
gspivey merged 1 commit into
developmentfrom
agent/tcp-dpdk-engine
Jul 1, 2026
Merged

gspivey merged 1 commit into
developmentfrom
agent/tcp-dpdk-engine

Conversation

@gspivey

@gspivey gspivey commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

Makes the DPDK TCP DUT apps actually runnable on a real NIC. They called TcpListener::bind / TcpStream::connect, which require a process-wide TcpContext and a running engine — but nothing built either, so an IPv4 bind failed with "TCP context not initialized". This is the keystone that unblocks rust-dpdk-tcp / tokio-dpdk-tcp perf.

Changes

dpdk-stdlib-net — the real-NIC backend (--no-pci fix)

  • Add DpdkBackend::new_real_nic(port_id, eal_args) that initialises EAL without --no-pci (mirrors dpdk-stdlib-udp's get_or_init_dpdk), so a real vfio-pci ENI is actually probed.
  • DpdkBackend::new hardcodes --no-pci → a null device that never sees the NIC. Using it for TCP/QUIC was why "real DPDK" paths touched nothing. (QUIC's real-NIC PR will reuse new_real_nic.)
  • Serialize the EAL-lifecycle backend tests with #[serial] — the stub's EAL state is process-global, so concurrent init/cleanup races mempool creation.

dpdk-stdlib-tcp — the engine driver + two bug fixes

  • New runtime module: init_dpdk_tcp_context(cfg) builds backend (new_real_nic) + ArpResolver(gateway_mac) + TcpEngine, spawns the single engine-driver thread (RX→engine, commands→engine, timers→engine), and publishes the global TcpContext.
  • Bug 1 (zeroed MACs): the driver extracts the Ethernet src/dst MAC from the raw frame and calls on_segment_with_macs, so a server's SYN-ACK targets the real peer (gateway) MAC instead of 00:..:00. Same fix applied to stream.rs::engine_loop.
  • Bug 2 (dead command sender): accept-side ConnectionHandles got a throwaway dummy CommandSender — Close/Shutdown/SetOption from accepted streams went nowhere and writes never woke the engine. Added TcpEngine::with_cmd_tx and threaded the live sender through handle_syn / handle_syn_with_macs.

apps

  • tcp-echo, tokio-tcp-echo, tcp-test-client gain --gateway-mac / --eal-args (+ server --perf-interval, client --local-ip) and call init_dpdk_tcp_context before bind/connect. plain-tcp-echo (kernel) is unchanged.

Tests

  • cargo build --workspace — clean
  • cargo test --workspace — 1031 passed / 0 failed
  • New unit tests: drive_once SYN-ACK targets the peer MAC (MAC regression), with_cmd_tx threads the live sender to the accept handle, new_real_nic smoke test.

Notes

  • Perf-runner token wiring (rust-dpdk-tcp / tokio-dpdk-tcp in run-perf-tests.sh) is deferred to the perf-runner PR so the shared script doesn't collide across the parallel feature PRs.
  • No .github/workflows changes.

🤖 Generated with Claude Code

…ly run

The TCP apps called TcpListener::bind / TcpStream::connect, which require a
process-wide TcpContext + a running engine — but nothing built either, so an
IPv4 bind failed with "TCP context not initialized". This wires up the missing
runtime and fixes two engine bugs the work surfaced.

- dpdk-stdlib-net: add DpdkBackend::new_real_nic(port_id, eal_args) which inits
  EAL WITHOUT --no-pci (mirrors dpdk-stdlib-udp's get_or_init_dpdk), so a real
  vfio-pci ENI is actually probed. DpdkBackend::new (--no-pci) is a null device
  that never sees the NIC — using it for TCP/QUIC was the root cause of "real
  DPDK" paths touching nothing. Serialize the EAL-lifecycle backend tests
  (#[serial]) since the stub's EAL state is process-global.
- dpdk-stdlib-tcp: new runtime module with init_dpdk_tcp_context() — builds the
  backend (new_real_nic) + ArpResolver(gateway_mac) + engine + spawns the single
  engine-driver thread, then publishes the global TcpContext.
- Engine bug 1 (zeroed MACs): the driver now extracts the Ethernet src/dst MAC
  from the raw frame and calls on_segment_with_macs, so a server's SYN-ACK is
  addressed to the real peer (gateway) MAC instead of 00:..:00. Same fix applied
  to stream.rs::engine_loop.
- Engine bug 2 (dead command sender): accept-side ConnectionHandles got a
  throwaway dummy CommandSender, so Close/Shutdown/SetOption from accepted
  streams went nowhere and writes never woke the engine. Add TcpEngine::with_cmd_tx
  and thread the live sender through handle_syn / handle_syn_with_macs.
- apps: tcp-echo, tokio-tcp-echo, tcp-test-client gain --gateway-mac / --eal-args
  (+ server --perf-interval, client --local-ip) and call init_dpdk_tcp_context
  before bind/connect. plain-tcp-echo (kernel) is unchanged.

Tests: cargo build --workspace clean; cargo test --workspace = 1031 passed / 0
failed. New unit tests: drive_once SYN-ACK targets the peer MAC (MAC regression),
with_cmd_tx threads the live sender to the accept handle, new_real_nic smoke test.

Perf-runner token wiring (rust-dpdk-tcp / tokio-dpdk-tcp) is deferred to the
perf-runner PR so the shared run-perf-tests.sh doesn't collide across PRs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Synthetic Performance Results — Graviton (run)

Commit: 62b4aa78

✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)

Synthetic UDP Performance Results

Measures framework overhead: sync dpdk_udp::UdpSocket vs async (std::sync::Mutex + try_recv_from).

IPv4 Baseline

Test Payload Sync PPS Async PPS Ratio (sync/async) Async ns/op
TX send_to 64B 11.8M 11.3M 1.0x 88
RX recv_from 64B 3.6M 4.7M 0.8x 214
TX send_to 1400B 1.8M 1.8M 1.0x 557
RX recv_from 1400B 1.1M 1.2M 0.9x 825

IPv6

Test Payload Sync PPS Async PPS Ratio (sync/async) Async ns/op
TX send_to (IPv6) 64B 8.8M 8.7M 1.0x 114
RX recv_from (IPv6) 64B 4.1M 5.7M 0.7x 176
TX send_to (IPv6) 1400B 3.0M 3.0M 1.0x 337
RX recv_from (IPv6) 1400B 1.1M 1.2M 0.9x 811

IPv6 vs IPv4 Comparison (sync path)

Test Payload IPv4 PPS IPv6 PPS IPv4/IPv6 Ratio
TX send_to (sync) 64B 11.8M 8.8M 1.35x
RX recv_from (sync) 64B 3.6M 4.1M 0.87x
TX send_to (sync) 1400B 1.8M 3.0M 0.61x
RX recv_from (sync) 1400B 1.1M 1.1M 0.96x

IPv4 avg sync/async ratio: 0.9x, worst: 1.0x | IPv6 vs IPv4 worst ratio: 1.35x (OK)

OK: IPv6 is 34.8% slower than IPv4 — within acceptable threshold (<50%). Expected due to larger headers (40B vs 20B) and mandatory UDP checksum.

Good: Async wrapper is within 1.0x of sync — minimal framework overhead.

@github-actions

Copy link
Copy Markdown

Synthetic Performance Results (run)

Commit: 62b4aa78

✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to 10.0.0.1:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)
✅ synthetic UDP socket bound to [2001:db8::1]:9000 (MAC: 02:00:00:00:00:01)

Synthetic UDP Performance Results

Measures framework overhead: sync dpdk_udp::UdpSocket vs async (std::sync::Mutex + try_recv_from).

IPv4 Baseline

Test Payload Sync PPS Async PPS Ratio (sync/async) Async ns/op
TX send_to 64B 11.8M 11.0M 1.1x 91
RX recv_from 64B 3.5M 4.7M 0.7x 213
TX send_to 1400B 1.8M 1.8M 1.0x 559
RX recv_from 1400B 1.1M 1.2M 0.9x 825

IPv6

Test Payload Sync PPS Async PPS Ratio (sync/async) Async ns/op
TX send_to (IPv6) 64B 8.7M 8.5M 1.0x 117
RX recv_from (IPv6) 64B 4.1M 5.7M 0.7x 176
TX send_to (IPv6) 1400B 3.0M 3.0M 1.0x 333
RX recv_from (IPv6) 1400B 1.1M 1.2M 0.9x 809

IPv6 vs IPv4 Comparison (sync path)

Test Payload IPv4 PPS IPv6 PPS IPv4/IPv6 Ratio
TX send_to (sync) 64B 11.8M 8.7M 1.36x
RX recv_from (sync) 64B 3.5M 4.1M 0.85x
TX send_to (sync) 1400B 1.8M 3.0M 0.60x
RX recv_from (sync) 1400B 1.1M 1.1M 0.97x

IPv4 avg sync/async ratio: 0.9x, worst: 1.1x | IPv6 vs IPv4 worst ratio: 1.36x (OK)

OK: IPv6 is 36.2% slower than IPv4 — within acceptable threshold (<50%). Expected due to larger headers (40B vs 20B) and mandatory UDP checksum.

Good: Async wrapper is within 1.1x of sync — minimal framework overhead.

@github-actions

Copy link
Copy Markdown

[CI] Stage: Deploy

Infrastructure ready.

  • Sender: i-0d4dd6bded2801a98 (DPDK ENI: 10.0.1.183)
  • Receiver: i-02bf2296369163511 (DPDK ENI: 10.0.1.167)
  • Both instances SSM-ready.

@github-actions

Copy link
Copy Markdown

[CI] Stage: Deploy

Infrastructure ready.

  • Sender: i-0f2cdf6702b44d3a9 (DPDK ENI: 10.0.1.106)
  • Receiver: i-0b67e1dd8dd3ca728 (DPDK ENI: 10.0.1.88)
  • Both instances SSM-ready.

@github-actions

Copy link
Copy Markdown

[CI] Stage: Summary

All tests PASSED.

ARP seeding: kernel /proc/net/arp (automatic)

  • tier1-dpdk-echo: 6 tests, 0 failures
  • tier2-kernel-interop: 4 tests, 0 failures
  • tier3-iperf-interop: 1 tests, 0 failures
  • tier3-iperf-interop: 1 tests, 0 failures

1 similar comment
@github-actions

Copy link
Copy Markdown

[CI] Stage: Summary

All tests PASSED.

ARP seeding: kernel /proc/net/arp (automatic)

  • tier1-dpdk-echo: 6 tests, 0 failures
  • tier2-kernel-interop: 4 tests, 0 failures
  • tier3-iperf-interop: 1 tests, 0 failures
  • tier3-iperf-interop: 1 tests, 0 failures

@github-actions

Copy link
Copy Markdown

✅ Integration Tests Passed (Run 28446092989)

Branch: 99/merge | Commit: 62b4aa78

Test Results

  • tier1-dpdk-echo.xml: 6 tests, 0 failures, skipped
  • tier2-kernel-interop.xml: 4 tests, 0 failures, skipped
  • tier3-iperf-sends.xml: 1 tests, 0 failures, skipped
  • tier3-our-app-sends.xml: 1 tests, 0 failures, skipped

Application Logs (last 20 lines)

receiver-echo-server.log

EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.88:9000 (MAC: 02:47:fd:42:86:b1)
echo listening on 10.0.1.88:9000 (MTU=9001, max_udp_payload=8973)
Shutting down gracefully...

sender-echo-server.log

EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.106:9000 (MAC: 02:7a:1d:6c:45:b5)
echo listening on 10.0.1.106:9000 (MTU=9001, max_udp_payload=8973)
Shutting down gracefully...

sender-test-client.log

EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
TELEMETRY: No legacy callbacks, legacy socket not created
DPDK bind failed (Port init failed: Invalid port ID: 0), falling back to tokio
Backend: tokio
Sending packets...
Sent 12 bytes: 'arp-probe #1'
Received 12 bytes from 10.0.1.88:9000: 'arp-probe #1'
Test complete
[2026-06-30T13:27:46Z] INFO: ARP resolution succeeded (got response from peer)
[2026-06-30T13:27:46Z] INFO: Test: udp_send_receive
[2026-06-30T13:27:47Z] INFO: UDP send/receive succeeded
[2026-06-30T13:27:47Z] INFO: Test: echo_roundtrip
[2026-06-30T13:27:48Z] INFO: Echo roundtrip succeeded: 5/5 responses received
[2026-06-30T13:27:48Z] INFO: Test: payload_integrity
[2026-06-30T13:27:48Z] INFO: Response received, checking payload match...
[2026-06-30T13:27:48Z] INFO: Payload integrity verified (found in response)
[2026-06-30T13:27:48Z] INFO: JUnit XML written to: /tmp/test-results/tier2-kernel-interop.xml
[2026-06-30T13:27:48Z] INFO: Tier 2 sender tests complete. Results: /tmp/test-results/tier2-kernel-interop.xml

receiver-test-client-iperf.log

[2026-06-30T13:32:06Z] INFO: iperf-sends: sent 10 packets, received 10 responses
[2026-06-30T13:32:06Z] INFO: iperf-sends: PASS (sent >= 5 packets)
[2026-06-30T13:32:06Z] INFO: JUnit XML written to: /tmp/test-results/tier3-iperf-sends.xml
[2026-06-30T13:32:06Z] INFO: iperf-sends test complete

sender-test-client-iperf.log

Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #3'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #4'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #4'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #5'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #5'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #6'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #6'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #7'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #7'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #8'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #8'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #9'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #9'
Sent 31 bytes: 'dpdk-to-kernel-test-payload #10'
Received 31 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #10'
Test complete
[2026-06-30T13:31:07Z] INFO: our-app-sends: sent 10 packets, received 10 responses
[2026-06-30T13:31:07Z] INFO: our-app-sends: PASS (sent >= 5 packets)
[2026-06-30T13:31:07Z] INFO: JUnit XML written to: /tmp/test-results/tier3-our-app-sends.xml
[2026-06-30T13:31:07Z] INFO: our-app-sends test complete
Full Application Logs (last 200 lines each)

receiver-echo-server.log

EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.88:9000 (MAC: 02:47:fd:42:86:b1)
echo listening on 10.0.1.88:9000 (MTU=9001, max_udp_payload=8973)
Shutting down gracefully...

sender-echo-server.log

EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.106:9000 (MAC: 02:7a:1d:6c:45:b5)
echo listening on 10.0.1.106:9000 (MTU=9001, max_udp_payload=8973)
Shutting down gracefully...

sender-test-client.log

[2026-06-30T13:23:16Z] INFO: Test: arp_resolution
UDP Test Client
Target: 10.0.1.88:9000
Bind address: 10.0.1.106:0
Message: 'arp-probe'
Count: 1
EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.106:32768 (MAC: 02:7a:1d:6c:45:b5)
Backend: dpdk
Sending packets...
Sent 12 bytes: 'arp-probe #1'
Received 12 bytes from 10.0.1.88:9000: 'arp-probe #1'
Test complete
[2026-06-30T13:23:17Z] INFO: ARP resolution succeeded (got response from peer)
[2026-06-30T13:23:17Z] INFO: Test: udp_send_receive
[2026-06-30T13:23:18Z] INFO: UDP send/receive succeeded
[2026-06-30T13:23:18Z] INFO: Test: echo_roundtrip
[2026-06-30T13:23:20Z] INFO: Echo roundtrip succeeded: 5/5 responses received
[2026-06-30T13:23:20Z] INFO: Test: payload_integrity
[2026-06-30T13:23:21Z] INFO: Response received, checking payload match...
[2026-06-30T13:23:21Z] INFO: Payload integrity verified (found in response)
[2026-06-30T13:23:21Z] INFO: Test: jumbo_diagnostics
[2026-06-30T13:23:21Z] INFO: === JUMBO FRAME DIAGNOSTICS ===
[2026-06-30T13:23:21Z] INFO: Interface MTU:
  9001
  65536
[2026-06-30T13:23:21Z] INFO:   ens5: MTU=9001
[2026-06-30T13:23:21Z] INFO:   lo: MTU=65536
[2026-06-30T13:23:21Z] INFO: Routing table MTU column:
Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                       
ens5	00000000	0101000A	0003	0	0	512	00000000	0	0	0                                                                             
ens5	0200000A	0101000A	0007	0	0	512	FFFFFFFF	0	0	0                                                                             
ens5	0001000A	00000000	0001	0	0	512	00FFFFFF	0	0	0                                                                             
ens5	0101000A	00000000	0005	0	0	512	FFFFFFFF	0	0	0                                                                             
[2026-06-30T13:23:21Z] INFO: DPDK port config (from echo server log):
[2026-06-30T13:23:21Z] INFO:   (no MTU info in echo log)
[2026-06-30T13:23:21Z] INFO: === END JUMBO DIAGNOSTICS ===
[2026-06-30T13:23:21Z] INFO: Test: jumbo_echo_8000
[2026-06-30T13:23:22Z] INFO: Jumbo output: UDP Test Client
Target: 10.0.1.88:9000
Bind address: 10.0.1.106:0
Payload size: 8000 bytes
Count: 3
EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.106:32768 (MAC: 02:7a:1d:6c:45:b5)
Backend: dpdk
Sending packets...
Sent 8000 bytes (binary payload)
Received 8000 bytes from 10.0.1.88:9000 (expected 8000, OK)
Sent 8000 bytes (binary payload)
Received 8000 bytes from 10.0.1.88:9000 (expected 8000, OK)
Sent 8000 bytes (binary payload)
Received 8000 bytes from 10.0.1.88:9000 (expected 8000, OK)
Test complete
[2026-06-30T13:23:22Z] INFO: Jumbo frame echo succeeded: 3/3 responses with correct size
[2026-06-30T13:23:22Z] INFO: JUnit XML written to: /tmp/test-results/tier1-dpdk-echo.xml
[2026-06-30T13:23:22Z] INFO: Tier 1 sender tests complete. Results: /tmp/test-results/tier1-dpdk-echo.xml
[2026-06-30T13:27:46Z] INFO: Test: arp_resolution
UDP Test Client
Target: 10.0.1.88:9000
Bind address: 0.0.0.0:0
Message: 'arp-probe'
Count: 1
EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
TELEMETRY: No legacy callbacks, legacy socket not created
DPDK bind failed (Port init failed: Invalid port ID: 0), falling back to tokio
Backend: tokio
Sending packets...
Sent 12 bytes: 'arp-probe #1'
Received 12 bytes from 10.0.1.88:9000: 'arp-probe #1'
Test complete
[2026-06-30T13:27:46Z] INFO: ARP resolution succeeded (got response from peer)
[2026-06-30T13:27:46Z] INFO: Test: udp_send_receive
[2026-06-30T13:27:47Z] INFO: UDP send/receive succeeded
[2026-06-30T13:27:47Z] INFO: Test: echo_roundtrip
[2026-06-30T13:27:48Z] INFO: Echo roundtrip succeeded: 5/5 responses received
[2026-06-30T13:27:48Z] INFO: Test: payload_integrity
[2026-06-30T13:27:48Z] INFO: Response received, checking payload match...
[2026-06-30T13:27:48Z] INFO: Payload integrity verified (found in response)
[2026-06-30T13:27:48Z] INFO: JUnit XML written to: /tmp/test-results/tier2-kernel-interop.xml
[2026-06-30T13:27:48Z] INFO: Tier 2 sender tests complete. Results: /tmp/test-results/tier2-kernel-interop.xml

receiver-test-client-iperf.log

[2026-06-30T13:32:06Z] INFO: iperf-sends: sent 10 packets, received 10 responses
[2026-06-30T13:32:06Z] INFO: iperf-sends: PASS (sent >= 5 packets)
[2026-06-30T13:32:06Z] INFO: JUnit XML written to: /tmp/test-results/tier3-iperf-sends.xml
[2026-06-30T13:32:06Z] INFO: iperf-sends test complete

sender-test-client-iperf.log

[2026-06-30T13:31:05Z] INFO: Pre-flight: checking DPDK state and ARP cache...
[2026-06-30T13:31:05Z] INFO: Local IP: 10.0.1.106, Peer IP: 10.0.1.88, Port: 9000
[2026-06-30T13:31:05Z] INFO: /proc/net/arp contents:
IP address       HW type     Flags       HW address            Mask     Device
10.0.1.88        0x1         0x2         02:47:fd:42:86:b1     *        ens5
10.0.1.106       0x1         0x2         02:7a:1d:6c:45:b5     *        ens5
10.0.1.250       0x1         0x2         02:a2:11:61:08:53     *        ens5
10.0.1.1         0x1         0x2         02:cd:f3:64:b6:95     *        ens5
[2026-06-30T13:31:05Z] INFO: DPDK runtime state:
No /var/run/dpdk/ directory
[2026-06-30T13:31:05Z] INFO: vfio-pci bindings:
0000:00:06.0
bind
module
new_id
remove_id
uevent
unbind
[2026-06-30T13:31:05Z] INFO: Test binary: /opt/dpdk-stdlib/target/release/test-client
-rwxr-xr-x. 2 root root 1943064 Jun 30 13:21 /opt/dpdk-stdlib/target/release/test-client
[2026-06-30T13:31:05Z] INFO: Launching test-client: /opt/dpdk-stdlib/target/release/test-client --target 10.0.1.88 --port 9000 --bind-ip 10.0.1.106 --count 10 --delay 200
[2026-06-30T13:31:07Z] INFO: Test client output: UDP Test Client
Target: 10.0.1.88:9000
Bind address: 10.0.1.106:0
Message: 'dpdk-to-kernel-test-payload'
Count: 10
EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.106:32768 (MAC: 02:7a:1d:6c:45:b5)
Backend: dpdk
Sending packets...
Sent 30 bytes: 'dpdk-to-kernel-test-payload #1'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #1'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #2'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #2'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #3'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #3'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #4'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #4'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #5'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #5'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #6'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #6'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #7'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #7'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #8'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #8'
Sent 30 bytes: 'dpdk-to-kernel-test-payload #9'
Received 30 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #9'
Sent 31 bytes: 'dpdk-to-kernel-test-payload #10'
Received 31 bytes from 10.0.1.88:9000: 'dpdk-to-kernel-test-payload #10'
Test complete
[2026-06-30T13:31:07Z] INFO: our-app-sends: sent 10 packets, received 10 responses
[2026-06-30T13:31:07Z] INFO: our-app-sends: PASS (sent >= 5 packets)
[2026-06-30T13:31:07Z] INFO: JUnit XML written to: /tmp/test-results/tier3-our-app-sends.xml
[2026-06-30T13:31:07Z] INFO: our-app-sends test complete
⚠️ SSM Command Failures (receiver-ssm-failure.log)
=== Polling timeout after 30s ===
Status: InProgress
Instance: i-0b67e1dd8dd3ca728 (receiver)
Command ID: cc7ac765-9484-4a35-9947-15c48a93bffe

=== STDOUT ===


=== STDERR ===


=== Polling timeout after 30s ===
Status: InProgress
Instance: i-0b67e1dd8dd3ca728 (receiver)
Command ID: 2fb7ed59-c139-4f97-a3d6-4af56dab4dcf

=== STDOUT ===


=== STDERR ===


=== Polling timeout after 30s ===
Status: InProgress
Instance: i-0b67e1dd8dd3ca728 (receiver)
Command ID: a5e53773-a90f-498c-a89c-ac6d08baecff

=== STDOUT ===


=== STDERR ===


=== Polling timeout after 30s ===
Status: InProgress
Instance: i-0b67e1dd8dd3ca728 (receiver)
Command ID: 9d2a6098-6e76-4d6c-996f-ff62a3e90610

=== STDOUT ===


=== STDERR ===


⚠️ SSM Command Failures (sender-ssm-failure.log)
=== Polling timeout 120s (SSM timeout: 90s, command: cd /opt/dpdk-stdlib && bash scripts/integration-tests/configure-eni.sh --action unbind && bash scripts/integration-tests/configure-eni.sh --action assign-ip --ip 10.0.1.106) ===
Status: InProgress
Instance: i-0f2cdf6702b44d3a9 (sender)
Command ID: 4aac911d-98cc-4646-92c3-2ee0ea43bf07

=== STDOUT ===


=== STDERR ===


=== Polling timeout after 30s ===
Status: InProgress
Instance: i-0f2cdf6702b44d3a9 (sender)
Command ID: 83c854df-99d4-4b8b-be1b-c842fbbc85f6

=== STDOUT ===


=== STDERR ===


Network & PCI State

receiver-network-interfaces.log

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 02:54:53:ac:f1:51 brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname eni-04190061058502b86
    altname device-number-0.0
    inet 10.0.1.60/24 metric 512 brd 10.0.1.255 scope global dynamic ens5
       valid_lft 2302sec preferred_lft 2302sec
    inet6 fe80::54:53ff:feac:f151/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

sender-network-interfaces.log

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 02:5b:95:b4:01:f7 brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname eni-0a5ae431981e9e5da
    altname device-number-0.0
    inet 10.0.1.64/24 metric 512 brd 10.0.1.255 scope global dynamic ens5
       valid_lft 2324sec preferred_lft 2324sec
    inet6 fe80::5b:95ff:feb4:1f7/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

receiver-networking-diag-baseline.txt

=== NETWORKING DIAGNOSTICS ===
timestamp: 2026-06-30T13:22:37Z
hostname: ip-10-0-1-60.ec2.internal
kernel: 6.18.35-68.127.amzn2023.x86_64

=== DPDK PORT STATUS ===

Network devices using DPDK-compatible driver
============================================
0000:00:06.0 'Elastic Network Adapter (ENA) ec20' drv=vfio-pci unused=ena

Network devices using kernel driver
===================================
0000:00:05.0 'Elastic Network Adapter (ENA) ec20' if=ens5 drv=ena unused=vfio-pci *Active*

No 'Baseband' devices detected
==============================

No 'Crypto' devices detected
============================

No 'DMA' devices detected
=========================

No 'Eventdev' devices detected
==============================

No 'Mempool' devices detected
=============================

No 'Compress' devices detected
==============================

No 'Misc (rawdev)' devices detected
===================================

No 'Regex' devices detected
===========================

=== IP ADDRESSES ===
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 02:54:53:ac:f1:51 brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname eni-04190061058502b86
    altname device-number-0.0
    inet 10.0.1.60/24 metric 512 brd 10.0.1.255 scope global dynamic ens5
       valid_lft 3170sec preferred_lft 3170sec
    inet6 fe80::54:53ff:feac:f151/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

=== ARP TABLE ===
10.0.1.1 dev ens5 lladdr 02:cd:f3:64:b6:95 REACHABLE 
10.0.1.250 dev ens5 lladdr 02:a2:11:61:08:53 REACHABLE 

=== ROUTE TABLE ===
default via 10.0.1.1 dev ens5 proto dhcp src 10.0.1.60 metric 512 
10.0.0.2 via 10.0.1.1 dev ens5 proto dhcp src 10.0.1.60 metric 512 
10.0.1.0/24 dev ens5 proto kernel scope link src 10.0.1.60 metric 512 
10.0.1.1 dev ens5 proto dhcp scope link src 10.0.1.60 metric 512 

=== IMDS: ENI INFORMATION ===
ENI MACs found: 02:47:fd:42:86:b1/ 02:54:53:ac:f1:51/ 

--- ENI: 02:47:fd:42:86:b1/ ---
  device-number: 1
  local-ipv4s: 10.0.1.88
  subnet-id: subnet-00fc0966f278e6d18
  subnet-cidr: 10.0.1.0/24

--- ENI: 02:54:53:ac:f1:51/ ---
  device-number: 0
  local-ipv4s: 10.0.1.60
  subnet-id: subnet-00fc0966f278e6d18
  subnet-cidr: 10.0.1.0/24


=== GATEWAY ARP TEST ===
Gateway IP: 10.0.1.1
Gateway ARP entry:
10.0.1.1 dev ens5 lladdr 02:cd:f3:64:b6:95 REACHABLE 

arping result:
ARPING 10.0.1.1 from 10.0.1.60 ens5
Unicast reply from 10.0.1.1 [02:CD:F3:64:B6:95]  0.539ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)

=== HUGEPAGE STATUS ===
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:     51200 kB
HugePages_Total:    1024
HugePages_Free:     1024
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:         2097152 kB

=== VFIO STATUS ===
total 0
drwxr-xr-x.  2 root root       80 Jun 30 13:22 .
drwxr-xr-x. 14 root root     3100 Jun 30 13:21 ..
crw-------.  1 root root 243,   0 Jun 30 13:22 noiommu-0
crw-rw-rw-.  1 root root  10, 196 Jun 30 13:15 vfio

noiommu mode:
Y

=== DPDK SHARED MEMORY ===
no /var/run/dpdk/ directory (clean state)

=== DPDK-RELATED DMESG (last 30 lines) ===
[    0.051629] printk: legacy console [ttyS0] enabled
[    0.052622] x2apic enabled
[    0.056736] mitigations: Enabled attack vectors: user_kernel, user_user, guest_host, guest_guest, SMT mitigations: auto
[    0.056842] x86/fpu: Enabled xstate features 0x2ff, context size is 2568 bytes, using 'compacted' format.
[    0.066589] audit: type=2000 audit(1782825317.988:1): state=initialized audit_enabled=0 res=1
[    0.086105] kprobes: kprobe jump-optimization is enabled. All kprobes are optimized if possible.
[    0.138178] ACPI: Interpreter enabled
[    0.138178] ACPI: Enabled 2 GPEs in block 00 to 0F
[    0.156170] pci 0000:00:05.0: enabling Extended Tags
[    0.234462] SGI XFS with ACLs, security attributes, quota, no debug enabled
[    0.249343] ACPI: \_SB_.LNKD: Enabled at IRQ 11
[    0.315150] IPI shorthand broadcast: enabled
[    7.016786] systemd[1]: Mounting dev-hugepages.mount - Huge Pages File System...
[    7.056638] systemd[1]: Mounted dev-hugepages.mount - Huge Pages File System.
[    7.121485] VFIO - User Level meta-driver version: 0.3
[    7.683413] ena 0000:00:05.0: Elastic Network Adapter (ENA) v2.17.0g
[    7.694671] ena 0000:00:05.0: ENA device version: 0.10
[    7.695364] ena 0000:00:05.0: ENA controller version: 0.0.1 implementation version 1
[    7.794548] ena 0000:00:05.0: ENA Large LLQ is disabled
[    7.806933] ena 0000:00:05.0: Elastic Network Adapter (ENA) found at mem c0500000, mac addr 02:54:53:ac:f1:51
[    7.853541] ena 0000:00:05.0 ens5: renamed from eth0
[  391.310816] pci 0000:00:06.0: enabling Extended Tags
[  391.314750] ena 0000:00:06.0: enabling device (0000 -> 0002)
[  391.325266] ena 0000:00:06.0: ENA device version: 0.10
[  391.326015] ena 0000:00:06.0: ENA controller version: 0.0.1 implementation version 1
[  391.425262] ena 0000:00:06.0: ENA Large LLQ is disabled
[  391.437464] ena 0000:00:06.0: Elastic Network Adapter (ENA) found at mem c0508000, mac addr 02:47:fd:42:86:b1
[  391.444790] ena 0000:00:06.0 ens6: renamed from eth0
[  426.878786] vfio-pci 0000:00:06.0: Adding to iommu group 0
[  426.880180] vfio-pci 0000:00:06.0: Adding kernel taint for vfio-noiommu group on device

=== DPDK-RELATED PROCESSES ===
no DPDK processes running

=== END DIAGNOSTICS ===

sender-networking-diag-baseline.txt

=== NETWORKING DIAGNOSTICS ===
timestamp: 2026-06-30T13:22:30Z
hostname: ip-10-0-1-64.ec2.internal
kernel: 6.18.35-68.127.amzn2023.x86_64

=== DPDK PORT STATUS ===

Network devices using DPDK-compatible driver
============================================
0000:00:06.0 'Elastic Network Adapter (ENA) ec20' drv=vfio-pci unused=ena

Network devices using kernel driver
===================================
0000:00:05.0 'Elastic Network Adapter (ENA) ec20' if=ens5 drv=ena unused=vfio-pci *Active*

No 'Baseband' devices detected
==============================

No 'Crypto' devices detected
============================

No 'DMA' devices detected
=========================

No 'Eventdev' devices detected
==============================

No 'Mempool' devices detected
=============================

No 'Compress' devices detected
==============================

No 'Misc (rawdev)' devices detected
===================================

No 'Regex' devices detected
===========================

=== IP ADDRESSES ===
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 02:5b:95:b4:01:f7 brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname eni-0a5ae431981e9e5da
    altname device-number-0.0
    inet 10.0.1.64/24 metric 512 brd 10.0.1.255 scope global dynamic ens5
       valid_lft 3177sec preferred_lft 3177sec
    inet6 fe80::5b:95ff:feb4:1f7/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

=== ARP TABLE ===
10.0.1.250 dev ens5 lladdr 02:a2:11:61:08:53 REACHABLE 
10.0.1.1 dev ens5 lladdr 02:cd:f3:64:b6:95 REACHABLE 

=== ROUTE TABLE ===
default via 10.0.1.1 dev ens5 proto dhcp src 10.0.1.64 metric 512 
10.0.0.2 via 10.0.1.1 dev ens5 proto dhcp src 10.0.1.64 metric 512 
10.0.1.0/24 dev ens5 proto kernel scope link src 10.0.1.64 metric 512 
10.0.1.1 dev ens5 proto dhcp scope link src 10.0.1.64 metric 512 

=== IMDS: ENI INFORMATION ===
ENI MACs found: 02:5b:95:b4:01:f7/ 02:7a:1d:6c:45:b5/ 

--- ENI: 02:5b:95:b4:01:f7/ ---
  device-number: 0
  local-ipv4s: 10.0.1.64
  subnet-id: subnet-00fc0966f278e6d18
  subnet-cidr: 10.0.1.0/24

--- ENI: 02:7a:1d:6c:45:b5/ ---
  device-number: 1
  local-ipv4s: 10.0.1.106
  subnet-id: subnet-00fc0966f278e6d18
  subnet-cidr: 10.0.1.0/24


=== GATEWAY ARP TEST ===
Gateway IP: 10.0.1.1
Gateway ARP entry:
10.0.1.1 dev ens5 lladdr 02:cd:f3:64:b6:95 REACHABLE 

arping result:
ARPING 10.0.1.1 from 10.0.1.64 ens5
Unicast reply from 10.0.1.1 [02:CD:F3:64:B6:95]  0.540ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)

=== HUGEPAGE STATUS ===
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:     51200 kB
HugePages_Total:    1024
HugePages_Free:     1024
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:         2097152 kB

=== VFIO STATUS ===
total 0
drwxr-xr-x.  2 root root       80 Jun 30 13:22 .
drwxr-xr-x. 14 root root     3100 Jun 30 13:21 ..
crw-------.  1 root root 243,   0 Jun 30 13:22 noiommu-0
crw-rw-rw-.  1 root root  10, 196 Jun 30 13:15 vfio

noiommu mode:
Y

=== DPDK SHARED MEMORY ===
no /var/run/dpdk/ directory (clean state)

=== DPDK-RELATED DMESG (last 30 lines) ===
[    0.056062] printk: legacy console [ttyS0] enabled
[    0.057088] x2apic enabled
[    0.061261] mitigations: Enabled attack vectors: user_kernel, user_user, guest_host, guest_guest, SMT mitigations: auto
[    0.061371] x86/fpu: Enabled xstate features 0x2ff, context size is 2568 bytes, using 'compacted' format.
[    0.071133] audit: type=2000 audit(1782825318.114:1): state=initialized audit_enabled=0 res=1
[    0.090603] kprobes: kprobe jump-optimization is enabled. All kprobes are optimized if possible.
[    0.151558] ACPI: Interpreter enabled
[    0.151558] ACPI: Enabled 2 GPEs in block 00 to 0F
[    0.160151] pci 0000:00:05.0: enabling Extended Tags
[    0.239659] SGI XFS with ACLs, security attributes, quota, no debug enabled
[    0.256914] ACPI: \_SB_.LNKD: Enabled at IRQ 11
[    0.378959] IPI shorthand broadcast: enabled
[    7.037181] systemd[1]: Mounting dev-hugepages.mount - Huge Pages File System...
[    7.081523] systemd[1]: Mounted dev-hugepages.mount - Huge Pages File System.
[    7.157384] VFIO - User Level meta-driver version: 0.3
[    7.730631] ena 0000:00:05.0: Elastic Network Adapter (ENA) v2.17.0g
[    7.747342] ena 0000:00:05.0: ENA device version: 0.10
[    7.748072] ena 0000:00:05.0: ENA controller version: 0.0.1 implementation version 1
[    7.844652] ena 0000:00:05.0: ENA Large LLQ is disabled
[    7.856849] ena 0000:00:05.0: Elastic Network Adapter (ENA) found at mem c0500000, mac addr 02:5b:95:b4:01:f7
[    7.903306] ena 0000:00:05.0 ens5: renamed from eth0
[  391.612022] pci 0000:00:06.0: enabling Extended Tags
[  391.615992] ena 0000:00:06.0: enabling device (0000 -> 0002)
[  391.628899] ena 0000:00:06.0: ENA device version: 0.10
[  391.629645] ena 0000:00:06.0: ENA controller version: 0.0.1 implementation version 1
[  391.730798] ena 0000:00:06.0: ENA Large LLQ is disabled
[  391.744035] ena 0000:00:06.0: Elastic Network Adapter (ENA) found at mem c0508000, mac addr 02:7a:1d:6c:45:b5
[  391.751330] ena 0000:00:06.0 ens6: renamed from eth0
[  420.257976] vfio-pci 0000:00:06.0: Adding to iommu group 0
[  420.259406] vfio-pci 0000:00:06.0: Adding kernel taint for vfio-noiommu group on device

=== DPDK-RELATED PROCESSES ===
no DPDK processes running

=== END DIAGNOSTICS ===
⚠️ Crash Diagnostics

receiver-dmesg-crashes.log

[    0.066007] pid_max: default: 32768 minimum: 301
[    0.159995] iommu: Default domain type: Translated
[    0.160021] NetLabel:  unlabeled traffic allowed by default
[    0.180758] PCI: CLS 0 bytes, default 64
[    0.264931] nvme nvme0: 2/0/0 default/read/poll queues
[    0.394471] systemd[1]: systemd 252.23-12.amzn2023 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP -GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 -BZIP2 -LZ4 +XZ +ZLIB -ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
[    0.394670] systemd[1]: No hostname configured, using default hostname.
[    0.491133] systemd[1]: Queued start job for default target initrd.target.
[    5.941280] systemd[1]: systemd 252.23-12.amzn2023 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP -GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 -BZIP2 -LZ4 +XZ +ZLIB -ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
[  463.077070] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:8242)
[  733.132260] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:8725)
[ 1172.684222] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:9674)

sender-dmesg-crashes.log

[    0.070500] pid_max: default: 32768 minimum: 301
[    0.164069] iommu: Default domain type: Translated
[    0.170134] NetLabel:  unlabeled traffic allowed by default
[    0.190727] PCI: CLS 0 bytes, default 64
[    0.268120] nvme nvme0: 2/0/0 default/read/poll queues
[    0.477173] systemd[1]: systemd 252.23-12.amzn2023 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP -GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 -BZIP2 -LZ4 +XZ +ZLIB -ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
[    0.477302] systemd[1]: No hostname configured, using default hostname.
[    0.559918] systemd[1]: Queued start job for default target initrd.target.
[    5.759884] systemd[1]: systemd 252.23-12.amzn2023 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP -GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 -BZIP2 -LZ4 +XZ +ZLIB -ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
[  990.792648] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:9541)
Kernel Console (dmesg)

receiver-console-output.log (PCI/driver events only)

[  463.075522] vfio-pci 0000:00:06.0: reset done
[  463.077070] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:8242)
[  463.078535] vfio-pci 0000:00:06.0: resetting
[  463.305398] vfio-pci 0000:00:06.0: reset done
[  541.690858] vfio-pci 0000:00:06.0: Removing from iommu group 0
[  542.702538] ena 0000:00:06.0: ENA device version: 0.10
[  542.703292] ena 0000:00:06.0: ENA controller version: 0.0.1 implementation version 1
[  542.802513] ena 0000:00:06.0: ENA Large LLQ is disabled
[  542.815114] ena 0000:00:06.0: Elastic Network Adapter (ENA) found at mem c0508000, mac addr 02:47:fd:42:86:b1
[  542.822347] ena 0000:00:06.0 ens6: renamed from eth0
[  562.395760] vfio-pci 0000:00:06.0: Adding to iommu group 0
[  562.396952] vfio-pci 0000:00:06.0: Adding kernel taint for vfio-noiommu group on device
[  732.908993] vfio-pci 0000:00:06.0: resetting
[  733.130718] vfio-pci 0000:00:06.0: reset done
[  733.132260] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:8725)
[  733.133658] vfio-pci 0000:00:06.0: resetting
[  733.350605] vfio-pci 0000:00:06.0: reset done
[  806.412287] vfio-pci 0000:00:06.0: Removing from iommu group 0
[  807.425109] ena 0000:00:06.0: ENA device version: 0.10
[  807.425850] ena 0000:00:06.0: ENA controller version: 0.0.1 implementation version 1
[  807.517725] ena 0000:00:06.0: ENA Large LLQ is disabled
[  807.529607] ena 0000:00:06.0: Elastic Network Adapter (ENA) found at mem c0508000, mac addr 02:47:fd:42:86:b1
[  807.539634] ena 0000:00:06.0 ens6: renamed from eth0 (while UP)
[ 1088.733643] vfio-pci 0000:00:06.0: Adding to iommu group 0
[ 1088.735041] vfio-pci 0000:00:06.0: Adding kernel taint for vfio-noiommu group on device
[ 1172.464956] vfio-pci 0000:00:06.0: resetting
[ 1172.682680] vfio-pci 0000:00:06.0: reset done
[ 1172.684222] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (echo:9674)
[ 1172.685656] vfio-pci 0000:00:06.0: resetting
[ 1172.902575] vfio-pci 0000:00:06.0: reset done

sender-console-output.log (PCI/driver events only)

[  990.794067] vfio-pci 0000:00:06.0: resetting
[  991.010975] vfio-pci 0000:00:06.0: reset done
[ 1051.697136] vfio-pci 0000:00:06.0: Removing from iommu group 0
[ 1052.709008] ena 0000:00:06.0: ENA device version: 0.10
[ 1052.709771] ena 0000:00:06.0: ENA controller version: 0.0.1 implementation version 1
[ 1052.808989] ena 0000:00:06.0: ENA Large LLQ is disabled
[ 1052.821124] ena 0000:00:06.0: Elastic Network Adapter (ENA) found at mem c0508000, mac addr 02:7a:1d:6c:45:b5
[ 1052.831896] ena 0000:00:06.0 ens6: renamed from eth0 (while UP)
[ 1081.894827] vfio-pci 0000:00:06.0: Adding to iommu group 0
[ 1081.896222] vfio-pci 0000:00:06.0: Adding kernel taint for vfio-noiommu group on device
[ 1188.090205] vfio-pci 0000:00:06.0: resetting
[ 1188.309693] vfio-pci 0000:00:06.0: reset done
[ 1188.311231] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (tokio-rt-worker:9982)
[ 1188.312770] vfio-pci 0000:00:06.0: resetting
[ 1188.529516] vfio-pci 0000:00:06.0: reset done
[ 1188.807015] vfio-pci 0000:00:06.0: resetting
[ 1189.019532] vfio-pci 0000:00:06.0: reset done
[ 1189.021072] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (tokio-rt-worker:10002)
[ 1189.022659] vfio-pci 0000:00:06.0: resetting
[ 1189.239526] vfio-pci 0000:00:06.0: reset done
[ 1190.529430] vfio-pci 0000:00:06.0: resetting
[ 1190.739546] vfio-pci 0000:00:06.0: reset done
[ 1190.741081] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (tokio-rt-worker:10025)
[ 1190.742671] vfio-pci 0000:00:06.0: resetting
[ 1190.959526] vfio-pci 0000:00:06.0: reset done
[ 1192.248932] vfio-pci 0000:00:06.0: resetting
[ 1192.459502] vfio-pci 0000:00:06.0: reset done
[ 1192.461048] vfio-pci 0000:00:06.0: vfio-noiommu device opened by user (tokio-rt-worker:10048)
[ 1192.462625] vfio-pci 0000:00:06.0: resetting
[ 1192.679474] vfio-pci 0000:00:06.0: reset done

@github-actions

Copy link
Copy Markdown

✅ Integration Tests Passed — Graviton (run)

Branch: 99/merge | Commit: 62b4aa78

Test Results

  • tier1-dpdk-echo.xml: 6 tests, 0 failures
  • tier2-kernel-interop.xml: 4 tests, 0 failures
  • tier3-iperf-sends.xml: 1 tests, 0 failures
  • tier3-our-app-sends.xml: 1 tests, 0 failures

Application Logs (last 20 lines)

receiver-echo-server.log

EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.167:9000 (MAC: 02:d3:3f:e1:78:c7)
echo listening on 10.0.1.167:9000 (MTU=9001, max_udp_payload=8973)
Shutting down gracefully...

sender-echo-server.log

EAL: Detected CPU lcores: 2
EAL: Detected NUMA nodes: 1
EAL: Detected shared linkage of DPDK
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
EAL: Using IOMMU type 8 (No-IOMMU)
EAL: Probe PCI driver: net_ena (1d0f:ec20) device: 0000:00:06.0 (socket -1)
TELEMETRY: No legacy callbacks, legacy socket not created
Warning: Some RX offloads not supported by device (flags: 0x1)
Warning: Some TX offloads not supported by device (flags: 0x1)
✅ DPDK UDP socket bound to 10.0.1.183:9000 (MAC: 02:25:f8:c5:e6:23)
echo listening on 10.0.1.183:9000 (MTU=9001, max_udp_payload=8973)
Shutting down gracefully...

sender-test-client.log

EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: VFIO support initialized
TELEMETRY: No legacy callbacks, legacy socket not created
DPDK bind failed (Port init failed: Invalid port ID: 0), falling back to tokio
Backend: tokio
Sending packets...
Sent 12 bytes: 'arp-probe #1'
Received 12 bytes from 10.0.1.167:9000: 'arp-probe #1'
Test complete
[2026-06-30T13:26:13Z] INFO: ARP resolution succeeded (got response from peer)
[2026-06-30T13:26:13Z] INFO: Test: udp_send_receive
[2026-06-30T13:26:14Z] INFO: UDP send/receive succeeded
[2026-06-30T13:26:14Z] INFO: Test: echo_roundtrip
[2026-06-30T13:26:15Z] INFO: Echo roundtrip succeeded: 5/5 responses received
[2026-06-30T13:26:15Z] INFO: Test: payload_integrity
[2026-06-30T13:26:15Z] INFO: Response received, checking payload match...
[2026-06-30T13:26:15Z] INFO: Payload integrity verified (found in response)
[2026-06-30T13:26:15Z] INFO: JUnit XML written to: /tmp/test-results/tier2-kernel-interop.xml
[2026-06-30T13:26:15Z] INFO: Tier 2 sender tests complete. Results: /tmp/test-results/tier2-kernel-interop.xml

@gspivey
gspivey merged commit ba6a13e into development Jul 1, 2026
7 checks passed
@gspivey
gspivey deleted the agent/tcp-dpdk-engine branch July 1, 2026 09:39
gspivey added a commit that referenced this pull request Jul 1, 2026
)

## Summary

Makes QUIC benchmarkable over a **real DPDK NIC** (not just in-process
loopback) and keeps the existing loopback bench intact.

**Stacked on #99** (for `DpdkBackend::new_real_nic`). GitHub will
retarget this PR to `development` when #99 merges. Merge #99 first.

### The bug this fixes
The QUIC provider built its backend via
`create_backend`/`DpdkBackend::new`, which init EAL with `--no-pci` — so
it **never probes the vfio-pci ENI** (a null device). Every
"native-dpdk" QUIC path (including the existing
`quic-echo-server`/`quic-test-client` integration tier) was therefore
running against a null device, and `ProviderConfig.eal_args` was dead
config that never reached EAL.

### Changes
- **`provider.rs`** — `start()` now builds the backend via
`DpdkBackend::new_real_nic(port_id, eal_args)` for `Dpdk`/`Auto` backend
types (real PCI probe; honors `eal_args`). `backend_override` (loopback
bench) still takes precedence, so `bench.rs` is unaffected. New
`ProviderBuilder::with_dpdk_port`.
- **`quic-echo-server`** — `--eal-args`/`--dpdk-port`, and a
`--throughput` mode that stream-echoes each chunk (for long-lived
sustained streams). Cert-PEM stdout protocol + `QUIC_SERVER_READY`
marker unchanged.
- **`quic-perf-client`** (new bin) — drives N bidi streams for a fixed
duration and prints one machine-parseable `PERF_RESULT gbps=.. bytes=..
hs_us=.. rx_bursts=.. tx_bursts=.. rx_drops=.. tx_drops=..` line.

### Validation (toolchain 1.91.0, warm cache)
- `cargo build --workspace` — clean
- `cargo test -p dpdk-stdlib-quic` — **63 passed / 0 failed** (45 lib
unit incl. new real-backend-path test; 1 perf-client `gbps` math;
loopback handshake/backend/ecn/gso/provider-init integration tests all
green → loopback bench unaffected)

### Notes / follow-ups
- v1 measures request/response goodput (one payload in flight per
stream), parallelised across `--streams`. Full pipelining + TX
batching/GSO are future work; the backend also allocs/copies one mbuf
per datagram, which bounds line rate.
- The 2-instance orchestration (`run-quic-perf.sh`) and the
`run-perf-tests.sh` `quic-*` tokens are intentionally in the **next** PR
(perf-runner wiring), to keep the shared script out of the parallel
feature PRs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gspivey added a commit that referenced this pull request Jul 1, 2026
…nfigs tokens (no YAML) (#101)

## Summary

Wires **QUIC IPv4**, **TCP IPv4**, and **UDP IPv6** performance tests
into the existing perf runner so they're dispatchable through
`perf-tests.yml` **with zero `.github/workflows` edits** — the workflow
is `workflow_dispatch` with a free-text `configs` input, so new
`--configs` tokens decoded inside `run-perf-tests.sh` are all that's
needed. This deliberately sidesteps the `workflow`-scope push blocker
(the same wall PR #97 is stuck behind).

All new tokens are **purely additive** — existing UDP behavior and the
default `CONFIGS` are unchanged.

## New `--configs` tokens

| Token | Suite | DUT | Benchmark |
|---|---|---|---|
| `rust-dpdk-tcp` | TCP v4 | `tcp-echo` (DPDK) | TRex ASTF |
| `tokio-dpdk-tcp` | TCP v4 | `tokio-tcp-echo` (DPDK) | TRex ASTF |
| `plain-rust-tcp` | TCP v4 | `plain-tcp-echo` (kernel) | TRex ASTF |
| `native-dpdk-v6` | UDP v6 | testpmd 5tswap | TRex STL (v6) |
| `rust-dpdk-v6` | UDP v6 | `echo` (DPDK) | TRex STL (v6) |
| `quic-stock` | QUIC | `quic-bench` loopback (stock) | in-process |
| `quic-native-dpdk` | QUIC | `quic-bench` loopback (native) |
in-process |
| `quic-native-dpdk-nic` | QUIC | `quic-echo-server`/`quic-perf-client`
| real-NIC, 2-instance |

## How it works

- **TCP**: `run_benchmark_for_config` branches on the `-tcp` suffix to
the ASTF (stateful) `run_tcp_benchmark.py`
(`--payload-sizes`/`--cps-rates`) instead of the STL/UDP
`run_benchmark.py`. New `start_dut_*_tcp` launchers reuse
`TREX_GATEWAY_MAC` for the DUT `--gateway-mac` (same VPC subnet → same
router MAC).
- **UDP IPv6**: any `-v6` token auto-enables `IP_VERSION=6` so the
existing Phase 2c assigns v6 addresses; `run_benchmark.py` already
auto-detects v6 from `--dst-ip`. `native-dpdk-v6` reuses testpmd
(IP-agnostic); `rust-dpdk-v6` runs `echo` with
`--gateway-mac`/`--peer-ip` NDP seed.
- **QUIC**: an early shim in `main()` short-circuits before any
PerfTestStack deploy (QUIC is app-to-app — TRex can't speak QUIC) and
delegates to `run-quic-benchmarks.sh` (loopback) / the new
**`scripts/run-quic-perf.sh`** (real-NIC, DpdkTestStack, cert transfer +
`PERF_RESULT` scrape).
- **Reporting**: v6 tokens added to the UDP tables; a new **TCP (ASTF)**
results table; `aggregate_results` made dict-safe for the list-shaped
TCP/QUIC `results`.

## Run it

```bash
gh workflow run perf-tests.yml --ref <branch> -f configs=tcp-native-dpdk     # ⇒ rust-dpdk-tcp etc.
gh workflow run perf-tests.yml --ref <branch> -f configs=rust-dpdk-tcp,tokio-dpdk-tcp,plain-rust-tcp
gh workflow run perf-tests.yml --ref <branch> -f configs=native-dpdk-v6,rust-dpdk-v6
gh workflow run perf-tests.yml --ref <branch> -f configs=quic-stock,quic-native-dpdk,quic-native-dpdk-nic
```

## Validation

- `bash -n` clean on `run-perf-tests.sh` + `run-quic-perf.sh`
- `python3 -m py_compile` clean on `run_benchmark.py` +
`run_tcp_benchmark.py`
- All embedded Python heredocs extracted and compiled OK
- (Real perf runs need AWS — validated by dispatch after merge.)

## Dependencies

Needs **#98** (IPv6/NDP), **#99** (TCP engine driver), **#100**
(real-NIC QUIC) merged for the DUT binaries/args these tokens invoke.
Scripts-only PR — no `.github/workflows` edit, no `workflow`-scope push
required.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant