Skip to content

Commit deb145b

Browse files
committed
virtio-balloon: Add api for free page hinting
Adding API endpoints to manage free page hinting . With three different endpoint: Start - To begin a new run for free page hinting, Status - To track the state of the hinting run, Stop - To stop the hinting run and allow the guest to reclaim the pages reported. Signed-off-by: Jack Thomson <jackabt@amazon.com>
1 parent d11864a commit deb145b

File tree

5 files changed

+353
-44
lines changed

5 files changed

+353
-44
lines changed

src/firecracker/src/api_server/parsed_request.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl TryFrom<&Request> for ParsedRequest {
7878

7979
match (request.method(), path, request.body.as_ref()) {
8080
(Method::Get, "", None) => parse_get_instance_info(),
81-
(Method::Get, "balloon", None) => parse_get_balloon(path_tokens.next()),
81+
(Method::Get, "balloon", None) => parse_get_balloon(path_tokens),
8282
(Method::Get, "version", None) => parse_get_version(),
8383
(Method::Get, "vm", None) if path_tokens.next() == Some("config") => {
8484
Ok(ParsedRequest::new_sync(VmmAction::GetFullVmConfig))
@@ -104,7 +104,7 @@ impl TryFrom<&Request> for ParsedRequest {
104104
(Method::Put, "vsock", Some(body)) => parse_put_vsock(body),
105105
(Method::Put, "entropy", Some(body)) => parse_put_entropy(body),
106106
(Method::Put, _, None) => method_to_error(Method::Put),
107-
(Method::Patch, "balloon", Some(body)) => parse_patch_balloon(body, path_tokens.next()),
107+
(Method::Patch, "balloon", body) => parse_patch_balloon(body, path_tokens),
108108
(Method::Patch, "drives", Some(body)) => parse_patch_drive(body, path_tokens.next()),
109109
(Method::Patch, "machine-config", Some(body)) => parse_patch_machine_config(body),
110110
(Method::Patch, "mmds", Some(body)) => parse_patch_mmds(body),
@@ -175,6 +175,9 @@ impl ParsedRequest {
175175
Self::success_response_with_data(balloon_config)
176176
}
177177
VmmData::BalloonStats(stats) => Self::success_response_with_data(stats),
178+
VmmData::HintingStatus(hinting_status) => {
179+
Self::success_response_with_data(hinting_status)
180+
}
178181
VmmData::InstanceInformation(info) => Self::success_response_with_data(info),
179182
VmmData::VmmVersion(version) => Self::success_response_with_data(
180183
&serde_json::json!({ "firecracker_version": version.as_str() }),
@@ -474,6 +477,17 @@ pub mod tests {
474477
&parsed_request,
475478
Err(RequestError::Generic(StatusCode::BadRequest, s)) if s == "Empty PATCH request.",
476479
));
480+
481+
sender
482+
.write_all(http_request("PATCH", "/balloon", None).as_bytes())
483+
.unwrap();
484+
connection.try_read().unwrap();
485+
let req = connection.pop_parsed_request().unwrap();
486+
let parsed_request = ParsedRequest::try_from(&req);
487+
assert!(matches!(
488+
&parsed_request,
489+
Err(RequestError::Generic(StatusCode::BadRequest, s)) if s == "Empty PATCH request.",
490+
));
477491
}
478492

479493
#[test]
@@ -559,6 +573,9 @@ pub mod tests {
559573
VmmData::BalloonStats(stats) => {
560574
http_response(&serde_json::to_string(stats).unwrap(), 200)
561575
}
576+
VmmData::HintingStatus(status) => {
577+
http_response(&serde_json::to_string(status).unwrap(), 200)
578+
}
562579
VmmData::Empty => http_response("", 204),
563580
VmmData::FullVmConfig(cfg) => {
564581
http_response(&serde_json::to_string(cfg).unwrap(), 200)
@@ -642,6 +659,18 @@ pub mod tests {
642659
ParsedRequest::try_from(&req).unwrap();
643660
}
644661

662+
#[test]
663+
fn test_try_from_get_balloon_hinting() {
664+
let (mut sender, receiver) = UnixStream::pair().unwrap();
665+
let mut connection = HttpConnection::new(receiver);
666+
sender
667+
.write_all(http_request("GET", "/balloon/hinting/status", None).as_bytes())
668+
.unwrap();
669+
connection.try_read().unwrap();
670+
let req = connection.pop_parsed_request().unwrap();
671+
ParsedRequest::try_from(&req).unwrap();
672+
}
673+
645674
#[test]
646675
fn test_try_from_get_machine_config() {
647676
let (mut sender, receiver) = UnixStream::pair().unwrap();
@@ -910,13 +939,52 @@ pub mod tests {
910939
connection.try_read().unwrap();
911940
let req = connection.pop_parsed_request().unwrap();
912941
ParsedRequest::try_from(&req).unwrap();
942+
913943
let body = "{ \"stats_polling_interval_s\": 1 }";
914944
sender
915945
.write_all(http_request("PATCH", "/balloon/statistics", Some(body)).as_bytes())
916946
.unwrap();
917947
connection.try_read().unwrap();
918948
let req = connection.pop_parsed_request().unwrap();
919949
ParsedRequest::try_from(&req).unwrap();
950+
951+
let body = "{ \"acknowledge_on_stop\": true }";
952+
sender
953+
.write_all(http_request("PATCH", "/balloon/hinting/start", Some(body)).as_bytes())
954+
.unwrap();
955+
connection.try_read().unwrap();
956+
let req = connection.pop_parsed_request().unwrap();
957+
ParsedRequest::try_from(&req).unwrap();
958+
959+
let body = "{}";
960+
sender
961+
.write_all(http_request("PATCH", "/balloon/hinting/start", Some(body)).as_bytes())
962+
.unwrap();
963+
connection.try_read().unwrap();
964+
let req = connection.pop_parsed_request().unwrap();
965+
ParsedRequest::try_from(&req).unwrap();
966+
967+
sender
968+
.write_all(http_request("PATCH", "/balloon/hinting/start", None).as_bytes())
969+
.unwrap();
970+
connection.try_read().unwrap();
971+
let req = connection.pop_parsed_request().unwrap();
972+
ParsedRequest::try_from(&req).unwrap();
973+
974+
let body = "";
975+
sender
976+
.write_all(http_request("PATCH", "/balloon/hinting/stop", Some(body)).as_bytes())
977+
.unwrap();
978+
connection.try_read().unwrap();
979+
let req = connection.pop_parsed_request().unwrap();
980+
ParsedRequest::try_from(&req).unwrap();
981+
982+
sender
983+
.write_all(http_request("PATCH", "/balloon/hinting/stop", None).as_bytes())
984+
.unwrap();
985+
connection.try_read().unwrap();
986+
let req = connection.pop_parsed_request().unwrap();
987+
ParsedRequest::try_from(&req).unwrap();
920988
}
921989

922990
#[test]

0 commit comments

Comments
 (0)