virtio-bindings
Rust FFI bindings to the Linux kernel virtio uapi, generated with bindgen for building VMMs.
Repository Health
Technical Analysis
virtio-bindings is a Rust crate maintained by the rust-vmm project that provides raw FFI bindings to the Linux kernel’s virtio userspace API (virtio_blk, virtio_net, virtio_gpu, virtio_scsi, virtio_mmio, virtio_ring, virtio_config, virtio_ids, and virtio_input), generated with bindgen directly from kernel uapi headers.
It exists so that virtual machine monitors written in Rust — such as Firecracker, Cloud Hypervisor, and crosvm — don’t each have to hand-maintain their own copy of virtio constants and struct layouts. The bindings are pre-generated and checked into the crate for 16 CPU architectures, so consumers get a zero-dependency, build-time-free way to reference the exact same device IDs, feature flags, and descriptor layouts the kernel itself uses.
What You Get
- Pre-generated Rust FFI bindings for virtio_blk, virtio_net, virtio_gpu, virtio_scsi, virtio_mmio, virtio_ring, virtio_config, virtio_ids, and virtio_input, checked into the crate for 16 target architectures (x86, x86_64, arm, aarch64, riscv32/64, mips variants, powerpc64, s390x, sparc, loongarch64, m68k, hexagon).
- Automatic per-architecture selection via
#[cfg_attr(target_arch = ...)]path attributes inlib.rs, so the correct bindings are picked at compile time with no build script or bindgen dependency for downstream consumers. - A
bindingsmodule that re-exports every header module in one place (virtio_bindings::bindings::virtio_blk::*) for straightforward importing. - A small hand-written
virtio_nethelper module with unit tests covering the Linux 6.18hash_value_lo/hash_value_hifield split, for cases where raw bindgen output needs a thin ergonomic wrapper. - A
scripts/generate-bindings.shscript and documented workflow (see CONTRIBUTING.md) for regenerating all bindings against a new Linux kernel checkout with bindgen-cli 0.71.1.
Common Use Cases
- Implementing a virtio device backend (block, net, console, vsock, scsi) inside a Rust virtual machine monitor without hand-transcribing kernel struct layouts and constants.
- Building on top of rust-vmm sibling crates (virtio-queue, virtio-device, virtio-blk, virtio-vsock) that already depend on virtio-bindings for their FFI layer.
- Cross-compiling a VMM or virtio driver for a non-x86 target (aarch64, riscv64, s390x, etc.) and needing architecture-correct virtio struct layouts without regenerating bindings yourself.
- Writing tests or fuzz targets that need to construct raw virtio descriptor/queue structures matching exactly what the guest kernel expects.
Under The Hood
Architecture virtio-bindings is a workspace member of rust-vmm’s vm-virtio monorepo, scoped to a single job: exposing the Linux kernel’s virtio uapi headers as Rust types. lib.rs declares one pub mod per virtio header (virtio_blk, virtio_config, virtio_gpu, virtio_ids, virtio_input, virtio_mmio, virtio_net, virtio_ring, virtio_scsi), each annotated with a chain of #[cfg_attr(target_arch = "...", path = "bindings/<arch>/<header>.rs")] attributes so the compiler selects the pre-generated file matching the build’s target architecture — no build.rs, no bindgen invocation at consumer compile time. All modules are re-exported together under a single pub mod bindings for a stable, ergonomic import path. One hand-authored module, virtio_net/mod.rs, sits alongside the generated code to patch in small ergonomic fixes (the Linux 6.18 hash_value_lo/hash_value_hi split) with its own unit tests, showing the maintainers keep generated and hand-written code cleanly separated.
Tech Stack The published crate has an empty [dependencies] table in Cargo.toml — it is a pure data/constants crate at compile time with zero runtime dependencies. Generating (not consuming) the bindings requires bindgen-cli 0.71.1 and a local Linux kernel source checkout, invoked via scripts/generate-bindings.sh, which runs make headers_install against the kernel tree and then bindgen per architecture with --with-derive-default --with-derive-partialeq. The crate targets Rust 2021 edition and sits inside the broader vm-virtio Cargo workspace alongside virtio-queue, virtio-device, virtio-blk, virtio-console, and virtio-vsock. CI runs on Buildkite via the shared rust-vmm-ci submodule, with additional fuzzing and Kani formal-verification proof pipelines defined for the workspace as a whole.
Code Quality The overwhelming majority of the source tree (src/bindings/**, 16 architecture directories) is bindgen-generated boilerplate, so conventional code-quality review doesn’t meaningfully apply there — it is allow-listed at the crate root with #![allow(clippy::all, non_upper_case_globals, non_camel_case_types, clippy::undocumented_unsafe_blocks)], an explicit acknowledgment of the raw-FFI nature of the surface. The one hand-written module, virtio_net/mod.rs, carries three #[test] functions verifying the manual hash-value field split introduced for Linux 6.18. Naming throughout mirrors the C kernel headers verbatim, which is correct and expected for a bindings crate rather than a quality gap. There is no runtime error-handling logic to evaluate, since the crate defines types and constants only.
API Design Getting started is a two-line affair: add virtio-bindings = "0.2" to Cargo.toml and use virtio_bindings::bindings::virtio_blk::*; to pull in a header’s constants and structs — there is no configuration, initialization, or builder pattern to learn. The tradeoff is that the public API is entirely dictated by upstream Linux kernel header names rather than designed for Rust ergonomics, so familiarity with the virtio specification and kernel uapi conventions is assumed. Documentation is minimal — a single-paragraph README with one usage example and a CONTRIBUTING.md describing the regeneration workflow — with no rustdoc narrative beyond what bindgen itself emits, so the practical learning curve depends on virtio/kernel domain knowledge more than on crate-level documentation.