BPF Trace - Advanced Debugging
Qtap Version: v0.11.3+ Status: Advanced feature for syscall-level debugging
Overview
The --bpf-trace flag enables syscall-level tracing of network operations, providing deep visibility into how applications interact with the Linux kernel. This is an advanced debugging feature that shows:
Individual syscall invocations (read, write, writev, recvfrom, accept4)
File descriptor (FD) numbers for each operation
Data transfer sizes
TLS/SSL detection per-syscall
Process IDs and executable paths
Use cases:
Debugging complex proxy scenarios (e.g., HTTP→HTTPS reverse proxies)
Understanding per-FD TLS state tracking issues
Investigating missing or corrupted traffic captures
Analyzing syscall-level data flow through applications
Syntax
Parameters
mod:<module>
BPF trace module to enable
mod:socket
exe.contains:<name>
Filter traces to executables containing this string
exe.contains:nginx
Available modules:
socket- Socket lifecycle and syscall tracing ✅ WORKSopenssl- OpenSSL library event tracking ✅ WORKS
Note: Use exe.contains (not bin.contains) for syscall filtering.
Basic Example
Configuration
Expected Output
Understanding the Output
Syscall Types
accept4
Accept incoming connection
Server accepting new client
recvfrom
Receive data from socket
Reading HTTP request
read
Read data from FD
Reading from SSL/TLS socket
write
Write data to FD
Writing to SSL/TLS socket
writev
Vectored write (scatter-gather)
Writing HTTP response with headers+body
Event Phases
Each syscall typically generates two events:
(init)event - Syscall entry (before execution)Completion event - Syscall exit (after execution, with actual byte counts)
Field Reference
process_data Messages
process_data MessagesThese appear after syscall completion and show Qtap's data processing decisions:
process_data (pre-protocol)- Data received before protocol detectionprocess_data (not ssl)- Data on plaintext socket (HTTP)process_data (conn_info = NULL)- Socket not tracked (e.g., log files)process_data (conn_info->is_open = false)- Connection already closed
Real-World Example: Nginx HTTP→HTTPS Reverse Proxy
Scenario
Nginx reverse proxy configuration:
Client → Nginx: HTTP on port 8000
Nginx → Backend: HTTPS to api.treatmyocd.com
Traffic Flow Visualization
Step-by-Step Syscall Trace
1. Accept Client Connection
Nginx accepts incoming HTTP connection from curl on fd 3.
2. Read HTTP Request from Client
Nginx reads 81 bytes of HTTP request from fd 3 (client socket).
3. Write HTTPS Request to Backend
Nginx writes 1806 bytes to fd 11 (backend HTTPS connection).
4. Read HTTPS Response from Backend
Nginx reads multiple chunks from fd 11 (backend response).
5. Write HTTP Response to Client
Nginx writes 941 bytes back to fd 3 (client) using writev.
Critical: This is where the nginx HTTP→HTTPS bug would manifest. If Qtap incorrectly marks the entire process as "has SSL" after seeing fd 11's TLS traffic, it might discard this writev data expecting SSL_write instead.
6. Write Access Log
Nginx writes 89 bytes to fd 4 (access log file). Qtap shows conn_info = NULL because fd 4 is not a network socket.
Filtering Options
Filter by Executable Name
How exe.contains works:
Matches substring anywhere in the executable path
Example:
exe.contains:nginxmatches both/usr/sbin/nginxand/custom/path/nginx-debug
No Filter (All Processes)
Warning: Tracing all processes generates massive log output and may impact system performance. Always use exe.contains filters in production.
Log Level Requirements
BPF trace output varies by log level:
warn
No syscall traces (silent)
info
Full syscall traces ✅ RECOMMENDED
debug
Full syscall traces + additional debug logs
Recommended configuration:
Debugging Use Cases
1. Missing Response Data
Symptom: Qtap captures request but shows 0 bytes received in response.
Diagnosis with BPF trace:
Look for:
writevorwritesyscalls that should contain response dataCheck
"ssl": falsevs expected TLS state per-FDLook for
process_datamessages showing why data was discarded
2. Per-FD TLS State Issues
Symptom: Mixed HTTP/HTTPS connections in same process cause capture failures.
Diagnosis:
Compare syscall traces for different file descriptors:
Check if
"ssl": true/falseis accurate per-FDLook for
process_data (not ssl)when SSL is expected (or vice versa)
Example buggy behavior:
3. Understanding Data Flow
Trace complete request lifecycle:
Group by file descriptor to see data flow:
Common Patterns
HTTP Server (Single FD)
HTTPS Client (Single FD with SSL)
Reverse Proxy (Two FDs - HTTP + HTTPS)
Troubleshooting
No "eBPF trace" Output
Check 1: Log level
Check 2: Filter matches
Check 3: Traffic generated
Check 4: Correct filter syntax
Too Much Output
Problem: Tracing all processes floods logs.
Solution: Add executable filter:
Syscall Not Appearing
Some syscalls may not appear if:
Different syscall variant used - e.g.,
readvinstead ofreadBuffered I/O - Application uses buffering, syscalls occur later
Connection pooling - FD reused, syscalls mixed with other requests
Performance Considerations
BPF trace adds overhead to every syscall:
< 10 req/sec
Negligible
Safe for production debugging
10-100 req/sec
Low (~5%)
Use with caution, monitor CPU
> 100 req/sec
Moderate (10-20%)
Only use in isolated environments
Best practices:
Use
exe.containsfilters to limit scopeEnable only during active debugging sessions
Monitor disk I/O (logs can grow rapidly)
Use log rotation if enabled long-term
Comparison: Regular Logs vs BPF Trace
Regular Qtap Logs (--log-level=info)
Pros: Human-readable, concise, shows final results Cons: No syscall details, can't debug per-FD issues
BPF Trace (--bpf-trace="mod:socket,exe.contains:nginx")
Pros: Syscall-level detail, per-FD visibility, shows TLS state decisions Cons: Verbose, requires interpretation, not user-friendly
When to use BPF trace:
Debugging complex proxy scenarios
Investigating missing captures
Understanding per-FD TLS state tracking
Analyzing syscall-level data flow
When to use regular logs:
Normal operation
User-facing traffic analysis
Compliance/audit logging
Related Configuration
BPF trace works alongside standard Qtap configuration:
Run with:
Known Limitations
No SSL_write/SSL_read visibility BPF trace shows syscalls (read/write) but not OpenSSL library calls (SSL_read/SSL_write).
Per-process TLS state The
"ssl": true/falsefield may reflect process-level state rather than per-FD state in some qtap versions.Filter syntax constraints
Must use
exe.contains(notbin.contains)Only substring matching (no regex)
Log volume Without filters, trace output can be 100x larger than regular logs.
Summary
Flag
--bpf-trace="mod:socket,exe.contains:nginx"
Log Level
info or debug
Output
Syscall-level traces (read, write, writev, accept4, recvfrom)
Filtering
By executable name substring
Use Cases
Debugging proxies, per-FD TLS issues, missing captures
Performance
Low overhead with filters, high without
Last updated