Skip to content
Draft
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ test_results/*
/resources/linux
/resources/x86_64
/resources/aarch64
.env
2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gcloud 534.0.0
rust 1.85.0
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-include .env

.PHONY: build
build:
./scripts/build.sh

.PHONY: upload
upload:
./scripts/upload.sh $(GCP_PROJECT_ID)

.PHONY: build-and-upload
build-and-upload: build upload
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 @@ -212,6 +212,10 @@
"syscall": "madvise",
"comment": "Used by the VirtIO balloon device and by musl for some customer workloads. It is also used by aws-lc during random number generation. They setup a memory page that mark with MADV_WIPEONFORK to be able to detect forks. They also call it with -1 to see if madvise is supported in certain platforms."
},
{
"syscall": "mincore",
"comment": "Used by get_memory_dirty_bitmap to check if memory pages are resident"
},
{
"syscall": "mmap",
"comment": "Used by the VirtIO balloon device",
Expand Down
10 changes: 7 additions & 3 deletions resources/seccomp/x86_64-unknown-linux-musl.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@
"syscall": "madvise",
"comment": "Used by the VirtIO balloon device and by musl for some customer workloads. It is also used by aws-lc during random number generation. They setup a memory page that mark with MADV_WIPEONFORK to be able to detect forks. They also call it with -1 to see if madvise is supported in certain platforms."
},
{
"syscall": "mincore",
"comment": "Used by get_memory_dirty_bitmap to check if memory pages are resident"
},
{
"syscall": "mmap",
"comment": "Used by the VirtIO balloon device",
Expand Down Expand Up @@ -524,8 +528,8 @@
"comment": "sigaltstack is used by Rust stdlib to remove alternative signal stack during thread teardown."
},
{
"syscall": "getrandom",
"comment": "getrandom is used by `HttpServer` to reinialize `HashMap` after moving to the API thread"
"syscall": "getrandom",
"comment": "getrandom is used by `HttpServer` to reinialize `HashMap` after moving to the API thread"
},
{
"syscall": "accept4",
Expand Down Expand Up @@ -1152,4 +1156,4 @@
}
]
}
}
}
17 changes: 17 additions & 0 deletions scripts/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

set -euo pipefail

# The format will be: v<major>.<minor>.<patch>_<commit_hash> — e.g. v1.7.2_8bb88311
# Extract full version from src/firecracker/swagger/firecracker.yaml
FC_VERSION=$(awk '/^info:/{flag=1} flag && /^ version:/{print $2; exit}' src/firecracker/swagger/firecracker.yaml)
commit_hash=$(git rev-parse --short=7 HEAD)
version_name="v${FC_VERSION}_${commit_hash}"
echo "Version name: $version_name"

echo "Starting to build Firecracker version: $version_name"
tools/devtool -y build --release

mkdir -p "./build/fc/${version_name}"
cp ./build/cargo_target/x86_64-unknown-linux-musl/release/firecracker "./build/fc/${version_name}/firecracker"
echo "Finished building Firecracker version: $version_name and copied to ./build/fc/${version_name}/firecracker"
13 changes: 13 additions & 0 deletions scripts/upload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

set -euo pipefail

GCP_PROJECT_ID=$1

gsutil -h "Cache-Control:no-cache, max-age=0" cp -r "build/fc/*" "gs://${GCP_PROJECT_ID}-fc-versions"
if [ "$GCP_PROJECT_ID" == "e2b-prod" ]; then
# Upload kernel to GCP public builds bucket
gsutil -h "Cache-Control:no-cache, max-age=0" cp -r "build/fc/*" "gs://${GCP_PROJECT_ID}-public-builds/firecrackers/"
fi

rm -rf build/fc/*
1 change: 1 addition & 0 deletions src/cpu-template-helper/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ pub fn build_microvm_from_config(
state: VmState::NotStarted,
vmm_version: CPU_TEMPLATE_HELPER_VERSION.to_string(),
app_name: "cpu-template-helper".to_string(),
memory_regions: None,
};
let mut vm_resources =
VmResources::from_json(&config, &instance_info, HTTP_MAX_PAYLOAD_SIZE, None)
Expand Down
4 changes: 2 additions & 2 deletions src/firecracker/src/api_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ mod tests {
Box::new(VmmAction::CreateSnapshot(CreateSnapshotParams {
snapshot_type: SnapshotType::Diff,
snapshot_path: PathBuf::new(),
mem_file_path: PathBuf::new(),
mem_file_path: Some(PathBuf::new()),
})),
start_time_us,
);
Expand All @@ -288,7 +288,7 @@ mod tests {
Box::new(VmmAction::CreateSnapshot(CreateSnapshotParams {
snapshot_type: SnapshotType::Diff,
snapshot_path: PathBuf::new(),
mem_file_path: PathBuf::new(),
mem_file_path: Some(PathBuf::new()),
})),
start_time_us,
);
Expand Down
50 changes: 50 additions & 0 deletions src/firecracker/src/api_server/parsed_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use super::request::logger::parse_put_logger;
use super::request::machine_configuration::{
parse_get_machine_config, parse_patch_machine_config, parse_put_machine_config,
};
use super::request::memory::{parse_get_memory, parse_get_memory_mappings};
use super::request::metrics::parse_put_metrics;
use super::request::mmds::{parse_get_mmds, parse_patch_mmds, parse_put_mmds};
use super::request::net::{parse_patch_net, parse_put_net};
Expand Down Expand Up @@ -82,6 +83,14 @@ impl TryFrom<&Request> for ParsedRequest {
Ok(ParsedRequest::new_sync(VmmAction::GetFullVmConfig))
}
(Method::Get, "machine-config", None) => parse_get_machine_config(),
(Method::Get, "memory", None) => match path_tokens.next() {
Some("mappings") => parse_get_memory_mappings(),
None => parse_get_memory(),
_ => Err(RequestError::InvalidPathMethod(
request_uri.to_string(),
Method::Get,
)),
},
(Method::Get, "mmds", None) => parse_get_mmds(),
(Method::Get, _, Some(_)) => method_to_error(Method::Get),
(Method::Put, "actions", Some(body)) => parse_put_actions(body),
Expand Down Expand Up @@ -172,6 +181,8 @@ impl ParsedRequest {
}
VmmData::BalloonStats(stats) => Self::success_response_with_data(stats),
VmmData::InstanceInformation(info) => Self::success_response_with_data(info),
VmmData::MemoryMappings(mappings) => Self::success_response_with_data(mappings),
VmmData::Memory(memory) => Self::success_response_with_data(memory),
VmmData::VmmVersion(version) => Self::success_response_with_data(
&serde_json::json!({ "firecracker_version": version.as_str() }),
),
Expand Down Expand Up @@ -568,6 +579,12 @@ pub mod tests {
VmmData::InstanceInformation(info) => {
http_response(&serde_json::to_string(info).unwrap(), 200)
}
VmmData::MemoryMappings(mappings) => {
http_response(&serde_json::to_string(mappings).unwrap(), 200)
}
VmmData::Memory(memory) => {
http_response(&serde_json::to_string(memory).unwrap(), 200)
}
VmmData::VmmVersion(version) => http_response(
&serde_json::json!({ "firecracker_version": version.as_str() }).to_string(),
200,
Expand All @@ -589,6 +606,15 @@ pub mod tests {
verify_ok_response_with(VmmData::MachineConfiguration(MachineConfig::default()));
verify_ok_response_with(VmmData::MmdsValue(serde_json::from_str("{}").unwrap()));
verify_ok_response_with(VmmData::InstanceInformation(InstanceInfo::default()));
verify_ok_response_with(VmmData::MemoryMappings(
vmm::vmm_config::instance_info::MemoryMappingsResponse { mappings: vec![] },
));
verify_ok_response_with(VmmData::Memory(
vmm::vmm_config::instance_info::MemoryResponse {
resident: vec![],
empty: vec![],
},
));
verify_ok_response_with(VmmData::VmmVersion(String::default()));

// Error.
Expand Down Expand Up @@ -662,6 +688,30 @@ pub mod tests {
ParsedRequest::try_from(&req).unwrap();
}

#[test]
fn test_try_from_get_memory_mappings() {
let (mut sender, receiver) = UnixStream::pair().unwrap();
let mut connection = HttpConnection::new(receiver);
sender
.write_all(http_request("GET", "/memory/mappings", None).as_bytes())
.unwrap();
connection.try_read().unwrap();
let req = connection.pop_parsed_request().unwrap();
ParsedRequest::try_from(&req).unwrap();
}

#[test]
fn test_try_from_get_memory() {
let (mut sender, receiver) = UnixStream::pair().unwrap();
let mut connection = HttpConnection::new(receiver);
sender
.write_all(http_request("GET", "/memory", None).as_bytes())
.unwrap();
connection.try_read().unwrap();
let req = connection.pop_parsed_request().unwrap();
ParsedRequest::try_from(&req).unwrap();
}

#[test]
fn test_try_from_get_version() {
let (mut sender, receiver) = UnixStream::pair().unwrap();
Expand Down
39 changes: 39 additions & 0 deletions src/firecracker/src/api_server/request/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use vmm::logger::{IncMetric, METRICS};
use vmm::rpc_interface::VmmAction;

use super::super::parsed_request::{ParsedRequest, RequestError};

pub(crate) fn parse_get_memory_mappings() -> Result<ParsedRequest, RequestError> {
METRICS.get_api_requests.instance_info_count.inc();
Ok(ParsedRequest::new_sync(VmmAction::GetMemoryMappings))
}

pub(crate) fn parse_get_memory() -> Result<ParsedRequest, RequestError> {
METRICS.get_api_requests.instance_info_count.inc();
Ok(ParsedRequest::new_sync(VmmAction::GetMemory))
}

#[cfg(test)]
mod tests {
use super::*;
use crate::api_server::parsed_request::RequestAction;

#[test]
fn test_parse_get_memory_mappings_request() {
match parse_get_memory_mappings().unwrap().into_parts() {
(RequestAction::Sync(action), _) if *action == VmmAction::GetMemoryMappings => {}
_ => panic!("Test failed."),
}
}

#[test]
fn test_parse_get_memory_request() {
match parse_get_memory().unwrap().into_parts() {
(RequestAction::Sync(action), _) if *action == VmmAction::GetMemory => {}
_ => panic!("Test failed."),
}
}
}
1 change: 1 addition & 0 deletions src/firecracker/src/api_server/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod entropy;
pub mod instance_info;
pub mod logger;
pub mod machine_configuration;
pub mod memory;
pub mod metrics;
pub mod mmds;
pub mod net;
Expand Down
4 changes: 2 additions & 2 deletions src/firecracker/src/api_server/request/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ mod tests {
let expected_config = CreateSnapshotParams {
snapshot_type: SnapshotType::Diff,
snapshot_path: PathBuf::from("foo"),
mem_file_path: PathBuf::from("bar"),
mem_file_path: Some(PathBuf::from("bar")),
};
assert_eq!(
vmm_action_from_request(parse_put_snapshot(&Body::new(body), Some("create")).unwrap()),
Expand All @@ -154,7 +154,7 @@ mod tests {
let expected_config = CreateSnapshotParams {
snapshot_type: SnapshotType::Full,
snapshot_path: PathBuf::from("foo"),
mem_file_path: PathBuf::from("bar"),
mem_file_path: Some(PathBuf::from("bar")),
};
assert_eq!(
vmm_action_from_request(parse_put_snapshot(&Body::new(body), Some("create")).unwrap()),
Expand Down
1 change: 1 addition & 0 deletions src/firecracker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ fn main_exec() -> Result<(), MainError> {
state: VmState::NotStarted,
vmm_version: FIRECRACKER_VERSION.to_string(),
app_name: "Firecracker".to_string(),
memory_regions: None,
};

if let Some(metrics_path) = arguments.single_value("metrics-path") {
Expand Down
83 changes: 82 additions & 1 deletion src/firecracker/swagger/firecracker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,35 @@ paths:
schema:
$ref: "#/definitions/Error"

/memory/mappings:
get:
summary: Gets the memory mappings with skippable pages bitmap.
operationId: getMemoryMappings
responses:
200:
description: OK
schema:
$ref: "#/definitions/MemoryMappingsResponse"
default:
description: Internal server error
schema:
$ref: "#/definitions/Error"

/memory:
get:
summary: Gets the memory info (resident and empty pages).
description: Returns an object with resident and empty bitmaps. The resident bitmap marks all pages that are resident. The empty bitmap marks zero pages (subset of resident pages). This is checked at the pageSize of each region. All regions must have the same page size.
operationId: getMemory
responses:
200:
description: OK
schema:
$ref: "#/definitions/MemoryResponse"
default:
description: Internal server error
schema:
$ref: "#/definitions/Error"

/version:
get:
summary: Gets the Firecracker version.
Expand Down Expand Up @@ -997,6 +1026,59 @@ definitions:
description: MicroVM hypervisor build version.
type: string

GuestMemoryRegionMapping:
type: object
description: Describes the region of guest memory that can be used for creating the memfile.
required:
- base_host_virt_addr
- size
- offset
- page_size
properties:
base_host_virt_addr:
type: integer
size:
description: The size of the region in bytes.
type: integer
offset:
description: The offset of the region in bytes.
type: integer
page_size:
description: The page size in bytes.
type: integer

MemoryMappingsResponse:
type: object
description: Response containing memory region mappings.
required:
- mappings
properties:
mappings:
type: array
description: The memory region mappings.
items:
$ref: "#/definitions/GuestMemoryRegionMapping"

MemoryResponse:
type: object
description: Response containing the memory info (resident and empty pages).
required:
- resident
- empty
properties:
resident:
type: array
description: The resident bitmap as a vector of u64 values. Each bit represents if the page is resident.
items:
type: integer
format: uint64
empty:
type: array
description: The empty bitmap as a vector of u64 values. Each bit represents if the page is zero (empty). This is a subset of the resident pages.
items:
type: integer
format: uint64

Logger:
type: object
description:
Expand Down Expand Up @@ -1198,7 +1280,6 @@ definitions:
SnapshotCreateParams:
type: object
required:
- mem_file_path
- snapshot_path
properties:
mem_file_path:
Expand Down
Loading