microsoft/openvmm

Public

mirrored from https://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
bcad144d35cefefc595e55c4f1d55ae0f218b040

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Guide/src/reference/backends/networking.md

166lines · modecode

1# Networking backends
2
3The networking backend system connects guest-facing NICs (frontends)
4to host-side packet I/O (backends) through a shared trait interface
5defined in the `net_backend` crate. This page explains how the
6pieces fit together, how packets flow, and how to navigate the code.
7
8## Architecture overview
9
10```text
11┌──────────────┐ ┌──────────────┐ ┌──────────────┐
12│ virtio_net │ │ netvsp │ │ gdma/bnic │
13│ (frontend) │ │ (frontend) │ │ (frontend) │
14└───────┬──────┘ └───────┬──────┘ └───────┬──────┘
15 │ │ │
16 │ &mut dyn BufferAccess │
17 │ (owned by frontend) │
18 │ │ │
19 ▼ ▼ ▼
20┌──────────────────────────────────────────────────┐
21│ dyn Queue (per-queue) │
22│ poll_ready · rx_avail · rx_poll │
23│ tx_avail · tx_poll │
24└──────────────────────────────────────────────────┘
25 ▲ ▲ ▲
26 │ │ │
27┌───────┴──────┐ ┌───────┴──────┐ ┌───────┴──────┐
28│ TapQueue │ │ConsommeQueue │ │ ManaQueue │
29│ DioQueue │ │LoopbackQueue │ │ (hardware) │
30│ ... │ │ NullQueue │ │ │
31└──────────────┘ └──────────────┘ └──────────────┘
32```
33
34There are three layers:
35
36- **Frontend** — the guest-visible NIC device (`virtio_net`,
37 `netvsp`, or `gdma`). Owns the `BufferAccess` implementation
38 (no `Arc` or `Mutex` needed — each queue is driven from a single
39 async task), translates between the guest-specific descriptor
40 format and the generic `Queue` interface, and drives the poll
41 loop.
42
43- **Queue** — a single TX/RX data path created by the backend.
44 Frontends interact with it entirely through the
45 [`Queue`](https://openvmm.dev/rustdoc/net_backend/trait.Queue.html)
46 trait. A device may have multiple queues for RSS.
47
48- **Endpoint** — a backend factory. One per NIC. The frontend calls
49 [`Endpoint::get_queues`](https://openvmm.dev/rustdoc/net_backend/trait.Endpoint.html#tymethod.get_queues)
50 when the guest activates the NIC and
51 [`Endpoint::stop`](https://openvmm.dev/rustdoc/net_backend/trait.Endpoint.html#tymethod.stop)
52 on teardown.
53
54See the
55[`net_backend` rustdoc](https://openvmm.dev/rustdoc/net_backend/)
56for the full trait signatures and type definitions.
57
58## Packet flow
59
60### Transmit (guest → host)
61
621. The guest posts a TX descriptor (e.g. a virtio descriptor chain
63 or a VMBus RNDIS message).
642. The frontend reads the descriptor from guest memory, extracts any
65 offload metadata (checksum, TSO, USO), and builds a `TxSegment` array.
66 Each segment carries a guest physical address and a length — **no
67 data is copied** at this point.
683. The frontend calls `queue.tx_avail(&mut pool, &segments)`. The
69 backend reads data directly from guest memory via
70 `pool.guest_memory()` and transmits it (e.g. writes to a TAP fd,
71 posts to hardware, or feeds it to a user-space TCP stack).
724. If the backend completes synchronously (`tx_avail` returns
73 `sync = true`), the frontend can immediately mark the descriptor
74 done. Otherwise, it polls `tx_poll` later for async completions.
75
76### Receive (host → guest)
77
781. The frontend pre-populates the backend with receive buffers by
79 calling `queue.rx_avail(&mut pool, &buffer_ids)`.
802. When `queue.poll_ready(cx, &mut pool)` signals readiness, the
81 backend has received a packet. It writes the packet data into
82 guest memory through `pool.write_packet(rx_id, metadata, data)`.
833. The frontend calls `queue.rx_poll(&mut pool, &mut ids)` to
84 collect the IDs of completed buffers, then delivers them to the
85 guest (e.g. by completing virtio descriptors or sending VMBus
86 completion packets).
874. The guest eventually returns the buffer, and the frontend recycles
88 it via `rx_avail`.
89
90### Guest memory access
91
92The `Queue` interface works with guest physical addresses rather
93than host buffers, giving each backend flexibility in how it
94accesses packet data. The patterns fall into three categories:
95
96**GPA pass-through (hardware DMA).** `net_mana` converts guest
97physical addresses into IO virtual addresses (`GuestMemory::iova`)
98and posts them as scatter-gather entries directly to GDMA hardware.
99The NIC DMAs packet data to/from guest memory without any host-side
100copy. This is the fastest path, but requires IOMMU mappings and
101contiguous-enough buffers; when those conditions aren't met, MANA
102falls back to bounce buffers.
103
104**Host-mediated copy.** Software backends like `net_consomme` and
105`net_dio` read TX data from guest memory with
106`GuestMemory::read_at`, process or forward it, and write RX data
107back with `BufferAccess::write_packet`. The data passes through
108host memory, but the `Queue` interface avoids any extra copies
109between the frontend and backend layers — the backend reads/writes
110guest RAM directly.
111
112## Lifecycle
113
1141. The frontend creates a
115 [`BufferAccess`](https://openvmm.dev/rustdoc/net_backend/trait.BufferAccess.html)
116 implementation and one `QueueConfig` per queue.
1172. It calls `endpoint.get_queues(configs, rss, &mut queues)`.
1183. It enters the poll loop: `poll_ready` → `rx_avail` / `rx_poll` /
119 `tx_avail` / `tx_poll`.
1204. On shutdown, it drops the queues and calls `endpoint.stop()`.
121
122## Backends
123
124| Backend | Crate | Transport | Platform |
125|---------|-------|-----------|----------|
126| TAP | `net_tap` | Linux TAP device | Linux |
127| DirectIO | `net_dio` | Windows vmswitch | Windows |
128| Consomme | `net_consomme` | User-space TCP/IP stack | Any |
129| MANA | `net_mana` | Azure hardware NIC (MANA/GDMA) | Linux |
130| Loopback | `net_backend` | Reflects TX → RX | Any |
131| Null | `net_backend` | Drops everything | Any |
132
133## Frontends
134
135| Frontend | Crate | Guest interface |
136|----------|-------|-----------------|
137| virtio-net | `virtio_net` | Virtio network device |
138| netvsp | `netvsp` | VMBus synthetic NIC |
139| GDMA/BNIC | `gdma` | MANA Basic NIC (emulated GDMA) |
140
141## Wrappers
142
143Wrappers implement `Endpoint` by delegating to an inner endpoint,
144adding cross-cutting behavior:
145
146- **PacketCapture** (`net_packet_capture`) — intercepts `rx_poll`
147 and `tx_avail` to write PCAP-format packet traces. The capture
148 path reads packet data from guest memory via `BufferAccess` and
149 writes enhanced packet blocks to a ring buffer. Capture can be
150 toggled at runtime; when disabled, the wrapper adds only an atomic
151 load per call.
152
153- **Disconnectable** (`net_backend`) — supports hot-plug and
154 hot-unplug by swapping the inner endpoint at runtime.
155
156## RSS and multi-queue
157
158When a frontend supports Receive Side Scaling (RSS), it passes
159multiple `QueueConfig` entries and an `RssConfig` (hash key +
160indirection table) to `get_queues`. The backend creates one `Queue`
161per entry and uses the RSS configuration to steer incoming packets
162to the appropriate queue. Each queue is driven independently by its
163own async task.
164
165Currently `netvsp` and `net_mana` support multi-queue; `virtio_net`
166is limited to a single queue pair.
167