vsock

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: BSD-3-Clause Imports: 3 Imported by: 0

README

go-virtio/vsock

Pure-Go virtio-vsock (socket device) driver targeting the go-virtio/common transport interfaces. Implements the modern-transport (Virtio 1.0+) init sequence and the three-virtqueue packet path for the standard PCI-bound virtio-vsock device (VID 0x1AF4, DID 0x1053).

Scope

This package sits at the same altitude as go-virtio/net: it owns device bring-up, the three virtqueues (rx / tx / event, Virtio 1.1 §5.10.2), and the on-the-wire struct virtio_vsock_hdr marshalling, exposing a packet-level SendPacket / ReceivePacket API.

It deliberately does not implement the connection state machine or the credit-based flow control (buf_alloc / fwd_cnt accounting) — those belong a layer up, exactly as net drives frames rather than TCP. The header's addressing and credit fields are surfaced on Packet so the upper layer can implement them.

Quick start

import (
    virtiovsock "github.com/go-virtio/vsock"
)

// transport is any value that implements go-virtio/common.Transport.
vs, err := virtiovsock.OpenVirtioVsock(transport)
if err != nil {
    return err
}

// Connection-request packet to the host (CID 2), port 1024.
err = vs.SendPacket(virtiovsock.Packet{
    SrcCID:  vs.GuestCID,
    DstCID:  virtiovsock.CIDHost,
    SrcPort: 1024,
    DstPort: 5000,
    Type:    virtiovsock.TypeStream,
    Op:      virtiovsock.OpRequest,
})

// Poll for one inbound packet.
pkt, err := vs.ReceivePacket(10000) // busy-poll budget

OpenVirtioVsock leaves the device in DRIVER_OK state with the rx and event queues pre-posted and GuestCID populated from device config.

Sibling packages

License

BSD-3-Clause. See LICENSE.

Documentation

Overview

Package vsock is a pure-Go virtio-vsock (socket device) driver. It drives a modern (Virtio 1.0+) PCI virtio-vsock device through the transport interfaces defined in github.com/go-virtio/common; the same code drives a UEFI-backed device, a bare-metal device, or a virtio-mmio device depending on which common.Transport implementation the caller supplies.

Scope — this package sits at the same altitude as go-virtio/net: it owns the device bring-up, the three virtqueues, and the on-the-wire struct virtio_vsock_hdr marshalling, and exposes a packet-level Send/Receive API. It deliberately does NOT implement the connection state machine or the credit-based flow control (buf_alloc / fwd_cnt accounting) — those belong a layer up, just as net drives frames, not TCP. The header's addressing and credit fields are surfaced on Packet so that upper layer can implement them.

  • Modern transport (VIRTIO_F_VERSION_1 mandatory). Legacy devices are rejected by the common init sequence.
  • Split-virtqueue layout; the packed ring is negotiated OUT.
  • Three virtqueues: rx (0), tx (1), event (2) per Virtio 1.1 §5.10.2.

References:

  • Virtio 1.1 §5.10 "Socket Device" — device-type 19 binding.
  • Virtio 1.1 §5.10.2 "Virtqueues" — rx / tx / event.
  • Virtio 1.1 §5.10.4 "Device configuration layout" — le64 guest_cid.
  • Virtio 1.1 §5.10.6 "Device Operation" — struct virtio_vsock_hdr.
  • Virtio 1.1 §3.1.1 "Device Initialization" — the status-bit choreography in OpenVirtioVsock.

Index

Constants

View Source
const (
	RxQueueIdx    uint16 = 0
	TxQueueIdx    uint16 = 1
	EventQueueIdx uint16 = 2
)

Virtqueue indices (Virtio 1.1 §5.10.2).

View Source
const (
	RxRingSize    uint16 = 32
	TxRingSize    uint16 = 32
	EventRingSize uint16 = 4
)

Desired ring sizes (clamped down to the device maximum, rounded to a power of two, during setup). The event queue is tiny — events are rare (only transport resets in this scope).

View Source
const (
	TypeStream    uint16 = 1
	TypeSeqpacket uint16 = 2
)

Packet type values (Virtio 1.1 §5.10.6 — virtio_vsock_hdr.type).

View Source
const (
	OpInvalid       uint16 = 0
	OpRequest       uint16 = 1
	OpResponse      uint16 = 2
	OpRst           uint16 = 3
	OpShutdown      uint16 = 4
	OpRW            uint16 = 5
	OpCreditUpdate  uint16 = 6
	OpCreditRequest uint16 = 7
)

Operation codes (Virtio 1.1 §5.10.6 — virtio_vsock_hdr.op).

View Source
const (
	CIDHypervisor uint64 = 0
	CIDHost       uint64 = 2
	CIDAny        uint64 = 0xFFFFFFFF
)

Well-known context IDs (Virtio 1.1 §5.10.4). VMADDR_CID_HOST = 2 is the peer CID a guest uses to reach the host.

View Source
const AcceptedFeatures uint64 = common.FeatureVersion1

