Skip to content
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

patch(v1.8) Live Migration and PVM Support #15

Open
wants to merge 1 commit into
base: firecracker-v1.8
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/hydrun.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: hydrun CI

on:
push:
pull_request:
schedule:
- cron: "0 0 * * 0"

jobs:
build-linux:
runs-on: ${{ matrix.target.runner }}
permissions:
contents: read
strategy:
matrix:
target:
# Binaries
- id: rust.x86_64
src: .
os: alpine:edge
flags: ""
cmd: ./Hydrunfile rust x86_64
dst: out/*
runner: depot-ubuntu-22.04-32
- id: rust.aarch64
src: .
os: alpine:edge
flags: ""
cmd: ./Hydrunfile rust aarch64
dst: out/*
runner: depot-ubuntu-22.04-arm-32

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Restore ccache
uses: actions/cache/restore@v4
with:
path: |
/tmp/ccache
key: cache-ccache-${{ matrix.target.id }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Set up hydrun
run: |
curl -L -o /tmp/hydrun "https://github.com/pojntfx/hydrun/releases/latest/download/hydrun.linux-$(uname -m)"
sudo install /tmp/hydrun /usr/local/bin
- name: Build with hydrun
working-directory: ${{ matrix.target.src }}
run: hydrun -o ${{ matrix.target.os }} ${{ matrix.target.flags }} "${{ matrix.target.cmd }}"
- name: Fix permissions for output
run: sudo chown -R $USER .
- name: Save ccache
uses: actions/cache/save@v4
with:
path: |
/tmp/ccache
key: cache-ccache-${{ matrix.target.id }}
- name: Upload output
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target.id }}
path: ${{ matrix.target.dst }}

publish-linux:
runs-on: ubuntu-latest
permissions:
contents: write
needs: build-linux

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download output
uses: actions/download-artifact@v4
with:
path: /tmp/out
- name: Extract branch name
id: extract_branch
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
- name: Publish pre-release to GitHub releases
if: ${{ github.ref == 'refs/heads/main-live-migration-pvm' || github.ref == 'refs/heads/main-live-migration' || github.ref == 'refs/heads/firecracker-v1.8-live-migration-pvm' || github.ref == 'refs/heads/firecracker-v1.8-live-migration' }}
uses: softprops/action-gh-release@v2
with:
tag_name: release-${{ steps.extract_branch.outputs.branch }}
prerelease: true
files: |
/tmp/out/*/*
- name: Publish release to GitHub releases
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
prerelease: false
files: |
/tmp/out/*/*
29 changes: 29 additions & 0 deletions Hydrunfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh

set -e

# Rust
if [ "$1" = "rust" ]; then
# Install native dependencies
apk add rust cargo clang-dev cmake linux-headers make git

# Configure Git
git config --global --add safe.directory '*'

# Build
cp "resources/seccomp/$2-unknown-linux-musl.json" "resources/seccomp/$2-alpine-linux-musl.json"
export RUSTFLAGS='-C target-feature=+crt-static'
cargo build --package firecracker --package jailer --package seccompiler --package rebase-snap --package cpu-template-helper --target "$2-alpine-linux-musl" --all-features --release

# Stage binaries
mkdir -p out

dir="./build/cargo_target/$2-alpine-linux-musl/release"
for file in $(ls "$dir"); do
if [[ -x "$dir/$file" && ! -d "$dir/$file" ]]; then
cp "$dir/$file" "./out/${file}.linux-$2"
fi
done

exit 0
fi
1 change: 1 addition & 0 deletions docs/cpu_templates/cpu-template-helper.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ CPU features to a heterogeneous fleet consisting of multiple CPU models.
| HV_X64_MSR_SYNDBG_PENDING_BUFFER | 0x400000f5 |
| HV_X64_MSR_SYNDBG_OPTIONS | 0x400000ff |
| HV_X64_MSR_TSC_INVARIANT_CONTROL | 0x40000118 |
| HV_X64_MSR_TSC_INVARIANT_CONTROL | 0x40000118 |

### ARM registers excluded from guest CPU configuration dump

Expand Down
4 changes: 4 additions & 0 deletions resources/seccomp/aarch64-unknown-linux-musl.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
{
"syscall": "fsync"
},
{
"syscall": "msync",
"comment": "Used for live migration to sync dirty pages"
},
{
"syscall": "close"
},
Expand Down
4 changes: 4 additions & 0 deletions resources/seccomp/x86_64-unknown-linux-musl.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
{
"syscall": "fsync"
},
{
"syscall": "msync",
"comment": "Used for live migration to sync dirty pages"
},
{
"syscall": "close"
},
Expand Down
8 changes: 8 additions & 0 deletions src/firecracker/src/api_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ impl ApiServer {
&METRICS.latencies_us.diff_create_snapshot,
"create diff snapshot",
)),
SnapshotType::Msync => Some((
&METRICS.latencies_us.diff_create_snapshot,
"memory synchronization snapshot",
)),
SnapshotType::MsyncAndState => Some((
&METRICS.latencies_us.diff_create_snapshot,
"memory synchronization and state snapshot",
)),
},
VmmAction::LoadSnapshot(_) => {
Some((&METRICS.latencies_us.load_snapshot, "load snapshot"))
Expand Down
5 changes: 5 additions & 0 deletions src/firecracker/src/api_server/request/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ fn parse_put_snapshot_load(body: &Body) -> Result<ParsedRequest, RequestError> {
mem_backend,
enable_diff_snapshots: snapshot_config.enable_diff_snapshots,
resume_vm: snapshot_config.resume_vm,
shared: snapshot_config.shared,
};

// Construct the `ParsedRequest` object.
Expand Down Expand Up @@ -181,6 +182,7 @@ mod tests {
},
enable_diff_snapshots: false,
resume_vm: false,
shared: false,
};
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
assert!(parsed_request
Expand Down Expand Up @@ -208,6 +210,7 @@ mod tests {
},
enable_diff_snapshots: true,
resume_vm: false,
shared: false,
};
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
assert!(parsed_request
Expand Down Expand Up @@ -235,6 +238,7 @@ mod tests {
},
enable_diff_snapshots: false,
resume_vm: true,
shared: false,
};
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
assert!(parsed_request
Expand All @@ -259,6 +263,7 @@ mod tests {
},
enable_diff_snapshots: false,
resume_vm: true,
shared: false,
};
let parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
assert_eq!(
Expand Down
7 changes: 7 additions & 0 deletions src/firecracker/swagger/firecracker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,8 @@ definitions:
enum:
- Full
- Diff
- Msync
- MsyncAndState
description:
Type of snapshot to create. It is optional and by default, a full
snapshot is created.
Expand Down Expand Up @@ -1234,6 +1236,11 @@ definitions:
type: boolean
description:
When set to true, the vm is also resumed if the snapshot load is successful.
shared:
type: boolean
description: When set to true and the guest memory backend is a file,
changes to the memory are asynchronously written back to the
backend as the VM is running.

TokenBucket:
type: object
Expand Down
20 changes: 19 additions & 1 deletion src/vmm/src/arch/x86_64/msr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const APIC_BASE_MSR: u32 = 0x800;
/// Number of APIC MSR indexes
const APIC_MSR_INDEXES: u32 = 0x400;

/// Custom MSRs fall in the range 0x4b564d00-0x4b564dff
/// /// Custom KVM MSRs fall in the range 0x4b564d00-0x4b564def (0x4b564df0-0x4b564dff is reserved for PVM)
const MSR_KVM_WALL_CLOCK_NEW: u32 = 0x4b56_4d00;
const MSR_KVM_SYSTEM_TIME_NEW: u32 = 0x4b56_4d01;
const MSR_KVM_ASYNC_PF_EN: u32 = 0x4b56_4d02;
Expand All @@ -58,6 +58,16 @@ const MSR_KVM_PV_EOI_EN: u32 = 0x4b56_4d04;
const MSR_KVM_POLL_CONTROL: u32 = 0x4b56_4d05;
const MSR_KVM_ASYNC_PF_INT: u32 = 0x4b56_4d06;

// Custom PVM MSRs fall in the range 0x4b564df0-0x4b564dff
const MSR_PVM_LINEAR_ADDRESS_RANGE: u32 = 0x4b56_4df0;
const MSR_PVM_VCPU_STRUCT: u32 = 0x4b56_4df1;
const MSR_PVM_SUPERVISOR_RSP: u32 = 0x4b56_4df2;
const MSR_PVM_SUPERVISOR_REDZONE: u32 = 0x4b56_4df3;
const MSR_PVM_EVENT_ENTRY: u32 = 0x4b56_4df4;
const MSR_PVM_RETU_RIP: u32 = 0x4b56_4df5;
const MSR_PVM_RETS_RIP: u32 = 0x4b56_4df6;
const MSR_PVM_SWITCH_CR3: u32 = 0x4b56_4df7;

/// Taken from arch/x86/include/asm/msr-index.h
/// Spectre mitigations control MSR
pub const MSR_IA32_SPEC_CTRL: u32 = 0x0000_0048;
Expand Down Expand Up @@ -237,6 +247,14 @@ static SERIALIZABLE_MSR_RANGES: &[MsrRange] = &[
MSR_RANGE!(MSR_KVM_POLL_CONTROL),
MSR_RANGE!(MSR_KVM_ASYNC_PF_INT),
MSR_RANGE!(MSR_IA32_TSX_CTRL),
MSR_RANGE!(MSR_PVM_LINEAR_ADDRESS_RANGE),
MSR_RANGE!(MSR_PVM_VCPU_STRUCT),
MSR_RANGE!(MSR_PVM_SUPERVISOR_RSP),
MSR_RANGE!(MSR_PVM_SUPERVISOR_REDZONE),
MSR_RANGE!(MSR_PVM_EVENT_ENTRY),
MSR_RANGE!(MSR_PVM_RETU_RIP),
MSR_RANGE!(MSR_PVM_RETS_RIP),
MSR_RANGE!(MSR_PVM_SWITCH_CR3),
];

/// Specifies whether a particular MSR should be included in vcpu serialization.
Expand Down
6 changes: 6 additions & 0 deletions src/vmm/src/logger/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,10 @@ pub struct PerformanceMetrics {
pub full_create_snapshot: SharedStoreMetric,
/// Measures the snapshot diff create time, at the API (user) level, in microseconds.
pub diff_create_snapshot: SharedStoreMetric,
/// Measures the snapshot memory synchronization time, at the VMM level, in microseconds.
pub msync_create_snapshot: SharedStoreMetric,
/// Measures the snapshot memory synchronization and state time, at the VMM level, in microseconds.
pub msync_and_state_create_snapshot: SharedStoreMetric,
/// Measures the snapshot load time, at the API (user) level, in microseconds.
pub load_snapshot: SharedStoreMetric,
/// Measures the microVM pausing duration, at the API (user) level, in microseconds.
Expand All @@ -627,6 +631,8 @@ impl PerformanceMetrics {
Self {
full_create_snapshot: SharedStoreMetric::new(),
diff_create_snapshot: SharedStoreMetric::new(),
msync_create_snapshot: SharedStoreMetric::new(),
msync_and_state_create_snapshot: SharedStoreMetric::new(),
load_snapshot: SharedStoreMetric::new(),
pause_vm: SharedStoreMetric::new(),
resume_vm: SharedStoreMetric::new(),
Expand Down
Loading
Loading