Skip to main content

Module virtq

Module virtq 

Source
Expand description

cbindgen:ignore Packed Virtqueue Implementation

This module provides a high-level API for virtio packed virtqueues, built on top of the lower-level ring primitives. It implements the VIRTIO 1.1+ packed ring format with proper memory ordering and event suppression support.

§Architecture

The implementation is split into layers:

  • High-level API ([VirtqProducer], [VirtqConsumer]): Manages buffer allocation, chain lifecycle, and notification decisions. This is the recommended API for most use cases.

  • Ring primitives ([RingProducer], [RingConsumer]): Low-level descriptor ring operations with explicit buffer chain management. Use this when you need full control over buffer layouts or custom allocation strategies.

  • Descriptor and event types ([Descriptor], [EventSuppression]): Raw virtio data structures for direct memory manipulation.

§Quick Start

§Single Readable/Writable Chain

// Producer (driver) side - build and submit a send chain
let mut chain = producer.chain()
    .readable(64)
    .writable(128)
    .build()?;
chain.write_all(b"request data")?;
let token = producer.submit(chain)?;
// ... wait for notification ...
if let Some(used) = producer.poll()? {
    match used {
        UsedChain::Data(_, segments) => process(segments),
        UsedChain::Ack(_) => {}
    }
}

// Consumer (device) side - receive a chain and reply/ack it
if let Some((chain, reply)) = consumer.poll(max_recv_len)? {
    let request = chain.to_bytes();
    match reply {
        ReplyChain::Writable(mut wc) => {
            let response = handle(request);
            wc.write_all(&response)?;
            consumer.complete(wc)?;
        }
        ReplyChain::Ack(ack) => {
            consumer.complete(ack)?;
        }
    }
}

// Multiple pending completions (no borrow on consumer)
let mut pending = Vec::new();
while let Some((chain, reply)) = consumer.poll(max_recv_len)? {
    pending.push((process(chain), reply));
}
for (result, reply) in pending {
    consumer.complete(reply)?;
}

§Multiple Chains

Each submit checks event suppression and notifies independently. Use [VirtqProducer::batch] when a higher-level protocol wants to publish multiple chains and kick the queue once.

let mut batch = producer.batch();
for data in entries {
    let mut chain = batch.chain()
        .readable(data.len())
        .writable(64)
        .build()?;
    chain.write_all(data)?;
    batch.submit(chain)?;
}
batch.finish()?;

§Completion Batching with Event Suppression

To receive a single notification when multiple requests complete:

// Submit chains
for data in entries {
    let mut chain = producer.chain()
        .readable(data.len())
        .writable(64)
        .build()?;
    chain.write_all(data)?;
    producer.submit(chain)?;
}

// Tell device: "notify me only after completing past this cursor"
let cursor = producer.used_cursor();
producer.set_used_suppression(SuppressionKind::Descriptor(cursor))?;

// Wait for single notification, then drain all responses
producer.drain(|used| {
    if let UsedChain::Data(token, data) = used {
        handle_response(token, data);
    }
})?;

§Event Suppression

Both sides can control when they want to be notified using [SuppressionKind]:

  • [SuppressionKind::Enable]: Always notify (default, lowest latency)
  • [SuppressionKind::Disable]: Never notify (polling mode, lowest overhead)
  • [SuppressionKind::Descriptor]: Notify at specific ring position (batching)

See [VirtqProducer::set_used_suppression] and [VirtqConsumer::set_avail_suppression].

§Low-Level API

For advanced use cases, the ring module exposes lower-level primitives:

  • [RingProducer] / [RingConsumer]: Direct ring access with [BufferChain] submission
  • [BufferChainBuilder]: Construct scatter-gather buffer lists
  • [RingCursor]: Track ring positions for event suppression

Example using low-level API:

let chain = BufferChainBuilder::new()
    .readable(header_addr, header_len)
    .readable(data_addr, data_len)
    .writable(response_addr, response_len)
    .build()?;

let result = ring_producer.submit_available_with_notify(&chain)?;
if result.notify {
    kick_device();
}

Modules§

msg
Wire format header for all virtqueue messages.

Structs§

AckChain
An ack-only reply for chains with no writable buffers.
Allocation
Allocation result
BufferChain
A chain of buffers ready for submission to the virtqueue.
BufferChainBuilder
A builder for buffer chains using type-state to enforce readable/writable order.
BufferElement
A single buffer element in a scatter-gather list.
BufferOwner
The owner of a mapped buffer, ensuring its lifetime.
BufferPool
Two tier buffer pool with small and large slabs.
ChainBuilder
Builder for configuring a descriptor chain’s buffer layout.
DescFlags
Descriptor flags as defined by VIRTIO specification.
DescTable
A table of descriptors stored in shared memory.
Descriptor
EventFlags
EventSuppression
Event suppression structure for controlling notifications.
Layout
Layout of a packed virtqueue ring in shared memory.
OwnedAlloc
Pool-owned allocation that is returned to the pool on drop.
QueueStats
Statistics about the current virtqueue state.
Readable
Type-state: Can add readable buffers
RecvChain
Payload received from the producer, safely copied out of shared memory.
RecyclePool
A recycling buffer provider with fixed-size slots.
RingConsumer
Consumer (device) side of a packed virtqueue.
RingCursor
Tracks position in a ring buffer with wrap-around handling.
RingProducer
Producer (driver) side of a packed virtqueue.
Segments
Ordered byte segments that make up one virtqueue payload.
SegmentsBuf
Borrowed Buf cursor over Segments.
SendChain
A configured send chain ready for writing and submission.
SubmitBatch
A scoped batch of producer submissions.
SubmitResult
Result of submitting a buffer to the ring.
Token
A token representing a sent chain in the virtqueue.
UsedBuffer
A buffer returned from the ring after being used by the device.
VirtqConsumer
A high-level virtqueue consumer (device side).
VirtqProducer
A high-level virtqueue producer (driver side).
Writable
Type-state: Can add writable buffers (no more readables allowed)
WritableChain
A reply chain with writable buffer capacity.

Enums§

AllocError
MemOp
Memory operation that failed in the backend.
ReplyChain
Consumer-side chain reply, either writable or ack-only.
RingError
SuppressionKind
Event suppression mode for controlling when notifications are sent.
UsedChain
A used chain observed by the driver (producer) side.
VirtqError
Errors that can occur in the virtqueue operations.

Traits§

BufferProvider
Trait for buffer providers.
MemOps
Backend-provided memory access for virtqueue.
Notifier
A trait for notifying the consumer about virtqueue events.