-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Snapshot editor #4045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ShadowCurse
merged 8 commits into
firecracker-microvm:main
from
ShadowCurse:snapshot_editor
Aug 25, 2023
Merged
Snapshot editor #4045
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d52a9b6
feat(snapshot): snapshot loading now also returns version
ShadowCurse a382573
feat(vmm): added `Default` to several structs
ShadowCurse 3a10361
feat(vmm): made more items public
ShadowCurse 68f1370
feat(vmm): added comments to public modules/structs
ShadowCurse 63f296e
feat(snapshot-editor): added snapshot-editor tool
ShadowCurse cfef3ff
doc(snapshot-editor): added documentation for `snapshot-editor` tool
ShadowCurse 7ca4835
test(snapshot-editor): added integration test
ShadowCurse 3319a27
doc(snapshot-editor): added `snapshot-editor` to the CHANGELOG
ShadowCurse File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| # Snapshot editor | ||
|
|
||
| The `snapshot-editor` is a program for modification of Firecracker snapshots. | ||
|
|
||
| ## Prior knowledge | ||
|
|
||
| Firecracker snapshot consists of 2 files: | ||
|
|
||
| - `vmstate` file: file with Firecracker internal data such as vcpu states, | ||
| devices states etc. | ||
| - `memory` file: file with guest memory. | ||
|
|
||
| `snapshot-editor` (currently) allows to modify only `vmstate` files only | ||
| on aarch64 platform. | ||
|
|
||
| ## Usage | ||
|
|
||
| ### `edit-vmstate` command | ||
|
|
||
| #### `remove-regs` subcommand (aarch64 only) | ||
|
|
||
| This command is used to remove specified registers from vcpu states inside | ||
| vmstate snapshot file. | ||
|
|
||
| Arguments: | ||
|
|
||
| - `VMSTATE_PATH` - path to the `vmstate` file | ||
| - `OUTPUT_PATH` - path to the file where the output will be placed | ||
| - `[REGS]` - set of u32 values representing registers ids as they are defined | ||
| in KVM. Can be both in decimal and in hex formats. | ||
|
|
||
| Usage: | ||
|
|
||
| ```bash | ||
| snapshot-editor edit-vmstate remove-regs \ | ||
| --vmstate-path <VMSTATE_PATH> \ | ||
| --output-path <OUTPUT_PATH> \ | ||
| [REGS]... | ||
bchalios marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
| Example: | ||
|
|
||
| ```bash | ||
| ./snapshot-editor edit-vmstate remove-regs \ | ||
| --vmstate-path ./vmstate_file \ | ||
| --output-path ./new_vmstate_file \ | ||
| 0x1 0x2 | ||
| ``` | ||
ShadowCurse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### `info-vmstate` command | ||
|
|
||
| #### `version` subcommand | ||
|
|
||
| This command is used to print version of the provided | ||
| vmstate file. | ||
|
|
||
| Arguments: | ||
|
|
||
| - `VMSTATE_PATH` - path to the `vmstate` file | ||
|
|
||
| Usage: | ||
|
|
||
| ```bash | ||
| snapshot-editor info-vmstate version --vmstate-path <VMSTATE_PATH> | ||
| ``` | ||
|
|
||
| Example: | ||
|
|
||
| ```bash | ||
| ./snapshot-editor info-vmstate version --vmstate-path ./vmstate_file | ||
| ``` | ||
|
|
||
| #### `vcpu-states` subcommand (aarch64 only) | ||
|
|
||
| This command is used to print the vCPU states inside vmstate snapshot file. | ||
|
|
||
| Arguments: | ||
|
|
||
| - `VMSTATE_PATH` - path to the `vmstate` file | ||
|
|
||
| Usage: | ||
|
|
||
| ```bash | ||
| snapshot-editor info-vmstate vcpu-states --vmstate-path <VMSTATE_PATH> | ||
| ``` | ||
|
|
||
| Example: | ||
|
|
||
| ```bash | ||
| ./snapshot-editor info-vmstate vcpu-states --vmstate-path ./vmstate_file | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| [package] | ||
| name = "snapshot-editor" | ||
| version = "1.5.0" | ||
| authors = ["Amazon Firecracker team <[email protected]>"] | ||
| edition = "2021" | ||
| build = "../../build.rs" | ||
| license = "Apache-2.0" | ||
|
|
||
| [dependencies] | ||
| clap = { version = "4.3.19", features = ["derive", "string"] } | ||
| clap-num = "1.0.2" | ||
| libc = "0.2.147" | ||
| snapshot = { path = "../snapshot" } | ||
| thiserror = "1.0.44" | ||
| vmm = { path = "../vmm" } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| // Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| use std::path::PathBuf; | ||
|
|
||
| use clap::Subcommand; | ||
| use clap_num::maybe_hex; | ||
| use vmm::arch::aarch64::regs::Aarch64RegisterVec; | ||
| use vmm::persist::MicrovmState; | ||
|
|
||
| use crate::utils::{open_vmstate, save_vmstate, UtilsError}; | ||
|
|
||
| #[derive(Debug, thiserror::Error)] | ||
| pub enum EditVmStateError { | ||
| #[error("{0}")] | ||
| Utils(#[from] UtilsError), | ||
| } | ||
|
|
||
| #[derive(Debug, Subcommand)] | ||
| pub enum EditVmStateSubCommand { | ||
| /// Remove registers from vcpu states. | ||
| RemoveRegs { | ||
| /// Set of registers to remove. | ||
| /// Values should be registers ids as the are defined in KVM. | ||
| #[arg(value_parser=maybe_hex::<u64>, num_args = 1.., value_delimiter = ' ')] | ||
| regs: Vec<u64>, | ||
| /// Path to the vmstate file. | ||
| #[arg(short, long)] | ||
| vmstate_path: PathBuf, | ||
| /// Path of output file. | ||
| #[arg(short, long)] | ||
| output_path: PathBuf, | ||
| }, | ||
| } | ||
|
|
||
| pub fn edit_vmstate_command(command: EditVmStateSubCommand) -> Result<(), EditVmStateError> { | ||
| match command { | ||
| EditVmStateSubCommand::RemoveRegs { | ||
| regs, | ||
| vmstate_path, | ||
| output_path, | ||
| } => edit(&vmstate_path, &output_path, |state| { | ||
| remove_regs(state, ®s) | ||
| })?, | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| fn edit( | ||
| vmstate_path: &PathBuf, | ||
| output_path: &PathBuf, | ||
| f: impl Fn(MicrovmState) -> Result<MicrovmState, EditVmStateError>, | ||
| ) -> Result<(), EditVmStateError> { | ||
| let (microvm_state, version) = open_vmstate(vmstate_path)?; | ||
| let microvm_state = f(microvm_state)?; | ||
| save_vmstate(microvm_state, output_path, version)?; | ||
| Ok(()) | ||
| } | ||
|
|
||
| fn remove_regs( | ||
| mut state: MicrovmState, | ||
| remove_regs: &[u64], | ||
| ) -> Result<MicrovmState, EditVmStateError> { | ||
| for (i, vcpu_state) in state.vcpu_states.iter_mut().enumerate() { | ||
| println!("Modifying state for vCPU {i}"); | ||
|
|
||
| let mut removed = vec![false; remove_regs.len()]; | ||
| let mut new_regs = Aarch64RegisterVec::default(); | ||
| for reg in vcpu_state.regs.iter().filter(|reg| { | ||
| if let Some(pos) = remove_regs.iter().position(|r| r == ®.id) { | ||
| removed[pos] = true; | ||
| false | ||
| } else { | ||
| true | ||
| } | ||
| }) { | ||
| new_regs.push(reg); | ||
| } | ||
bchalios marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| vcpu_state.regs = new_regs; | ||
| for (reg, removed) in remove_regs.iter().zip(removed.iter()) { | ||
| print!("Regsiter {reg:#x}: "); | ||
| match removed { | ||
| true => println!("removed"), | ||
| false => println!("not present"), | ||
| } | ||
| } | ||
| } | ||
| Ok(state) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_remove_regs() { | ||
| const KVM_REG_SIZE_U8: u64 = 0; | ||
| const KVM_REG_SIZE_U16: u64 = 0x10000000000000; | ||
| const KVM_REG_SIZE_U32: u64 = 0x20000000000000; | ||
|
|
||
| use vmm::arch::aarch64::regs::Aarch64RegisterRef; | ||
| use vmm::vstate::vcpu::aarch64::VcpuState; | ||
|
|
||
| let vcpu_state = VcpuState { | ||
| regs: { | ||
| let mut regs = Aarch64RegisterVec::default(); | ||
| let reg_data: u8 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U8, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| let reg_data: u16 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U16, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| let reg_data: u32 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U32, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| regs | ||
| }, | ||
| ..Default::default() | ||
| }; | ||
| let state = MicrovmState { | ||
| vcpu_states: vec![vcpu_state], | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| let new_state = remove_regs(state, &[KVM_REG_SIZE_U32]).unwrap(); | ||
|
|
||
| let expected_vcpu_state = VcpuState { | ||
| regs: { | ||
| let mut regs = Aarch64RegisterVec::default(); | ||
| let reg_data: u8 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U8, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| let reg_data: u16 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U16, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| regs | ||
| }, | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| assert_eq!(new_state.vcpu_states[0].regs, expected_vcpu_state.regs); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_remove_non_existed_regs() { | ||
| const KVM_REG_SIZE_U8: u64 = 0; | ||
| const KVM_REG_SIZE_U16: u64 = 0x10000000000000; | ||
| const KVM_REG_SIZE_U32: u64 = 0x20000000000000; | ||
|
|
||
| use vmm::arch::aarch64::regs::Aarch64RegisterRef; | ||
| use vmm::vstate::vcpu::aarch64::VcpuState; | ||
|
|
||
| let vcpu_state = VcpuState { | ||
| regs: { | ||
| let mut regs = Aarch64RegisterVec::default(); | ||
| let reg_data: u8 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U8, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| let reg_data: u16 = 69; | ||
| regs.push(Aarch64RegisterRef::new( | ||
| KVM_REG_SIZE_U16, | ||
| ®_data.to_le_bytes(), | ||
| )); | ||
| regs | ||
| }, | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| let state_clone = MicrovmState { | ||
| vcpu_states: vec![vcpu_state.clone()], | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| let state = MicrovmState { | ||
| vcpu_states: vec![vcpu_state], | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| let new_state = remove_regs(state_clone, &[KVM_REG_SIZE_U32]).unwrap(); | ||
|
|
||
| assert_eq!(new_state.vcpu_states[0].regs, state.vcpu_states[0].regs); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.