virtio is a standardized I/O virtualization specification for virtual machines. Instead of emulating the registers and interrupts of a real hardware device (slow, complex), virtio defines a shared-memory ring-buffer protocol that both the guest driver and the hypervisor implement directly.
Because both sides know they are in a virtual environment, the protocol skips the overhead of pretending to be real hardware. This is called paravirtualization — the guest is aware it’s virtualized and cooperates with the hypervisor for better performance.
Why ring buffers?
The fundamental performance problem in virtualization is the VM exit: every time the guest needs to talk to the hypervisor (to send a packet, read a disk block, etc.), the CPU must switch from guest mode to host mode. This context switch costs thousands of CPU cycles — far more than the work itself.
A naïve design would do one VM exit per packet:
guest sends packet → VM exit → hypervisor copies packet → VM entry → repeat
Virtio’s ring buffer avoids this. Guest and hypervisor share a region of physical memory. The guest writes packet descriptors (a pointer and a length — not the packet itself) into a circular ring in that shared memory, then sends a single notification to the hypervisor. The hypervisor drains the whole ring in one go:
guest fills ring with N descriptors → one notification → hypervisor processes N packets at once
Two benefits:
- Batching: one VM exit amortised across many packets
- Zero-copy: the packet data sits in memory that both sides can see; no copying through the hypervisor
Each virtio device has at least two rings: one for guest→host traffic (TX) and one for host→guest (RX).
virtio-net
virtio-net is the network device in the virtio spec. From the guest’s perspective it looks like a PCI NIC; the guest runs the virtio-net driver. On the hypervisor side (QEMU is the common case), it connects to a TAP interface on the host.
Network offloads
A real NIC can offload certain expensive computations from the CPU to the NIC’s hardware. When a guest uses virtio-net, these same offloads can be passed through to the host NIC, so the guest gets the benefit without doing the work itself.
Checksum offload: When sending a TCP or UDP packet, the kernel normally computes the checksum in software before handing it to the NIC. With checksum offload, the kernel marks the packet “checksum needed” and the NIC computes it in hardware. With virtio-net, the guest can mark a packet this way, pass it to the host, and the host NIC computes the checksum — the guest CPU never touches it.
GSO — Generic Segmentation Offload (sending): TCP has a maximum segment size (MSS, typically 1460 bytes for standard Ethernet). When an app sends a large buffer (e.g. 64 KB), the kernel would normally split it into ~44 segments and compute headers for each. With GSO, the kernel hands one large “super-segment” to the NIC and the NIC (or a software layer) splits it. With virtio-net passthrough, the guest can hand a 64 KB buffer all the way to the host NIC’s TSO (TCP Segmentation Offload) hardware — the guest network stack does far less work.
GRO — Generic Receive Offload (receiving): The reverse of GSO. When many small TCP packets from the same flow arrive, GRO coalesces them into one large buffer before passing up the stack. Fewer receive calls, less overhead. With virtio-net, the guest can receive already-coalesced buffers from the host.
In short: offloads are CPU-intensive networking tasks (checksum, split, merge) that the guest delegates to the host kernel or host NIC hardware, saving guest CPU cycles.
Other virtio devices
The same ring-buffer approach is used for other device classes: virtio-blk (block storage), virtio-scsi, virtio-gpu, virtio-balloon (memory ballooning), virtio-vsock (host↔guest socket channel without a network stack).