AcceptedFeatures is the feature mask the driver negotiates ON. The packet-level driver needs no vsock-specific feature bit (stream is the baseline); the only bit we accept is the non-negotiable VIRTIO_F_VERSION_1.

View Source
const TxPollIterations = 200000

TxPollIterations is the default busy-poll budget for SendPacket while waiting for the device to return the transmitted descriptor.

View Source
const VsockHdrSize = 44

VsockHdrSize is the on-the-wire byte length of struct virtio_vsock_hdr (Virtio 1.1 §5.10.6.1), all fields little-endian:

0   le64 src_cid
8   le64 dst_cid
16  le32 src_port
20  le32 dst_port
24  le32 len          (payload byte count following the header)
28  le16 type
30  le16 op
32  le32 flags
36  le32 buf_alloc
40  le32 fwd_cnt

Variables

View Source
var (
	ErrNotModernDevice   = commonVsockError("go-virtio/vsock: device doesn't offer VIRTIO_F_VERSION_1 (legacy-only)")
	ErrFeaturesNotOK     = commonVsockError("go-virtio/vsock: FEATURES_OK status bit didn't stick after DriverFeature write")
	ErrInitWrongDeviceID = commonVsockError("go-virtio/vsock: PCI device ID is not 0x1053 (modern vsock device)")
	ErrQueueNotAvailable = commonVsockError("go-virtio/vsock: device reports QueueSize=0 for a required queue")
	ErrTransmitTimeout   = commonVsockError("go-virtio/vsock: TX poll timeout (device did not return descriptor)")
	ErrReceiveTimeout    = commonVsockError("go-virtio/vsock: RX poll timeout (no packet received within budget)")
	ErrPacketTooLarge    = commonVsockError("go-virtio/vsock: header + payload exceeds one page")
	ErrShortPacket       = commonVsockError("go-virtio/vsock: received buffer shorter than virtio_vsock_hdr (44 bytes)")
)

Sentinel errors for the virtio-vsock path.

Functions

func AcceptFeatures

func AcceptFeatures(deviceFeatures uint64) (uint64, error)

AcceptFeatures returns the negotiated feature mask: the intersection of what the device offers and what we accept. Requires VIRTIO_F_VERSION_1 (else the device is legacy-only).

Types

type Packet

type Packet struct {
	SrcCID, DstCID   uint64
	SrcPort, DstPort uint32
	Type             uint16
	Op               uint16
	Flags            uint32
	BufAlloc         uint32
	FwdCnt           uint32
	Data             []byte
}

Packet is one virtio-vsock packet: the header fields plus the payload. On SendPacket the `len` header field is derived from len(Data); on ReceivePacket Data is the payload the device delivered.

type VirtioVsock

type VirtioVsock struct {
	// Cfg is the modern-transport handle.
	Cfg *common.ModernConfig

	// GuestCID is the context ID the device assigned to this guest
	// (Virtio 1.1 §5.10.4), read from DeviceCfg at OpenVirtioVsock.
	GuestCID uint64

	// NegotiatedFeatures records the driver-feature handshake result.
	NegotiatedFeatures uint64
	// contains filtered or unexported fields
}

VirtioVsock wraps one initialised virtio-vsock device.

func OpenVirtioVsock

func OpenVirtioVsock(t common.Transport) (*VirtioVsock, error)

OpenVirtioVsock drives the full bring-up of one virtio-vsock device:

  1. Verify the PCI device ID is 0x1053 (modern vsock).
  2. InitModernConfig walks PCI caps + populates the BAR locators.
  3. Reset → ACK → DRIVER status progression.
  4. Read DeviceFeature, mask to VERSION_1, write DriverFeature.
  5. Set FEATURES_OK, verify it stuck.
  6. Allocate + publish rx (0), tx (1), event (2) queues.
  7. DRIVER_OK status.
  8. Read guest_cid from DeviceCfg.
  9. Pre-post receive + event buffers and notify the device.

func (*VirtioVsock) EventQueue

func (v *VirtioVsock) EventQueue() *common.Virtqueue

func (*VirtioVsock) ReceivePacket

func (v *VirtioVsock) ReceivePacket(pollIterations int) (Packet, error)

ReceivePacket polls the rx queue for one packet, busy-spinning up to pollIterations cycles. On success it copies the payload out, reclaims and re-posts the descriptor (best-effort), and returns the parsed Packet. Returns ErrReceiveTimeout if no packet arrives in budget.

func (*VirtioVsock) RxQueue

func (v *VirtioVsock) RxQueue() *common.Virtqueue

RxQueue / TxQueue / EventQueue expose the per-direction virtqueue handles for diagnostic inspection.

func (*VirtioVsock) SendPacket

func (v *VirtioVsock) SendPacket(p Packet) error

SendPacket marshals p (header + payload) into a fresh DMA buffer, enqueues it on the tx queue, notifies the device, and busy-polls the used ring for completion. Returns ErrPacketTooLarge if the payload plus header exceeds one page, or ErrTransmitTimeout if the device does not return the descriptor within TxPollIterations.

func (*VirtioVsock) TxQueue

func (v *VirtioVsock) TxQueue() *common.Virtqueue

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL