Bundle vmlinux.h files to eliminate network dependency during builds (#41)

* feat: bundle vmlinux.h files to eliminate network dependency during builds

- Add bundled vmlinux.h for x86, aarch64, and arm (~3MB total)
- Remove network download code from build.rs
- Remove ureq dependency and transitive deps
- Update Dockerfile to copy bundled headers
- Remove obsolete vmlinux_min.h
- Update documentation to reflect bundled approach

Fixes #38
This commit is contained in:
Marco Cadetg
2025-10-09 12:07:40 +02:00
committed by GitHub
parent 24efc498f5
commit 0d02b99b79
10 changed files with 150225 additions and 1176 deletions
Generated
+390 -665
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -75,7 +75,6 @@ windows = { version = "0.59", features = [
[target.'cfg(target_os = "linux")'.build-dependencies]
libbpf-cargo = "0.25"
ureq = { version = "2.10", default-features = false, features = ["tls"] }
[features]
default = []
+3
View File
@@ -24,6 +24,9 @@ COPY Cargo.toml Cargo.lock ./
# Copy build script for eBPF compilation
COPY build.rs ./
# Copy bundled eBPF vmlinux headers (required for eBPF compilation)
COPY resources/ebpf/vmlinux ./resources/ebpf/vmlinux
# Copy source code
COPY src ./src
COPY assets/services ./assets/services
+101 -200
View File
@@ -4,29 +4,94 @@ This document explains how to work with eBPF kernel headers in this project.
## Current Setup
We use a **minimal vmlinux header** (`vmlinux_min.h`) instead of the full kernel headers. This approach has trade-offs that should be considered:
The project bundles **architecture-specific vmlinux.h files** from the [libbpf/vmlinux.h](https://github.com/libbpf/vmlinux.h) repository. This eliminates network dependencies during builds and ensures reproducible builds.
**Benefits of minimal vmlinux_min.h:**
### Bundled vmlinux.h Files
- **Small size**: 5.5KB (203 lines) vs 3.4MB (100K+ lines) full vmlinux.h
- **Git-friendly**: Small file size, manageable diffs, easier to review
- **Portable**: Works across kernel versions with CO-RE/BTF
- **Clear dependencies**: Shows exactly which kernel structures we depend on
Pre-downloaded vmlinux.h files (based on Linux kernel 6.14) are included in the repository at:
- `resources/ebpf/vmlinux/x86/vmlinux.h` (for x86_64, ~1.1MB)
- `resources/ebpf/vmlinux/aarch64/vmlinux.h` (for aarch64, ~1.0MB)
- `resources/ebpf/vmlinux/arm/vmlinux.h` (for armv7, ~981KB)
**Drawbacks of minimal vmlinux_min.h:**
These files are automatically used during the build process based on the target architecture. **No network access is required** during compilation.
- **Manual maintenance**: Need to update when adding new eBPF features that access different kernel structures
- **Potential for missing definitions**: Easy to forget required types when extending functionality
- **Development overhead**: Requires understanding of kernel internals to extract correct definitions
**Benefits:**
- **Zero network dependency**: Works in restricted build environments (COPR, Fedora build systems, etc.)
- **Reproducible builds**: Same headers every time, no external dependencies
- **Complete kernel definitions**: All kernel structures available, no missing types
- **No manual maintenance**: Auto-generated from kernel BTF
- **Cross-kernel compatibility**: CO-RE/BTF ensures portability across kernel versions
**Alternative approach (full vmlinux.h):**
**Trade-offs:**
- Repository size: ~3MB total for all architectures (acceptable for modern git)
- Not immediately clear which kernel structures are actually used by the code
- **Pros**: Complete kernel definitions, auto-generated, no manual maintenance, never missing types
- **Cons**: Very large file (3.4MB), but can be gitignored and generated during build process
## Updating Bundled vmlinux.h Files
## How to Generate Full vmlinux.h (if needed)
The bundled vmlinux.h files are based on kernel 6.14 from the libbpf repository. To update them to a newer kernel version:
If you need to generate a complete vmlinux.h file for your kernel:
```bash
# Update all architectures at once
for arch in x86 aarch64 arm; do
# Get the symlink target (e.g., vmlinux_6.14.h)
target=$(curl -sL "https://raw.githubusercontent.com/libbpf/vmlinux.h/main/include/${arch}/vmlinux.h")
# Download the actual file
curl -sL "https://raw.githubusercontent.com/libbpf/vmlinux.h/main/include/${arch}/${target}" \
-o "resources/ebpf/vmlinux/${arch}/vmlinux.h"
echo "Updated ${arch} to ${target}"
done
```
Or update a single architecture:
```bash
# Example: Update x86 only
arch="x86"
target=$(curl -sL "https://raw.githubusercontent.com/libbpf/vmlinux.h/main/include/${arch}/vmlinux.h")
curl -sL "https://raw.githubusercontent.com/libbpf/vmlinux.h/main/include/${arch}/${target}" \
-o "resources/ebpf/vmlinux/${arch}/vmlinux.h"
```
After updating, commit the changes to the repository.
## Building with eBPF Support
To build rustnet with eBPF support on Linux:
```bash
# Install build dependencies
sudo apt-get install libelf-dev clang llvm # Debian/Ubuntu
sudo yum install elfutils-libelf-devel clang llvm # RedHat/CentOS/Fedora
# Build with eBPF feature
cargo build --release --features ebpf
# The bundled vmlinux.h files will be used automatically
# No network access required!
```
## Testing eBPF Functionality
After building with eBPF support, test that it works correctly:
```bash
# Option 1: Run with sudo (always works)
sudo cargo run --features ebpf
# Option 2: Set capabilities (Linux only, see README.md Permissions section)
sudo setcap 'cap_net_raw,cap_net_admin,cap_sys_admin,cap_bpf,cap_perfmon+eip' ./target/release/rustnet
./target/release/rustnet
# Check the TUI Statistics panel to verify it shows "Process Detection: eBPF + procfs"
```
**Note**: eBPF kprobe programs require specific Linux capabilities. See the main [README.md Permissions section](README.md#permissions) for detailed capability requirements. The required capabilities may vary by kernel version.
## Generating vmlinux.h from Your Local Kernel (Optional)
If you need to generate a vmlinux.h file for your specific kernel (e.g., for debugging or custom kernel builds):
```bash
# Method 1: Using bpftool (requires root/CAP_BPF)
@@ -43,198 +108,34 @@ make scripts_gdb
bpftool btf dump file vmlinux format c > vmlinux.h
```
## How to Create Minimal Headers from Full vmlinux.h
### 1. Identify Required Structures
First, analyze your eBPF program to find which kernel structures you access:
```bash
# Find all struct references in your eBPF code
grep -E "struct [a-zA-Z_]+" socket_tracker.bpf.c
# Find BPF_CORE_READ usage to see field accesses
grep -E "BPF_CORE_READ.*\\..*" socket_tracker.bpf.c
# Common structures for socket tracking:
# - struct sock (contains __sk_common)
# - struct sock_common (network fields)
# - struct msghdr (for sendmsg calls)
# - struct sockaddr_in (IPv4 addresses)
# - struct pt_regs (kprobe context)
```
### 2. Extract Definitions from Full vmlinux.h
Use these commands to extract specific structures:
```bash
# Extract a specific struct (e.g., sock_common)
awk '/^struct sock_common {/,/^}/' vmlinux.h
# Extract type definitions
grep "typedef.*__u[0-9]*\|typedef.*__be[0-9]*" vmlinux.h
# Extract multiple related structures
grep -A 50 "struct sock_common {" vmlinux.h
grep -A 20 "struct sock {" vmlinux.h
grep -A 10 "struct msghdr {" vmlinux.h
```
### 3. Create Minimal Header
Create a new header file with:
1. **Header guards and CO-RE pragma**:
```c
#ifndef __VMLINUX_MIN_H__
#define __VMLINUX_MIN_H__
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)
#endif
```
2. **Basic types** (only what you need):
```c
typedef unsigned char __u8;
typedef unsigned int __u32;
typedef __u32 __be32;
// etc.
```
3. **Required structures** with **only the fields you access**:
```c
struct sock_common {
// Only include fields accessed by BPF_CORE_READ
__be32 skc_daddr;
__be32 skc_rcv_saddr;
__be16 skc_dport;
__u16 skc_num;
// ... other fields you actually use
};
```
4. **Footer**:
```c
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute pop
#endif
#endif
```
### 4. Automated Extraction Script
For complex projects, you can create a script to automate extraction:
```bash
#!/bin/bash
# extract_minimal_vmlinux.sh
FULL_VMLINUX="vmlinux.h"
OUTPUT="vmlinux_min.h"
BPF_SOURCE="socket_tracker.bpf.c"
# Find structs used in BPF program
STRUCTS=$(grep -oE "struct [a-zA-Z_]+" "$BPF_SOURCE" | sort -u | cut -d' ' -f2)
echo "Extracting structures: $STRUCTS"
# Start minimal header
cat > "$OUTPUT" << 'EOF'
#ifndef __VMLINUX_MIN_H__
#define __VMLINUX_MIN_H__
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)
#endif
/* Basic types */
EOF
# Extract basic types
grep "typedef.*__u[0-9]*\|typedef.*__be[0-9]*\|typedef.*__kernel" "$FULL_VMLINUX" | head -20 >> "$OUTPUT"
echo "" >> "$OUTPUT"
echo "/* Network structures */" >> "$OUTPUT"
# Extract each required struct
for struct in $STRUCTS; do
echo "Extracting struct $struct..."
awk "/^struct $struct \{/,/^}/" "$FULL_VMLINUX" >> "$OUTPUT"
echo "" >> "$OUTPUT"
done
# Close header
cat >> "$OUTPUT" << 'EOF'
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute pop
#endif
#endif /* __VMLINUX_MIN_H__ */
EOF
echo "Minimal vmlinux header created: $OUTPUT"
```
## Testing Your Minimal Header
After creating your minimal header:
```bash
# Test compilation
cargo build --features ebpf
# If compilation fails, check for missing definitions
# and add them to your minimal header
# Verify eBPF program loads
# Option 1: Run with sudo (always works)
sudo cargo run --features ebpf
# Option 2: Set capabilities (Linux only, see README.md Permissions section)
sudo setcap 'cap_net_raw,cap_net_admin,cap_sys_admin,cap_bpf,cap_perfmon+eip' ./target/debug/rustnet
cargo run --features ebpf
# Check the TUI Statistics panel to verify it shows "Process Detection: eBPF + procfs"
```
**Note**: eBPF kprobe programs require specific Linux capabilities. See the main [README.md Permissions section](README.md#permissions) for detailed capability requirements. The required capabilities may vary by kernel version.
## Best Practices
1. **Start minimal**: Only include structures and fields you actually access
2. **Use CO-RE**: Always include the preserve_access_index pragma for portability
3. **Document sources**: Note which kernel version/source your definitions came from
4. **Test across kernels**: Verify your program works on different kernel versions
5. **Keep synchronized**: Update minimal headers when your eBPF program changes
This is typically not needed since the bundled headers work across kernel versions thanks to CO-RE/BTF.
## Troubleshooting
### Compilation Errors
- **Missing struct definition**: Add the struct to your minimal header
- **Missing field**: Include the specific field in your struct definition
- **Type errors**: Ensure all referenced types are defined
**"Bundled vmlinux.h not found"**:
- Ensure the `resources/ebpf/vmlinux/` directory exists
- Verify you've cloned the full repository (not a partial checkout)
- Check that the vmlinux.h file exists for your target architecture
**Missing build dependencies**:
- Install clang, llvm, and libelf-dev
- Ensure rustfmt is installed: `rustup component add rustfmt`
### Runtime Errors
- **BTF verification failed**: Check that field names match kernel structures
- **Access violations**: Ensure you're accessing fields that exist in target kernel
**"BTF verification failed"**:
- Your kernel may not have BTF support enabled
- Linux kernel 4.19+ with BTF support is recommended
- Check if BTF is available: `ls /sys/kernel/btf/vmlinux`
### Field Access Issues
**"Permission denied" when loading eBPF**:
- See the [README.md Permissions section](README.md#permissions) for capability setup
- Required capabilities: `CAP_NET_RAW`, `CAP_NET_ADMIN`, `CAP_BPF`, `CAP_PERFMON`
- Some kernels may also require `CAP_SYS_ADMIN`
- **Wrong offset**: Make sure struct layout matches target kernel
- **Missing CO-RE relocations**: Verify preserve_access_index pragma is present
## Why Not Use Full vmlinux.h?
While using the full vmlinux.h works, it has downsides:
- **Huge file size** (3+ MB): Slows down compilation and git operations
- **Unclear dependencies**: Hard to see what your program actually needs
- **Kernel-specific**: Generated for one specific kernel version
- **Review complexity**: Impossible to review 100K+ lines in PRs
The minimal approach gives you the benefits of vmlinux.h (CO-RE support, exact field layouts) without the downsides.
**eBPF fails to load, falls back to procfs**:
- This is expected behavior when eBPF can't load
- Check the TUI Statistics panel to see which detection method is active
- Common reasons: insufficient capabilities, incompatible kernel, BTF not available
-2
View File
@@ -24,13 +24,11 @@ The experimental eBPF support provides efficient process identification but has
### Current Limitations
- **Process Names Limited to 16 Characters**: Uses kernel `comm` field, causing truncation (e.g., "Firefox" → "Socket Thread")
- **Thread Names vs Process Names**: Shows thread command names instead of full executable names
- **Minimal vmlinux.h Maintenance**: Current approach requires manual updates when adding new kernel structure access
### Planned Improvements
- **Hybrid eBPF + Procfs Approach**: Use eBPF for connection tracking, selectively lookup full process names via procfs for better accuracy
- **Full Executable Path Resolution**: Investigate accessing full process executable path from eBPF programs
- **Better Process-Thread Mapping**: Improve mapping from thread IDs to parent process information
- **vmlinux.h Strategy**: Consider switching to full auto-generated vmlinux.h for easier maintenance vs current minimal approach
- **Enhanced BTF Support**: Better compatibility across different kernel versions and distributions
- **Performance Optimizations**: Reduce eBPF map lookups and improve connection-to-process matching efficiency
+18 -65
View File
@@ -18,6 +18,7 @@ fn main() -> Result<()> {
println!("cargo:rerun-if-changed=src/network/platform/linux_ebpf/programs/");
println!("cargo:rerun-if-changed=src/cli.rs");
println!("cargo:rerun-if-changed=resources/ebpf/vmlinux/");
Ok(())
}
@@ -149,70 +150,22 @@ fn download_windows_npcap_sdk() -> Result<()> {
}
#[cfg(all(target_os = "linux", feature = "ebpf"))]
fn download_vmlinux_header(arch: &str) -> Result<PathBuf> {
use std::fs;
use std::io::{Read, Write};
fn get_vmlinux_header(arch: &str) -> Result<PathBuf> {
// Use bundled vmlinux.h from resources directory
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
let bundled_dir = manifest_dir.join("resources/ebpf/vmlinux").join(arch);
let bundled_file = bundled_dir.join("vmlinux.h");
// Cache directory in OUT_DIR
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
let cache_dir = out_dir.join("vmlinux_headers").join(arch);
let vmlinux_file = cache_dir.join("vmlinux.h");
// Return cached version if it exists
if vmlinux_file.exists() {
println!("cargo:warning=Using cached vmlinux.h for {}", arch);
return Ok(cache_dir);
if bundled_file.exists() {
println!("cargo:warning=Using bundled vmlinux.h for {}", arch);
Ok(bundled_dir)
} else {
Err(anyhow::anyhow!(
"Bundled vmlinux.h not found for architecture '{}'. Expected at: {}",
arch,
bundled_file.display()
))
}
// Download from libbpf/vmlinux.h repository
// Note: vmlinux.h is a symlink, so we first download it to get the target filename
let symlink_url = format!(
"https://raw.githubusercontent.com/libbpf/vmlinux.h/main/include/{}/vmlinux.h",
arch
);
println!("cargo:warning=Downloading vmlinux.h for {} from {}", arch, symlink_url);
// Create cache directory
fs::create_dir_all(&cache_dir)?;
// Download the symlink to get the actual filename
let response = ureq::get(&symlink_url)
.call()
.map_err(|e| anyhow::anyhow!("Failed to download vmlinux.h symlink: {}", e))?;
let mut symlink_content = String::new();
response.into_reader()
.read_to_string(&mut symlink_content)
.map_err(|e| anyhow::anyhow!("Failed to read symlink: {}", e))?;
// The symlink content is just the target filename, e.g. "vmlinux_6.14.h"
let target_filename = symlink_content.trim();
// Download the actual vmlinux header file
let actual_url = format!(
"https://raw.githubusercontent.com/libbpf/vmlinux.h/main/include/{}/{}",
arch, target_filename
);
println!("cargo:warning=Following symlink to {}", target_filename);
let response = ureq::get(&actual_url)
.call()
.map_err(|e| anyhow::anyhow!("Failed to download {}: {}", target_filename, e))?;
let mut content = Vec::new();
response.into_reader()
.read_to_end(&mut content)
.map_err(|e| anyhow::anyhow!("Failed to read response: {}", e))?;
// Write to cache
let mut file = fs::File::create(&vmlinux_file)?;
file.write_all(&content)?;
println!("cargo:warning=Downloaded and cached vmlinux.h for {}", arch);
Ok(cache_dir)
}
#[cfg(all(target_os = "linux", feature = "ebpf"))]
@@ -240,9 +193,9 @@ fn compile_ebpf_programs() {
_ => ("-D__TARGET_ARCH_x86", "x86"), // fallback
};
// Download architecture-specific vmlinux.h if not cached
let vmlinux_include_path = download_vmlinux_header(vmlinux_arch)
.expect("Failed to download vmlinux.h");
// Get bundled architecture-specific vmlinux.h
let vmlinux_include_path = get_vmlinux_header(vmlinux_arch)
.expect("Failed to locate bundled vmlinux.h");
SkeletonBuilder::new()
.source(src)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,243 +0,0 @@
#ifndef __VMLINUX_MIN_H__
#define __VMLINUX_MIN_H__
/*
* Minimal vmlinux.h with only the kernel structures needed for our eBPF socket tracker.
* This replaces the full vmlinux.h (3.4MB) with just the essential definitions.
*
* Generated for Linux kernel structures used in socket tracking.
* See EBPF_BUILD.md for instructions on how to regenerate or customize.
*/
/* Define this to trigger kernel field names in bpf_tracing.h */
#define __VMLINUX_H__
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)
#endif
/* Basic kernel types */
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned int __u32;
typedef unsigned long long __u64;
typedef signed char __s8;
typedef signed short __s16;
typedef signed int __s32;
typedef signed long long __s64;
typedef __u16 __be16;
typedef __u32 __be32;
typedef __u64 __be64;
typedef __u32 __wsum;
typedef __u16 __kernel_sa_family_t;
typedef _Bool bool;
/* Additional type definitions needed for kernel structures */
typedef __u64 __addrpair;
typedef __u32 __portpair;
typedef struct { __s64 counter; } atomic64_t;
typedef struct { __s32 counter; } atomic_t;
/* BPF map types and flags */
enum {
BPF_MAP_TYPE_HASH = 1,
};
enum {
BPF_ANY = 0,
};
/* Network address structures */
struct in_addr {
__be32 s_addr;
};
struct in6_addr {
union {
__u8 u6_addr8[16];
__be16 u6_addr16[8];
__be32 u6_addr32[4];
} in6_u;
};
/* Socket address structures */
struct sockaddr_in {
__kernel_sa_family_t sin_family;
__be16 sin_port;
struct in_addr sin_addr;
unsigned char __pad[8];
};
/* Forward declarations for complex types we don't need to fully define */
struct proto;
struct sk_buff_head;
/* Simple structures we need defined */
struct hlist_node {
struct hlist_node *next, **pprev;
};
struct iov_iter {
/* We don't access fields, just need size/layout for msghdr */
void *__opaque[8]; /* Approximate size, CO-RE will handle differences */
};
/* Minimal possible_net_t - we don't access its internals */
typedef struct {
void *net; /* We don't dereference this, just need the field present */
} possible_net_t;
/* Socket common structure - core networking fields */
struct sock_common {
/* Address pair for IPv4 */
union {
__addrpair skc_addrpair; /* We don't use this directly */
struct {
__be32 skc_daddr; /* destination IPv4 address */
__be32 skc_rcv_saddr; /* source IPv4 address */
};
};
/* Hash - we don't use this but it's part of the layout */
union {
unsigned int skc_hash;
__u16 skc_u16hashes[2];
};
/* Port pair */
union {
__portpair skc_portpair; /* We don't use this directly */
struct {
__be16 skc_dport; /* destination port */
__u16 skc_num; /* source port */
};
};
/* Basic socket properties */
short unsigned int skc_family;
volatile unsigned char skc_state;
unsigned char skc_reuse: 4;
unsigned char skc_reuseport: 1;
unsigned char skc_ipv6only: 1;
unsigned char skc_net_refcnt: 1;
int skc_bound_dev_if;
/* Hash table linkage - we don't use these but they're part of layout */
union {
struct hlist_node skc_bind_node;
struct hlist_node skc_portaddr_node;
};
/* Protocol and network namespace */
struct proto *skc_prot;
possible_net_t skc_net;
/* IPv6 addresses - these come after the above fields */
struct in6_addr skc_v6_daddr;
struct in6_addr skc_v6_rcv_saddr;
/* Socket cookie for identification */
atomic64_t skc_cookie;
/* Additional fields exist but we don't need them for CO-RE access */
};
/* Main socket structure - we only need the common part */
struct sock {
struct sock_common __sk_common;
/*
* Many more fields exist here, but we only access __sk_common
* CO-RE will handle the field relocations regardless of what
* other fields are present in different kernel versions
*/
};
/* Message header for sendmsg syscalls */
struct msghdr {
void *msg_name; /* Socket name (sockaddr_in* for UDP) */
int msg_namelen; /* Length of socket name */
int msg_inq; /* Bytes in receive queue */
struct iov_iter msg_iter; /* Data payload iterator */
/* Control messages - we don't use these but they're part of layout */
union {
void *msg_control;
void *msg_control_user;
};
bool msg_control_is_user: 1;
bool msg_get_inq: 1;
/* Additional fields may exist but we only need msg_name */
};
/* FRED (Flexible Return and Event Delivery) support structures */
struct fred_cs {
__u64 cs: 16;
__u64 sl: 2;
__u64 wfe: 1;
};
struct fred_ss {
__u64 ss: 16;
__u64 sti: 1;
__u64 swevent: 1;
__u64 nmi: 1;
int: 13;
__u64 vector: 8;
short: 8;
__u64 type: 4;
char: 4;
__u64 enclave: 1;
};
/*
* Architecture-specific pt_regs for kprobe context
* x86_64 specific - for PT_REGS_PARM1/PT_REGS_PARM2 macros
* Field names must match kernel exactly for CO-RE relocations
*/
struct pt_regs {
/*
* C ABI says these regs are callee-preserved. They aren't saved on kernel entry
* unless syscall needs a complete, fully filled "struct pt_regs".
*/
long unsigned int r15;
long unsigned int r14;
long unsigned int r13;
long unsigned int r12;
long unsigned int bp; /* Must match kernel BTF field names */
long unsigned int bx; /* Must match kernel BTF field names */
/* These regs are callee-clobbered. Always saved on kernel entry. */
long unsigned int r11;
long unsigned int r10;
long unsigned int r9;
long unsigned int r8;
long unsigned int ax; /* Must match kernel BTF field names */
long unsigned int cx; /* Must match kernel BTF field names */
long unsigned int dx; /* Must match kernel BTF field names */
long unsigned int si; /* Must match kernel BTF field names */
long unsigned int di; /* Must match kernel BTF field names */
/*
* On syscall entry, this is syscall#. On CPU exception, this is error code.
* On hw interrupt, it's IRQ number:
*/
long unsigned int orig_ax;
/* Return frame for iretq */
long unsigned int ip; /* Must match kernel BTF field names */
union {
__u16 cs;
__u64 csx;
struct fred_cs fred_cs;
};
long unsigned int flags; /* Must match kernel BTF field names */
long unsigned int sp; /* Must match kernel BTF field names */
union {
__u16 ss;
__u64 ssx;
struct fred_ss fred_ss;
};
};
#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute pop
#endif
#endif /* __VMLINUX_MIN_H__ */