Skip to content

Commit 8920e26

Browse files
committed
add "secret_free" parameter to /machine-config endpoint
This will later indicate to Firecracker that guest memory should be backed by guest_memfd. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent fd3ab21 commit 8920e26

File tree

5 files changed

+106
-2
lines changed

5 files changed

+106
-2
lines changed

src/vmm/src/resources.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ pub struct VmResources {
110110
}
111111

112112
impl VmResources {
113+
/// Whether this [`VmResources`] object contains any devices that require host kernel access
114+
/// into guest memory.
115+
pub fn has_any_io_devices(&self) -> bool {
116+
!self.block.devices.is_empty()
117+
|| self.vsock.get().is_some()
118+
|| self.net_builder.iter().next().is_some()
119+
}
120+
113121
/// Configures Vmm resources as described by the `config_json` param.
114122
pub fn from_json(
115123
config_json: &str,
@@ -217,6 +225,11 @@ impl VmResources {
217225
BalloonConfigError::IncompatibleWith("huge pages"),
218226
));
219227
}
228+
if self.machine_config.mem_config.secret_free {
229+
return Err(ResourcesError::BalloonDevice(
230+
BalloonConfigError::IncompatibleWith("secret freedom"),
231+
));
232+
}
220233
}
221234

222235
SharedDeviceType::Vsock(vsock) => {
@@ -256,12 +269,23 @@ impl VmResources {
256269
return Err(MachineConfigError::IncompatibleBalloonSize);
257270
}
258271

272+
#[cfg(target_arch = "x86_64")]
273+
if self.has_any_io_devices() && self.machine_config.mem_config.secret_free {
274+
return Err(MachineConfigError::Incompatible("secret freedom", "I/O"));
275+
}
276+
259277
if self.balloon.get().is_some() && updated.huge_pages != HugePageConfig::None {
260278
return Err(MachineConfigError::Incompatible(
261279
"balloon device",
262280
"huge pages",
263281
));
264282
}
283+
if self.balloon.get().is_some() && updated.mem_config.secret_free {
284+
return Err(MachineConfigError::Incompatible(
285+
"balloon device",
286+
"secret freedom",
287+
));
288+
}
265289
self.machine_config = updated;
266290

267291
Ok(())
@@ -320,6 +344,10 @@ impl VmResources {
320344
return Err(BalloonConfigError::IncompatibleWith("huge pages"));
321345
}
322346

347+
if self.machine_config.mem_config.secret_free {
348+
return Err(BalloonConfigError::IncompatibleWith("secret freedom"));
349+
}
350+
323351
self.balloon.set(config)
324352
}
325353

@@ -343,6 +371,11 @@ impl VmResources {
343371
&mut self,
344372
block_device_config: BlockDeviceConfig,
345373
) -> Result<(), DriveError> {
374+
#[cfg(target_arch = "x86_64")]
375+
if self.machine_config.mem_config.secret_free {
376+
return Err(DriveError::NoSecretFreeIOOnX86);
377+
}
378+
346379
self.block.insert(block_device_config)
347380
}
348381

@@ -351,12 +384,22 @@ impl VmResources {
351384
&mut self,
352385
body: NetworkInterfaceConfig,
353386
) -> Result<(), NetworkInterfaceError> {
387+
#[cfg(target_arch = "x86_64")]
388+
if self.machine_config.mem_config.secret_free {
389+
return Err(NetworkInterfaceError::NoSecretFreeIOOnX86);
390+
}
391+
354392
let _ = self.net_builder.build(body)?;
355393
Ok(())
356394
}
357395

358396
/// Sets a vsock device to be attached when the VM starts.
359397
pub fn set_vsock_device(&mut self, config: VsockDeviceConfig) -> Result<(), VsockConfigError> {
398+
#[cfg(target_arch = "x86_64")]
399+
if self.machine_config.mem_config.secret_free {
400+
return Err(VsockConfigError::NoSecretFreeIOOnX86);
401+
}
402+
360403
self.vsock.insert(config)
361404
}
362405

src/vmm/src/vmm_config/drive.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ pub enum DriveError {
2424
DeviceUpdate(VmmError),
2525
/// A root block device already exists!
2626
RootBlockDeviceAlreadyAdded,
27+
/// A block device was added on x86 while secret freedom was enabled.
28+
#[cfg(target_arch = "x86_64")]
29+
NoSecretFreeIOOnX86,
2730
}
2831

2932
/// Use this structure to set up the Block Device before booting the kernel.

src/vmm/src/vmm_config/machine_config.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ pub struct MemoryConfig {
9999
#[cfg(target_arch = "aarch64")]
100100
#[serde(default)]
101101
pub initial_swiotlb_size: usize,
102+
/// Whether guest_memfd should be used to back normal guest memory. If this is enabled
103+
/// and any devices are attached to the VM, then initial_swiotlb_size must be non-zero,
104+
/// as I/O into secret free memory is not possible.
105+
#[serde(default)]
106+
pub secret_free: bool,
102107
}
103108

