vmbus_channel/bus.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Vmbus bus definitions.
5
6use async_trait::async_trait;
7use guestmem::GuestMemory;
8use guid::Guid;
9use inspect::Inspect;
10use mesh::MeshPayload;
11use mesh::payload::Protobuf;
12use mesh::rpc::FailableRpc;
13use mesh::rpc::Rpc;
14use std::fmt::Display;
15use std::time::Duration;
16use vmbus_core::protocol;
17use vmbus_core::protocol::GpadlId;
18use vmbus_core::protocol::PipeFlags;
19use vmbus_core::protocol::PipeUserDefinedData;
20use vmbus_core::protocol::UserDefinedData;
21use vmcore::interrupt::Interrupt;
22
23/// Input for creating a channel offer.
24#[derive(Debug)]
25pub struct OfferInput {
26 /// Parameters describing the offer.
27 pub params: OfferParams,
28 /// The event to signal when the guest needs attention.
29 pub event: Interrupt,
30 /// A mesh channel to send channel-related requests to.
31 pub request_send: mesh::Sender<ChannelRequest>,
32 /// A mesh channel to receive channel-related requests to.
33 pub server_request_recv: mesh::Receiver<ChannelServerRequest>,
34}
35
36/// Resources for an offered channel.
37#[derive(Debug, Default)]
38pub struct OfferResources {
39 /// Untrusted guest memory access.
40 untrusted_memory: GuestMemory,
41 /// Private guest memory access. This will be `None` unless running in a paravisor of a hardware
42 /// isolated VM.
43 private_memory: Option<GuestMemory>,
44}
45
46impl OfferResources {
47 /// Creates a new `OfferResources`.
48 pub fn new(untrusted_memory: GuestMemory, private_memory: Option<GuestMemory>) -> Self {
49 OfferResources {
50 untrusted_memory,
51 private_memory,
52 }
53 }
54
55 /// Returns the `GuestMemory` to use based on the whether the open request requests confidential
56 /// memory.
57 ///
58 /// The open request reflects both whether the device indicated it supports confidential
59 /// external memory when it was offered, and whether the currently connected vmbus client
60 /// supports it. As such, you must not attempt to get the guest memory until a channel is
61 /// opened, and you should not retain the guest memory after it is closed, as the client and
62 /// its capabilities may change across opens.
63 pub fn guest_memory(&self, open_request: &OpenRequest) -> &GuestMemory {
64 self.get_memory(open_request.use_confidential_external_memory)
65 }
66
67 pub(crate) fn ring_memory(&self, open_request: &OpenRequest) -> &GuestMemory {
68 self.get_memory(open_request.use_confidential_ring)
69 }
70
71 fn get_memory(&self, private: bool) -> &GuestMemory {
72 if private {
73 self.private_memory
74 .as_ref()
75 .expect("private memory should be present if confidential memory is requested")
76 } else {
77 &self.untrusted_memory
78 }
79 }
80}
81
82/// A request from the VMBus control plane.
83#[derive(Debug, MeshPayload)]
84pub enum ChannelRequest {
85 /// Open the channel.
86 Open(Rpc<OpenRequest, bool>),
87 /// Close the channel.
88 ///
89 /// Although there is no response from the host, this is still modeled as an
90 /// RPC so that the caller can know that the vmbus client's state has been
91 /// updated.
92 Close(Rpc<(), ()>),
93 /// Create a new GPADL.
94 Gpadl(Rpc<GpadlRequest, bool>),
95 /// Tear down an existing GPADL.
96 TeardownGpadl(Rpc<GpadlId, ()>),
97 /// Modify the channel's target VP.
98 Modify(Rpc<ModifyRequest, i32>),
99}
100
101/// GPADL information from the guest.
102#[derive(Debug, MeshPayload)]
103pub struct GpadlRequest {
104 /// The GPADL ID.
105 pub id: GpadlId,
106 /// The number of ranges in the GPADL.
107 pub count: u16,
108 /// The GPA range buffer.
109 pub buf: Vec<u64>,
110}
111
112/// Modify channel request.
113#[derive(Debug, MeshPayload)]
114pub enum ModifyRequest {
115 /// Change the target VP to `target_vp`.
116 TargetVp {
117 /// The new target VP.
118 target_vp: u32,
119 },
120}
121
122/// A request to the VMBus control plane.
123#[derive(mesh::MeshPayload)]
124pub enum ChannelServerRequest {
125 /// A request to restore the channel.
126 ///
127 /// The input parameter indicates if the channel was saved open.
128 Restore(FailableRpc<bool, RestoreResult>),
129 /// A request to revoke the channel.
130 ///
131 /// A channel can also be revoked by dropping it. This request is only necessary if you need to
132 /// wait for the revoke operation to complete.
133 Revoke(Rpc<(), ()>),
134}
135
136/// The result of a [`ChannelServerRequest::Restore`] operation.
137#[derive(Debug, MeshPayload)]
138pub struct RestoreResult {
139 /// The open request, if the channel was opened restored.
140 pub open_request: Option<OpenRequest>,
141 /// The active GPADLs.
142 pub gpadls: Vec<RestoredGpadl>,
143}
144
145/// A restored GPADL.
146#[derive(Debug, MeshPayload)]
147pub struct RestoredGpadl {
148 /// The GPADL request.
149 pub request: GpadlRequest,
150 /// Whether the GPADL was saved in the accepted state.
151 ///
152 /// If true, failure to restore this is fatal to the restore operation. If
153 /// false, the device will later get another GPADL offer for this same
154 /// GPADL.
155 ///
156 /// This is needed because the device may have saved itself with a
157 /// dependency on this GPADL even if the response did not make it into the
158 /// vmbus server saved state.
159 pub accepted: bool,
160}
161
162/// Trait implemented by VMBus servers.
163#[async_trait]
164pub trait ParentBus: Send + Sync {
165 /// Offers a new channel.
166 async fn add_child(&self, request: OfferInput) -> anyhow::Result<OfferResources>;
167
168 /// Clones the bus.
169 ///
170 /// TODO: This is needed for now to support transparent subchannel offers.
171 /// Remove this once subchannels can be pre-created at primary channel offer
172 /// time.
173 fn clone_bus(&self) -> Box<dyn ParentBus>;
174
175 /// Returns whether [`OfferInput::event`] needs to be backed by an OS event.
176 ///
177 /// TODO: Remove this and just return the appropriate notify type directly
178 /// once subchannel creation and enable are separated.
179 fn use_event(&self) -> bool {
180 true
181 }
182}
183
184/// Channel open-specific data.
185#[derive(Debug, Copy, Clone, mesh::MeshPayload)]
186pub struct OpenData {
187 /// The target VP for interrupts to the guest, or `None` if interrupts are disabled.
188 pub target_vp: Option<u32>,
189 /// The page offset into the ring GPADL of the host-to-guest ring buffer.
190 pub ring_offset: u32,
191 /// The ring buffer's GPADL ID.
192 pub ring_gpadl_id: GpadlId,
193 /// The event flag used to notify the guest.
194 pub event_flag: u16,
195 /// An connection ID used when the guest notifies the host.
196 pub connection_id: u32,
197 /// User data provided by the opener.
198 pub user_data: UserDefinedData,
199}
200
201/// Information provided to devices when a channel is opened.
202#[derive(Debug, Clone, mesh::MeshPayload)]
203pub struct OpenRequest {
204 /// Channel open-specific data.
205 pub open_data: OpenData,
206 /// The interrupt used to signal the guest.
207 pub interrupt: Interrupt,
208 /// Indicates if the currently connected vmbus client, as well as the channel the request is
209 /// for, supports the use of confidential ring buffers.
210 pub use_confidential_ring: bool,
211 /// Indicates if the currently connected vmbus client, as well as the channel the request is
212 /// for, supports the use of confidential external memory.
213 pub use_confidential_external_memory: bool,
214 /// Indicates if the currently connected vmbus client is expected to pin any external memory
215 /// used by the channel. This is only true if the vmbus client supports GPA pinning and the
216 /// channel indicated it requires pinned external memory. It can only be true for paravisor
217 /// channels in a VM that supports the GPA pinning hypercalls.
218 pub is_external_memory_pinned: bool,
219}
220
221impl OpenRequest {
222 /// Creates a new `OpenRequest`.
223 pub fn new(
224 open_data: OpenData,
225 interrupt: Interrupt,
226 feature_flags: protocol::FeatureFlags,
227 offer_flags: protocol::OfferFlags,
228 ) -> Self {
229 Self {
230 open_data,
231 interrupt,
232 use_confidential_ring: feature_flags.confidential_channels()
233 && offer_flags.confidential_ring_buffer(),
234 use_confidential_external_memory: feature_flags.confidential_channels()
235 && offer_flags.confidential_external_memory(),
236 is_external_memory_pinned: feature_flags.gpa_pinning()
237 && offer_flags.require_pinned_external_memory(),
238 }
239 }
240}
241
242#[derive(Debug, Default, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Protobuf, Inspect)]
243/// The identifying IDs for a channel offer.
244#[mesh(package = "vmbus")]
245pub struct OfferKey {
246 /// The interface ID describing the type of channel.
247 #[mesh(1)]
248 pub interface_id: Guid,
249 /// The unique instance ID for the channel.
250 #[mesh(2)]
251 pub instance_id: Guid,
252 /// The subchannel index. Index 0 indicates a primary (normal channel).
253 #[mesh(3)]
254 pub subchannel_index: u16,
255}
256
257impl Display for OfferKey {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 write!(
260 f,
261 "{{{}}}-{{{}}}-{}",
262 self.interface_id, self.instance_id, self.subchannel_index
263 )
264 }
265}
266
267impl From<&protocol::OfferChannel> for OfferKey {
268 fn from(offer: &protocol::OfferChannel) -> Self {
269 Self {
270 interface_id: offer.interface_id,
271 instance_id: offer.instance_id,
272 subchannel_index: offer.subchannel_index,
273 }
274 }
275}
276
277/// Channel offer parameters.
278#[derive(Debug, Clone, Default, mesh::MeshPayload)]
279pub struct OfferParams {
280 /// An informational string describing the channel type.
281 pub interface_name: String,
282 /// The unique instance ID for the channel.
283 pub instance_id: Guid,
284 /// The interface ID describing the type of channel.
285 pub interface_id: Guid,
286 /// The amount of MMIO space needed by the channel, in megabytes.
287 pub mmio_megabytes: u16,
288 /// The amount of optional MMIO space used by the channel, in megabytes.
289 pub mmio_megabytes_optional: u16,
290 /// The channel's type.
291 pub channel_type: ChannelType,
292 /// The subchannel index. Index 0 indicates a primary (normal channel).
293 pub subchannel_index: u16,
294 /// Indicates whether the channel's interrupts should use monitor pages,
295 /// and the interrupt latency if it's enabled.
296 pub mnf_interrupt_latency: Option<Duration>,
297 /// The order in which channels with the same interface will be offered to
298 /// the guest (optional).
299 pub offer_order: Option<u64>,
300 /// Indicates whether the channel supports using encrypted memory for any
301 /// external GPADLs and GPA direct ranges. This is only used when hardware
302 /// isolation is in use.
303 pub allow_confidential_external_memory: bool,
304}
305
306impl OfferParams {
307 /// Gets the offer key for this offer.
308 pub fn key(&self) -> OfferKey {
309 OfferKey {
310 interface_id: self.interface_id,
311 instance_id: self.instance_id,
312 subchannel_index: self.subchannel_index,
313 }
314 }
315}
316
317/// The channel type.
318#[derive(Debug, Copy, Clone, MeshPayload, Inspect)]
319#[inspect(external_tag)]
320pub enum ChannelType {
321 /// A channel representing a device.
322 Device {
323 /// If true, the ring buffer packets should contain pipe headers.
324 pipe_packets: bool,
325 },
326 /// A channel representing an interface for the guest to open.
327 Interface {
328 /// Interface-specific user-defined data to put in the channel offer.
329 user_defined: UserDefinedData,
330 },
331 /// A channel representing a pipe.
332 Pipe {
333 /// If true, the pipe uses message mode. Otherwise, it uses byte mode.
334 message_mode: bool,
335 /// Provider-defined offer data.
336 user_defined: PipeUserDefinedData,
337 /// Pipe capabilities.
338 pipe_flags: PipeFlags,
339 },
340 /// A channel representing a Hyper-V socket.
341 HvSocket {
342 /// If true, this is a connect to the guest. Otherwise, this is a
343 /// connect from the guest.
344 is_connect: bool,
345 /// If true, the connection is for a container in the guest.
346 is_for_container: bool,
347 /// The silo ID to connect to. Use `Guid::ZERO` to not specify a silo ID.
348 silo_id: Guid,
349 },
350}
351
352impl Default for ChannelType {
353 fn default() -> Self {
354 Self::Device {
355 pipe_packets: false,
356 }
357 }
358}