Skip to content

Commit

Permalink
feat: Add live migration and PVM support
Browse files Browse the repository at this point in the history
Signed-off-by: Felicitas Pojtinger <felicitas@pojtinger.com>
  • Loading branch information
pojntfx committed Aug 31, 2024
1 parent 14c4096 commit abae153
Show file tree
Hide file tree
Showing 16 changed files with 372 additions and 81 deletions.
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

0 comments on commit abae153

Please sign in to comment.