104109
/// Struct used in PUT `/machine-config` API call.
@@ -289,6 +294,7 @@ impl MachineConfig {
289294
let mem_size_mib = update.mem_size_mib.unwrap_or(self.mem_size_mib);
290295
let page_config = update.huge_pages.unwrap_or(self.huge_pages);
291296
let mem_config = update.mem_config.unwrap_or(self.mem_config);
297+
let track_dirty_pages = update.track_dirty_pages.unwrap_or(self.track_dirty_pages);
292298

293299
if mem_size_mib == 0 || !page_config.is_valid_mem_size(mem_size_mib) {
294300
return Err(MachineConfigError::InvalidMemorySize);
@@ -301,6 +307,20 @@ impl MachineConfig {
301307
return Err(MachineConfigError::InvalidSwiotlbRegionSize);
302308
}
303309

310+
if mem_config.secret_free && page_config != HugePageConfig::None {
311+
return Err(MachineConfigError::Incompatible(
312+
"secret freedom",
313+
"huge pages",
314+
));
315+
}
316+
317+
if mem_config.secret_free && track_dirty_pages {
318+
return Err(MachineConfigError::Incompatible(
319+
"secret freedom",
320+
"diff snapshots",
321+
));
322+
}
323+
304324
let cpu_template = match update.cpu_template {
305325
None => self.cpu_template.clone(),
306326
Some(StaticCpuTemplate::None) => None,
@@ -313,7 +333,7 @@ impl MachineConfig {
313333
mem_config,
314334
smt,
315335
cpu_template,
316-
track_dirty_pages: update.track_dirty_pages.unwrap_or(self.track_dirty_pages),
336+
track_dirty_pages,
317337
huge_pages: page_config,
318338
#[cfg(feature = "gdb")]
319339
gdb_socket_path: update.gdb_socket_path.clone(),
@@ -325,7 +345,7 @@ impl MachineConfig {
325345
mod tests {
326346
use crate::cpu_config::templates::{CpuTemplateType, CustomCpuTemplate, StaticCpuTemplate};
327347
use crate::vmm_config::machine_config::{
328-
HugePageConfig, MachineConfig, MachineConfigError, MachineConfigUpdate,
348+
HugePageConfig, MachineConfig, MachineConfigError, MachineConfigUpdate, MemoryConfig,
329349
};
330350

331351
#[test]
@@ -379,6 +399,38 @@ mod tests {
379399
.unwrap();
380400
assert_eq!(updated.huge_pages, HugePageConfig::Hugetlbfs2M);
381401
assert_eq!(updated.mem_size_mib, 32);
402+
403+
let res = mconf.update(&MachineConfigUpdate {
404+
huge_pages: Some(HugePageConfig::Hugetlbfs2M),
405+
mem_config: Some(MemoryConfig {
406+
secret_free: true,
407+
..Default::default()
408+
}),
409+
..Default::default()
410+
});
411+
assert_eq!(
412+
res,
413+
Err(MachineConfigError::Incompatible(
414+
"secret freedom",
415+
"huge pages"
416+
))
417+
);
418+
419+
let res = mconf.update(&MachineConfigUpdate {
420+
track_dirty_pages: Some(true),
421+
mem_config: Some(MemoryConfig {
422+
secret_free: true,
423+
..Default::default()
424+
}),
425+
..Default::default()
426+
});
427+
assert_eq!(
428+
res,
429+
Err(MachineConfigError::Incompatible(
430+
"secret freedom",
431+
"diff snapshots"
432+
))
433+
);
382434
}
383435

384436
#[test]

src/vmm/src/vmm_config/net.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ pub enum NetworkInterfaceError {
7171
GuestMacAddressInUse(String),
7272
/// Cannot open/create the tap device: {0}
7373
OpenTap(#[from] TapError),
74+
/// A net device was added on x86 while secret freedom was enabled.
75+
#[cfg(target_arch = "x86_64")]
76+
NoSecretFreeIOOnX86,
7477
}
7578

7679
/// Builder for a list of network devices.

src/vmm/src/vmm_config/vsock.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub enum VsockConfigError {
1717
CreateVsockBackend(VsockUnixBackendError),
1818
/// Cannot create vsock device: {0}
1919
CreateVsockDevice(VsockError),
20+
/// A vsock device was added on x86 while secret freedom was enabled.
21+
#[cfg(target_arch = "x86_64")]
22+
NoSecretFreeIOOnX86,
2023
}
2124

2225
/// This struct represents the strongly typed equivalent of the json body

0 commit comments

Comments
 (0)