diff --git a/Cargo.lock b/Cargo.lock index f8c984286cd..6980b5eec3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,7 @@ name = "api_server" version = "0.1.0" dependencies = [ "libc", + "log", "logger", "micro_http", "mmds", @@ -114,6 +115,7 @@ dependencies = [ "serde_derive", "serde_json", "thiserror", + "tracing", "utils", "vmm", ] @@ -191,7 +193,7 @@ version = "0.66.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "cexpr", "clang-sys", "lazy_static", @@ -216,9 +218,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "byteorder" @@ -379,6 +381,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tracing", "utils", "vmm", ] @@ -477,6 +480,7 @@ dependencies = [ "logger", "micro_http", "serde_json", + "tracing", "utils", ] @@ -537,6 +541,7 @@ dependencies = [ "cargo_toml", "event-manager", "libc", + "log", "logger", "mmds", "regex", @@ -546,6 +551,8 @@ dependencies = [ "snapshot", "thiserror", "timerfd", + "tracing", + "tracing-subscriber", "userfaultfd 0.6.0", "utils", "vmm", @@ -649,7 +656,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.4", + "rustix 0.38.8", "windows-sys", ] @@ -676,6 +683,7 @@ dependencies = [ "nix", "regex", "thiserror", + "tracing", "utils", ] @@ -751,9 +759,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "log" @@ -774,6 +782,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tracing", "utils", "vm-superio", ] @@ -829,6 +838,7 @@ dependencies = [ "serde_json", "snapshot", "thiserror", + "tracing", "utils", "versionize", "versionize_derive", @@ -862,6 +872,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -890,6 +910,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "paste" version = "1.0.14" @@ -902,6 +928,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pin-project-lite" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" + [[package]] name = "pin-utils" version = "0.1.0" @@ -1016,6 +1048,7 @@ version = "1.5.0-dev" dependencies = [ "libc", "thiserror", + "tracing", "utils", ] @@ -1076,14 +1109,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys 0.4.5", "windows-sys", ] @@ -1111,6 +1144,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tracing", "utils", ] @@ -1163,12 +1197,27 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + [[package]] name = "snapshot" version = "0.1.0" @@ -1176,6 +1225,7 @@ dependencies = [ "criterion", "libc", "thiserror", + "tracing", "versionize", "versionize_derive", ] @@ -1240,6 +1290,16 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "timerfd" version = "1.5.0" @@ -1293,6 +1353,75 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-flame" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bae117ee14789185e129aaee5d93750abe67fdc5a9a62650452bfe4e122a3a9" +dependencies = [ + "lazy_static", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + [[package]] name = "typenum" version = "1.16.0" @@ -1347,7 +1476,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ec82f2a09c9279eb320bd9945f0df0232613d4621c093d8ba02edcb45624fd4" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "cfg-if", "libc", "nix", @@ -1382,12 +1511,19 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tracing", "versionize", "versionize_derive", "vm-memory", "vmm-sys-util", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -1463,7 +1599,7 @@ name = "vmm" version = "0.1.0" dependencies = [ "aws-lc-rs", - "bitflags 2.3.3", + "bitflags 2.4.0", "criterion", "derive_more", "device_tree", @@ -1486,6 +1622,9 @@ dependencies = [ "snapshot", "thiserror", "timerfd", + "tracing", + "tracing-flame", + "tracing-subscriber", "userfaultfd 0.5.1", "utils", "versionize", diff --git a/src/api_server/Cargo.toml b/src/api_server/Cargo.toml index cd29a75c58e..c8b233dfe72 100644 --- a/src/api_server/Cargo.toml +++ b/src/api_server/Cargo.toml @@ -21,6 +21,8 @@ mmds = { path = "../mmds" } seccompiler = { path = "../seccompiler" } utils = { path = "../utils" } vmm = { path = "../vmm" } +tracing = { version = "0.1.37", features = ["max_level_debug"] } [dev-dependencies] libc = "0.2.117" +log = "0.4.19" \ No newline at end of file diff --git a/src/api_server/src/lib.rs b/src/api_server/src/lib.rs index 2852705f8c2..0e24e11ba34 100644 --- a/src/api_server/src/lib.rs +++ b/src/api_server/src/lib.rs @@ -43,6 +43,10 @@ pub struct ApiServer { } impl ApiServer { + #[tracing::instrument( + level = "trace", + skip(api_request_sender, vmm_response_receiver, to_vmm_fd) + )] /// Constructor for `ApiServer`. /// /// Returns the newly formed `ApiServer`. @@ -59,6 +63,10 @@ impl ApiServer { } } + #[tracing::instrument( + level = "trace", + skip(self, server, process_time_reporter, seccomp_filter, api_payload_limit) + )] /// Runs the Api Server. /// /// # Arguments @@ -128,6 +136,7 @@ impl ApiServer { } } + #[tracing::instrument(level = "trace", skip(self, request, request_processing_start_us))] /// Handles an API request received through the associated socket. pub fn handle_request( &mut self, @@ -158,6 +167,7 @@ impl ApiServer { } } + #[tracing::instrument(level = "trace", skip(self, vmm_action, request_processing_start_us))] fn serve_vmm_action_request( &mut self, vmm_action: Box, @@ -199,6 +209,7 @@ impl ApiServer { response } + #[tracing::instrument(level = "trace", skip(status, body))] /// An HTTP response which also includes a body. pub(crate) fn json_response + Debug>(status: StatusCode, body: T) -> Response { let mut response = Response::new(Version::Http11, status); @@ -206,6 +217,7 @@ impl ApiServer { response } + #[tracing::instrument(level = "trace", skip(msg))] fn json_fault_message + serde::Serialize + Debug>(msg: T) -> String { json!({ "fault_message": msg }).to_string() } diff --git a/src/api_server/src/parsed_request.rs b/src/api_server/src/parsed_request.rs index 12eacb24bc0..57c0b342108 100644 --- a/src/api_server/src/parsed_request.rs +++ b/src/api_server/src/parsed_request.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; -use logger::{error, info, log_enabled, Level}; +use logger::{error, info, Level}; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use serde::ser::Serialize; use serde_json::Value; @@ -41,6 +41,7 @@ pub(crate) struct ParsingInfo { } impl ParsingInfo { + #[tracing::instrument(level = "trace", skip(self, message))] pub fn append_deprecation_message(&mut self, message: &str) { match self.deprecation_message.as_mut() { None => self.deprecation_message = Some(message.to_owned()), @@ -48,6 +49,7 @@ impl ParsingInfo { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn take_deprecation_message(&mut self) -> Option { self.deprecation_message.take() } @@ -61,6 +63,7 @@ pub(crate) struct ParsedRequest { impl TryFrom<&Request> for ParsedRequest { type Error = Error; + #[tracing::instrument(level = "trace", skip(request))] fn try_from(request: &Request) -> Result { let request_uri = request.uri().get_abs_path().to_string(); log_received_api_request(describe( @@ -121,6 +124,7 @@ impl TryFrom<&Request> for ParsedRequest { } impl ParsedRequest { + #[tracing::instrument(level = "trace", skip(action))] pub(crate) fn new(action: RequestAction) -> Self { Self { action, @@ -128,14 +132,17 @@ impl ParsedRequest { } } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn into_parts(self) -> (RequestAction, ParsingInfo) { (self.action, self.parsing_info) } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn parsing_info(&mut self) -> &mut ParsingInfo { &mut self.parsing_info } + #[tracing::instrument(level = "trace", skip(body_data))] pub(crate) fn success_response_with_data(body_data: &T) -> Response where T: ?Sized + Serialize + Debug, @@ -146,6 +153,7 @@ impl ParsedRequest { response } + #[tracing::instrument(level = "trace", skip(body_data))] pub(crate) fn success_response_with_mmds_value(body_data: &Value) -> Response { info!("The request was executed successfully. Status code: 200 OK."); let mut response = Response::new(Version::Http11, StatusCode::OK); @@ -157,6 +165,7 @@ impl ParsedRequest { response } + #[tracing::instrument(level = "trace", skip(request_outcome))] pub(crate) fn convert_to_response( request_outcome: &std::result::Result, ) -> Response { @@ -205,12 +214,14 @@ impl ParsedRequest { } } + #[tracing::instrument(level = "trace", skip(vmm_action))] /// Helper function to avoid boiler-plate code. pub(crate) fn new_sync(vmm_action: VmmAction) -> ParsedRequest { ParsedRequest::new(RequestAction::Sync(Box::new(vmm_action))) } } +#[tracing::instrument(level = "trace", skip(api_description))] /// Helper function for writing the received API requests to the log. /// /// The `info` macro is used for logging. @@ -219,6 +230,7 @@ fn log_received_api_request(api_description: String) { info!("The API server received a {}.", api_description); } +#[tracing::instrument(level = "trace", skip(method, path, body))] /// Helper function for metric-logging purposes on API requests. /// /// # Arguments @@ -232,7 +244,7 @@ fn describe(method: Method, path: &str, body: Option<&Body>) -> String { ("/cpu-config", Some(payload_value)) => { // If the log level is at Debug or higher, include the CPU template in // the log line. - if log_enabled!(Level::Debug) { + if tracing::enabled!(Level::DEBUG) { describe_with_body(method, path, payload_value) } else { format!( @@ -246,6 +258,7 @@ fn describe(method: Method, path: &str, body: Option<&Body>) -> String { } } +#[tracing::instrument(level = "trace", skip(method, path, payload_value))] fn describe_with_body(method: Method, path: &str, payload_value: &Body) -> String { format!( "{:?} request on {:?} with body {:?}", @@ -257,6 +270,7 @@ fn describe_with_body(method: Method, path: &str, payload_value: &Body) -> Strin ) } +#[tracing::instrument(level = "trace", skip(method))] /// Generates a `GenericError` for each request method. pub(crate) fn method_to_error(method: Method) -> Result { match method { @@ -296,6 +310,7 @@ pub(crate) enum Error { // It's convenient to turn errors into HTTP responses directly. impl From for Response { + #[tracing::instrument(level = "trace", skip(err))] fn from(err: Error) -> Self { let msg = ApiServer::json_fault_message(format!("{}", err)); match err { @@ -309,6 +324,7 @@ impl From for Response { } // This function is supposed to do id validation for requests. +#[tracing::instrument(level = "trace", skip(id))] pub(crate) fn checked_id(id: &str) -> Result<&str, Error> { // todo: are there any checks we want to do on id's? // not allow them to be empty strings maybe? @@ -341,6 +357,7 @@ pub mod tests { use super::*; impl PartialEq for ParsedRequest { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &ParsedRequest) -> bool { if self.parsing_info.deprecation_message != other.parsing_info.deprecation_message { return false; @@ -355,6 +372,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(req))] pub(crate) fn vmm_action_from_request(req: ParsedRequest) -> VmmAction { match req.action { RequestAction::Sync(vmm_action) => *vmm_action, @@ -362,6 +380,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(req, msg))] pub(crate) fn depr_action_from_req(req: ParsedRequest, msg: Option) -> VmmAction { let (action_req, mut parsing_info) = req.into_parts(); match action_req { @@ -375,6 +394,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(body, status_code))] fn http_response(body: &str, status_code: i32) -> String { let header = format!( "HTTP/1.1 {} \r\nServer: Firecracker API\r\nConnection: keep-alive\r\n", @@ -394,6 +414,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(request_type, endpoint, body))] fn http_request(request_type: &str, endpoint: &str, body: Option<&str>) -> String { let req_no_body = format!( "{} {} HTTP/1.1\r\nContent-Type: application/json\r\n", diff --git a/src/api_server/src/request/actions.rs b/src/api_server/src/request/actions.rs index 5e9eb6df0aa..ac95847d4c7 100644 --- a/src/api_server/src/request/actions.rs +++ b/src/api_server/src/request/actions.rs @@ -28,6 +28,7 @@ struct ActionBody { action_type: ActionType, } +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_actions(body: &Body) -> Result { METRICS.put_api_requests.actions_count.inc(); let action_body = serde_json::from_slice::(body.raw()).map_err(|err| { diff --git a/src/api_server/src/request/balloon.rs b/src/api_server/src/request/balloon.rs index 7b98f796ec2..abbc99e2fb5 100644 --- a/src/api_server/src/request/balloon.rs +++ b/src/api_server/src/request/balloon.rs @@ -10,6 +10,7 @@ use super::super::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(path_second_token))] pub(crate) fn parse_get_balloon(path_second_token: Option<&str>) -> Result { match path_second_token { Some(stats_path) => match stats_path { @@ -23,12 +24,14 @@ pub(crate) fn parse_get_balloon(path_second_token: Option<&str>) -> Result Result { Ok(ParsedRequest::new_sync(VmmAction::SetBalloonDevice( serde_json::from_slice::(body.raw())?, ))) } +#[tracing::instrument(level = "trace", skip(body, path_second_token))] pub(crate) fn parse_patch_balloon( body: &Body, path_second_token: Option<&str>, diff --git a/src/api_server/src/request/boot_source.rs b/src/api_server/src/request/boot_source.rs index 9360307dc27..3192aa6902b 100644 --- a/src/api_server/src/request/boot_source.rs +++ b/src/api_server/src/request/boot_source.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_boot_source(body: &Body) -> Result { METRICS.put_api_requests.boot_source_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::ConfigureBootSource( diff --git a/src/api_server/src/request/cpu_configuration.rs b/src/api_server/src/request/cpu_configuration.rs index e1f39b46454..781335a7f0f 100644 --- a/src/api_server/src/request/cpu_configuration.rs +++ b/src/api_server/src/request/cpu_configuration.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_cpu_config(body: &Body) -> Result { METRICS.put_api_requests.cpu_cfg_count.inc(); diff --git a/src/api_server/src/request/drive.rs b/src/api_server/src/request/drive.rs index 88c5ab5c7fd..de88f84dfc9 100644 --- a/src/api_server/src/request/drive.rs +++ b/src/api_server/src/request/drive.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{checked_id, Error, ParsedRequest}; use crate::request::{Body, StatusCode}; +#[tracing::instrument(level = "trace", skip(body, id_from_path))] pub(crate) fn parse_put_drive( body: &Body, id_from_path: Option<&str>, @@ -38,6 +39,7 @@ pub(crate) fn parse_put_drive( } } +#[tracing::instrument(level = "trace", skip(body, id_from_path))] pub(crate) fn parse_patch_drive( body: &Body, id_from_path: Option<&str>, diff --git a/src/api_server/src/request/entropy.rs b/src/api_server/src/request/entropy.rs index e27b53e06fe..55be6d236ba 100644 --- a/src/api_server/src/request/entropy.rs +++ b/src/api_server/src/request/entropy.rs @@ -7,6 +7,7 @@ use vmm::vmm_config::entropy::EntropyDeviceConfig; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_entropy(body: &Body) -> Result { let cfg = serde_json::from_slice::(body.raw())?; Ok(ParsedRequest::new_sync(VmmAction::SetEntropyDevice(cfg))) diff --git a/src/api_server/src/request/instance_info.rs b/src/api_server/src/request/instance_info.rs index c39034f6fc2..06768d32827 100644 --- a/src/api_server/src/request/instance_info.rs +++ b/src/api_server/src/request/instance_info.rs @@ -6,6 +6,7 @@ use vmm::rpc_interface::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; +#[tracing::instrument(level = "trace", skip())] pub(crate) fn parse_get_instance_info() -> Result { METRICS.get_api_requests.instance_info_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::GetVmInstanceInfo)) diff --git a/src/api_server/src/request/logger.rs b/src/api_server/src/request/logger.rs index 9e386b00e81..d1ff0dbadf4 100644 --- a/src/api_server/src/request/logger.rs +++ b/src/api_server/src/request/logger.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_logger(body: &Body) -> Result { METRICS.put_api_requests.logger_count.inc(); let res = serde_json::from_slice::(body.raw()); @@ -22,7 +23,7 @@ pub(crate) fn parse_put_logger(body: &Body) -> Result { mod tests { use std::path::PathBuf; - use vmm::vmm_config::logger::LoggerLevel; + use vmm::vmm_config::logger::LevelFilter; use super::*; use crate::parsed_request::tests::vmm_action_from_request; @@ -37,10 +38,12 @@ mod tests { }"#; let mut expected_cfg = LoggerConfig { - log_path: PathBuf::from("log"), - level: LoggerLevel::Warning, - show_level: false, - show_log_origin: false, + log_path: Some(PathBuf::from("log")), + level: Some(LevelFilter::Warn), + show_level: Some(false), + show_log_origin: Some(false), + filter: None, + profile_path: None, }; match vmm_action_from_request(parse_put_logger(&Body::new(body)).unwrap()) { VmmAction::ConfigureLogger(cfg) => assert_eq!(cfg, expected_cfg), @@ -55,10 +58,12 @@ mod tests { }"#; expected_cfg = LoggerConfig { - log_path: PathBuf::from("log"), - level: LoggerLevel::Debug, - show_level: false, - show_log_origin: false, + log_path: Some(PathBuf::from("log")), + level: Some(LevelFilter::Debug), + show_level: Some(false), + show_log_origin: Some(false), + filter: None, + profile_path: None, }; match vmm_action_from_request(parse_put_logger(&Body::new(body)).unwrap()) { VmmAction::ConfigureLogger(cfg) => assert_eq!(cfg, expected_cfg), diff --git a/src/api_server/src/request/machine_configuration.rs b/src/api_server/src/request/machine_configuration.rs index 44cd042a541..72f90b9057b 100644 --- a/src/api_server/src/request/machine_configuration.rs +++ b/src/api_server/src/request/machine_configuration.rs @@ -8,11 +8,13 @@ use super::super::VmmAction; use crate::parsed_request::{method_to_error, Error, ParsedRequest}; use crate::request::{Body, Method}; +#[tracing::instrument(level = "trace", skip())] pub(crate) fn parse_get_machine_config() -> Result { METRICS.get_api_requests.machine_cfg_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::GetVmMachineConfig)) } +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_machine_config(body: &Body) -> Result { METRICS.put_api_requests.machine_cfg_count.inc(); let config = serde_json::from_slice::(body.raw()).map_err(|err| { @@ -27,6 +29,7 @@ pub(crate) fn parse_put_machine_config(body: &Body) -> Result Result { METRICS.patch_api_requests.machine_cfg_count.inc(); let config_update = diff --git a/src/api_server/src/request/metrics.rs b/src/api_server/src/request/metrics.rs index 57b4f2f9d66..5f7933b038a 100644 --- a/src/api_server/src/request/metrics.rs +++ b/src/api_server/src/request/metrics.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_metrics(body: &Body) -> Result { METRICS.put_api_requests.metrics_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::ConfigureMetrics( diff --git a/src/api_server/src/request/mmds.rs b/src/api_server/src/request/mmds.rs index b13862996f0..13e2de2fb94 100644 --- a/src/api_server/src/request/mmds.rs +++ b/src/api_server/src/request/mmds.rs @@ -10,11 +10,13 @@ use vmm::vmm_config::mmds::MmdsConfig; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip())] pub(crate) fn parse_get_mmds() -> Result { METRICS.get_api_requests.mmds_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::GetMMDS)) } +#[tracing::instrument(level = "trace", skip(body))] fn parse_put_mmds_config(body: &Body) -> Result { let config: MmdsConfig = serde_json::from_slice(body.raw()).map_err(|err| { METRICS.put_api_requests.mmds_fails.inc(); @@ -35,6 +37,7 @@ fn parse_put_mmds_config(body: &Body) -> Result { Ok(parsed_request) } +#[tracing::instrument(level = "trace", skip(body, path_second_token))] pub(crate) fn parse_put_mmds( body: &Body, path_second_token: Option<&str>, @@ -58,6 +61,7 @@ pub(crate) fn parse_put_mmds( } } +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_patch_mmds(body: &Body) -> Result { METRICS.patch_api_requests.mmds_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::PatchMMDS( diff --git a/src/api_server/src/request/net.rs b/src/api_server/src/request/net.rs index 4232ec6cb9b..acdaf85c105 100644 --- a/src/api_server/src/request/net.rs +++ b/src/api_server/src/request/net.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{checked_id, Error, ParsedRequest}; use crate::request::{Body, StatusCode}; +#[tracing::instrument(level = "trace", skip(body, id_from_path))] pub(crate) fn parse_put_net( body: &Body, id_from_path: Option<&str>, @@ -40,6 +41,7 @@ pub(crate) fn parse_put_net( ))) } +#[tracing::instrument(level = "trace", skip(body, id_from_path))] pub(crate) fn parse_patch_net( body: &Body, id_from_path: Option<&str>, diff --git a/src/api_server/src/request/snapshot.rs b/src/api_server/src/request/snapshot.rs index 3563c85f9b9..be27d5cd0fb 100644 --- a/src/api_server/src/request/snapshot.rs +++ b/src/api_server/src/request/snapshot.rs @@ -22,6 +22,7 @@ pub const MISSING_FIELD: &str = pub const TOO_MANY_FIELDS: &str = "too many fields: either `mem_backend` or `mem_file_path` exclusively is required"; +#[tracing::instrument(level = "trace", skip(body, request_type_from_path))] pub(crate) fn parse_put_snapshot( body: &Body, request_type_from_path: Option<&str>, @@ -44,6 +45,7 @@ pub(crate) fn parse_put_snapshot( } } +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_patch_vm_state(body: &Body) -> Result { let vm = serde_json::from_slice::(body.raw())?; @@ -53,6 +55,7 @@ pub(crate) fn parse_patch_vm_state(body: &Body) -> Result } } +#[tracing::instrument(level = "trace", skip(body))] fn parse_put_snapshot_load(body: &Body) -> Result { let snapshot_config = serde_json::from_slice::(body.raw())?; diff --git a/src/api_server/src/request/version.rs b/src/api_server/src/request/version.rs index 19f2ab942ff..6196a780b46 100644 --- a/src/api_server/src/request/version.rs +++ b/src/api_server/src/request/version.rs @@ -6,6 +6,7 @@ use vmm::rpc_interface::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; +#[tracing::instrument(level = "trace", skip())] pub(crate) fn parse_get_version() -> Result { METRICS.get_api_requests.vmm_version_count.inc(); Ok(ParsedRequest::new_sync(VmmAction::GetVmmVersion)) diff --git a/src/api_server/src/request/vsock.rs b/src/api_server/src/request/vsock.rs index 8203c44d74e..9b01066e696 100644 --- a/src/api_server/src/request/vsock.rs +++ b/src/api_server/src/request/vsock.rs @@ -8,6 +8,7 @@ use super::super::VmmAction; use crate::parsed_request::{Error, ParsedRequest}; use crate::request::Body; +#[tracing::instrument(level = "trace", skip(body))] pub(crate) fn parse_put_vsock(body: &Body) -> Result { METRICS.put_api_requests.vsock_count.inc(); let vsock_cfg = serde_json::from_slice::(body.raw()).map_err(|err| { diff --git a/src/cpu-template-helper/Cargo.toml b/src/cpu-template-helper/Cargo.toml index 9be03d9c608..8725af9088a 100644 --- a/src/cpu-template-helper/Cargo.toml +++ b/src/cpu-template-helper/Cargo.toml @@ -17,6 +17,7 @@ libc = "0.2.147" serde = { version = "1.0.183", features = ["derive"] } serde_json = "1.0.104" thiserror = "1.0.44" +tracing = { version = "0.1.37", features = ["max_level_debug"] } vmm = { path = "../vmm" } diff --git a/src/cpu-template-helper/src/fingerprint/compare.rs b/src/cpu-template-helper/src/fingerprint/compare.rs index 2140f14e9f2..44fd74a712a 100644 --- a/src/cpu-template-helper/src/fingerprint/compare.rs +++ b/src/cpu-template-helper/src/fingerprint/compare.rs @@ -22,6 +22,7 @@ struct Diff<'a, T: Serialize> { curr: &'a T, } +#[tracing::instrument(level = "trace", skip(prev, curr, filters))] pub fn compare( prev: Fingerprint, curr: Fingerprint, @@ -98,6 +99,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip())] fn build_sample_fingerprint() -> Fingerprint { Fingerprint { firecracker_version: crate::utils::CPU_TEMPLATE_HELPER_VERSION.to_string(), diff --git a/src/cpu-template-helper/src/fingerprint/dump.rs b/src/cpu-template-helper/src/fingerprint/dump.rs index 6563d1e1a9a..902f4bf7b13 100644 --- a/src/cpu-template-helper/src/fingerprint/dump.rs +++ b/src/cpu-template-helper/src/fingerprint/dump.rs @@ -24,6 +24,7 @@ pub enum FingerprintDumpError { ShellCommand(String, String), } +#[tracing::instrument(level = "trace", skip(vmm))] pub fn dump(vmm: Arc>) -> Result { Ok(Fingerprint { firecracker_version: crate::utils::CPU_TEMPLATE_HELPER_VERSION.to_string(), @@ -46,6 +47,7 @@ pub fn dump(vmm: Arc>) -> Result { }) } +#[tracing::instrument(level = "trace", skip())] fn get_kernel_version() -> Result { // SAFETY: An all-zeroed value for `libc::utsname` is valid. let mut name: libc::utsname = unsafe { std::mem::zeroed() }; @@ -65,12 +67,14 @@ fn get_kernel_version() -> Result { Ok(version.to_string()) } +#[tracing::instrument(level = "trace", skip(path))] fn read_sysfs_file(path: &str) -> Result { let s = read_to_string(path) .map_err(|err| FingerprintDumpError::ReadSysfsFile(path.to_string(), err))?; Ok(s.trim_end_matches('\n').to_string()) } +#[tracing::instrument(level = "trace", skip(cmd))] fn run_shell_command(cmd: &str) -> Result { let output = std::process::Command::new("bash") .args(["-c", cmd]) diff --git a/src/cpu-template-helper/src/main.rs b/src/cpu-template-helper/src/main.rs index d694aecb7fe..d0217dce045 100644 --- a/src/cpu-template-helper/src/main.rs +++ b/src/cpu-template-helper/src/main.rs @@ -111,12 +111,13 @@ enum FingerprintOperation { }, } +#[tracing::instrument(level = "trace", skip(cli))] fn run(cli: Cli) -> Result<(), HelperError> { match cli.command { Command::Template(op) => match op { TemplateOperation::Dump { config, output } => { let config = read_to_string(config)?; - let (vmm, _) = utils::build_microvm_from_config(&config)?; + let ((vmm, _), _flame_guard) = utils::build_microvm_from_config(&config)?; let cpu_config = template::dump::dump(vmm)?; @@ -141,7 +142,8 @@ fn run(cli: Cli) -> Result<(), HelperError> { } TemplateOperation::Verify { config } => { let config = read_to_string(config)?; - let (vmm, vm_resources) = utils::build_microvm_from_config(&config)?; + let ((vmm, vm_resources), _flame_guard) = + utils::build_microvm_from_config(&config)?; let cpu_template = vm_resources .vm_config @@ -156,7 +158,7 @@ fn run(cli: Cli) -> Result<(), HelperError> { Command::Fingerprint(op) => match op { FingerprintOperation::Dump { config, output } => { let config = read_to_string(config)?; - let (vmm, _) = utils::build_microvm_from_config(&config)?; + let ((vmm, _), _flame_guard) = utils::build_microvm_from_config(&config)?; let fingerprint = fingerprint::dump::dump(vmm)?; @@ -180,6 +182,7 @@ fn run(cli: Cli) -> Result<(), HelperError> { Ok(()) } +#[tracing::instrument(level = "trace", skip())] fn main() -> Result<(), HelperError> { let cli = Cli::parse(); let result = run(cli); @@ -200,6 +203,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip(kernel_image_path, rootfs_path))] pub fn generate_config(kernel_image_path: &str, rootfs_path: &str) -> String { format!( r#"{{ @@ -219,6 +223,10 @@ mod tests { ) } + #[tracing::instrument( + level = "trace", + skip(kernel_image_path, rootfs_path, cpu_template_path) + )] pub fn generate_config_with_template( kernel_image_path: &str, rootfs_path: &str, @@ -243,6 +251,10 @@ mod tests { ) } + #[tracing::instrument( + level = "trace", + skip(kernel_image_path, rootfs_path, cpu_template_path) + )] fn generate_config_file( kernel_image_path: &str, rootfs_path: &str, @@ -303,6 +315,7 @@ mod tests { }"#; // Build a sample custom CPU template. + #[tracing::instrument(level = "trace", skip())] fn generate_sample_template() -> TempFile { let file = TempFile::new().unwrap(); file.as_file() @@ -312,6 +325,7 @@ mod tests { } // Build a sample fingerprint file. + #[tracing::instrument(level = "trace", skip())] fn generate_sample_fingerprint() -> TempFile { let fingerprint = fingerprint::Fingerprint { firecracker_version: crate::utils::CPU_TEMPLATE_HELPER_VERSION.to_string(), diff --git a/src/cpu-template-helper/src/template/dump/aarch64.rs b/src/cpu-template-helper/src/template/dump/aarch64.rs index 454a7e16f7a..9c0fe31e70f 100644 --- a/src/cpu-template-helper/src/template/dump/aarch64.rs +++ b/src/cpu-template-helper/src/template/dump/aarch64.rs @@ -7,6 +7,7 @@ use vmm::cpu_config::templates::{CpuConfiguration, CustomCpuTemplate, RegisterVa use crate::utils::aarch64::reg_modifier; +#[tracing::instrument(level = "trace", skip(cpu_config))] pub fn config_to_template(cpu_config: &CpuConfiguration) -> CustomCpuTemplate { let mut reg_modifiers: Vec = cpu_config .regs @@ -41,6 +42,7 @@ mod tests { const KVM_REG_SIZE_U64: u64 = 0x0030000000000000; const KVM_REG_SIZE_U128: u64 = 0x0040000000000000; + #[tracing::instrument(level = "trace", skip())] fn build_sample_regs() -> Aarch64RegisterVec { let mut v = Aarch64RegisterVec::default(); v.push(Aarch64RegisterRef::new( @@ -58,6 +60,7 @@ mod tests { v } + #[tracing::instrument(level = "trace", skip())] fn build_expected_reg_modifiers() -> Vec { vec![ reg_modifier!(KVM_REG_SIZE_U32, 0x0000_ffff), diff --git a/src/cpu-template-helper/src/template/dump/mod.rs b/src/cpu-template-helper/src/template/dump/mod.rs index 882d2a933d6..49c6df85356 100644 --- a/src/cpu-template-helper/src/template/dump/mod.rs +++ b/src/cpu-template-helper/src/template/dump/mod.rs @@ -23,6 +23,7 @@ pub enum DumpError { DumpCpuConfig(#[from] DumpCpuConfigError), } +#[tracing::instrument(level = "trace", skip(vmm))] pub fn dump(vmm: Arc>) -> Result { // Get CPU configuration. let cpu_configs = vmm.lock().unwrap().dump_cpu_config()?; @@ -46,7 +47,7 @@ mod tests { let tmp_file = TempFile::new().unwrap(); let valid_config = generate_config(&kernel_image_path, tmp_file.as_path().to_str().unwrap()); - let (vmm, _) = build_microvm_from_config(&valid_config).unwrap(); + let ((vmm, _), _flame_guard) = build_microvm_from_config(&valid_config).unwrap(); assert!(dump(vmm).is_ok()); } diff --git a/src/cpu-template-helper/src/template/dump/x86_64.rs b/src/cpu-template-helper/src/template/dump/x86_64.rs index 025d4ecb397..228c47d8e51 100644 --- a/src/cpu-template-helper/src/template/dump/x86_64.rs +++ b/src/cpu-template-helper/src/template/dump/x86_64.rs @@ -11,6 +11,7 @@ use vmm::cpu_config::x86_64::custom_cpu_template::{ use crate::utils::x86_64::{cpuid_leaf_modifier, cpuid_reg_modifier, msr_modifier}; +#[tracing::instrument(level = "trace", skip(cpu_config))] /// Convert `&CpuConfiguration` to `CustomCputemplate`. pub fn config_to_template(cpu_config: &CpuConfiguration) -> CustomCpuTemplate { CustomCpuTemplate { @@ -19,6 +20,7 @@ pub fn config_to_template(cpu_config: &CpuConfiguration) -> CustomCpuTemplate { } } +#[tracing::instrument(level = "trace", skip(cpuid))] fn cpuid_to_modifiers(cpuid: &Cpuid) -> Vec { cpuid .inner() @@ -39,6 +41,7 @@ fn cpuid_to_modifiers(cpuid: &Cpuid) -> Vec { .collect() } +#[tracing::instrument(level = "trace", skip(msrs))] fn msrs_to_modifier(msrs: &HashMap) -> Vec { let mut msrs: Vec = msrs .iter() @@ -58,6 +61,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip())] fn build_sample_cpuid() -> Cpuid { Cpuid::Intel(IntelCpuid(BTreeMap::from([ ( @@ -93,6 +97,7 @@ mod tests { ]))) } + #[tracing::instrument(level = "trace", skip())] fn build_expected_cpuid_modifiers() -> Vec { vec![ cpuid_leaf_modifier!( @@ -120,6 +125,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] fn build_sample_msrs() -> HashMap { HashMap::from([ (0x1, 0xffff_ffff_ffff_ffff), @@ -129,6 +135,7 @@ mod tests { ]) } + #[tracing::instrument(level = "trace", skip())] fn build_expected_msr_modifiers() -> Vec { vec![ msr_modifier!(0x1, 0xffff_ffff_ffff_ffff), diff --git a/src/cpu-template-helper/src/template/strip/aarch64.rs b/src/cpu-template-helper/src/template/strip/aarch64.rs index 2d32832edda..18cc4d2e773 100644 --- a/src/cpu-template-helper/src/template/strip/aarch64.rs +++ b/src/cpu-template-helper/src/template/strip/aarch64.rs @@ -7,6 +7,7 @@ use vmm::cpu_config::templates::CustomCpuTemplate; use crate::template::strip::{strip_common, StripError}; use crate::utils::aarch64::RegModifierMap; +#[tracing::instrument(level = "trace", skip(templates))] #[allow(dead_code)] pub fn strip(templates: Vec) -> Result, StripError> { // Convert `Vec` to `Vec>`. @@ -42,6 +43,7 @@ mod tests { // * An addr 0x0 modifier exists in all the templates but its value is different. // * An addr 0x1 modifier exists in all the templates and its value is same. // * An addr 0x2 modifier only exist in the third template. + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_input_templates() -> Vec { vec![ @@ -67,6 +69,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_expected_templates() -> Vec { vec![ diff --git a/src/cpu-template-helper/src/template/strip/mod.rs b/src/cpu-template-helper/src/template/strip/mod.rs index 0b128f1a1a7..75e8448fb24 100644 --- a/src/cpu-template-helper/src/template/strip/mod.rs +++ b/src/cpu-template-helper/src/template/strip/mod.rs @@ -25,6 +25,7 @@ pub enum StripError { NumberOfInputs, } +#[tracing::instrument(level = "trace", skip(maps))] fn strip_common(maps: &mut [HashMap>]) -> Result<(), StripError> where K: ModifierMapKey + Debug, diff --git a/src/cpu-template-helper/src/template/strip/x86_64.rs b/src/cpu-template-helper/src/template/strip/x86_64.rs index b297ab6319d..e36f376d5e4 100644 --- a/src/cpu-template-helper/src/template/strip/x86_64.rs +++ b/src/cpu-template-helper/src/template/strip/x86_64.rs @@ -7,6 +7,7 @@ use vmm::cpu_config::x86_64::custom_cpu_template::{CpuidLeafModifier, RegisterMo use crate::template::strip::{strip_common, StripError}; use crate::utils::x86_64::{CpuidModifierMap, MsrModifierMap}; +#[tracing::instrument(level = "trace", skip(templates))] #[allow(dead_code)] pub fn strip(templates: Vec) -> Result, StripError> { // Convert `Vec` to two `Vec>` of modifiers. @@ -60,6 +61,7 @@ mod tests { // * A CPUID leaf 0x1 / subleaf 0x0 modifier only exists in the second template. // * A CPUID leaf 0x2 / subleaf 0x1 modifier exists in all the templates, but EAX value is same // and EBX value is different across them. + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_input_cpuid_templates() -> Vec { vec![ @@ -105,6 +107,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_expected_cpuid_templates() -> Vec { vec![ @@ -142,6 +145,7 @@ mod tests { // * An addr 0x0 modifier exists in all the templates but its value is different. // * An addr 0x1 modifier exists in all the templates and its value is same. // * An addr 0x2 modifier only exists in the third template. + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_input_msr_templates() -> Vec { vec![ @@ -170,6 +174,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_expected_msr_templates() -> Vec { vec![ diff --git a/src/cpu-template-helper/src/template/verify/aarch64.rs b/src/cpu-template-helper/src/template/verify/aarch64.rs index b47ed07339b..c7b4be2a0b6 100644 --- a/src/cpu-template-helper/src/template/verify/aarch64.rs +++ b/src/cpu-template-helper/src/template/verify/aarch64.rs @@ -6,6 +6,7 @@ use vmm::cpu_config::templates::CustomCpuTemplate; use super::{verify_common, VerifyError}; use crate::utils::aarch64::RegModifierMap; +#[tracing::instrument(level = "trace", skip(cpu_template, cpu_config))] pub fn verify( cpu_template: CustomCpuTemplate, cpu_config: CustomCpuTemplate, diff --git a/src/cpu-template-helper/src/template/verify/mod.rs b/src/cpu-template-helper/src/template/verify/mod.rs index 7ae5b9e910e..ce22b0a8cd4 100644 --- a/src/cpu-template-helper/src/template/verify/mod.rs +++ b/src/cpu-template-helper/src/template/verify/mod.rs @@ -26,6 +26,7 @@ pub enum VerifyError { ValueMismatched(String, String), } +#[tracing::instrument(level = "trace", skip(template, config))] /// Verify that the given CPU template is applied as intended. /// /// This function is an arch-agnostic part of CPU template verification. As template formats differ diff --git a/src/cpu-template-helper/src/template/verify/x86_64.rs b/src/cpu-template-helper/src/template/verify/x86_64.rs index a700d12c811..1310bf18b50 100644 --- a/src/cpu-template-helper/src/template/verify/x86_64.rs +++ b/src/cpu-template-helper/src/template/verify/x86_64.rs @@ -6,6 +6,7 @@ use vmm::cpu_config::templates::CustomCpuTemplate; use super::{verify_common, VerifyError}; use crate::utils::x86_64::{CpuidModifierMap, MsrModifierMap}; +#[tracing::instrument(level = "trace", skip(cpu_template, cpu_config))] pub fn verify( cpu_template: CustomCpuTemplate, cpu_config: CustomCpuTemplate, diff --git a/src/cpu-template-helper/src/utils/aarch64.rs b/src/cpu-template-helper/src/utils/aarch64.rs index 676541ac325..b12f4755dc6 100644 --- a/src/cpu-template-helper/src/utils/aarch64.rs +++ b/src/cpu-template-helper/src/utils/aarch64.rs @@ -14,6 +14,7 @@ pub struct RegModifierMapKey(pub u64); impl ModifierMapKey for RegModifierMapKey {} impl Display for RegModifierMapKey { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ID={:#x}", self.0) } @@ -23,6 +24,7 @@ impl Display for RegModifierMapKey { pub struct RegModifierMap(pub HashMap>); impl From> for RegModifierMap { + #[tracing::instrument(level = "trace", skip(modifiers))] fn from(modifiers: Vec) -> Self { let mut map = HashMap::new(); for modifier in modifiers { @@ -33,6 +35,7 @@ impl From> for RegModifierMap { } impl From for Vec { + #[tracing::instrument(level = "trace", skip(modifier_map))] fn from(modifier_map: RegModifierMap) -> Self { let mut modifier_vec = modifier_map .0 @@ -92,6 +95,7 @@ mod tests { assert_eq!(key.to_string(), "ID=0x1234"); } + #[tracing::instrument(level = "trace", skip())] fn build_sample_reg_modifier_vec() -> Vec { vec![ reg_modifier!(0x0, 0x0), @@ -100,6 +104,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] fn build_sample_reg_modifier_map() -> RegModifierMap { RegModifierMap(HashMap::from([ reg_modifier_map!(0x0, 0x0), diff --git a/src/cpu-template-helper/src/utils/mod.rs b/src/cpu-template-helper/src/utils/mod.rs index dbde959f115..94c01eb345a 100644 --- a/src/cpu-template-helper/src/utils/mod.rs +++ b/src/cpu-template-helper/src/utils/mod.rs @@ -36,6 +36,7 @@ pub trait DiffString { impl DiffString for V { // Generate a string to display difference of filtered values between CPU template and guest // CPU config. + #[tracing::instrument(level = "trace", skip(template,config))] #[rustfmt::skip] fn to_diff_string(template: V, config: V) -> String { let mut diff = String::new(); @@ -68,9 +69,17 @@ pub enum UtilsError { BuildMicroVm(#[from] StartMicrovmError), } +#[allow(clippy::type_complexity)] +#[tracing::instrument(level = "trace", skip(config))] pub fn build_microvm_from_config( config: &str, -) -> Result<(Arc>, VmResources), UtilsError> { +) -> Result< + ( + (Arc>, VmResources), + Option, + ), + UtilsError, +> { // Prepare resources from the given config file. let instance_info = InstanceInfo { id: "anonymous-instance".to_string(), @@ -78,8 +87,9 @@ pub fn build_microvm_from_config( vmm_version: CPU_TEMPLATE_HELPER_VERSION.to_string(), app_name: "cpu-template-helper".to_string(), }; - let vm_resources = VmResources::from_json(config, &instance_info, HTTP_MAX_PAYLOAD_SIZE, None) - .map_err(UtilsError::CreateVmResources)?; + let (vm_resources, flame_guard) = + VmResources::from_json(config, &instance_info, HTTP_MAX_PAYLOAD_SIZE, None) + .map_err(UtilsError::CreateVmResources)?; let mut event_manager = EventManager::new().unwrap(); let seccomp_filters = get_empty_filters(); @@ -91,9 +101,10 @@ pub fn build_microvm_from_config( &seccomp_filters, )?; - Ok((vmm, vm_resources)) + Ok(((vmm, vm_resources), flame_guard)) } +#[tracing::instrument(level = "trace", skip(path, suffix))] pub fn add_suffix(path: &Path, suffix: &str) -> PathBuf { // Extract the part of the filename before the extension. let mut new_file_name = OsString::from(path.file_stem().unwrap()); @@ -126,6 +137,7 @@ pub mod tests { impl ModifierMapKey for MockModifierMapKey {} impl Display for MockModifierMapKey { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ID={:#x}", self.0) } diff --git a/src/cpu-template-helper/src/utils/x86_64.rs b/src/cpu-template-helper/src/utils/x86_64.rs index e83b387bb14..e804a03515f 100644 --- a/src/cpu-template-helper/src/utils/x86_64.rs +++ b/src/cpu-template-helper/src/utils/x86_64.rs @@ -22,6 +22,7 @@ pub struct CpuidModifierMapKey { impl ModifierMapKey for CpuidModifierMapKey {} impl Display for CpuidModifierMapKey { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -38,6 +39,7 @@ impl Display for CpuidModifierMapKey { pub struct CpuidModifierMap(pub HashMap>); impl From> for CpuidModifierMap { + #[tracing::instrument(level = "trace", skip(leaf_modifiers))] fn from(leaf_modifiers: Vec) -> Self { let mut map = HashMap::new(); for leaf_modifier in leaf_modifiers { @@ -58,6 +60,7 @@ impl From> for CpuidModifierMap { } impl From for Vec { + #[tracing::instrument(level = "trace", skip(modifier_map))] fn from(modifier_map: CpuidModifierMap) -> Self { let mut leaf_modifiers = Vec::::new(); for (modifier_key, modifier_value) in modifier_map.0 { @@ -100,6 +103,7 @@ pub struct MsrModifierMapKey(pub u32); impl ModifierMapKey for MsrModifierMapKey {} impl Display for MsrModifierMapKey { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "index={:#x}", self.0) } @@ -109,6 +113,7 @@ impl Display for MsrModifierMapKey { pub struct MsrModifierMap(pub HashMap>); impl From> for MsrModifierMap { + #[tracing::instrument(level = "trace", skip(modifiers))] fn from(modifiers: Vec) -> Self { let mut map = HashMap::new(); for modifier in modifiers { @@ -119,6 +124,7 @@ impl From> for MsrModifierMap { } impl From for Vec { + #[tracing::instrument(level = "trace", skip(modifier_map))] fn from(modifier_map: MsrModifierMap) -> Self { let mut modifier_vec = modifier_map .0 @@ -239,6 +245,7 @@ mod tests { ) } + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_sample_cpuid_modifier_vec() -> Vec { vec![ @@ -252,6 +259,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] #[rustfmt::skip] fn build_sample_cpuid_modifier_map() -> CpuidModifierMap { CpuidModifierMap(HashMap::from([ @@ -281,6 +289,7 @@ mod tests { assert_eq!(key.to_string(), "index=0x1234"); } + #[tracing::instrument(level = "trace", skip())] fn build_sample_msr_modifier_vec() -> Vec { vec![ msr_modifier!(0x0, 0x0), @@ -289,6 +298,7 @@ mod tests { ] } + #[tracing::instrument(level = "trace", skip())] fn build_sample_msr_modifier_map() -> MsrModifierMap { MsrModifierMap(HashMap::from([ msr_modifier_map!(0x0, 0x0), diff --git a/src/dumbo/Cargo.toml b/src/dumbo/Cargo.toml index 670bb37542c..0ba0a6aa6a0 100644 --- a/src/dumbo/Cargo.toml +++ b/src/dumbo/Cargo.toml @@ -11,6 +11,7 @@ bench = false [dependencies] bitflags = "1.3.2" derive_more = { version = "0.99.17", default-features = false, features = ["from"] } +tracing = { version = "0.1.37", features = ["max_level_debug"] } logger = { path = "../logger" } micro_http = { git = "https://github.com/firecracker-microvm/micro-http", rev = "4b18a04" } diff --git a/src/dumbo/src/lib.rs b/src/dumbo/src/lib.rs index 4c57db791f0..e560265c5f7 100644 --- a/src/dumbo/src/lib.rs +++ b/src/dumbo/src/lib.rs @@ -34,11 +34,13 @@ pub trait ByteBuffer: Index { } impl ByteBuffer for [u8] { + #[tracing::instrument(level = "trace", skip(self))] #[inline] fn len(&self) -> usize { self.len() } + #[tracing::instrument(level = "trace", skip(self, offset, buf))] #[inline] fn read_to_slice(&self, offset: usize, buf: &mut [u8]) { let buf_len = buf.len(); @@ -52,14 +54,17 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip(buf))] fn bb_len(buf: &T) -> usize { buf.len() } + #[tracing::instrument(level = "trace", skip(buf))] fn bb_is_empty(buf: &T) -> bool { buf.len() == 0 } + #[tracing::instrument(level = "trace", skip(src, dst))] fn bb_read_from_1(src: &T, dst: &mut [u8]) { src.read_to_slice(1, dst); } diff --git a/src/dumbo/src/pdu/arp.rs b/src/dumbo/src/pdu/arp.rs index 12f3b6c6741..b9847e9559a 100644 --- a/src/dumbo/src/pdu/arp.rs +++ b/src/dumbo/src/pdu/arp.rs @@ -73,6 +73,7 @@ pub struct EthIPv4ArpFrame<'a, T: 'a> { #[allow(clippy::len_without_is_empty)] impl<'a, T: NetworkBytes + Debug> EthIPv4ArpFrame<'a, T> { + #[tracing::instrument(level = "trace", skip(bytes))] /// Interprets the given bytes as an ARP frame, without doing any validity checks beforehand. /// /// # Panics @@ -86,6 +87,7 @@ impl<'a, T: NetworkBytes + Debug> EthIPv4ArpFrame<'a, T> { } } + #[tracing::instrument(level = "trace", skip(bytes))] /// Tries to interpret a byte slice as a valid IPv4 over Ethernet ARP request. /// /// If no error occurs, it guarantees accessor methods (which make use of various `_unchecked` @@ -122,60 +124,70 @@ impl<'a, T: NetworkBytes + Debug> EthIPv4ArpFrame<'a, T> { Ok(maybe) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the hardware type of the frame. #[inline] pub fn htype(&self) -> u16 { self.bytes.ntohs_unchecked(HTYPE_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the protocol type of the frame. #[inline] pub fn ptype(&self) -> u16 { self.bytes.ntohs_unchecked(PTYPE_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the hardware address length of the frame. #[inline] pub fn hlen(&self) -> u8 { self.bytes[HLEN_OFFSET] } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the protocol address length of the frame. #[inline] pub fn plen(&self) -> u8 { self.bytes[PLEN_OFFSET] } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the type of operation within the frame. #[inline] pub fn operation(&self) -> u16 { self.bytes.ntohs_unchecked(OPER_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the sender hardware address. #[inline] pub fn sha(&self) -> MacAddr { MacAddr::from_bytes_unchecked(&self.bytes[SHA_OFFSET..ETH_IPV4_SPA_OFFSET]) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the sender protocol address. #[inline] pub fn spa(&self) -> Ipv4Addr { Ipv4Addr::from(self.bytes.ntohl_unchecked(ETH_IPV4_SPA_OFFSET)) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the target hardware address. #[inline] pub fn tha(&self) -> MacAddr { MacAddr::from_bytes_unchecked(&self.bytes[ETH_IPV4_THA_OFFSET..ETH_IPV4_TPA_OFFSET]) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the target protocol address. #[inline] pub fn tpa(&self) -> Ipv4Addr { Ipv4Addr::from(self.bytes.ntohl_unchecked(ETH_IPV4_TPA_OFFSET)) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the frame. #[inline] pub fn len(&self) -> usize { @@ -186,6 +198,10 @@ impl<'a, T: NetworkBytes + Debug> EthIPv4ArpFrame<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> EthIPv4ArpFrame<'a, T> { + #[tracing::instrument( + level = "trace", + skip(buf, htype, ptype, hlen, plen, operation, sha, spa, tha, tpa) + )] #[allow(clippy::too_many_arguments)] fn write_raw( buf: T, @@ -219,6 +235,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthIPv4ArpFrame<'a, T> { Ok(frame) } + #[tracing::instrument(level = "trace", skip(buf, sha, spa, tha, tpa))] /// Attempts to write an ARP request to `buf`, based on the specified hardware and protocol /// addresses. #[inline] @@ -243,6 +260,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthIPv4ArpFrame<'a, T> { ) } + #[tracing::instrument(level = "trace", skip(buf, sha, spa, tha, tpa))] /// Attempts to write an ARP reply to `buf`, based on the specified hardware and protocol /// addresses. #[inline] @@ -267,42 +285,49 @@ impl<'a, T: NetworkBytesMut + Debug> EthIPv4ArpFrame<'a, T> { ) } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the hardware type of the frame. #[inline] pub fn set_htype(&mut self, value: u16) { self.bytes.htons_unchecked(HTYPE_OFFSET, value); } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the protocol type of the frame. #[inline] pub fn set_ptype(&mut self, value: u16) { self.bytes.htons_unchecked(PTYPE_OFFSET, value); } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the hardware address length of the frame. #[inline] pub fn set_hlen(&mut self, value: u8) { self.bytes[HLEN_OFFSET] = value; } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the protocol address length of the frame. #[inline] pub fn set_plen(&mut self, value: u8) { self.bytes[PLEN_OFFSET] = value; } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the operation within the frame. #[inline] pub fn set_operation(&mut self, value: u16) { self.bytes.htons_unchecked(OPER_OFFSET, value); } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the sender hardware address. #[inline] pub fn set_sha(&mut self, addr: MacAddr) { self.bytes[SHA_OFFSET..ETH_IPV4_SPA_OFFSET].copy_from_slice(addr.get_bytes()); } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the sender protocol address. #[inline] pub fn set_spa(&mut self, addr: Ipv4Addr) { @@ -310,12 +335,14 @@ impl<'a, T: NetworkBytesMut + Debug> EthIPv4ArpFrame<'a, T> { .htonl_unchecked(ETH_IPV4_SPA_OFFSET, u32::from(addr)); } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the target hardware address. #[inline] pub fn set_tha(&mut self, addr: MacAddr) { self.bytes[ETH_IPV4_THA_OFFSET..ETH_IPV4_TPA_OFFSET].copy_from_slice(addr.get_bytes()); } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the target protocol address. #[inline] pub fn set_tpa(&mut self, addr: Ipv4Addr) { @@ -324,6 +351,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthIPv4ArpFrame<'a, T> { } } +#[tracing::instrument(level = "trace", skip(buf, addr))] /// This function checks if `buf` may hold an Ethernet frame which encapsulates an /// `EthIPv4ArpRequest` for the given address. Cannot produce false negatives. #[inline] diff --git a/src/dumbo/src/pdu/bytes.rs b/src/dumbo/src/pdu/bytes.rs index 76c54455355..d29864d5ca1 100644 --- a/src/dumbo/src/pdu/bytes.rs +++ b/src/dumbo/src/pdu/bytes.rs @@ -135,12 +135,14 @@ pub trait NetworkBytesMut: NetworkBytes + DerefMut { } impl<'a> NetworkBytes for &'a [u8] { + #[tracing::instrument(level = "trace", skip(self, len))] #[inline] fn shrink_unchecked(&mut self, len: usize) { *self = &self[..len]; } } impl<'a> NetworkBytes for &'a mut [u8] { + #[tracing::instrument(level = "trace", skip(self, len))] #[inline] fn shrink_unchecked(&mut self, len: usize) { *self = &mut std::mem::take(self)[..len]; @@ -159,6 +161,7 @@ pub(super) struct InnerBytes<'a, T: 'a> { } impl<'a, T: Debug> InnerBytes<'a, T> { + #[tracing::instrument(level = "trace", skip(bytes))] /// Creates a new instance as a wrapper around `bytes`. #[inline] pub fn new(bytes: T) -> Self { @@ -172,6 +175,7 @@ impl<'a, T: Debug> InnerBytes<'a, T> { impl<'a, T: Deref + Debug> Deref for InnerBytes<'a, T> { type Target = [u8]; + #[tracing::instrument(level = "trace", skip(self))] #[inline] fn deref(&self) -> &[u8] { self.bytes.deref() @@ -179,6 +183,7 @@ impl<'a, T: Deref + Debug> Deref for InnerBytes<'a, T> { } impl<'a, T: DerefMut + Debug> DerefMut for InnerBytes<'a, T> { + #[tracing::instrument(level = "trace", skip(self))] #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.bytes.deref_mut() @@ -186,6 +191,7 @@ impl<'a, T: DerefMut + Debug> DerefMut for InnerBytes<'a, T> { } impl<'a, T: NetworkBytes + Debug> NetworkBytes for InnerBytes<'a, T> { + #[tracing::instrument(level = "trace", skip(self, len))] #[inline] fn shrink_unchecked(&mut self, len: usize) { self.bytes.shrink_unchecked(len); diff --git a/src/dumbo/src/pdu/ethernet.rs b/src/dumbo/src/pdu/ethernet.rs index 2849867cc50..ce1dfda83d7 100644 --- a/src/dumbo/src/pdu/ethernet.rs +++ b/src/dumbo/src/pdu/ethernet.rs @@ -41,6 +41,7 @@ pub struct EthernetFrame<'a, T: 'a> { #[allow(clippy::len_without_is_empty)] impl<'a, T: NetworkBytes + Debug> EthernetFrame<'a, T> { + #[tracing::instrument(level = "trace", skip(bytes))] /// Interprets `bytes` as an Ethernet frame without any validity checks. /// /// # Panics @@ -54,6 +55,7 @@ impl<'a, T: NetworkBytes + Debug> EthernetFrame<'a, T> { } } + #[tracing::instrument(level = "trace", skip(bytes))] /// Checks whether the specified byte sequence can be interpreted as an Ethernet frame. #[inline] pub fn from_bytes(bytes: T) -> Result { @@ -64,36 +66,42 @@ impl<'a, T: NetworkBytes + Debug> EthernetFrame<'a, T> { Ok(EthernetFrame::from_bytes_unchecked(bytes)) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the destination MAC address. #[inline] pub fn dst_mac(&self) -> MacAddr { MacAddr::from_bytes_unchecked(&self.bytes[DST_MAC_OFFSET..SRC_MAC_OFFSET]) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the source MAC address. #[inline] pub fn src_mac(&self) -> MacAddr { MacAddr::from_bytes_unchecked(&self.bytes[SRC_MAC_OFFSET..ETHERTYPE_OFFSET]) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the ethertype of the frame. #[inline] pub fn ethertype(&self) -> u16 { self.bytes.ntohs_unchecked(ETHERTYPE_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the offset of the payload within the frame. #[inline] pub fn payload_offset(&self) -> usize { PAYLOAD_OFFSET } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the payload of the frame as an `[&u8]` slice. #[inline] pub fn payload(&self) -> &[u8] { self.bytes.split_at(self.payload_offset()).1 } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the frame. #[inline] pub fn len(&self) -> usize { @@ -102,6 +110,7 @@ impl<'a, T: NetworkBytes + Debug> EthernetFrame<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { + #[tracing::instrument(level = "trace", skip(buf, dst_mac, src_mac, ethertype))] /// Attempts to write an Ethernet frame using the given header fields to `buf`. fn new_with_header( buf: T, @@ -123,6 +132,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { Ok(frame) } + #[tracing::instrument(level = "trace", skip(buf, dst_mac, src_mac, ethertype))] /// Attempts to write an incomplete Ethernet frame (whose length is currently unknown) to `buf`, /// using the specified header fields. #[inline] @@ -137,6 +147,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { )?)) } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the destination MAC address. #[inline] pub fn set_dst_mac(&mut self, addr: MacAddr) -> &mut Self { @@ -144,6 +155,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the source MAC address. #[inline] pub fn set_src_mac(&mut self, addr: MacAddr) -> &mut Self { @@ -151,6 +163,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the ethertype of the frame. #[inline] pub fn set_ethertype(&mut self, value: u16) -> &mut Self { @@ -158,6 +171,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the payload of the frame as a `&mut [u8]` slice. #[inline] pub fn payload_mut(&mut self) -> &mut [u8] { @@ -168,6 +182,7 @@ impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { } impl<'a, T: NetworkBytes + Debug> Incomplete> { + #[tracing::instrument(level = "trace", skip(self, payload_len))] /// Completes the inner frame by shrinking it to its actual length. /// /// # Panics @@ -249,6 +264,7 @@ mod kani_proofs { pub const MAX_FRAME_SIZE: usize = 1514; impl<'a, T: NetworkBytesMut + Debug> EthernetFrame<'a, T> { + #[tracing::instrument(level = "trace", skip(self))] fn is_valid(&self) -> bool { self.len() >= PAYLOAD_OFFSET } @@ -259,6 +275,7 @@ mod kani_proofs { // performance degradation given a necessary loop unrolling. Using this stub, // we read the same information from the buffer while avoiding the loop, thus, // notably improving performance. + #[tracing::instrument(level = "trace", skip(input))] pub fn read_be_u16(input: &[u8]) -> u16 { u16::from_be_bytes([input[0], input[1]]) } diff --git a/src/dumbo/src/pdu/ipv4.rs b/src/dumbo/src/pdu/ipv4.rs index d26ba7e594a..d7a863a4165 100644 --- a/src/dumbo/src/pdu/ipv4.rs +++ b/src/dumbo/src/pdu/ipv4.rs @@ -63,6 +63,7 @@ pub struct IPv4Packet<'a, T: 'a> { #[allow(clippy::len_without_is_empty)] impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { + #[tracing::instrument(level = "trace", skip(bytes))] /// Interpret `bytes` as an IPv4Packet without checking the validity of the header fields, and /// the length of the inner byte sequence. /// @@ -77,6 +78,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { } } + #[tracing::instrument(level = "trace", skip(bytes, verify_checksum))] /// Attempts to interpret `bytes` as an IPv4 packet, checking the validity of the header fields /// and the length of the inner byte sequence. pub fn from_bytes(bytes: T, verify_checksum: bool) -> Result { @@ -118,6 +120,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { Ok(packet) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `version` header field, and the header length. /// /// This method returns the actual length (in bytes) of the header, and not the value of the @@ -130,6 +133,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { (x >> 4, header_len) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the packet header length (in bytes). #[inline] pub fn header_len(&self) -> usize { @@ -137,6 +141,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { header_len } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the values of the `dscp` and `ecn` header fields. #[inline] pub fn dscp_and_ecn(&self) -> (u8, u8) { @@ -144,18 +149,21 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { (x >> 2, x & 0b11) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the 'total length' header field. #[inline] pub fn total_len(&self) -> u16 { self.bytes.ntohs_unchecked(TOTAL_LEN_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `identification` header field. #[inline] pub fn identification(&self) -> u16 { self.bytes.ntohs_unchecked(IDENTIFICATION_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the values of the `flags` and `fragment offset` header fields. #[inline] pub fn flags_and_fragment_offset(&self) -> (u8, u16) { @@ -163,36 +171,42 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { ((x >> 13) as u8, x & 0x1fff) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `ttl` header field. #[inline] pub fn ttl(&self) -> u8 { self.bytes[TTL_OFFSET] } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `protocol` header field. #[inline] pub fn protocol(&self) -> u8 { self.bytes[PROTOCOL_OFFSET] } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `header checksum` header field. #[inline] pub fn header_checksum(&self) -> u16 { self.bytes.ntohs_unchecked(HEADER_CHECKSUM_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the source IPv4 address of the packet. #[inline] pub fn source_address(&self) -> Ipv4Addr { Ipv4Addr::from(self.bytes.ntohl_unchecked(SOURCE_ADDRESS_OFFSET)) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the destination IPv4 address of the packet. #[inline] pub fn destination_address(&self) -> Ipv4Addr { Ipv4Addr::from(self.bytes.ntohl_unchecked(DESTINATION_ADDRESS_OFFSET)) } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Returns a byte slice containing the payload, using the given header length value to compute /// the payload offset. /// @@ -204,12 +218,14 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { self.bytes.split_at(header_len).1 } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a byte slice that contains the payload of the packet. #[inline] pub fn payload(&self) -> &[u8] { self.payload_unchecked(self.header_len()) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the inner byte sequence. /// /// This is equal to the output of the `total_len()` method for properly constructed instances @@ -219,6 +235,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { self.bytes.len() } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Computes and returns the packet header checksum using the provided header length. /// /// A nice description of how this works can be found [here]. May panic for invalid values of @@ -242,6 +259,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { !(sum as u16) } + #[tracing::instrument(level = "trace", skip(self))] /// Computes and returns the packet header checksum. #[inline] pub fn compute_checksum(&self) -> u16 { @@ -250,6 +268,7 @@ impl<'a, T: NetworkBytes + Debug> IPv4Packet<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { + #[tracing::instrument(level = "trace", skip(buf, protocol, src_addr, dst_addr))] /// Attempts to write an IPv4 packet header to `buf`, making sure there is enough space. /// /// This method returns an incomplete packet, because the size of the payload might be unknown @@ -280,6 +299,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { Ok(Incomplete::new(packet)) } + #[tracing::instrument(level = "trace", skip(self, version, header_len))] /// Sets the values of the `version` and `ihl` header fields (the latter is computed from the /// value of `header_len`). #[inline] @@ -290,6 +310,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, dscp, ecn))] /// Sets the values of the `dscp` and `ecn` header fields. #[inline] pub fn set_dscp_and_ecn(&mut self, dscp: u8, ecn: u8) -> &mut Self { @@ -297,6 +318,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `total length` header field. #[inline] pub fn set_total_len(&mut self, value: u16) -> &mut Self { @@ -304,6 +326,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `identification` header field. #[inline] pub fn set_identification(&mut self, value: u16) -> &mut Self { @@ -311,6 +334,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, flags, fragment_offset))] /// Sets the values of the `flags` and `fragment offset` header fields. #[inline] pub fn set_flags_and_fragment_offset(&mut self, flags: u8, fragment_offset: u16) -> &mut Self { @@ -320,6 +344,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `ttl` header field. #[inline] pub fn set_ttl(&mut self, value: u8) -> &mut Self { @@ -327,6 +352,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `protocol` header field. #[inline] pub fn set_protocol(&mut self, value: u8) -> &mut Self { @@ -334,6 +360,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `header checksum` header field. #[inline] pub fn set_header_checksum(&mut self, value: u16) -> &mut Self { @@ -341,6 +368,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the source address of the packet. #[inline] pub fn set_source_address(&mut self, addr: Ipv4Addr) -> &mut Self { @@ -349,6 +377,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Sets the destination address of the packet. #[inline] pub fn set_destination_address(&mut self, addr: Ipv4Addr) -> &mut Self { @@ -357,6 +386,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Returns a mutable byte slice representing the payload of the packet, using the provided /// header length to compute the payload offset. /// @@ -368,6 +398,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { self.bytes.split_at_mut(header_len).1 } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a mutable byte slice representing the payload of the packet. #[inline] pub fn payload_mut(&mut self) -> &mut [u8] { @@ -384,6 +415,7 @@ impl<'a, T: NetworkBytesMut + Debug> IPv4Packet<'a, T> { /// shrinking the inner byte sequence to be as large as the packet itself (this includes setting /// the `total length` header field). impl<'a, T: NetworkBytesMut + Debug> Incomplete> { + #[tracing::instrument(level = "trace", skip(self, header_len, payload_len, compute_checksum))] /// Transforms `self` into an `IPv4Packet` based on the supplied header and payload length. May /// panic for invalid values of the input parameters. /// @@ -418,6 +450,10 @@ impl<'a, T: NetworkBytesMut + Debug> Incomplete> { self.inner } + #[tracing::instrument( + level = "trace", + skip(self, options_len, payload_len, compute_checksum) + )] /// Transforms `self` into an `IPv4Packet` based on the supplied options and payload length. /// /// # Panics @@ -435,6 +471,7 @@ impl<'a, T: NetworkBytesMut + Debug> Incomplete> { self.with_header_and_payload_len_unchecked(header_len, payload_len, compute_checksum) } + #[tracing::instrument(level = "trace", skip(self, payload_len, compute_checksum))] /// Transforms `self` into an `IPv4Packet` based on the supplied payload length. May panic for /// invalid values of the input parameters. /// @@ -452,6 +489,7 @@ impl<'a, T: NetworkBytesMut + Debug> Incomplete> { } } +#[tracing::instrument(level = "trace", skip(buf, addr))] /// This function checks if `buf` may hold an IPv4Packet heading towards the given address. Cannot /// produce false negatives. #[inline] @@ -567,6 +605,7 @@ mod tests { // Using a helper function here instead of a closure because it's hard (impossible?) to // specify lifetime bounds for closure arguments. + #[tracing::instrument(level = "trace", skip(buf))] fn p(buf: &mut [u8]) -> IPv4Packet<&mut [u8]> { IPv4Packet::from_bytes_unchecked(buf) } diff --git a/src/dumbo/src/pdu/mod.rs b/src/dumbo/src/pdu/mod.rs index c050b0e7014..da3b58f7425 100644 --- a/src/dumbo/src/pdu/mod.rs +++ b/src/dumbo/src/pdu/mod.rs @@ -34,17 +34,20 @@ pub struct Incomplete { } impl Incomplete { + #[tracing::instrument(level = "trace", skip(inner))] #[inline] fn new(inner: T) -> Self { Incomplete { inner } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a reference to the wrapped object. #[inline] pub fn inner(&self) -> &T { &self.inner } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a mutable reference to the wrapped object. #[inline] pub fn inner_mut(&mut self) -> &mut T { @@ -59,6 +62,7 @@ enum ChecksumProto { Udp = PROTOCOL_UDP, } +#[tracing::instrument(level = "trace", skip(bytes, src_addr, dst_addr, protocol))] /// Computes the checksum of a TCP/UDP packet. Since both protocols use /// the same algorithm to compute the checksum. /// diff --git a/src/dumbo/src/pdu/tcp.rs b/src/dumbo/src/pdu/tcp.rs index 5b466c899e1..0772ad9aab4 100644 --- a/src/dumbo/src/pdu/tcp.rs +++ b/src/dumbo/src/pdu/tcp.rs @@ -99,30 +99,35 @@ pub struct TcpSegment<'a, T: 'a> { #[allow(clippy::len_without_is_empty)] impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { + #[tracing::instrument(level = "trace", skip(self))] /// Returns the source port. #[inline] pub fn source_port(&self) -> u16 { self.bytes.ntohs_unchecked(SOURCE_PORT_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the destination port. #[inline] pub fn destination_port(&self) -> u16 { self.bytes.ntohs_unchecked(DESTINATION_PORT_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the sequence number. #[inline] pub fn sequence_number(&self) -> u32 { self.bytes.ntohl_unchecked(SEQ_NUMBER_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the acknowledgement number (only valid if the `ACK` flag is set). #[inline] pub fn ack_number(&self) -> u32 { self.bytes.ntohl_unchecked(ACK_NUMBER_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the header length, the value of the reserved bits, and whether the `NS` flag /// is set or not. #[inline] @@ -135,30 +140,35 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { (header_len, rsvd, ns) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the header. #[inline] pub fn header_len(&self) -> usize { self.header_len_rsvd_ns().0 } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the TCP header flags, with the exception of `NS`. #[inline] pub fn flags_after_ns(&self) -> Flags { Flags::from_bits_truncate(self.bytes[FLAGS_AFTER_NS_OFFSET]) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `window size` header field. #[inline] pub fn window_size(&self) -> u16 { self.bytes.ntohs_unchecked(WINDOW_SIZE_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `checksum` header field. #[inline] pub fn checksum(&self) -> u16 { self.bytes.ntohs_unchecked(CHECKSUM_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the value of the `urgent pointer` header field (only valid if the /// `URG` flag is set). #[inline] @@ -166,6 +176,7 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { self.bytes.ntohs_unchecked(URG_POINTER_OFFSET) } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Returns the TCP header options as an `[&u8]` slice. /// /// # Panics @@ -176,6 +187,7 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { &self.bytes[OPTIONS_OFFSET..header_len] } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Returns a slice which contains the payload of the segment. May panic if the value of /// `header_len` is invalid. /// @@ -187,24 +199,28 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { self.bytes.split_at(header_len).1 } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the segment. #[inline] pub fn len(&self) -> usize { self.bytes.len() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a slice which contains the payload of the segment. #[inline] pub fn payload(&self) -> &[u8] { self.payload_unchecked(self.header_len()) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the payload. #[inline] pub fn payload_len(&self) -> usize { self.len() - self.header_len() } + #[tracing::instrument(level = "trace", skip(self, src_addr, dst_addr))] /// Computes the TCP checksum of the segment. More details about TCP checksum computation can /// be found [here]. /// @@ -213,6 +229,7 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { crate::pdu::compute_checksum(&self.bytes, src_addr, dst_addr, ChecksumProto::Tcp) } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Parses TCP header options (only `MSS` is supported for now). /// /// If no error is encountered, returns the `MSS` value, or `None` if the option is not @@ -262,6 +279,7 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { Ok(None) } + #[tracing::instrument(level = "trace", skip(bytes))] /// Interprets `bytes` as a TCP segment without any validity checks. /// /// # Panics @@ -275,6 +293,7 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { } } + #[tracing::instrument(level = "trace", skip(bytes, verify_checksum))] /// Attempts to interpret `bytes` as a TCP segment, checking the validity of the header fields. /// /// The `verify_checksum` parameter must contain the source and destination addresses from the @@ -309,6 +328,7 @@ impl<'a, T: NetworkBytes + Debug> TcpSegment<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the source port. #[inline] pub fn set_source_port(&mut self, value: u16) -> &mut Self { @@ -316,6 +336,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the destination port. #[inline] pub fn set_destination_port(&mut self, value: u16) -> &mut Self { @@ -323,6 +344,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the sequence number field. #[inline] pub fn set_sequence_number(&mut self, value: u32) -> &mut Self { @@ -330,6 +352,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the acknowledgement number field. #[inline] pub fn set_ack_number(&mut self, value: u32) -> &mut Self { @@ -337,6 +360,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, header_len, ns))] /// Sets the value of the `ihl` header field based on `header_len` (which should be a multiple /// of 4), clears the reserved bits, and sets the `NS` flag according to the last parameter. // TODO: Check that header_len | 0b11 == 0 and the resulting data_offset is valid? @@ -350,6 +374,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, flags))] /// Sets the value of the header byte containing every TCP flag except `NS`. #[inline] pub fn set_flags_after_ns(&mut self, flags: Flags) -> &mut Self { @@ -357,6 +382,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `window size` field. #[inline] pub fn set_window_size(&mut self, value: u16) -> &mut Self { @@ -364,6 +390,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `checksum` field. #[inline] pub fn set_checksum(&mut self, value: u16) -> &mut Self { @@ -371,6 +398,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the value of the `urgent pointer` field. #[inline] pub fn set_urgent_pointer(&mut self, value: u16) -> &mut Self { @@ -378,6 +406,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, header_len))] /// Returns a mutable slice containing the segment payload. /// /// # Panics @@ -388,6 +417,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self.bytes.split_at_mut(header_len).1 } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a mutable slice containing the segment payload. #[inline] pub fn payload_mut(&mut self) -> &mut [u8] { @@ -395,6 +425,22 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { self.payload_mut_unchecked(header_len) } + #[tracing::instrument( + level = "trace", + skip( + buf, + src_port, + dst_port, + seq_number, + ack_number, + flags_after_ns, + window_size, + mss_option, + mss_remaining, + payload, + compute_checksum + ) + )] /// Writes a complete TCP segment. /// /// # Arguments @@ -443,6 +489,19 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { .finalize(src_port, dst_port, compute_checksum)) } + #[tracing::instrument( + level = "trace", + skip( + buf, + seq_number, + ack_number, + flags_after_ns, + window_size, + mss_option, + mss_remaining, + payload + ) + )] /// Writes an incomplete TCP segment, which is missing the `source port`, `destination port`, /// and `checksum` fields. /// @@ -551,6 +610,7 @@ impl<'a, T: NetworkBytesMut + Debug> TcpSegment<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> Incomplete> { + #[tracing::instrument(level = "trace", skip(self, src_port, dst_port, compute_checksum))] /// Transforms `self` into a `TcpSegment` by specifying values for the `source port`, /// `destination port`, and (optionally) the information required to compute the TCP checksum. #[inline] @@ -724,6 +784,7 @@ mod tests { // Using a helper function here instead of a closure because it's hard (impossible?) to // specify lifetime bounds for closure arguments. + #[tracing::instrument(level = "trace", skip(buf))] fn p(buf: &mut [u8]) -> TcpSegment<&mut [u8]> { TcpSegment::from_bytes_unchecked(buf) } diff --git a/src/dumbo/src/pdu/udp.rs b/src/dumbo/src/pdu/udp.rs index 37e13026956..8b460e29eea 100644 --- a/src/dumbo/src/pdu/udp.rs +++ b/src/dumbo/src/pdu/udp.rs @@ -48,6 +48,7 @@ pub struct UdpDatagram<'a, T: 'a> { #[allow(clippy::len_without_is_empty)] impl<'a, T: NetworkBytes + Debug> UdpDatagram<'a, T> { + #[tracing::instrument(level = "trace", skip(bytes))] /// Interprets `bytes` as a UDP datagram without any validity checks. /// /// # Panics @@ -61,6 +62,7 @@ impl<'a, T: NetworkBytes + Debug> UdpDatagram<'a, T> { } } + #[tracing::instrument(level = "trace", skip(bytes, verify_checksum))] /// Interprets `bytes` as a UDP datagram if possible or returns /// the reason for failing to do so. #[inline] @@ -85,30 +87,35 @@ impl<'a, T: NetworkBytes + Debug> UdpDatagram<'a, T> { Ok(datagram) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the source port of the UDP datagram. #[inline] pub fn source_port(&self) -> u16 { self.bytes.ntohs_unchecked(SOURCE_PORT_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the destination port of the UDP datagram. #[inline] pub fn destination_port(&self) -> u16 { self.bytes.ntohs_unchecked(DESTINATION_PORT_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the datagram from its header. #[inline] pub fn len(&self) -> u16 { self.bytes.ntohs_unchecked(LENGTH_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the checksum value of the packet. #[inline] pub fn checksum(&self) -> u16 { self.bytes.ntohs_unchecked(CHECKSUM_OFFSET) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the payload of the UDP datagram as an `[&u8]` slice. #[inline] pub fn payload(&self) -> &[u8] { @@ -116,6 +123,7 @@ impl<'a, T: NetworkBytes + Debug> UdpDatagram<'a, T> { self.bytes.split_at(PAYLOAD_OFFSET).1 } + #[tracing::instrument(level = "trace", skip(self, src_addr, dst_addr))] /// Computes the checksum of a UDP datagram. #[inline] pub fn compute_checksum(&self, src_addr: Ipv4Addr, dst_addr: Ipv4Addr) -> u16 { @@ -124,6 +132,7 @@ impl<'a, T: NetworkBytes + Debug> UdpDatagram<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> UdpDatagram<'a, T> { + #[tracing::instrument(level = "trace", skip(buf, payload))] /// Writes an incomplete UDP datagram, which is missing the `checksum`, `src_port` and /// `dst_port` fields. /// @@ -148,6 +157,7 @@ impl<'a, T: NetworkBytesMut + Debug> UdpDatagram<'a, T> { Ok(Incomplete::new(packet)) } + #[tracing::instrument(level = "trace", skip(self, src_port))] /// Sets the source port of the UDP datagram. #[inline] pub fn set_source_port(&mut self, src_port: u16) -> &mut Self { @@ -155,6 +165,7 @@ impl<'a, T: NetworkBytesMut + Debug> UdpDatagram<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, dst_port))] /// Sets the destination port of the UDP datagram. #[inline] pub fn set_destination_port(&mut self, dst_port: u16) -> &mut Self { @@ -163,12 +174,14 @@ impl<'a, T: NetworkBytesMut + Debug> UdpDatagram<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self))] /// Sets the payload of the UDP datagram. #[inline] pub fn payload_mut(&mut self) -> &mut [u8] { &mut self.bytes[PAYLOAD_OFFSET..] } + #[tracing::instrument(level = "trace", skip(self, len))] /// Sets the length field in the UDP datagram header. #[inline] pub fn set_len(&mut self, len: u16) -> &mut Self { @@ -176,6 +189,7 @@ impl<'a, T: NetworkBytesMut + Debug> UdpDatagram<'a, T> { self } + #[tracing::instrument(level = "trace", skip(self, checksum))] /// Sets the checksum of a UDP datagram. #[inline] pub fn set_checksum(&mut self, checksum: u16) -> &mut Self { @@ -185,6 +199,7 @@ impl<'a, T: NetworkBytesMut + Debug> UdpDatagram<'a, T> { } impl<'a, T: NetworkBytesMut + Debug> Incomplete> { + #[tracing::instrument(level = "trace", skip(self, src_port, dst_port, compute_checksum))] /// Transforms `self` into a `UdpDatagram` by specifying values for the `source port`, /// `destination port`, and (optionally) the information required to compute the checksum. #[inline] diff --git a/src/dumbo/src/tcp/connection.rs b/src/dumbo/src/tcp/connection.rs index 2fdbc338695..58f602d6504 100644 --- a/src/dumbo/src/tcp/connection.rs +++ b/src/dumbo/src/tcp/connection.rs @@ -200,6 +200,7 @@ pub struct Connection { status_flags: ConnStatusFlags, } +#[tracing::instrument(level = "trace", skip(segment))] fn parse_mss_option( segment: &TcpSegment, ) -> Result { @@ -210,11 +211,16 @@ fn parse_mss_option( } } +#[tracing::instrument(level = "trace", skip(segment))] fn is_valid_syn(segment: &TcpSegment) -> bool { segment.flags_after_ns() == TcpFlags::SYN && segment.payload_len() == 0 } impl Connection { + #[tracing::instrument( + level = "trace", + skip(segment, local_rwnd_size, rto_period, rto_count_max) + )] /// Attempts to create a new `Connection` in response to an incoming `SYN` segment. /// /// # Arguments @@ -273,42 +279,52 @@ impl Connection { }) } + #[tracing::instrument(level = "trace", skip(self, flags))] fn flags_intersect(&self, flags: ConnStatusFlags) -> bool { self.status_flags.intersects(flags) } + #[tracing::instrument(level = "trace", skip(self, flags))] fn set_flags(&mut self, flags: ConnStatusFlags) { self.status_flags.insert(flags); } + #[tracing::instrument(level = "trace", skip(self, flags))] fn clear_flags(&mut self, flags: ConnStatusFlags) { self.status_flags.remove(flags); } + #[tracing::instrument(level = "trace", skip(self))] fn syn_received(&self) -> bool { self.flags_intersect(ConnStatusFlags::SYN_RECEIVED) } + #[tracing::instrument(level = "trace", skip(self))] fn synack_pending(&self) -> bool { self.syn_received() && !self.synack_sent() } + #[tracing::instrument(level = "trace", skip(self))] fn synack_sent(&self) -> bool { self.flags_intersect(ConnStatusFlags::SYNACK_SENT) } + #[tracing::instrument(level = "trace", skip(self))] fn is_reset(&self) -> bool { self.flags_intersect(ConnStatusFlags::RESET) } + #[tracing::instrument(level = "trace", skip(self))] fn fin_sent(&self) -> bool { self.flags_intersect(ConnStatusFlags::FIN_SENT) } + #[tracing::instrument(level = "trace", skip(self))] fn fin_acked(&self) -> bool { self.flags_intersect(ConnStatusFlags::FIN_ACKED) } + #[tracing::instrument(level = "trace", skip(self, segment))] fn is_same_syn(&self, segment: &TcpSegment) -> bool { // This only really makes sense before getting into ESTABLISHED, but that's fine // because we only use it before that point. @@ -320,22 +336,26 @@ impl Connection { matches!(parse_mss_option(segment), Ok(mss) if mss == self.mss) } + #[tracing::instrument(level = "trace", skip(self, s))] fn reset_for_segment(&mut self, s: &TcpSegment) { if !self.rst_pending() { self.send_rst = Some(RstConfig::new(s)); } } + #[tracing::instrument(level = "trace", skip(self))] fn rst_pending(&self) -> bool { self.send_rst.is_some() } + #[tracing::instrument(level = "trace", skip(self, now))] fn rto_expired(&self, now: u64) -> bool { now - self.rto_start >= self.rto_period } // We send a FIN control segment if every data byte up to the self.send_fin sequence number // has been ACKed by the other endpoint, and no FIN has been previously sent. + #[tracing::instrument(level = "trace", skip(self))] fn can_send_first_fin(&self) -> bool { !self.fin_sent() && matches!(self.send_fin, Some(fin_seq) if fin_seq == self.highest_ack_received) @@ -343,6 +363,7 @@ impl Connection { // Returns the window size which should be written to an outgoing segment. This is going to be // even more useful when we'll support window scaling. + #[tracing::instrument(level = "trace", skip(self))] fn local_rwnd(&self) -> u16 { let rwnd = (self.local_rwnd_edge - self.ack_to_send).0; @@ -354,21 +375,25 @@ impl Connection { } // Will actually become meaningful when/if we implement window scaling. + #[tracing::instrument(level = "trace", skip(self, window_size))] fn remote_window_size(&self, window_size: u16) -> u32 { u32::from(window_size) } // Computes the remote rwnd edge given the ACK number and window size from an incoming segment. + #[tracing::instrument(level = "trace", skip(self, ack, window_size))] fn compute_remote_rwnd_edge(&self, ack: Wrapping, window_size: u16) -> Wrapping { ack + Wrapping(self.remote_window_size(window_size)) } // Has this name just in case the pending_ack status will be more than just some boolean at // some point in the future. + #[tracing::instrument(level = "trace", skip(self))] fn enqueue_ack(&mut self) { self.pending_ack = true; } + #[tracing::instrument(level = "trace", skip(self))] /// Closes this half of the connection. /// /// Subsequent calls after the first one do not have any effect. The sequence number of the @@ -380,6 +405,7 @@ impl Connection { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a valid configuration for a `RST` segment, which can be sent to the other /// endpoint to signal the connection should be reset. #[inline] @@ -391,6 +417,7 @@ impl Connection { } } + #[tracing::instrument(level = "trace", skip(self))] /// Specifies that a `RST` segment should be sent to the other endpoint, and then the /// connection should be destroyed. #[inline] @@ -400,12 +427,14 @@ impl Connection { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns `true` if the connection is past the `ESTABLISHED` point. #[inline] pub fn is_established(&self) -> bool { self.flags_intersect(ConnStatusFlags::ESTABLISHED) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns `true` if a `FIN` has been received. #[inline] pub fn fin_received(&self) -> bool { @@ -413,6 +442,7 @@ impl Connection { } // TODO: The description of this method is also a TODO in disguise. + #[tracing::instrument(level = "trace", skip(self))] /// Returns `true` if the connection is done communicating with the other endpoint. /// /// Maybe it would be a good idea to return true only after our FIN has also been ACKed? @@ -425,18 +455,21 @@ impl Connection { self.is_reset() || (self.fin_received() && self.flags_intersect(ConnStatusFlags::FIN_SENT)) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the first sequence number which has not been sent yet for the current window. #[inline] pub fn first_not_sent(&self) -> Wrapping { self.first_not_sent } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the highest acknowledgement number received for the current window. #[inline] pub fn highest_ack_received(&self) -> Wrapping { self.highest_ack_received } + #[tracing::instrument(level = "trace", skip(self, value))] /// Advances the right edge of the local receive window. /// /// This is effectively allowing the other endpoint to send more data, because no byte can be @@ -460,18 +493,21 @@ impl Connection { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the right edge of the receive window advertised by the other endpoint. #[inline] pub fn remote_rwnd_edge(&self) -> Wrapping { self.remote_rwnd_edge } + #[tracing::instrument(level = "trace", skip(self))] /// Returns `true` if a retransmission caused by the reception of a duplicate `ACK` is pending. #[inline] pub fn dup_ack_pending(&self) -> bool { self.dup_ack } + #[tracing::instrument(level = "trace", skip(self))] /// Describes whether a control segment can be sent immediately, a retransmission is pending, /// or there's nothing to transmit until more segments are received. /// @@ -496,6 +532,7 @@ impl Connection { // We use this helper method to set up self.send_rst and prepare a return value in one go. It's // only used by the receive_segment() method. + #[tracing::instrument(level = "trace", skip(self, s, flags))] fn reset_for_segment_helper( &mut self, s: &TcpSegment, @@ -505,6 +542,7 @@ impl Connection { Ok((None, RecvStatusFlags::CONN_RESETTING | flags)) } + #[tracing::instrument(level = "trace", skip(self, s, buf, now))] /// Handles an incoming segment. /// /// When no errors occur, returns a pair consisting of how many @@ -731,6 +769,10 @@ impl Connection { // destination L3 addresses (which are required for checksum computation). We need this stupid // ?Sized trait bound, because otherwise Sized would be implied, and we can have unsized types // which implement ByteBuffer (such as [u8]), since payload expects a reference to some R. + #[tracing::instrument( + level = "trace", + skip(self, buf, mss_reserved, seq, ack, flags_after_ns, payload) + )] fn write_segment<'a, R: ByteBuffer + ?Sized + Debug>( &mut self, buf: &'a mut [u8], @@ -768,6 +810,7 @@ impl Connection { } // Control segments are segments with no payload (at least I like to use this name). + #[tracing::instrument(level = "trace", skip(self, buf, mss_reserved))] fn write_control_segment<'a, R: ByteBuffer + ?Sized + Debug>( &mut self, buf: &'a mut [u8], @@ -806,6 +849,7 @@ impl Connection { self.write_segment::(buf, mss_reserved, seq, ack, flags_after_ns, None) } + #[tracing::instrument(level = "trace", skip(self, buf, mss_reserved, payload_src, now))] /// Writes a new segment (if available) to the specified buffer. /// /// The `payload_src` argument is required because the `Connection` does not have an internal @@ -1041,6 +1085,7 @@ pub(crate) mod tests { } impl ConnectionTester { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> Self { ConnectionTester { buf: [0u8; 2000], @@ -1057,6 +1102,7 @@ pub(crate) mod tests { } } + #[tracing::instrument(level = "trace", skip(self, s))] fn passive_open( &self, s: &TcpSegment, @@ -1071,6 +1117,7 @@ pub(crate) mod tests { // This helps write segments; it uses a lot of default values, and sets the ACK and SEQ // numbers to 0, and self.remote_isn respectively. + #[tracing::instrument(level = "trace", skip(self, buf, add_mss_option, payload))] fn write_segment_helper<'a>( &self, buf: &'a mut [u8], @@ -1094,14 +1141,17 @@ pub(crate) mod tests { .unwrap() } + #[tracing::instrument(level = "trace", skip(self, buf))] pub fn write_syn<'a>(&self, buf: &'a mut [u8]) -> TcpSegment<'a, &'a mut [u8]> { self.write_segment_helper(buf, true, None) } + #[tracing::instrument(level = "trace", skip(self, buf))] pub fn write_ctrl<'a>(&self, buf: &'a mut [u8]) -> TcpSegment<'a, &'a mut [u8]> { self.write_segment_helper(buf, false, None) } + #[tracing::instrument(level = "trace", skip(self, buf, data_buf))] pub fn write_data<'a>( &self, buf: &'a mut [u8], @@ -1112,6 +1162,7 @@ pub(crate) mod tests { segment } + #[tracing::instrument(level = "trace", skip(self, c, s))] fn receive_segment( &mut self, c: &mut Connection, @@ -1120,6 +1171,7 @@ pub(crate) mod tests { c.receive_segment(s, self.buf.as_mut(), self.now) } + #[tracing::instrument(level = "trace", skip(self, c, payload_src))] fn write_next_segment( &mut self, c: &mut Connection, @@ -1135,6 +1187,10 @@ pub(crate) mod tests { // that the receive_segment() method also returns the specified RecvStatusFlags. We // also make sure the outgoing RST segment has additional_segment_flags set besides // TcpFlags::RST. + #[tracing::instrument( + level = "trace", + skip(self, c, s, recv_flags, additional_segment_flags) + )] fn should_reset_after( &mut self, c: &mut Connection, @@ -1174,6 +1230,7 @@ pub(crate) mod tests { } // Checks that the next segment sent by c is a SYNACK. + #[tracing::instrument(level = "trace", skip(self, c))] fn check_synack_is_next(&mut self, c: &mut Connection) { let send_buf = [0u8; 2000]; let payload_src = Some((send_buf.as_ref(), c.highest_ack_received)); @@ -1196,6 +1253,7 @@ pub(crate) mod tests { } // Verifies whether we are dealing with a control segment with the specified flags. + #[tracing::instrument(level = "trace", skip(s, options_len, flags_after_ns))] fn check_control_segment( s: &TcpSegment, options_len: usize, @@ -1207,6 +1265,7 @@ pub(crate) mod tests { // Checks if the segment ACKs the specified sequence number, and whether the additional_flags // are set (besides ACK). + #[tracing::instrument(level = "trace", skip(s, ack_number, additional_flags))] fn check_acks( s: &TcpSegment, ack_number: u32, @@ -1219,10 +1278,12 @@ pub(crate) mod tests { // The following "check_" helper functions ensure a Connection in a certain state does not have // any unwarranted status flags set. We wouldn't need to look at this if we used a state enum // instead of a status flags set. + #[tracing::instrument(level = "trace", skip(c))] fn check_syn_received(c: &Connection) { assert_eq!(c.status_flags, ConnStatusFlags::SYN_RECEIVED); } + #[tracing::instrument(level = "trace", skip(c))] fn check_synack_sent(c: &Connection) { assert_eq!( c.status_flags, @@ -1230,6 +1291,7 @@ pub(crate) mod tests { ); } + #[tracing::instrument(level = "trace", skip(c))] fn check_established(c: &Connection) { assert_eq!( c.status_flags, @@ -1239,6 +1301,7 @@ pub(crate) mod tests { ); } + #[tracing::instrument(level = "trace", skip(c))] fn check_fin_received_but_not_sent(c: &Connection) { assert_eq!( c.status_flags, diff --git a/src/dumbo/src/tcp/endpoint.rs b/src/dumbo/src/tcp/endpoint.rs index e9d0461776b..7e89eb3875b 100644 --- a/src/dumbo/src/tcp/endpoint.rs +++ b/src/dumbo/src/tcp/endpoint.rs @@ -81,6 +81,15 @@ pub struct Endpoint { // is the only option). impl Endpoint { + #[tracing::instrument( + level = "trace", + skip( + segment, + eviction_threshold, + connection_rto_period, + connection_rto_count_max + ) + )] pub fn new( segment: &TcpSegment, eviction_threshold: NonZeroU64, @@ -114,6 +123,7 @@ impl Endpoint { }) } + #[tracing::instrument(level = "trace", skip(segment))] pub fn new_with_defaults( segment: &TcpSegment, ) -> Result { @@ -126,6 +136,7 @@ impl Endpoint { ) } + #[tracing::instrument(level = "trace", skip(self, s, callback))] pub fn receive_segment Response>( &mut self, s: &TcpSegment, @@ -244,6 +255,7 @@ impl Endpoint { } } + #[tracing::instrument(level = "trace", skip(self, buf, mss_reserved))] pub fn write_next_segment<'a>( &mut self, buf: &'a mut [u8], @@ -276,17 +288,20 @@ impl Endpoint { } } + #[tracing::instrument(level = "trace", skip(self))] #[inline] pub fn is_done(&self) -> bool { self.connection.is_done() } + #[tracing::instrument(level = "trace", skip(self))] #[inline] pub fn is_evictable(&self) -> bool { timestamp_cycles().wrapping_sub(self.last_segment_received_timestamp) > self.eviction_threshold } + #[tracing::instrument(level = "trace", skip(self))] pub fn next_segment_status(&self) -> NextSegmentStatus { let can_send_new_data = !self.response_buf.is_empty() && seq_after( @@ -301,18 +316,21 @@ impl Endpoint { } } + #[tracing::instrument(level = "trace", skip(self))] #[inline] pub fn connection(&self) -> &Connection { &self.connection } } +#[tracing::instrument(level = "trace", skip(status_code, body))] fn build_response(status_code: StatusCode, body: Body) -> Response { let mut response = Response::new(Version::default(), status_code); response.set_body(body); response } +#[tracing::instrument(level = "trace", skip(byte_stream, callback))] /// Parses the request bytes and builds a `micro_http::Response` by the given callback function. fn parse_request_bytes Response>( byte_stream: &[u8], @@ -359,6 +377,7 @@ mod tests { use crate::tcp::tests::mock_callback; impl Endpoint { + #[tracing::instrument(level = "trace", skip(self, value))] pub fn set_eviction_threshold(&mut self, value: u64) { self.eviction_threshold = value; } diff --git a/src/dumbo/src/tcp/handler.rs b/src/dumbo/src/tcp/handler.rs index 764b5f452ae..4906f1d7709 100644 --- a/src/dumbo/src/tcp/handler.rs +++ b/src/dumbo/src/tcp/handler.rs @@ -88,6 +88,7 @@ struct ConnectionTuple { } impl ConnectionTuple { + #[tracing::instrument(level = "trace", skip(remote_addr, remote_port))] fn new(remote_addr: Ipv4Addr, remote_port: u16) -> Self { ConnectionTuple { remote_addr, @@ -152,6 +153,10 @@ enum RecvSegmentOutcome { } impl TcpIPv4Handler { + #[tracing::instrument( + level = "trace", + skip(local_ipv4_addr, local_port, max_connections, max_pending_resets) + )] /// Creates a new `TcpIPv4Handler`. /// /// The handler acts as if bound to `local_addr`:`local_port`, and will accept at most @@ -178,31 +183,37 @@ impl TcpIPv4Handler { } } + #[tracing::instrument(level = "trace", skip(self, ipv4_addr))] /// Setter for the local IPv4 address of this TCP handler. pub fn set_local_ipv4_addr(&mut self, ipv4_addr: Ipv4Addr) { self.local_ipv4_addr = ipv4_addr; } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the local IPv4 address of this TCP handler. pub fn local_ipv4_addr(&self) -> Ipv4Addr { self.local_ipv4_addr } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the local port of this TCP handler. pub fn local_port(&self) -> u16 { self.local_port } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the max connections of this TCP handler. pub fn max_connections(&self) -> usize { self.max_connections } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the max pending resets of this TCP handler. pub fn max_pending_resets(&self) -> usize { self.max_pending_resets } + #[tracing::instrument(level = "trace", skip(self, packet, callback))] /// Contains logic for handling incoming segments. /// /// Any changes to the state of the handler are communicated through an `Ok(RecvEvent)`. @@ -286,6 +297,7 @@ impl TcpIPv4Handler { } } + #[tracing::instrument(level = "trace", skip(self, value, tuple))] fn check_timeout(&mut self, value: u64, tuple: ConnectionTuple) { match self.next_timeout { Some((t, _)) if t > value => self.next_timeout = Some((value, tuple)), @@ -294,6 +306,7 @@ impl TcpIPv4Handler { }; } + #[tracing::instrument(level = "trace", skip(self))] fn find_next_timeout(&mut self) { let mut next_timeout = None; for (tuple, endpoint) in self.connections.iter() { @@ -312,6 +325,7 @@ impl TcpIPv4Handler { // Returns true if the endpoint has been added to the set of active connections (it may have // been there already). + #[tracing::instrument(level = "trace", skip(self, tuple, status))] fn check_next_segment_status( &mut self, tuple: ConnectionTuple, @@ -334,11 +348,13 @@ impl TcpIPv4Handler { false } + #[tracing::instrument(level = "trace", skip(self, tuple, endpoint))] fn add_connection(&mut self, tuple: ConnectionTuple, endpoint: Endpoint) { self.check_next_segment_status(tuple, endpoint.next_segment_status()); self.connections.insert(tuple, endpoint); } + #[tracing::instrument(level = "trace", skip(self, tuple))] fn remove_connection(&mut self, tuple: ConnectionTuple) { // Just in case it's in there somewhere. self.active_connections.remove(&tuple); @@ -352,6 +368,7 @@ impl TcpIPv4Handler { } // TODO: I guess this should be refactored at some point to also remove the endpoint if found. + #[tracing::instrument(level = "trace", skip(self))] fn find_evictable_connection(&self) -> Option { for (tuple, endpoint) in self.connections.iter() { if endpoint.is_evictable() { @@ -361,6 +378,7 @@ impl TcpIPv4Handler { None } + #[tracing::instrument(level = "trace", skip(self, tuple, cfg))] fn enqueue_rst_config(&mut self, tuple: ConnectionTuple, cfg: RstConfig) { // We simply forgo sending any RSTs if the queue is already full. if self.rst_queue.len() < self.max_pending_resets { @@ -368,10 +386,12 @@ impl TcpIPv4Handler { } } + #[tracing::instrument(level = "trace", skip(self, tuple, s))] fn enqueue_rst(&mut self, tuple: ConnectionTuple, s: &TcpSegment) { self.enqueue_rst_config(tuple, RstConfig::new(s)); } + #[tracing::instrument(level = "trace", skip(self, buf))] /// Attempts to write one packet, from either the `RST` queue or one of the existing endpoints, /// to `buf`. /// @@ -487,6 +507,7 @@ impl TcpIPv4Handler { Ok((len, event)) } + #[tracing::instrument(level = "trace", skip(self))] /// Describes the status of the next segment to be sent by the handler. #[inline] pub fn next_segment_status(&self) -> NextSegmentStatus { @@ -510,12 +531,14 @@ mod tests { use crate::pdu::bytes::NetworkBytesMut; use crate::tcp::tests::mock_callback; + #[tracing::instrument(level = "trace", skip(p))] fn inner_tcp_mut<'a, T: NetworkBytesMut + Debug>( p: &'a mut IPv4Packet<'_, T>, ) -> TcpSegment<'a, &'a mut [u8]> { TcpSegment::from_bytes(p.payload_mut(), None).unwrap() } + #[tracing::instrument(level = "trace", skip(h, buf))] #[allow(clippy::type_complexity)] fn write_next<'a>( h: &mut TcpIPv4Handler, @@ -532,6 +555,7 @@ mod tests { }) } + #[tracing::instrument(level = "trace", skip(h, buf, expected_event))] fn next_written_segment<'a>( h: &mut TcpIPv4Handler, buf: &'a mut [u8], @@ -550,6 +574,7 @@ mod tests { // Calls write_next_packet until either an error occurs, or there's nothing left to send. // When successful, returns how many packets were written. The remote_addr argument is used // to check the packets are sent to the appropriate destination. + #[tracing::instrument(level = "trace", skip(h, src_addr, remote_addr))] fn drain_packets( h: &mut TcpIPv4Handler, src_addr: Ipv4Addr, diff --git a/src/dumbo/src/tcp/mod.rs b/src/dumbo/src/tcp/mod.rs index db63cc6371c..0c1fb76d365 100644 --- a/src/dumbo/src/tcp/mod.rs +++ b/src/dumbo/src/tcp/mod.rs @@ -46,6 +46,7 @@ pub enum RstConfig { } impl RstConfig { + #[tracing::instrument(level = "trace", skip(s))] /// Creates a `RstConfig` in response to the given segment. pub fn new(s: &TcpSegment) -> Self { if s.flags_after_ns().intersects(TcpFlags::ACK) { @@ -57,6 +58,7 @@ impl RstConfig { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the sequence number, acknowledgement number, and TCP flags (not counting `NS`) that /// must be set on the outgoing `RST` segment. pub fn seq_ack_tcp_flags(self) -> (u32, u32, TcpFlags) { @@ -67,6 +69,7 @@ impl RstConfig { } } +#[tracing::instrument(level = "trace", skip(a, b))] /// Returns true if `a` comes after `b` in the sequence number space, relative to the maximum /// possible window size. /// @@ -78,6 +81,7 @@ pub fn seq_after(a: Wrapping, b: Wrapping) -> bool { a != b && (a - b).0 < MAX_WINDOW_SIZE } +#[tracing::instrument(level = "trace", skip(a, b))] /// Returns true if `a` comes after, or is at `b` in the sequence number space, relative to /// the maximum possible window size. /// @@ -97,6 +101,7 @@ mod tests { // In tcp tests, some of the functions require a callback parameter. Since we do not care, // for the purpose of those tests, what that callback does, we need to provide a dummy one. + #[tracing::instrument(level = "trace", skip(_request))] pub fn mock_callback(_request: Request) -> Response { Response::new(Version::Http11, StatusCode::OK) } diff --git a/src/firecracker/Cargo.toml b/src/firecracker/Cargo.toml index cd6b15d5fe6..31d3c06e344 100644 --- a/src/firecracker/Cargo.toml +++ b/src/firecracker/Cargo.toml @@ -15,9 +15,12 @@ bench = false [dependencies] event-manager = "0.3.0" libc = "0.2.147" +log = "0.4.19" serde_json = "1.0.104" thiserror = "1.0.44" timerfd = "1.5.0" +tracing = { version = "0.1.37", features = ["max_level_debug"] } +tracing-subscriber = "0.3.17" api_server = { path = "../api_server" } logger = { path = "../logger" } diff --git a/src/firecracker/examples/seccomp/harmless.rs b/src/firecracker/examples/seccomp/harmless.rs index ab961548bed..e396273b5a9 100644 --- a/src/firecracker/examples/seccomp/harmless.rs +++ b/src/firecracker/examples/seccomp/harmless.rs @@ -1,5 +1,6 @@ // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +#[tracing::instrument(level = "trace", skip())] fn main() { unsafe { // Harmless print to standard output. diff --git a/src/firecracker/examples/seccomp/jailer.rs b/src/firecracker/examples/seccomp/jailer.rs index f82e3f5e249..1980fe1efac 100644 --- a/src/firecracker/examples/seccomp/jailer.rs +++ b/src/firecracker/examples/seccomp/jailer.rs @@ -7,6 +7,7 @@ use std::process::{Command, Stdio}; use seccompiler::{apply_filter, deserialize_binary}; +#[tracing::instrument(level = "trace", skip())] fn main() { let args: Vec = args().collect(); let exec_file = &args[1]; diff --git a/src/firecracker/examples/seccomp/malicious.rs b/src/firecracker/examples/seccomp/malicious.rs index 14ef85e8253..43b96563ba5 100644 --- a/src/firecracker/examples/seccomp/malicious.rs +++ b/src/firecracker/examples/seccomp/malicious.rs @@ -1,5 +1,6 @@ // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +#[tracing::instrument(level = "trace", skip())] fn main() { unsafe { // In this example, the malicious component is outputting to standard input. diff --git a/src/firecracker/examples/seccomp/panic.rs b/src/firecracker/examples/seccomp/panic.rs index 7998552a4d1..51302c56d8f 100644 --- a/src/firecracker/examples/seccomp/panic.rs +++ b/src/firecracker/examples/seccomp/panic.rs @@ -5,6 +5,7 @@ use std::fs::File; use seccompiler::{apply_filter, deserialize_binary}; +#[tracing::instrument(level = "trace", skip())] fn main() { let args: Vec = args().collect(); let bpf_path = &args[1]; diff --git a/src/firecracker/examples/uffd/malicious_handler.rs b/src/firecracker/examples/uffd/malicious_handler.rs index 288db524d49..df3eb9a3e78 100644 --- a/src/firecracker/examples/uffd/malicious_handler.rs +++ b/src/firecracker/examples/uffd/malicious_handler.rs @@ -10,6 +10,7 @@ use std::os::unix::io::AsRawFd; use uffd_utils::create_pf_handler; +#[tracing::instrument(level = "trace", skip())] fn main() { let uffd_handler = create_pf_handler(); diff --git a/src/firecracker/examples/uffd/uffd_utils.rs b/src/firecracker/examples/uffd/uffd_utils.rs index 9f2310c6076..4e77deb6911 100644 --- a/src/firecracker/examples/uffd/uffd_utils.rs +++ b/src/firecracker/examples/uffd/uffd_utils.rs @@ -58,6 +58,7 @@ pub enum MemPageState { } impl UffdPfHandler { + #[tracing::instrument(level = "trace", skip(stream, data, size))] pub fn from_unix_stream(stream: UnixStream, data: *const u8, size: usize) -> Self { let mut message_buf = vec![0u8; 1024]; let (bytes_read, file) = stream @@ -89,6 +90,7 @@ impl UffdPfHandler { } } + #[tracing::instrument(level = "trace", skip(self, start, end, state))] pub fn update_mem_state_mappings(&mut self, start: u64, end: u64, state: &MemPageState) { for region in self.mem_regions.iter_mut() { for (key, value) in region.page_states.iter_mut() { @@ -99,6 +101,7 @@ impl UffdPfHandler { } } + #[tracing::instrument(level = "trace", skip(self, region))] fn populate_from_file(&self, region: &MemRegion) -> (u64, u64) { let src = self.backing_buffer as u64 + region.mapping.offset; let start_addr = region.mapping.base_host_virt_addr; @@ -118,6 +121,7 @@ impl UffdPfHandler { return (start_addr, start_addr + len as u64); } + #[tracing::instrument(level = "trace", skip(self, addr))] fn zero_out(&mut self, addr: u64) -> (u64, u64) { let page_size = get_page_size().unwrap(); @@ -132,6 +136,7 @@ impl UffdPfHandler { return (addr, addr + page_size as u64); } + #[tracing::instrument(level = "trace", skip(self, addr))] pub fn serve_pf(&mut self, addr: *mut u8) { let page_size = get_page_size().unwrap(); @@ -173,6 +178,7 @@ impl UffdPfHandler { } } +#[tracing::instrument(level = "trace", skip(stream))] fn get_peer_process_credentials(stream: UnixStream) -> libc::ucred { let mut creds: libc::ucred = libc::ucred { pid: 0, @@ -197,6 +203,7 @@ fn get_peer_process_credentials(stream: UnixStream) -> libc::ucred { creds } +#[tracing::instrument(level = "trace", skip(mappings))] fn create_mem_regions(mappings: &Vec) -> Vec { let page_size = get_page_size().unwrap(); let mut mem_regions: Vec = Vec::with_capacity(mappings.len()); @@ -220,6 +227,7 @@ fn create_mem_regions(mappings: &Vec) -> Vec mem_regions } +#[tracing::instrument(level = "trace", skip())] pub fn create_pf_handler() -> UffdPfHandler { let uffd_sock_path = std::env::args().nth(1).expect("No socket path given"); let mem_file_path = std::env::args().nth(2).expect("No memory file given"); diff --git a/src/firecracker/examples/uffd/valid_handler.rs b/src/firecracker/examples/uffd/valid_handler.rs index c83e3ce1300..15340d797e1 100644 --- a/src/firecracker/examples/uffd/valid_handler.rs +++ b/src/firecracker/examples/uffd/valid_handler.rs @@ -11,6 +11,7 @@ use std::os::unix::io::AsRawFd; use uffd_utils::{create_pf_handler, MemPageState}; +#[tracing::instrument(level = "trace", skip())] fn main() { let mut uffd_handler = create_pf_handler(); diff --git a/src/firecracker/src/api_server_adapter.rs b/src/firecracker/src/api_server_adapter.rs index f91d06cb041..d7234eb3015 100644 --- a/src/firecracker/src/api_server_adapter.rs +++ b/src/firecracker/src/api_server_adapter.rs @@ -45,6 +45,10 @@ struct ApiServerAdapter { } impl ApiServerAdapter { + #[tracing::instrument( + level = "trace", + skip(api_event_fd, from_api, to_api, vm_resources, vmm, event_manager) + )] /// Runs the vmm to completion, while any arising control events are deferred /// to a `RuntimeApiController`. fn run_microvm( @@ -72,6 +76,7 @@ impl ApiServerAdapter { } } + #[tracing::instrument(level = "trace", skip(self, req_action))] fn handle_request(&mut self, req_action: VmmAction) { let response = self.controller.handle_request(req_action); // Send back the result. @@ -82,6 +87,7 @@ impl ApiServerAdapter { } } impl MutEventSubscriber for ApiServerAdapter { + #[tracing::instrument(level = "trace", skip(self, event))] /// Handle a read event (EPOLLIN). fn process(&mut self, event: Events, _: &mut EventOps) { let source = event.fd(); @@ -124,6 +130,7 @@ impl MutEventSubscriber for ApiServerAdapter { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.api_event_fd, EventSet::IN)) { error!("Failed to register activate event: {}", err); @@ -131,8 +138,26 @@ impl MutEventSubscriber for ApiServerAdapter { } } +#[tracing::instrument( + level = "trace", + skip( + seccomp_filters, + config_json, + bind_path, + instance_info, + process_time_reporter, + boot_timer_enabled, + api_payload_limit, + mmds_size_limit, + metadata_json, + logger_handles + ) +)] #[allow(clippy::too_many_arguments)] -pub(crate) fn run_with_api( +pub(crate) fn run_with_api< + F: Fn(&tracing::Metadata<'_>) -> bool, + G: Fn(&tracing::Metadata<'_>) -> bool, +>( seccomp_filters: &mut BpfThreadMap, config_json: Option, bind_path: PathBuf, @@ -142,6 +167,7 @@ pub(crate) fn run_with_api( api_payload_limit: usize, mmds_size_limit: usize, metadata_json: Option<&str>, + logger_handles: vmm::vmm_config::logger::LoggerHandles, ) -> Result<(), ApiServerError> { // FD to notify of API events. This is a blocking eventfd by design. // It is used in the config/pre-boot loop which is a simple blocking loop @@ -211,6 +237,7 @@ pub(crate) fn run_with_api( boot_timer_enabled, mmds_size_limit, metadata_json, + logger_handles, ) .map_err(ApiServerError::MicroVMStoppedWithError), }; diff --git a/src/firecracker/src/main.rs b/src/firecracker/src/main.rs index 1a1d3f836d6..7716aa9c0e4 100644 --- a/src/firecracker/src/main.rs +++ b/src/firecracker/src/main.rs @@ -8,12 +8,13 @@ mod seccomp; use std::fs::{self, File}; use std::path::PathBuf; use std::process::ExitCode; +use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::{io, panic}; use api_server_adapter::ApiServerError; use event_manager::SubscriberOps; -use logger::{error, info, ProcessTimeReporter, StoreMetric, LOGGER, METRICS}; +use logger::{error, info, ProcessTimeReporter, StoreMetric, METRICS}; use seccomp::FilterError; use seccompiler::BpfThreadMap; use snapshot::{Error as SnapshotError, Snapshot}; @@ -25,8 +26,8 @@ use vmm::resources::VmResources; use vmm::signal_handler::register_signal_handlers; use vmm::version_map::{FC_VERSION_TO_SNAP_VERSION, VERSION_MAP}; use vmm::vmm_config::instance_info::{InstanceInfo, VmState}; -use vmm::vmm_config::logger::{init_logger, LoggerConfig, LoggerConfigError, LoggerLevel}; -use vmm::vmm_config::metrics::{init_metrics, MetricsConfig, MetricsConfigError}; +use vmm::vmm_config::logger::LevelFilter; +use vmm::vmm_config::metrics::{init_metrics, MetricsConfig}; use vmm::{EventManager, FcExitCode, HTTP_MAX_PAYLOAD_SIZE}; use crate::seccomp::SeccompConfig; @@ -35,7 +36,6 @@ use crate::seccomp::SeccompConfig; // runtime file. // see https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s15.html for more information. const DEFAULT_API_SOCK_PATH: &str = "/run/firecracker.socket"; -const DEFAULT_INSTANCE_ID: &str = "anonymous-instance"; const FIRECRACKER_VERSION: &str = env!("FIRECRACKER_VERSION"); const MMDS_CONTENT_ARG: &str = "metadata"; @@ -47,12 +47,17 @@ enum MainError { ParseArguments(#[from] utils::arg_parser::Error), #[error("When printing Snapshot Data format: {0}")] PrintSnapshotDataFormat(#[from] SnapshotVersionError), - #[error("Invalid value for logger level: {0}.Possible values: [Error, Warning, Info, Debug]")] - InvalidLogLevel(LoggerConfigError), + #[error( + "Invalid value for logger level: {0}.Possible values: [Off, Error, Warning, Info, Debug, \ + Trace]" + )] + InvalidLogLevel(::Err), + #[error("Failed to deserialize log filter: {0}")] + DeserializeLogFilter(serde_json::Error), #[error("Could not initialize logger: {0}")] - LoggerInitialization(LoggerConfigError), + LoggerInitialization(vmm::vmm_config::logger::InitLoggerError), #[error("Could not initialize metrics: {0:?}")] - MetricsInitialization(MetricsConfigError), + MetricsInitialization(vmm::vmm_config::metrics::MetricsConfigError), #[error("Seccomp error: {0}")] SeccompFilter(FilterError), #[error("RunWithApiError error: {0}")] @@ -62,6 +67,7 @@ enum MainError { } impl From for ExitCode { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: MainError) -> Self { let exit_code = match value { MainError::ParseArguments(_) => FcExitCode::ArgParsing, @@ -75,6 +81,7 @@ impl From for ExitCode { } } +#[tracing::instrument(level = "trace", skip())] fn main() -> ExitCode { let result = main_exec(); if let Err(err) = result { @@ -86,11 +93,8 @@ fn main() -> ExitCode { } } +#[tracing::instrument(level = "trace", skip())] fn main_exec() -> Result<(), MainError> { - LOGGER - .configure(Some(DEFAULT_INSTANCE_ID.to_string())) - .expect("Failed to register logger"); - register_signal_handlers().map_err(MainError::RegisterSignalHandlers)?; #[cfg(target_arch = "aarch64")] @@ -124,124 +128,141 @@ fn main_exec() -> Result<(), MainError> { let http_max_payload_size_str = HTTP_MAX_PAYLOAD_SIZE.to_string(); - let mut arg_parser = ArgParser::new() - .arg( - Argument::new("api-sock") - .takes_value(true) - .default_value(DEFAULT_API_SOCK_PATH) - .help("Path to unix domain socket used by the API."), - ) - .arg( - Argument::new("id") - .takes_value(true) - .default_value(DEFAULT_INSTANCE_ID) - .help("MicroVM unique identifier."), - ) - .arg( - Argument::new("seccomp-filter") - .takes_value(true) - .forbids(vec!["no-seccomp"]) - .help( - "Optional parameter which allows specifying the path to a custom seccomp \ - filter. For advanced users.", - ), - ) - .arg( - Argument::new("no-seccomp") - .takes_value(false) - .forbids(vec!["seccomp-filter"]) - .help( - "Optional parameter which allows starting and using a microVM without seccomp \ - filtering. Not recommended.", + let mut arg_parser = + ArgParser::new() + .arg( + Argument::new("api-sock") + .takes_value(true) + .default_value(DEFAULT_API_SOCK_PATH) + .help("Path to unix domain socket used by the API."), + ) + .arg( + Argument::new("id") + .takes_value(true) + .default_value("anonymous-instance") + .help("MicroVM unique identifier."), + ) + .arg( + Argument::new("seccomp-filter") + .takes_value(true) + .forbids(vec!["no-seccomp"]) + .help( + "Optional parameter which allows specifying the path to a custom seccomp \ + filter. For advanced users.", + ), + ) + .arg( + Argument::new("no-seccomp") + .takes_value(false) + .forbids(vec!["seccomp-filter"]) + .help( + "Optional parameter which allows starting and using a microVM without \ + seccomp filtering. Not recommended.", + ), + ) + .arg( + Argument::new("start-time-us").takes_value(true).help( + "Process start time (wall clock, microseconds). This parameter is optional.", ), - ) - .arg( - Argument::new("start-time-us") - .takes_value(true) - .help("Process start time (wall clock, microseconds). This parameter is optional."), - ) - .arg( - Argument::new("start-time-cpu-us").takes_value(true).help( + ) + .arg(Argument::new("start-time-cpu-us").takes_value(true).help( "Process start CPU time (wall clock, microseconds). This parameter is optional.", - ), - ) - .arg(Argument::new("parent-cpu-time-us").takes_value(true).help( - "Parent process CPU time (wall clock, microseconds). This parameter is optional.", - )) - .arg( - Argument::new("config-file") - .takes_value(true) - .help("Path to a file that contains the microVM configuration in JSON format."), - ) - .arg( - Argument::new(MMDS_CONTENT_ARG) - .takes_value(true) - .help("Path to a file that contains metadata in JSON format to add to the mmds."), - ) - .arg( - Argument::new("no-api") - .takes_value(false) - .requires("config-file") - .help( - "Optional parameter which allows starting and using a microVM without an \ - active API socket.", + )) + .arg(Argument::new("parent-cpu-time-us").takes_value(true).help( + "Parent process CPU time (wall clock, microseconds). This parameter is optional.", + )) + .arg( + Argument::new("config-file") + .takes_value(true) + .help("Path to a file that contains the microVM configuration in JSON format."), + ) + .arg( + Argument::new(MMDS_CONTENT_ARG).takes_value(true).help( + "Path to a file that contains metadata in JSON format to add to the mmds.", ), - ) - .arg( - Argument::new("log-path") - .takes_value(true) - .help("Path to a fifo or a file used for configuring the logger on startup."), - ) - .arg( - Argument::new("level") - .takes_value(true) - .requires("log-path") - .default_value("Warning") - .help("Set the logger level."), - ) - .arg( - Argument::new("show-level") - .takes_value(false) - .requires("log-path") - .help("Whether or not to output the level in the logs."), - ) - .arg( - Argument::new("show-log-origin") - .takes_value(false) - .requires("log-path") - .help( - "Whether or not to include the file path and line number of the log's origin.", + ) + .arg( + Argument::new("start-time-us").takes_value(true).help( + "Process start time (wall clock, microseconds). This parameter is optional.", ), - ) - .arg( - Argument::new("metrics-path") - .takes_value(true) - .help("Path to a fifo or a file used for configuring the metrics on startup."), - ) - .arg(Argument::new("boot-timer").takes_value(false).help( - "Whether or not to load boot timer device for logging elapsed time since \ - InstanceStart command.", - )) - .arg(Argument::new("version").takes_value(false).help( - "Print the binary version number and a list of supported snapshot data format \ - versions.", - )) - .arg( - Argument::new("describe-snapshot") - .takes_value(true) - .help("Print the data format version of the provided snapshot state file."), - ) - .arg( - Argument::new("http-api-max-payload-size") - .takes_value(true) - .default_value(&http_max_payload_size_str) - .help("Http API request payload max size, in bytes."), - ) - .arg( - Argument::new("mmds-size-limit") - .takes_value(true) - .help("Mmds data store limit, in bytes."), - ); + ) + .arg(Argument::new("start-time-cpu-us").takes_value(true).help( + "Process start CPU time (wall clock, microseconds). This parameter is optional.", + )) + .arg(Argument::new("parent-cpu-time-us").takes_value(true).help( + "Parent process CPU time (wall clock, microseconds). This parameter is optional.", + )) + .arg( + Argument::new("config-file") + .takes_value(true) + .help("Path to a file that contains the microVM configuration in JSON format."), + ) + .arg( + Argument::new(MMDS_CONTENT_ARG).takes_value(true).help( + "Path to a file that contains metadata in JSON format to add to the mmds.", + ), + ) + .arg( + Argument::new("no-api") + .takes_value(false) + .requires("config-file") + .help( + "Optional parameter which allows starting and using a microVM without an \ + active API socket.", + ), + ) + .arg( + Argument::new("log-path") + .takes_value(true) + .help("Path to a fifo or a file used for configuring the logger on startup."), + ) + .arg( + Argument::new("log-filter") + .takes_value(true) + .help("Filter for logging, if set overrides `level`."), + ) + .arg( + Argument::new("level") + .takes_value(true) + .help("Set the logger level."), + ) + .arg( + Argument::new("show-level") + .takes_value(false) + .help("Whether or not to output the level in the logs."), + ) + .arg(Argument::new("show-log-origin").takes_value(false).help( + "Whether or not to include the file path and line number of the log's origin.", + )) + .arg( + Argument::new("metrics-path") + .takes_value(true) + .help("Path to a fifo or a file used for configuring the metrics on startup."), + ) + .arg(Argument::new("boot-timer").takes_value(false).help( + "Whether or not to load boot timer device for logging elapsed time since \ + InstanceStart command.", + )) + .arg(Argument::new("version").takes_value(false).help( + "Print the binary version number and a list of supported snapshot data format \ + versions.", + )) + .arg( + Argument::new("describe-snapshot") + .takes_value(true) + .help("Print the data format version of the provided snapshot state file."), + ) + .arg( + Argument::new("http-api-max-payload-size") + .takes_value(true) + .default_value(&http_max_payload_size_str) + .help("Http API request payload max size, in bytes."), + ) + .arg( + Argument::new("mmds-size-limit") + .takes_value(true) + .help("Mmds data store limit, in bytes."), + ); arg_parser.parse_from_cmdline()?; let arguments = arg_parser.arguments(); @@ -279,23 +300,31 @@ fn main_exec() -> Result<(), MainError> { app_name: "Firecracker".to_string(), }; - LOGGER.set_instance_id(instance_id.to_owned()); - - if let Some(log) = arguments.single_value("log-path") { - // It's safe to unwrap here because the field's been provided with a default value. - let level = arguments.single_value("level").unwrap().to_owned(); - let logger_level = LoggerLevel::from_string(level).map_err(MainError::InvalidLogLevel)?; - let show_level = arguments.flag_present("show-level"); - let show_log_origin = arguments.flag_present("show-log-origin"); - - let logger_config = LoggerConfig { - log_path: PathBuf::from(log), - level: logger_level, - show_level, - show_log_origin, + // Configure logger, the logger handles can be used to re-configure the logger with the API. + let (logger_handles, _flame_guard) = { + let level_res = arguments + .single_value("level") + .map(|s| LevelFilter::from_str(s)) + .transpose(); + let level = level_res.map_err(MainError::InvalidLogLevel)?; + + let filter = if let Some(log_filter) = arguments.single_value("log-filter") { + Some(serde_json::from_str(log_filter).map_err(MainError::DeserializeLogFilter)?) + } else { + None }; - init_logger(logger_config, &instance_info).map_err(MainError::LoggerInitialization)?; - } + let logger_config = vmm::vmm_config::logger::LoggerConfig { + log_path: arguments.single_value("log-path").map(PathBuf::from), + level, + show_level: Some(arguments.flag_present("show-level")), + show_log_origin: Some(arguments.flag_present("show-log-origin")), + filter, + profile_path: None, + }; + logger_config + .init() + .map_err(MainError::LoggerInitialization)? + }; if let Some(metrics_path) = arguments.single_value("metrics-path") { let metrics_config = MetricsConfig { @@ -378,6 +407,7 @@ fn main_exec() -> Result<(), MainError> { api_payload_limit, mmds_size_limit, metadata_json.as_deref(), + logger_handles, ) .map_err(MainError::RunWithApi) } else { @@ -397,6 +427,7 @@ fn main_exec() -> Result<(), MainError> { } } +#[tracing::instrument(level = "trace", skip())] /// Enable SSBD mitigation through `prctl`. #[cfg(target_arch = "aarch64")] pub fn enable_ssbd_mitigation() { @@ -434,10 +465,12 @@ pub fn enable_ssbd_mitigation() { } // Log a warning for any usage of deprecated parameters. +#[tracing::instrument(level = "trace", skip())] #[allow(unused)] fn warn_deprecated_parameters() {} // Print supported snapshot data format versions. +#[tracing::instrument(level = "trace", skip())] fn print_supported_snapshot_versions() { let mut versions: Vec<_> = FC_VERSION_TO_SNAP_VERSION .iter() @@ -462,6 +495,7 @@ enum SnapshotVersionError { } // Print data format of provided snapshot state file. +#[tracing::instrument(level = "trace", skip(snapshot_path))] fn print_snapshot_data_format(snapshot_path: &str) -> Result<(), SnapshotVersionError> { let mut snapshot_reader = File::open(snapshot_path).map_err(SnapshotVersionError::OpenSnapshot)?; @@ -487,6 +521,18 @@ pub enum BuildFromJsonError { } // Configure and start a microVM as described by the command-line JSON. +#[tracing::instrument( + level = "trace", + skip( + seccomp_filters, + event_manager, + config_json, + instance_info, + boot_timer_enabled, + mmds_size_limit, + metadata_json + ) +)] fn build_microvm_from_json( seccomp_filters: &BpfThreadMap, event_manager: &mut EventManager, @@ -496,7 +542,7 @@ fn build_microvm_from_json( mmds_size_limit: usize, metadata_json: Option<&str>, ) -> Result<(VmResources, Arc>), BuildFromJsonError> { - let mut vm_resources = + let (mut vm_resources, _flame_guard) = VmResources::from_json(&config_json, &instance_info, mmds_size_limit, metadata_json) .map_err(BuildFromJsonError::ParseFromJson)?; vm_resources.boot_timer = boot_timer_enabled; @@ -521,6 +567,17 @@ enum RunWithoutApiError { BuildMicroVMFromJson(BuildFromJsonError), } +#[tracing::instrument( + level = "trace", + skip( + seccomp_filters, + config_json, + instance_info, + bool_timer_enabled, + mmds_size_limit, + metadata_json + ) +)] fn run_without_api( seccomp_filters: &BpfThreadMap, config_json: Option, @@ -561,7 +618,7 @@ fn run_without_api( .expect("Failed to start the event manager"); if let Some(exit_code) = vmm.lock().unwrap().shutdown_exit_code() { - return Err(RunWithoutApiError::Shutdown(exit_code)); + break Err(RunWithoutApiError::Shutdown(exit_code)); } } } diff --git a/src/firecracker/src/metrics.rs b/src/firecracker/src/metrics.rs index 9f7d97ef698..6726fd51e4c 100644 --- a/src/firecracker/src/metrics.rs +++ b/src/firecracker/src/metrics.rs @@ -21,6 +21,7 @@ pub(crate) struct PeriodicMetrics { } impl PeriodicMetrics { + #[tracing::instrument(level = "trace", skip())] /// PeriodicMetrics constructor. Can panic on `TimerFd` creation failure. pub fn new() -> Self { let write_metrics_event_fd = TimerFd::new_custom(ClockId::Monotonic, true, true) @@ -32,6 +33,7 @@ impl PeriodicMetrics { } } + #[tracing::instrument(level = "trace", skip(self, interval_ms))] /// Start the periodic metrics engine which will flush metrics every `interval_ms` millisecs. pub(crate) fn start(&mut self, interval_ms: u64) { // Arm the log write timer. @@ -46,6 +48,7 @@ impl PeriodicMetrics { self.write_metrics(); } + #[tracing::instrument(level = "trace", skip(self))] fn write_metrics(&mut self) { if let Err(err) = METRICS.write() { METRICS.logger.missed_metrics_count.inc(); @@ -60,6 +63,7 @@ impl PeriodicMetrics { } impl MutEventSubscriber for PeriodicMetrics { + #[tracing::instrument(level = "trace", skip(self, event))] /// Handle a read event (EPOLLIN). fn process(&mut self, event: Events, _: &mut EventOps) { let source = event.fd(); @@ -84,6 +88,7 @@ impl MutEventSubscriber for PeriodicMetrics { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.write_metrics_event_fd, EventSet::IN)) { error!("Failed to register metrics event: {}", err); diff --git a/src/firecracker/src/seccomp.rs b/src/firecracker/src/seccomp.rs index 735632bfc9e..15161a3ba05 100644 --- a/src/firecracker/src/seccomp.rs +++ b/src/firecracker/src/seccomp.rs @@ -45,6 +45,7 @@ pub enum SeccompConfig { } impl SeccompConfig { + #[tracing::instrument(level = "trace", skip(no_seccomp, seccomp_filter))] /// Given the relevant command line args, return the appropriate config type. pub fn from_args + Debug>( no_seccomp: bool, @@ -63,6 +64,7 @@ impl SeccompConfig { } } +#[tracing::instrument(level = "trace", skip(config))] /// Retrieve the appropriate filters, based on the SeccompConfig. pub fn get_filters(config: SeccompConfig) -> Result { match config { @@ -72,6 +74,7 @@ pub fn get_filters(config: SeccompConfig) -> Result { } } +#[tracing::instrument(level = "trace", skip())] /// Retrieve the default filters containing the syscall rules required by `Firecracker` /// to function. The binary file is generated via the `build.rs` script of this crate. fn get_default_filters() -> Result { @@ -82,6 +85,7 @@ fn get_default_filters() -> Result { filter_thread_categories(map) } +#[tracing::instrument(level = "trace", skip(reader))] /// Retrieve custom seccomp filters. fn get_custom_filters(reader: R) -> Result { let map = deserialize_binary(BufReader::new(reader), DESERIALIZATION_BYTES_LIMIT) @@ -89,6 +93,7 @@ fn get_custom_filters(reader: R) -> Result Result { let (filters, invalid_filters): (BpfThreadMap, BpfThreadMap) = map diff --git a/src/firecracker/tests/verify_dependencies.rs b/src/firecracker/tests/verify_dependencies.rs index 47222263671..28a343065fe 100644 --- a/src/firecracker/tests/verify_dependencies.rs +++ b/src/firecracker/tests/verify_dependencies.rs @@ -40,6 +40,7 @@ fn test_no_comparison_requirements() { ); } +#[tracing::instrument(level = "trace", skip(path))] /// Parses the specified Cargo.toml file and returns any dependencies specified using a comparison /// requirements. /// @@ -57,6 +58,7 @@ fn violating_dependencies_of_cargo_toml + Debug>( .collect() } +#[tracing::instrument(level = "trace", skip(depsset))] /// Returns an iterator over all dependencies in the given DepsSet specified using comparison /// requirements /// diff --git a/src/jailer/Cargo.toml b/src/jailer/Cargo.toml index 5280e99e831..b23267e41d7 100644 --- a/src/jailer/Cargo.toml +++ b/src/jailer/Cargo.toml @@ -17,5 +17,6 @@ libc = "0.2.147" nix = { version = "0.26.2", default-features = false, features = ["dir"] } regex = { version = "1.9.3", default-features = false, features = ["std"] } thiserror = "1.0.44" +tracing = { version = "0.1.37", features = ["max_level_debug"] } utils = { path = "../utils" } diff --git a/src/jailer/src/cgroup.rs b/src/jailer/src/cgroup.rs index 349bf0183ae..0efff14acd7 100644 --- a/src/jailer/src/cgroup.rs +++ b/src/jailer/src/cgroup.rs @@ -39,6 +39,7 @@ impl CgroupBuilder { // It will discover cgroup mount points and hierarchies configured // on the system and cache the info required to create cgroups later // within this hierarchies + #[tracing::instrument(level = "trace", skip(ver))] pub fn new(ver: u8) -> Result { if ver != 1 && ver != 2 { return Err(JailerError::CgroupInvalidVersion(ver.to_string())); @@ -103,6 +104,7 @@ impl CgroupBuilder { } // Creates a new cggroup and returns it + #[tracing::instrument(level = "trace", skip(self, file, value, id, parent_cg))] pub fn new_cgroup( &mut self, file: String, @@ -136,6 +138,7 @@ impl CgroupBuilder { // Returns the path to the root of the hierarchy for the controller specified // Cgroups for a controller are arranged in a hierarchy; multiple controllers // may share the same hierarchy + #[tracing::instrument(level = "trace", skip(self, controller))] fn get_v1_hierarchy_path(&mut self, controller: &str) -> Result<&PathBuf, JailerError> { // First try and see if the path is already discovered. match self.hierarchies.entry(controller.to_string()) { @@ -217,6 +220,7 @@ pub trait Cgroup { // writing to /A//file, but we can still continue, because step 4) only cares about // the file no longer being empty, regardless of who actually got to populated its contents. +#[tracing::instrument(level = "trace", skip(path, file_name, retry_depth))] fn inherit_from_parent_aux( path: &mut PathBuf, file_name: &str, @@ -258,12 +262,14 @@ fn inherit_from_parent_aux( // The path reference is &mut here because we do a push to get the destination file name. However, // a pop follows shortly after (see fn inherit_from_parent_aux), reverting to the original value. +#[tracing::instrument(level = "trace", skip(path, file_name, depth))] fn inherit_from_parent(path: &mut PathBuf, file_name: &str, depth: u16) -> Result<(), JailerError> { inherit_from_parent_aux(path, file_name, depth) } // Extract the controller name from the cgroup file. The cgroup file must follow // this format: .. +#[tracing::instrument(level = "trace", skip(file))] fn get_controller_from_filename(file: &str) -> Result<&str, JailerError> { let v: Vec<&str> = file.split('.').collect(); @@ -277,6 +283,7 @@ fn get_controller_from_filename(file: &str) -> Result<&str, JailerError> { impl CgroupV1 { // Create a new cgroupsv1 controller + #[tracing::instrument(level = "trace", skip(file, value, id, parent_cg, controller_path))] pub fn new( file: String, value: String, @@ -304,6 +311,7 @@ impl CgroupV1 { } impl Cgroup for CgroupV1 { + #[tracing::instrument(level = "trace", skip(self))] fn write_value(&self) -> Result<(), JailerError> { let location = &mut self.base.location.clone(); @@ -320,6 +328,7 @@ impl Cgroup for CgroupV1 { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn attach_pid(&self) -> Result<(), JailerError> { let pid = process::id(); let location = &self.base.location.join("tasks"); @@ -335,6 +344,7 @@ impl CgroupV2 { // To be able to use a leaf controller within a nested cgroup hierarchy, // the controller needs to be enabled by writing to the cgroup.subtree_control // of it's parent. This rule applies recursively. + #[tracing::instrument(level = "trace", skip(path, controller))] fn write_all_subtree_control

(path: P, controller: &str) -> Result<(), JailerError> where P: AsRef + Debug, @@ -357,6 +367,7 @@ impl CgroupV2 { // Returns true if the controller is available to be enabled from a // cgroup path specified by the mount_point parameter + #[tracing::instrument(level = "trace", skip(controller, mount_point))] fn controller_available

(controller: &str, mount_point: P) -> bool where P: AsRef + Debug, @@ -376,6 +387,7 @@ impl CgroupV2 { } // Create a new cgroupsv2 controller + #[tracing::instrument(level = "trace", skip(file, value, id, parent_cg, unified_path))] pub fn new( file: String, value: String, @@ -403,6 +415,7 @@ impl CgroupV2 { } impl Cgroup for CgroupV2 { + #[tracing::instrument(level = "trace", skip(self))] fn write_value(&self) -> Result<(), JailerError> { let location = &mut self.0.location.clone(); let controller = get_controller_from_filename(&self.0.file)?; @@ -422,6 +435,7 @@ impl Cgroup for CgroupV2 { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn attach_pid(&self) -> Result<(), JailerError> { let pid = process::id(); let location = &self.0.location.join("cgroup.procs"); @@ -453,6 +467,7 @@ pub mod test_util { const MOCK_PROCDIR: &'static str = "/tmp/firecracker/test/jailer/proc"; pub const MOCK_SYS_CGROUPS_DIR: &'static str = "/tmp/firecracker/test/jailer/sys_cgroup"; + #[tracing::instrument(level = "trace", skip(filename, contents))] pub fn create_file_with_contents + Debug>( filename: P, contents: &str, @@ -468,6 +483,7 @@ pub mod test_util { Ok(()) } + #[tracing::instrument(level = "trace", skip())] pub fn new() -> std::result::Result { // create a mock /proc/mounts file in a temporary directory fs::create_dir_all(Self::MOCK_PROCDIR)?; @@ -483,6 +499,7 @@ pub mod test_util { // Populate the mocked proc/mounts file with cgroupv2 entries // Also create a directory structure that simulates cgroupsv2 layout + #[tracing::instrument(level = "trace", skip(self))] pub fn add_v2_mounts(&mut self) -> std::result::Result<(), std::io::Error> { writeln!( self.mounts_file, @@ -500,6 +517,7 @@ pub mod test_util { } // Populate the mocked proc/mounts file with cgroupv1 entries + #[tracing::instrument(level = "trace", skip(self))] pub fn add_v1_mounts(&mut self) -> std::result::Result<(), std::io::Error> { let controllers = vec![ "memory", @@ -524,6 +542,7 @@ pub mod test_util { // Cleanup created files when object goes out of scope impl Drop for MockCgroupFs { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { let _ = fs::remove_file(PROC_MOUNTS); let _ = fs::remove_dir_all("/tmp/firecracker/test"); @@ -544,6 +563,7 @@ mod tests { use crate::cgroup::test_util::MockCgroupFs; // Utility function to read the first line in a file + #[tracing::instrument(level = "trace", skip(filename))] fn read_first_line

(filename: P) -> std::result::Result where P: AsRef + Debug, diff --git a/src/jailer/src/chroot.rs b/src/jailer/src/chroot.rs index 5f4bbaf3665..91941bf8165 100644 --- a/src/jailer/src/chroot.rs +++ b/src/jailer/src/chroot.rs @@ -16,6 +16,7 @@ const CURRENT_DIR_NUL_TERMINATED: &[u8] = b".\0"; // This uses switching to a new mount namespace + pivot_root(), together with the regular chroot, // to provide a hardened jail (at least compared to only relying on chroot). +#[tracing::instrument(level = "trace", skip(path))] pub fn chroot(path: &Path) -> Result<(), JailerError> { // We unshare into a new mount namespace. // SAFETY: The call is safe because we're invoking a C library diff --git a/src/jailer/src/env.rs b/src/jailer/src/env.rs index d26f9d61689..44d28db4b5f 100644 --- a/src/jailer/src/env.rs +++ b/src/jailer/src/env.rs @@ -56,6 +56,7 @@ const FOLDER_PERMISSIONS: u32 = 0o700; const PID_FILE_EXTENSION: &str = ".pid"; // Helper function, since we'll use libc::dup2 a bunch of times for daemonization. +#[tracing::instrument(level = "trace", skip(old_fd, new_fd))] fn dup2(old_fd: libc::c_int, new_fd: libc::c_int) -> Result<(), JailerError> { // SAFETY: This is safe because we are using a library function with valid parameters. SyscallReturnCode(unsafe { libc::dup2(old_fd, new_fd) }) @@ -68,6 +69,7 @@ fn dup2(old_fd: libc::c_int, new_fd: libc::c_int) -> Result<(), JailerError> { // not use the CLONE_VM flag, this will result with the original stack replicated, in a similar // manner to the fork syscall. The libc wrapper prevents use of a NULL stack pointer, so we will // call the syscall directly. +#[tracing::instrument(level = "trace", skip(child_stack, flags))] fn clone(child_stack: *mut libc::c_void, flags: libc::c_int) -> Result { // Clone parameters order is different between x86_64 and aarch64. #[cfg(target_arch = "x86_64")] @@ -104,6 +106,7 @@ pub struct Env { } impl fmt::Debug for Env { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Env") .field("id", &self.id) @@ -131,6 +134,7 @@ impl fmt::Debug for Env { } impl Env { + #[tracing::instrument(level = "trace", skip(arguments, start_time_us, start_time_cpu_us))] pub fn new( arguments: &arg_parser::Arguments, start_time_us: u64, @@ -253,18 +257,22 @@ impl Env { }) } + #[tracing::instrument(level = "trace", skip(self))] pub fn chroot_dir(&self) -> &Path { self.chroot_dir.as_path() } + #[tracing::instrument(level = "trace", skip(self))] pub fn gid(&self) -> u32 { self.gid } + #[tracing::instrument(level = "trace", skip(self))] pub fn uid(&self) -> u32 { self.uid } + #[tracing::instrument(level = "trace", skip(exec_file))] fn validate_exec_file(exec_file: &str) -> Result<(PathBuf, String), JailerError> { let exec_file_path = canonicalize(exec_file) .map_err(|err| JailerError::Canonicalize(PathBuf::from(exec_file), err))?; @@ -288,6 +296,7 @@ impl Env { Ok((exec_file_path, exec_file_name)) } + #[tracing::instrument(level = "trace", skip(resource_limits, args))] fn parse_resource_limits( resource_limits: &mut ResourceLimits, args: &[String], @@ -309,6 +318,7 @@ impl Env { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, chroot_exec_file))] fn exec_into_new_pid_ns(&mut self, chroot_exec_file: PathBuf) -> Result<(), JailerError> { // Compute jailer's total CPU time up to the current time. self.jailer_cpu_time_us = @@ -335,6 +345,7 @@ impl Env { } } + #[tracing::instrument(level = "trace", skip(self, pid, chroot_exec_file))] fn save_exec_file_pid( &mut self, pid: i32, @@ -355,6 +366,7 @@ impl Env { write!(pid_file, "{}", pid).map_err(|err| JailerError::Write(pid_file_path, err)) } + #[tracing::instrument(level = "trace", skip(self, dev_path_str, dev_major, dev_minor))] fn mknod_and_own_dev( &self, dev_path_str: &'static [u8], @@ -394,6 +406,7 @@ impl Env { }) } + #[tracing::instrument(level = "trace", skip(self, folder))] fn setup_jailed_folder(&self, folder: &[u8]) -> Result<(), JailerError> { let folder_cstr = CStr::from_bytes_with_nul(folder).map_err(JailerError::FromBytesWithNul)?; @@ -415,6 +428,7 @@ impl Env { .map_err(|err| JailerError::ChangeFileOwner(path_buf, err)) } + #[tracing::instrument(level = "trace", skip(self))] fn copy_exec_to_chroot(&mut self) -> Result { let exec_file_name = self .exec_file_path @@ -443,6 +457,7 @@ impl Env { Ok(exec_file_name.to_os_string()) } + #[tracing::instrument(level = "trace", skip(path))] fn join_netns(path: &str) -> Result<(), JailerError> { // The fd backing the file will be automatically dropped at the end of the scope let netns = @@ -454,6 +469,7 @@ impl Env { .map_err(JailerError::SetNetNs) } + #[tracing::instrument(level = "trace", skip(self, chroot_exec_file))] fn exec_command(&self, chroot_exec_file: PathBuf) -> io::Error { Command::new(chroot_exec_file) .args(["--id", &self.id]) @@ -469,6 +485,7 @@ impl Env { .exec() } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(target_arch = "aarch64")] fn copy_cache_info(&self) -> Result<(), JailerError> { use crate::{readln_special, to_cstring, writeln_special}; @@ -530,6 +547,7 @@ impl Env { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(target_arch = "aarch64")] fn copy_midr_el1_info(&self) -> Result<(), JailerError> { use crate::{readln_special, to_cstring, writeln_special}; @@ -558,6 +576,7 @@ impl Env { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn run(mut self) -> Result<(), JailerError> { let exec_file_name = self.copy_exec_to_chroot()?; let chroot_exec_file = PathBuf::from("/").join(exec_file_name); @@ -681,6 +700,7 @@ mod tests { } impl ArgVals<'_> { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> ArgVals<'static> { File::create(PSEUDO_EXEC_FILE_PATH).unwrap(); ArgVals { @@ -699,6 +719,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(arg_vals))] fn make_args(arg_vals: &ArgVals) -> Vec { let mut arg_vec = vec![ "--binary-name", @@ -750,14 +771,17 @@ mod tests { arg_vec } + #[tracing::instrument(level = "trace", skip(dev))] fn get_major(dev: u64) -> u32 { unsafe { libc::major(dev) } } + #[tracing::instrument(level = "trace", skip(dev))] fn get_minor(dev: u64) -> u32 { unsafe { libc::minor(dev) } } + #[tracing::instrument(level = "trace", skip())] fn create_env() -> Env { // Create a standard environment. let arg_parser = build_arg_parser(); diff --git a/src/jailer/src/main.rs b/src/jailer/src/main.rs index 1f618b08170..c8194496ae4 100644 --- a/src/jailer/src/main.rs +++ b/src/jailer/src/main.rs @@ -144,6 +144,7 @@ pub enum JailerError { Write(PathBuf, io::Error), } +#[tracing::instrument(level = "trace", skip())] /// Create an ArgParser object which contains info about the command line argument parser and /// populate it with the expected arguments and their characteristics. pub fn build_arg_parser() -> ArgParser<'static> { @@ -225,6 +226,7 @@ pub fn build_arg_parser() -> ArgParser<'static> { // It's called writeln_special because we have to use this rather convoluted way of writing // to special cgroup files, to avoid getting errors. It would be nice to know why that happens :-s +#[tracing::instrument(level = "trace", skip(file_path, value))] pub fn writeln_special(file_path: &T, value: V) -> Result<(), JailerError> where T: AsRef + Debug, @@ -234,6 +236,7 @@ where .map_err(|err| JailerError::Write(PathBuf::from(file_path.as_ref()), err)) } +#[tracing::instrument(level = "trace", skip(file_path))] pub fn readln_special + Debug>(file_path: &T) -> Result { let mut line = fs::read_to_string(file_path) .map_err(|err| JailerError::ReadToString(PathBuf::from(file_path.as_ref()), err))?; @@ -244,6 +247,7 @@ pub fn readln_special + Debug>(file_path: &T) -> Result Result<(), JailerError> { // First try using the close_range syscall to close all open FDs in the range of 3..UINT_MAX // SAFETY: if the syscall is not available then ENOSYS will be returned @@ -259,6 +263,7 @@ fn close_fds_by_close_range() -> Result<(), JailerError> { .map_err(JailerError::CloseRange) } +#[tracing::instrument(level = "trace", skip())] fn close_fds_by_reading_proc() -> Result<(), JailerError> { // Calling this method means that close_range failed (we might be on kernel < 5.9). // We can't use std::fs::ReadDir here as under the hood we need access to the dirfd in order to @@ -290,6 +295,7 @@ fn close_fds_by_reading_proc() -> Result<(), JailerError> { } // Closes all FDs other than 0 (STDIN), 1 (STDOUT) and 2 (STDERR) +#[tracing::instrument(level = "trace", skip())] fn close_inherited_fds() -> Result<(), JailerError> { // The approach we take here is to firstly try to use the close_range syscall // which is available on kernels > 5.9. @@ -300,6 +306,7 @@ fn close_inherited_fds() -> Result<(), JailerError> { Ok(()) } +#[tracing::instrument(level = "trace", skip())] fn sanitize_process() -> Result<(), JailerError> { // First thing to do is make sure we don't keep any inherited FDs // other that IN, OUT and ERR. @@ -310,6 +317,7 @@ fn sanitize_process() -> Result<(), JailerError> { Ok(()) } +#[tracing::instrument(level = "trace", skip())] fn clean_env_vars() { // Remove environment variables received from // the parent process so there are no leaks @@ -319,6 +327,7 @@ fn clean_env_vars() { } } +#[tracing::instrument(level = "trace", skip(path))] /// Turns an AsRef into a CString (c style string). /// The expect should not fail, since Linux paths only contain valid Unicode chars (do they?), /// and do not contain null bytes (do they?). @@ -332,6 +341,7 @@ pub fn to_cstring + Debug>(path: T) -> Result Result<(), JailerError> { let result = main_exec(); if let Err(e) = result { @@ -342,6 +352,7 @@ fn main() -> Result<(), JailerError> { } } +#[tracing::instrument(level = "trace", skip())] fn main_exec() -> Result<(), JailerError> { sanitize_process() .unwrap_or_else(|err| panic!("Failed to sanitize the Jailer process: {}", err)); @@ -391,6 +402,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip(test_fn))] fn run_close_fds_test(test_fn: fn() -> Result<(), JailerError>) { let n = 100; diff --git a/src/jailer/src/resource_limits.rs b/src/jailer/src/resource_limits.rs index 4cd2dc97e79..add65dbf56c 100644 --- a/src/jailer/src/resource_limits.rs +++ b/src/jailer/src/resource_limits.rs @@ -24,6 +24,7 @@ pub enum Resource { } impl From for u32 { + #[tracing::instrument(level = "trace", skip(resource))] fn from(resource: Resource) -> u32 { match resource { #[allow(clippy::unnecessary_cast)] @@ -45,6 +46,7 @@ impl From for u32 { } impl From for i32 { + #[tracing::instrument(level = "trace", skip(resource))] fn from(resource: Resource) -> i32 { match resource { #[allow(clippy::unnecessary_cast)] @@ -66,6 +68,7 @@ impl From for i32 { } impl Display for Resource { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Resource::RlimitFsize => write!(f, "size of file"), @@ -81,6 +84,7 @@ pub struct ResourceLimits { } impl Default for ResourceLimits { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { ResourceLimits { file_size: None, @@ -90,6 +94,7 @@ impl Default for ResourceLimits { } impl ResourceLimits { + #[tracing::instrument(level = "trace", skip(self))] pub fn install(self) -> Result<(), JailerError> { if let Some(file_size) = self.file_size { // Set file size limit. @@ -101,6 +106,7 @@ impl ResourceLimits { Ok(()) } + #[tracing::instrument(level = "trace", skip(resource, target))] fn set_limit(resource: Resource, target: libc::rlim_t) -> Result<(), JailerError> { let rlim: libc::rlimit = libc::rlimit { rlim_cur: target, @@ -114,10 +120,12 @@ impl ResourceLimits { .map_err(|_| JailerError::Setrlimit(resource.to_string())) } + #[tracing::instrument(level = "trace", skip(self, file_size))] pub fn set_file_size(&mut self, file_size: u64) { self.file_size = Some(file_size); } + #[tracing::instrument(level = "trace", skip(self, no_file))] pub fn set_no_file(&mut self, no_file: u64) { self.no_file = no_file; } diff --git a/src/logger/Cargo.toml b/src/logger/Cargo.toml index 908a508b931..59a7d60ece6 100644 --- a/src/logger/Cargo.toml +++ b/src/logger/Cargo.toml @@ -16,4 +16,5 @@ serde = { version = "1.0.136", features = ["derive", "rc"] } serde_json = "1.0.78" thiserror = "1.0.32" vm-superio = "0.7.0" +tracing = { version = "0.1.37", features = ["max_level_debug"] } utils = { path = "../utils" } diff --git a/src/logger/src/init.rs b/src/logger/src/init.rs index 2207fd93683..180e7b6ebf9 100644 --- a/src/logger/src/init.rs +++ b/src/logger/src/init.rs @@ -30,6 +30,7 @@ impl Init { } } + #[tracing::instrument(level = "trace", skip(self,f))] /// Performs an initialization routine. /// /// The given closure will be executed if the current state is `UNINITIALIZED`. @@ -67,6 +68,7 @@ impl Init { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Checks if the current state is `INITIALIZED`. #[inline] pub fn is_initialized(&self) -> bool { diff --git a/src/logger/src/lib.rs b/src/logger/src/lib.rs index e9fe7d19d13..4f1b9678797 100644 --- a/src/logger/src/lib.rs +++ b/src/logger/src/lib.rs @@ -6,16 +6,10 @@ //! Crate that implements Firecracker specific functionality as far as logging and metrics //! collecting. -mod init; -mod logger; mod metrics; -use std::sync::LockResult; +pub use tracing::{debug, error, info, trace, warn, Level}; -pub use log::Level::*; -pub use log::{warn, *}; - -pub use crate::logger::{LoggerError, LOGGER}; #[cfg(target_arch = "aarch64")] pub use crate::metrics::RTCDeviceMetrics; pub use crate::metrics::{ @@ -30,6 +24,7 @@ pub type FcLineWriter = std::io::LineWriter; /// that are not generally available. const DEV_PREVIEW_LOG_PREFIX: &str = "[DevPreview]"; +#[tracing::instrument(level = "trace", skip(feature_name, msg_opt))] /// Log a standard warning message indicating a given feature name /// is in development preview. pub fn log_dev_preview_warning(feature_name: &str, msg_opt: Option) { @@ -41,15 +36,7 @@ pub fn log_dev_preview_warning(feature_name: &str, msg_opt: Option) { } } -fn extract_guard(lock_result: LockResult) -> G { - match lock_result { - Ok(guard) => guard, - // If a thread panics while holding this lock, the writer within should still be usable. - // (we might get an incomplete log line or something like that). - Err(poisoned) => poisoned.into_inner(), - } -} - +#[tracing::instrument(level = "trace", skip(metric, start_time_us))] /// Helper function for updating the value of a store metric with elapsed time since some time in a /// past. pub fn update_metric_with_elapsed_time(metric: &SharedStoreMetric, start_time_us: u64) -> u64 { diff --git a/src/logger/src/logger.rs b/src/logger/src/logger.rs deleted file mode 100644 index df82ea545c9..00000000000 --- a/src/logger/src/logger.rs +++ /dev/null @@ -1,776 +0,0 @@ -// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -//! Utility for sending log related messages to a storing destination or simply to stdout/stderr. -//! The logging destination is specified upon the initialization of the logging system. -//! -//! # Enabling logging -//! There are 2 ways to enable the logging functionality: -//! -//! 1) Calling `LOGGER.configure()`. This will enable the logger to work in limited mode. -//! In this mode the logger can only write messages to stdout or stderr. - -//! The logger can be configured in this way any number of times before calling `LOGGER.init()`. -//! -//! 2) Calling `LOGGER.init()`. This will enable the logger to work in full mode. -//! In this mode the logger can write messages to arbitrary buffers. -//! The logger can be initialized only once. Any call to the `LOGGER.init()` following that will -//! fail with an explicit error. -//! -//! ## Example for logging to stdout/stderr -//! -//! ``` -//! use std::ops::Deref; -//! -//! use logger::{error, warn, LOGGER}; -//! -//! // Optionally do an initial configuration for the logger. -//! if let Err(err) = LOGGER.deref().configure(Some("MY-INSTANCE".to_string())) { -//! println!("Could not configure the log subsystem: {}", err); -//! return; -//! } -//! warn!("this is a warning"); -//! error!("this is an error"); -//! ``` -//! ## Example for logging to a `File`: -//! -//! ``` -//! use std::io::Cursor; -//! -//! use libc::c_char; -//! use logger::{error, warn, LOGGER}; -//! -//! let mut logs = Cursor::new(vec![0; 15]); -//! -//! // Initialize the logger to log to a FIFO that was created beforehand. -//! assert!(LOGGER -//! .init("Running Firecracker v.x".to_string(), Box::new(logs),) -//! .is_ok()); -//! // The following messages should appear in the in-memory buffer `logs`. -//! warn!("this is a warning"); -//! error!("this is an error"); -//! ``` - -//! # Plain log format -//! The current logging system is built upon the upstream crate 'log' and reexports the macros -//! provided by it for flushing plain log content. Log messages are printed through the use of five -//! macros: -//! * error!() -//! * warning!() -//! * info!() -//! * debug!() -//! * trace!() -//! -//! Each call to the desired macro will flush a line of the following format: -//! ``` [:::] ```. -//! The first component is always the timestamp which has the `%Y-%m-%dT%H:%M:%S.%f` format. -//! The level will depend on the macro used to flush a line and will be one of the following: -//! `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`. -//! The file path and the line provides the exact location of where the call to the macro was made. -//! ## Example of a log line: -//! ```bash -//! 2018-11-07T05:34:25.180751152 [anonymous-instance:ERROR:vmm/src/lib.rs:1173] Failed to write -//! metrics: Failed to write logs. Error: operation would block -//! ``` -//! # Limitations -//! Logs can be flushed either to stdout/stderr or to a byte-oriented sink (File, FIFO, Ring Buffer -//! etc). - -use std::fmt::{self, Debug}; -use std::io::{sink, stdout, Write}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Mutex, RwLock}; -use std::{result, thread}; - -use lazy_static::lazy_static; -use log::{max_level, set_logger, set_max_level, LevelFilter, Log, Metadata, Record}; -use utils::time::LocalTime; - -use super::extract_guard; -use crate::init; -use crate::init::Init; -use crate::metrics::{IncMetric, METRICS}; - -/// Type for returning functions outcome. -pub type Result = result::Result; - -// Values used by the Logger. -const DEFAULT_MAX_LEVEL: LevelFilter = LevelFilter::Warn; - -lazy_static! { - static ref _LOGGER_INNER: Logger = Logger::new(); - - /// Static instance used for handling human-readable logs. - pub static ref LOGGER: &'static Logger = { - set_logger(_LOGGER_INNER.deref()).expect("Failed to set logger"); - _LOGGER_INNER.deref() - }; -} - -/// Logger representing the logging subsystem. -// All member fields have types which are Sync, and exhibit interior mutability, so -// we can call logging operations using a non-mut static global variable. -pub struct Logger { - init: Init, - // Human readable logs will be outputted here. - log_buf: Mutex>, - show_level: AtomicBool, - show_file_path: AtomicBool, - show_line_numbers: AtomicBool, - instance_id: RwLock, -} - -impl fmt::Debug for Logger { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Logger") - .field("init", &self.init) - .field("log_buf", &"?") - .field("show_level", &self.show_level) - .field("show_file_path", &self.show_file_path) - .field("show_line_numbers", &self.show_line_numbers) - .field("instance_id", &self.instance_id) - .finish() - } -} - -impl Logger { - /// Creates a new instance of the current logger. - fn new() -> Logger { - Logger { - init: Init::new(), - log_buf: Mutex::new(Box::new(sink())), - show_level: AtomicBool::new(true), - show_line_numbers: AtomicBool::new(true), - show_file_path: AtomicBool::new(true), - instance_id: RwLock::new(String::new()), - } - } - - fn show_level(&self) -> bool { - self.show_level.load(Ordering::Relaxed) - } - - fn show_file_path(&self) -> bool { - self.show_file_path.load(Ordering::Relaxed) - } - - fn show_line_numbers(&self) -> bool { - self.show_line_numbers.load(Ordering::Relaxed) - } - - /// Enables or disables including the level in the log message's tag portion. - /// - /// # Arguments - /// - /// * `option` - Boolean deciding whether to include log level in log message. - /// - /// # Example - /// - /// ``` - /// use std::ops::Deref; - /// - /// use logger::{warn, LOGGER}; - /// - /// let l = LOGGER.deref(); - /// l.set_include_level(true); - /// assert!(l.configure(Some("MY-INSTANCE".to_string())).is_ok()); - /// warn!("A warning log message with level included"); - /// ``` - /// The code above will more or less print: - /// ```bash - /// 2018-11-07T05:34:25.180751152 [MY-INSTANCE:WARN:logger/src/lib.rs:290] A warning log - /// message with level included - /// ``` - pub fn set_include_level(&self, option: bool) -> &Self { - self.show_level.store(option, Ordering::Relaxed); - self - } - - /// Enables or disables including the file path and the line numbers in the tag of - /// the log message. Not including the file path will also hide the line numbers from the tag. - /// - /// # Arguments - /// - /// * `file_path` - Boolean deciding whether to include file path of the log message's origin. - /// * `line_numbers` - Boolean deciding whether to include the line number of the file where the - /// log message orginated. - /// - /// # Example - /// - /// ``` - /// use std::ops::Deref; - /// - /// use logger::{warn, LOGGER}; - /// - /// let l = LOGGER.deref(); - /// l.set_include_origin(false, false); - /// assert!(l.configure(Some("MY-INSTANCE".to_string())).is_ok()); - /// - /// warn!("A warning log message with log origin disabled"); - /// ``` - /// The code above will more or less print: - /// ```bash - /// 2018-11-07T05:34:25.180751152 [MY-INSTANCE:WARN] A warning log message with log origin - /// disabled - /// ``` - pub fn set_include_origin(&self, file_path: bool, line_numbers: bool) -> &Self { - self.show_file_path.store(file_path, Ordering::Relaxed); - // If the file path is not shown, do not show line numbers either. - self.show_line_numbers - .store(file_path && line_numbers, Ordering::Relaxed); - self - } - - /// Sets the ID for this logger session. - pub fn set_instance_id(&self, instance_id: String) -> &Self { - let mut guard = extract_guard(self.instance_id.write()); - *guard = instance_id; - self - } - - /// Explicitly sets the max log level for the Logger. - /// The default level is WARN. So, ERROR and WARN statements will be shown (i.e. all that is - /// bigger than the level code). - /// - /// # Arguments - /// - /// * `level` - Set the highest log level. - /// # Example - /// - /// ``` - /// use std::ops::Deref; - /// - /// use logger::{info, warn, LOGGER}; - /// - /// let l = LOGGER.deref(); - /// l.set_max_level(log::LevelFilter::Warn); - /// assert!(l.configure(Some("MY-INSTANCE".to_string())).is_ok()); - /// info!("An informational log message"); - /// warn!("A test warning message"); - /// ``` - /// The code above will more or less print: - /// ```bash - /// 2018-11-07T05:34:25.180751152 [MY-INSTANCE:INFO:logger/src/lib.rs:389] A test warning - /// message - /// ``` - pub fn set_max_level(&self, level: LevelFilter) -> &Self { - set_max_level(level); - self - } - - /// Get the current thread's name. - fn get_thread_name(&self) -> String { - thread::current().name().unwrap_or("-").to_string() - } - - /// Creates the first portion (to the left of the separator) - /// of the log statement based on the logger settings. - fn create_prefix(&self, record: &Record) -> String { - let mut prefix: Vec = vec![]; - - let instance_id = extract_guard(self.instance_id.read()); - if !instance_id.is_empty() { - prefix.push(instance_id.to_string()); - } - - // Attach current thread name to prefix. - prefix.push(self.get_thread_name()); - - if self.show_level() { - prefix.push(record.level().to_string()); - }; - - if self.show_file_path() { - prefix.push(record.file().unwrap_or("unknown").to_string()); - }; - - if self.show_line_numbers() { - if let Some(line) = record.line() { - prefix.push(line.to_string()); - } - } - - format!("[{}]", prefix.join(":")) - } - - /// if the max level hasn't been configured yet, set it to default - fn try_init_max_level(&self) { - // if the max level hasn't been configured yet, set it to default - if max_level() == LevelFilter::Off { - self.set_max_level(DEFAULT_MAX_LEVEL); - } - } - - /// Preconfigure the logger prior to initialization. - /// Performs the most basic steps in order to enable the logger to write to stdout or stderr - /// even before calling LOGGER.init(). Calling this method is optional. - /// This function can be called any number of times before the initialization. - /// Any calls made after the initialization will result in `Err()`. - /// - /// # Arguments - /// - /// * `instance_id` - Unique string identifying this logger session. This id is temporary and - /// will be overwritten upon initialization. - /// - /// # Example - /// - /// ``` - /// use std::ops::Deref; - /// - /// use logger::LOGGER; - /// - /// LOGGER - /// .deref() - /// .configure(Some("MY-INSTANCE".to_string())) - /// .unwrap(); - /// ``` - pub fn configure(&self, instance_id: Option) -> Result<()> { - self.init - .call_init(|| { - if let Some(some_instance_id) = instance_id { - self.set_instance_id(some_instance_id); - } - - self.try_init_max_level(); - - // don't finish the initialization - false - }) - .map_err(LoggerError::Init) - } - - /// Initialize log system (once and only once). - /// Every call made after the first will have no effect besides returning `Ok` or `Err`. - /// - /// # Arguments - /// - /// * `header` - Info about the app that uses the logger. - /// * `log_dest` - Buffer for plain text logs. Needs to implements `Write` and `Send`. - /// - /// # Example - /// - /// ``` - /// use std::io::Cursor; - /// - /// use logger::LOGGER; - /// - /// let mut logs = Cursor::new(vec![0; 15]); - /// - /// LOGGER.init("Running Firecracker v.x".to_string(), Box::new(logs)); - /// ``` - pub fn init(&self, header: String, log_dest: Box) -> Result<()> { - self.init - .call_init(|| { - let mut g = extract_guard(self.log_buf.lock()); - *g = log_dest; - - self.try_init_max_level(); - - // finish init - true - }) - .map_err(LoggerError::Init)?; - - self.write_log(&header); - - Ok(()) - } - - /// Handles the common logic of writing regular log messages. - /// - /// Writes `msg` followed by a newline to the destination, flushing afterwards. - fn write_log(&self, msg: &str) { - let mut guard; - let mut writer: Box = if self.init.is_initialized() { - guard = extract_guard(self.log_buf.lock()); - Box::new(guard.as_mut()) - } else { - Box::new(stdout()) - }; - // Writes `msg` followed by newline and flushes, if either operation returns an error, - // increment missed log count. - // This approach is preferable over `Result::and` as if `write!` returns an error it then - // does not attempt to flush. - if writeln!(writer, "{msg}") - .and_then(|_| writer.flush()) - .is_err() - { - // No reason to log the error to stderr here, just increment the metric. - METRICS.logger.missed_log_count.inc(); - } - } -} - -/// Describes the errors which may occur while handling logging scenarios. -#[derive(Debug, thiserror::Error)] -pub enum LoggerError { - /// Initialization Error. - #[error("Logger initialization failure: {0}")] - Init(init::Error), -} - -/// Implements the "Log" trait from the externally used "log" crate. -impl Log for Logger { - fn enabled(&self, _metadata: &Metadata) -> bool { - // No filtering beyond what the log crate already does based on level. - true - } - - fn log(&self, record: &Record) { - let msg = format!( - "{} {} {}", - LocalTime::now(), - self.create_prefix(record), - record.args() - ); - self.write_log(&msg); - } - - // This is currently not used. - fn flush(&self) { - unreachable!(); - } -} - -#[cfg(test)] -mod tests { - use std::fs::{create_dir, read_to_string, remove_dir, remove_file, OpenOptions}; - use std::io::{BufWriter, Read, Write}; - use std::sync::Arc; - - use log::{info, Level}; - - use super::*; - - const TEST_INSTANCE_ID: &str = "TEST-INSTANCE-ID"; - const TEST_APP_HEADER: &str = "App header"; - - const LOG_SOURCE: &str = "logger.rs"; - const LOG_LINE: u32 = 0; - - struct LogWriter { - buf: Arc>>, - } - - impl Write for LogWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - let mut data = self.buf.lock().unwrap(); - data.append(&mut buf.to_vec()); - - Ok(buf.len()) - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } - } - - struct LogReader { - buf: Arc>>, - } - - impl Read for LogReader { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let mut data = self.buf.lock().unwrap(); - - let len = std::cmp::min(data.len(), buf.len()); - buf[..len].copy_from_slice(&data[..len]); - - data.drain(..len); - - Ok(len) - } - } - - fn log_channel() -> (LogWriter, LogReader) { - let buf = Arc::new(Mutex::new(vec![])); - (LogWriter { buf: buf.clone() }, LogReader { buf }) - } - - impl Logger { - fn mock_new() -> Logger { - let logger = Logger::new(); - logger.set_instance_id(TEST_INSTANCE_ID.to_string()); - - logger - } - - fn mock_log(&self, level: Level, msg: &str) { - self.log( - &log::Record::builder() - .level(level) - .args(format_args!("{}", msg)) - .file(Some(LOG_SOURCE)) - .line(Some(LOG_LINE)) - .build(), - ); - } - - fn mock_init(&self) -> LogReader { - let (writer, mut reader) = log_channel(); - assert!(self - .init(TEST_APP_HEADER.to_string(), Box::new(writer)) - .is_ok()); - validate_log( - &mut Box::new(&mut reader), - &format!("{}\n", TEST_APP_HEADER), - ); - - reader - } - } - - fn validate_log(log_reader: &mut dyn Read, expected: &str) { - let mut log = Vec::new(); - log_reader.read_to_end(&mut log).unwrap(); - - assert!(log.len() >= expected.len()); - assert_eq!( - expected, - std::str::from_utf8(&log[log.len() - expected.len()..]).unwrap() - ); - } - - #[test] - fn test_default_values() { - let l = Logger::new(); - assert!(l.show_line_numbers()); - assert!(l.show_level()); - } - - #[test] - fn test_write_log() { - // Data to log to file for test. - const TEST_HEADER: &str = "test_log"; - const TEST_STR: &str = "testing flushing"; - // File to use for test. - const TEST_DIR: &str = "./tmp"; - const TEST_FILE: &str = "test.txt"; - let test_path = format!("{}/{}", TEST_DIR, TEST_FILE); - - // Creates ./tmp directory - create_dir(TEST_DIR).unwrap(); - // A buffered writer to a file - let file = OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(&test_path) - .unwrap(); - let writer = Box::new(BufWriter::new(file)); - // Create a logger with this buffered writer as the `dest`. - let logger = Logger::new(); - logger.init(String::from(TEST_HEADER), writer).unwrap(); - // Log some generic data - logger.write_log(TEST_STR); - // To drop the logger without calling its destructor, or to `forget` it - // (https://doc.rust-lang.org/stable/std/mem/fn.forget.html) will lead - // to a memory leak, so for this test I do not do this. - // As such this test simply illustrates the `write_log` function will - // always flush such that in the occurrence of the crash the expected - // behavior that all temporally distant logs from a crash are flushed. - - // Read from the log file. - let file_contents = read_to_string(&test_path).unwrap(); - // Asserts the contents of the log file are as expected. - assert_eq!(file_contents, format!("{}\n{}\n", TEST_HEADER, TEST_STR)); - // Removes the log file. - remove_file(&test_path).unwrap(); - // Removes /tmp directory - remove_dir(TEST_DIR).unwrap(); - } - - #[test] - fn test_configure() { - let logger = Logger::new(); - let crnt_thread_name = logger.get_thread_name(); - - // Assert that `configure()` can be called successfully any number of times. - assert!(logger.configure(Some(TEST_INSTANCE_ID.to_string())).is_ok()); - assert!(logger.configure(None).is_ok()); - assert!(logger.configure(Some(TEST_INSTANCE_ID.to_string())).is_ok()); - - // Assert that `init()` works after `configure()` - let (writer, mut reader) = log_channel(); - assert!(logger - .init(TEST_APP_HEADER.to_string(), Box::new(writer)) - .is_ok()); - validate_log( - &mut Box::new(&mut reader), - &format!("{}\n", TEST_APP_HEADER), - ); - // Check that the logs are written to the configured writer. - logger.mock_log(Level::Info, "info"); - validate_log( - &mut Box::new(&mut reader), - &format!( - "[TEST-INSTANCE-ID:{}:INFO:logger.rs:0] info\n", - crnt_thread_name - ), - ); - } - - #[test] - fn test_init() { - let logger = Logger::new(); - let crnt_thread_name = logger.get_thread_name(); - // Assert that the first call to `init()` is successful. - let (writer, mut reader) = log_channel(); - logger.set_instance_id(TEST_INSTANCE_ID.to_string()); - assert!(logger - .init(TEST_APP_HEADER.to_string(), Box::new(writer)) - .is_ok()); - validate_log( - &mut Box::new(&mut reader), - &format!("{}\n", TEST_APP_HEADER), - ); - // Check that the logs are written to the configured writer. - logger.mock_log(Level::Info, "info"); - validate_log( - &mut Box::new(&mut reader), - &format!( - "[TEST-INSTANCE-ID:{}:INFO:logger.rs:0] info\n", - crnt_thread_name - ), - ); - - // Assert that initialization works only once. - let (writer_2, mut reader_2) = log_channel(); - assert!(logger - .init(TEST_APP_HEADER.to_string(), Box::new(writer_2)) - .is_err()); - // Check that the logs are written only to the first writer. - logger.mock_log(Level::Info, "info"); - validate_log( - &mut Box::new(&mut reader), - &format!( - "[TEST-INSTANCE-ID:{}:INFO:logger.rs:0] info\n", - crnt_thread_name - ), - ); - validate_log(&mut Box::new(&mut reader_2), ""); - } - - #[test] - fn test_create_prefix() { - let logger = Logger::mock_new(); - let mut reader = logger.mock_init(); - let crnt_thread_name = logger.get_thread_name(); - // Test with empty instance id. - logger.set_instance_id("".to_string()); - - // Check that the prefix is empty when `show_level` and `show_origin` are false. - logger - .set_include_level(false) - .set_include_origin(false, true); - logger.mock_log(Level::Info, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!("[{}] msg\n", crnt_thread_name), - ); - - // Check that the prefix is correctly shown when all flags are true. - logger - .set_include_level(true) - .set_include_origin(true, true); - logger.mock_log(Level::Info, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!("[{}:INFO:logger.rs:0] msg\n", crnt_thread_name), - ); - - // Check show_line_numbers=false. - logger - .set_include_level(true) - .set_include_origin(true, false); - logger.mock_log(Level::Debug, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!("[{}:DEBUG:logger.rs] msg\n", crnt_thread_name), - ); - - // Check show_file_path=false. - logger - .set_include_level(true) - .set_include_origin(false, true); - logger.mock_log(Level::Error, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!("[{}:ERROR] msg\n", crnt_thread_name), - ); - - // Check show_level=false. - logger - .set_include_level(false) - .set_include_origin(true, true); - logger.mock_log(Level::Info, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!("[{}:logger.rs:0] msg\n", crnt_thread_name), - ); - - // Test with a mock instance id. - logger.set_instance_id(TEST_INSTANCE_ID.to_string()); - - // Check that the prefix contains only the instance id when all flags are false. - logger - .set_include_level(false) - .set_include_origin(false, false); - logger.mock_log(Level::Info, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!("[TEST-INSTANCE-ID:{}] msg\n", crnt_thread_name), - ); - - // Check that the prefix is correctly shown when all flags are true. - logger - .set_include_level(true) - .set_include_origin(true, true); - logger.mock_log(Level::Warn, "msg"); - validate_log( - &mut Box::new(&mut reader), - &format!( - "[TEST-INSTANCE-ID:{}:WARN:logger.rs:0] msg\n", - crnt_thread_name - ), - ); - } - - #[test] - fn test_thread_name_custom() { - let custom_thread = thread::Builder::new() - .name("custom-thread".to_string()) - .spawn(move || { - let logger = Logger::mock_new(); - let mut reader = logger.mock_init(); - logger - .set_include_level(false) - .set_include_origin(false, false); - logger.set_instance_id("".to_string()); - logger.mock_log(Level::Info, "thread-msg"); - validate_log(&mut Box::new(&mut reader), "[custom-thread] thread-msg\n"); - }) - .unwrap(); - let r = custom_thread.join(); - assert!(r.is_ok()); - } - - #[test] - fn test_static_logger() { - log::set_max_level(log::LevelFilter::Info); - LOGGER.set_instance_id(TEST_INSTANCE_ID.to_string()); - - let mut reader = LOGGER.mock_init(); - - info!("info"); - validate_log(&mut Box::new(&mut reader), "info\n"); - } - - #[test] - fn test_error_messages() { - assert_eq!( - format!("{}", LoggerError::Init(init::Error::AlreadyInitialized)), - "Logger initialization failure: The component is already initialized." - ); - } -} diff --git a/src/logger/src/metrics.rs b/src/logger/src/metrics.rs index 0a3884935d5..24a8ee3ded4 100644 --- a/src/logger/src/metrics.rs +++ b/src/logger/src/metrics.rs @@ -67,13 +67,13 @@ use std::ops::Deref; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Mutex, OnceLock}; -#[cfg(target_arch = "aarch64")] -use log::warn; use serde::{Serialize, Serializer}; #[cfg(target_arch = "aarch64")] use vm_superio::rtc_pl031::RtcEvents; use super::FcLineWriter; +#[cfg(target_arch = "aarch64")] +use crate::warn; /// Static instance used for handling metrics. pub static METRICS: Metrics = @@ -100,6 +100,7 @@ impl Metrics { } } + #[tracing::instrument(level = "trace", skip(self, metrics_dest))] /// Initialize metrics system (once and only once). /// Every call made after the first will have no effect besides returning `Ok` or `Err`. /// @@ -118,6 +119,7 @@ impl Metrics { .map_err(|_| MetricsError::AlreadyInitialized) } + #[tracing::instrument(level = "trace", skip(self))] /// Writes metrics to the destination provided as argument upon initialization of the metrics. /// Upon failure, an error is returned if metrics system is initialized and metrics could not be /// written. @@ -172,6 +174,7 @@ impl Metrics { impl Deref for Metrics { type Target = T; + #[tracing::instrument(level = "trace", skip(self))] fn deref(&self) -> &Self::Target { &self.app_metrics } @@ -251,26 +254,31 @@ impl IncMetric for SharedIncMetric { // be an asm "LOCK; something" and thus atomic across multiple threads, simply because of the // fetch_and_add (as opposed to "store(load() + 1)") implementation for atomics. // TODO: would a stronger ordering make a difference here? + #[tracing::instrument(level = "trace", skip(self, value))] fn add(&self, value: usize) { self.0.fetch_add(value, Ordering::Relaxed); } + #[tracing::instrument(level = "trace", skip(self))] fn count(&self) -> usize { self.0.load(Ordering::Relaxed) } } impl StoreMetric for SharedStoreMetric { + #[tracing::instrument(level = "trace", skip(self))] fn fetch(&self) -> usize { self.0.load(Ordering::Relaxed) } + #[tracing::instrument(level = "trace", skip(self, value))] fn store(&self, value: usize) { self.0.store(value, Ordering::Relaxed); } } impl Serialize for SharedIncMetric { + #[tracing::instrument(level = "trace", skip(self, serializer))] /// Reset counters of each metrics. Here we suppose that Serialize's goal is to help with the /// flushing of metrics. /// !!! Any print of the metrics will also reset them. Use with caution !!! @@ -287,6 +295,7 @@ impl Serialize for SharedIncMetric { } impl Serialize for SharedStoreMetric { + #[tracing::instrument(level = "trace", skip(self, serializer))] fn serialize(&self, serializer: S) -> Result { serializer.serialize_u64(self.0.load(Ordering::Relaxed) as u64) } @@ -305,6 +314,10 @@ pub struct ProcessTimeReporter { } impl ProcessTimeReporter { + #[tracing::instrument( + level = "trace", + skip(start_time_us, start_time_cpu_us, parent_cpu_time_us) + )] /// Constructor for the process time-related reporter. pub fn new( start_time_us: Option, @@ -318,6 +331,7 @@ impl ProcessTimeReporter { } } + #[tracing::instrument(level = "trace", skip(self))] /// Obtain process start time in microseconds. pub fn report_start_time(&self) { if let Some(start_time) = self.start_time_us { @@ -329,6 +343,7 @@ impl ProcessTimeReporter { } } + #[tracing::instrument(level = "trace", skip(self))] /// Obtain process CPU start time in microseconds. pub fn report_cpu_start_time(&self) { if let Some(cpu_start_time) = self.start_time_cpu_us { @@ -881,12 +896,14 @@ impl RTCDeviceMetrics { #[cfg(target_arch = "aarch64")] impl RtcEvents for RTCDeviceMetrics { + #[tracing::instrument(level = "trace", skip(self))] fn invalid_read(&self) { self.missed_read_count.inc(); self.error_count.inc(); warn!("Guest read at invalid offset.") } + #[tracing::instrument(level = "trace", skip(self))] fn invalid_write(&self) { self.missed_write_count.inc(); self.error_count.inc(); @@ -896,10 +913,12 @@ impl RtcEvents for RTCDeviceMetrics { #[cfg(target_arch = "aarch64")] impl RtcEvents for &'static RTCDeviceMetrics { + #[tracing::instrument(level = "trace", skip(self))] fn invalid_read(&self) { RTCDeviceMetrics::invalid_read(self); } + #[tracing::instrument(level = "trace", skip(self))] fn invalid_write(&self) { RTCDeviceMetrics::invalid_write(self); } @@ -1146,6 +1165,7 @@ impl SerializeToUtcTimestampMs { } impl Serialize for SerializeToUtcTimestampMs { + #[tracing::instrument(level = "trace", skip(self, serializer))] fn serialize(&self, serializer: S) -> Result { serializer.serialize_i64( i64::try_from(utils::time::get_time_ns(utils::time::ClockType::Real) / 1_000_000) diff --git a/src/mmds/Cargo.toml b/src/mmds/Cargo.toml index 1ba82482356..f351ff3f2f1 100644 --- a/src/mmds/Cargo.toml +++ b/src/mmds/Cargo.toml @@ -23,4 +23,5 @@ dumbo = { path = "../dumbo" } logger = { path = "../logger" } micro_http = { git = "https://github.com/firecracker-microvm/micro-http", rev = "4b18a04" } snapshot = { path = "../snapshot" } -utils = { path = "../utils" } \ No newline at end of file +utils = { path = "../utils" } +tracing = { version = "0.1.37", features = ["max_level_debug"] } \ No newline at end of file diff --git a/src/mmds/src/data_store.rs b/src/mmds/src/data_store.rs index bc94c014446..4ea4b2a5356 100644 --- a/src/mmds/src/data_store.rs +++ b/src/mmds/src/data_store.rs @@ -28,6 +28,7 @@ pub enum MmdsVersion { } impl Display for MmdsVersion { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { MmdsVersion::V1 => write!(f, "V1"), @@ -59,12 +60,14 @@ pub enum Error { // Used for ease of use in tests. impl Default for Mmds { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self::default_with_limit(51200) } } impl Mmds { + #[tracing::instrument(level = "trace", skip(data_store_limit))] pub fn default_with_limit(data_store_limit: usize) -> Self { Mmds { data_store: Value::default(), @@ -74,6 +77,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self))] /// This method is needed to check if data store is initialized. /// When a PATCH request is made on an uninitialized Mmds structure this method /// should return a NotFound error. @@ -85,6 +89,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self, version))] /// Set the MMDS version. pub fn set_version(&mut self, version: MmdsVersion) -> Result<(), Error> { match version { @@ -101,6 +106,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self))] /// Return the MMDS version by checking the token authority field. pub fn version(&self) -> MmdsVersion { if self.token_authority.is_none() { @@ -110,6 +116,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self, instance_id))] /// Sets the Additional Authenticated Data to be used for encryption and /// decryption of the session token when MMDS version 2 is enabled. pub fn set_aad(&mut self, instance_id: &str) { @@ -118,6 +125,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self, token))] /// Checks if the provided token has not expired. pub fn is_valid_token(&self, token: &str) -> Result { self.token_authority @@ -126,6 +134,7 @@ impl Mmds { .map(|ta| ta.is_valid(token)) } + #[tracing::instrument(level = "trace", skip(self, ttl_seconds))] /// Generate a new Mmds token using the token authority. pub fn generate_token(&mut self, ttl_seconds: u32) -> Result { self.token_authority @@ -134,10 +143,12 @@ impl Mmds { .and_then(|ta| ta.generate_token_secret(ttl_seconds)) } + #[tracing::instrument(level = "trace", skip(self, data_store_limit))] pub fn set_data_store_limit(&mut self, data_store_limit: usize) { self.data_store_limit = data_store_limit; } + #[tracing::instrument(level = "trace", skip(self, data))] pub fn put_data(&mut self, data: Value) -> Result<(), Error> { // It is safe to unwrap because any map keys are all strings and // we are using default serializer which does not return error. @@ -151,6 +162,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self, patch_data))] pub fn patch_data(&mut self, patch_data: Value) -> Result<(), Error> { self.check_data_store_initialized()?; let mut data_store_clone = self.data_store.clone(); @@ -168,10 +180,12 @@ impl Mmds { // We do not check size of data_store before returning a result because due // to limit from put/patch the data_store can not be bigger than the limit // imposed by the server. + #[tracing::instrument(level = "trace", skip(self))] pub fn data_store_value(&self) -> Value { self.data_store.clone() } + #[tracing::instrument(level = "trace", skip(json))] /// Returns the serde::Value in IMDS format plaintext. /// Currently, only JSON objects and strings can be IMDS formatted. /// @@ -240,6 +254,7 @@ impl Mmds { } } + #[tracing::instrument(level = "trace", skip(self, path, format))] /// Returns the subtree located at path. When the path corresponds to a leaf, it returns the /// value. Returns Error::NotFound when the path is invalid. pub fn get_value(&self, path: String, format: OutputFormat) -> Result { @@ -267,6 +282,7 @@ mod tests { use super::*; impl Mmds { + #[tracing::instrument(level = "trace", skip(self))] pub fn get_data_str(&self) -> String { if self.data_store.is_null() { return String::from("{}"); diff --git a/src/mmds/src/lib.rs b/src/mmds/src/lib.rs index 3c7b9e3f5c9..8874441d906 100644 --- a/src/mmds/src/lib.rs +++ b/src/mmds/src/lib.rs @@ -39,6 +39,7 @@ pub enum Error { } impl From for OutputFormat { + #[tracing::instrument(level = "trace", skip(media_type))] fn from(media_type: MediaType) -> Self { match media_type { MediaType::ApplicationJson => OutputFormat::Json, @@ -48,12 +49,14 @@ impl From for OutputFormat { } // Builds the `micro_http::Response` with a given HTTP version, status code, and body. +#[tracing::instrument(level = "trace", skip(http_version, status_code, body))] fn build_response(http_version: Version, status_code: StatusCode, body: Body) -> Response { let mut response = Response::new(http_version, status_code); response.set_body(body); response } +#[tracing::instrument(level = "trace", skip(target, patch))] /// Patch provided JSON document (given as `serde_json::Value`) in-place with JSON Merge Patch /// [RFC 7396](https://tools.ietf.org/html/rfc7396). pub fn json_patch(target: &mut Value, patch: &Value) { @@ -83,6 +86,7 @@ pub fn json_patch(target: &mut Value, patch: &Value) { } // Make the URI a correct JSON pointer value. +#[tracing::instrument(level = "trace", skip(uri))] fn sanitize_uri(mut uri: String) -> String { let mut len = u32::MAX as usize; // Loop while the deduping decreases the sanitized len. @@ -95,6 +99,7 @@ fn sanitize_uri(mut uri: String) -> String { uri } +#[tracing::instrument(level = "trace", skip(mmds, request))] pub fn convert_to_response(mmds: Arc>, request: Request) -> Response { let uri = request.uri().get_abs_path(); if uri.is_empty() { @@ -113,6 +118,7 @@ pub fn convert_to_response(mmds: Arc>, request: Request) -> Response } } +#[tracing::instrument(level = "trace", skip(mmds, request))] fn respond_to_request_mmdsv1(mmds: &Mmds, request: Request) -> Response { // Allow only GET requests. match request.method() { @@ -129,6 +135,7 @@ fn respond_to_request_mmdsv1(mmds: &Mmds, request: Request) -> Response { } } +#[tracing::instrument(level = "trace", skip(mmds, request))] fn respond_to_request_mmdsv2(mmds: &mut Mmds, request: Request) -> Response { // Fetch custom headers from request. let token_headers = match TokenHeaders::try_from(request.headers.custom_entries()) { @@ -159,6 +166,7 @@ fn respond_to_request_mmdsv2(mmds: &mut Mmds, request: Request) -> Response { } } +#[tracing::instrument(level = "trace", skip(mmds, request, token_headers))] fn respond_to_get_request_checked( mmds: &Mmds, request: Request, @@ -189,6 +197,7 @@ fn respond_to_get_request_checked( } } +#[tracing::instrument(level = "trace", skip(mmds, request))] fn respond_to_get_request_unchecked(mmds: &Mmds, request: Request) -> Response { let uri = request.uri().get_abs_path(); @@ -226,6 +235,7 @@ fn respond_to_get_request_unchecked(mmds: &Mmds, request: Request) -> Response { } } +#[tracing::instrument(level = "trace", skip(mmds, request, token_headers))] fn respond_to_put_request( mmds: &mut Mmds, request: Request, @@ -298,6 +308,7 @@ mod tests { use super::*; use crate::token::{MAX_TOKEN_TTL_SECONDS, MIN_TOKEN_TTL_SECONDS}; + #[tracing::instrument(level = "trace", skip())] fn populate_mmds() -> Arc> { let data = r#"{ "name": { @@ -322,6 +333,7 @@ mod tests { mmds } + #[tracing::instrument(level = "trace", skip())] fn get_json_data() -> &'static str { r#"{ "age": 43, diff --git a/src/mmds/src/ns.rs b/src/mmds/src/ns.rs index 80617002574..3669c362500 100644 --- a/src/mmds/src/ns.rs +++ b/src/mmds/src/ns.rs @@ -70,6 +70,17 @@ pub struct MmdsNetworkStack { } impl MmdsNetworkStack { + #[tracing::instrument( + level = "trace", + skip( + mac_addr, + ipv4_addr, + tcp_port, + max_connections, + max_pending_resets, + mmds + ) + )] pub fn new( mac_addr: MacAddr, ipv4_addr: Ipv4Addr, @@ -93,6 +104,7 @@ impl MmdsNetworkStack { } } + #[tracing::instrument(level = "trace", skip(mmds_ipv4_addr, mmds))] pub fn new_with_defaults(mmds_ipv4_addr: Option, mmds: Arc>) -> Self { let mac_addr = MacAddr::from_str(DEFAULT_MAC_ADDR).unwrap(); let ipv4_addr = mmds_ipv4_addr.unwrap_or_else(|| Ipv4Addr::from(DEFAULT_IPV4_ADDR)); @@ -108,19 +120,23 @@ impl MmdsNetworkStack { ) } + #[tracing::instrument(level = "trace", skip(self, ipv4_addr))] pub fn set_ipv4_addr(&mut self, ipv4_addr: Ipv4Addr) { self.ipv4_addr = ipv4_addr; self.tcp_handler.set_local_ipv4_addr(ipv4_addr); } + #[tracing::instrument(level = "trace", skip(self))] pub fn ipv4_addr(&self) -> Ipv4Addr { self.ipv4_addr } + #[tracing::instrument(level = "trace", skip())] pub fn default_ipv4_addr() -> Ipv4Addr { Ipv4Addr::from(DEFAULT_IPV4_ADDR) } + #[tracing::instrument(level = "trace", skip(self, src))] /// Check if a frame is destined for `mmds` /// /// This returns `true` if the frame is an ARP or IPv4 frame destined for @@ -137,6 +153,7 @@ impl MmdsNetworkStack { } } + #[tracing::instrument(level = "trace", skip(self, src))] /// Handles a frame destined for `mmds` /// /// It assumes that the frame is indeed destined for `mmds`, so the caller @@ -159,6 +176,7 @@ impl MmdsNetworkStack { false } + #[tracing::instrument(level = "trace", skip(self, eth))] fn detour_arp(&mut self, eth: EthernetFrame<&[u8]>) -> bool { if let Ok(arp) = EthIPv4ArpFrame::request_from_bytes(eth.payload()) { self.remote_mac_addr = arp.sha(); @@ -169,6 +187,7 @@ impl MmdsNetworkStack { false } + #[tracing::instrument(level = "trace", skip(self, eth))] fn detour_ipv4(&mut self, eth: EthernetFrame<&[u8]>) -> bool { // TODO: We skip verifying the checksum, just in case the device model relies on offloading // checksum computation from the guest driver to some other entity. Clear up this entire @@ -216,6 +235,7 @@ impl MmdsNetworkStack { // - None, if the MMDS network stack has no frame to send at this point. The buffer can be // used for something else by the device model. // - Some(len), if a frame of the given length has been written to the specified buffer. + #[tracing::instrument(level = "trace", skip(self, buf))] pub fn write_next_frame(&mut self, buf: &mut [u8]) -> Option { // We try to send ARP replies first. if self.pending_arp_reply_dest.is_some() { @@ -253,6 +273,7 @@ impl MmdsNetworkStack { None } + #[tracing::instrument(level = "trace", skip(self, buf, ethertype))] fn prepare_eth_unsized<'a>( &self, buf: &'a mut [u8], @@ -261,6 +282,7 @@ impl MmdsNetworkStack { EthernetFrame::write_incomplete(buf, self.remote_mac_addr, self.mac_addr, ethertype) } + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_arp_reply(&self, buf: &mut [u8]) -> Result, WriteArpFrameError> { let arp_reply_dest = self .pending_arp_reply_dest @@ -287,6 +309,7 @@ impl MmdsNetworkStack { )) } + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_packet(&mut self, buf: &mut [u8]) -> Result, WritePacketError> { let mut eth_unsized = self.prepare_eth_unsized(buf, ETHERTYPE_IPV4)?; @@ -332,6 +355,7 @@ mod tests { // Helper methods which only make sense for testing. impl MmdsNetworkStack { + #[tracing::instrument(level = "trace", skip(self, buf, for_mmds))] fn write_arp_request(&mut self, buf: &mut [u8], for_mmds: bool) -> usize { // Write a reply and then modify it into a request. self.pending_arp_reply_dest = Some(REMOTE_ADDR); @@ -353,6 +377,7 @@ mod tests { len } + #[tracing::instrument(level = "trace", skip(self, buf, addr, flags))] fn write_incoming_tcp_segment( &self, buf: &mut [u8], @@ -389,6 +414,7 @@ mod tests { eth_unsized.with_payload_len_unchecked(packet_len).len() } + #[tracing::instrument(level = "trace", skip(self, buf))] fn next_frame_as_ipv4_packet<'a>(&mut self, buf: &'a mut [u8]) -> IPv4Packet<&'a [u8]> { let len = self.write_next_frame(buf).unwrap().get(); let eth = EthernetFrame::from_bytes(&buf[..len]).unwrap(); diff --git a/src/mmds/src/persist.rs b/src/mmds/src/persist.rs index 8aabb14849b..a0330caa7b7 100644 --- a/src/mmds/src/persist.rs +++ b/src/mmds/src/persist.rs @@ -30,6 +30,7 @@ impl Persist<'_> for MmdsNetworkStack { type ConstructorArgs = Arc>; type Error = (); + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { let mut mac_addr = [0; MAC_ADDR_LEN]; mac_addr.copy_from_slice(self.mac_addr.get_bytes()); @@ -43,6 +44,7 @@ impl Persist<'_> for MmdsNetworkStack { } } + #[tracing::instrument(level = "trace", skip(mmds, state))] fn restore( mmds: Self::ConstructorArgs, state: &Self::State, diff --git a/src/mmds/src/token.rs b/src/mmds/src/token.rs index e8d0ca3e6b2..2c67c277be0 100644 --- a/src/mmds/src/token.rs +++ b/src/mmds/src/token.rs @@ -83,6 +83,7 @@ pub struct TokenAuthority { // TODO When https://github.com/RustCrypto/AEADs/pull/532 is merged replace these manual // implementation with `#[derive(Debug)]`. impl fmt::Debug for TokenAuthority { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TokenAuthority") .field("num_encrypted_tokens", &self.num_encrypted_tokens) @@ -93,6 +94,7 @@ impl fmt::Debug for TokenAuthority { } impl TokenAuthority { + #[tracing::instrument(level = "trace", skip())] /// Create a new token authority entity. pub fn new() -> Result { let mut file = File::open(Path::new(RANDOMNESS_POOL))?; @@ -105,12 +107,14 @@ impl TokenAuthority { }) } + #[tracing::instrument(level = "trace", skip(self, instance_id))] /// Set Additional Authenticated Data to be used for /// encryption and decryption of the session token. pub fn set_aad(&mut self, instance_id: &str) { self.aad = format!("microvmid={}", instance_id); } + #[tracing::instrument(level = "trace", skip(self, ttl_seconds))] /// Generate encoded token string using the token time to live provided. pub fn generate_token_secret(&mut self, ttl_seconds: u32) -> Result { // Check number of tokens encrypted under the current key. We need to @@ -127,6 +131,7 @@ impl TokenAuthority { Ok(encoded_token) } + #[tracing::instrument(level = "trace", skip(self, ttl_seconds))] /// Create a new Token structure to encrypt. fn create_token(&mut self, ttl_seconds: u32) -> Result { // Validate token time to live against bounds. @@ -146,6 +151,7 @@ impl TokenAuthority { Ok(Token::new(iv, payload, tag)) } + #[tracing::instrument(level = "trace", skip(self, expiry, iv))] /// Encrypt expiry using AES-GCM block cipher and return payload and tag obtained. fn encrypt_expiry( &self, @@ -171,6 +177,7 @@ impl TokenAuthority { Ok((expiry_as_bytes, tag_as_bytes)) } + #[tracing::instrument(level = "trace", skip(self, encoded_token))] /// Attempts to decrypt expiry value within token sequence. Returns false if expiry /// cannot be decrypted. If decryption succeeds, returns true if token has not expired /// (i.e. current time is greater than expiry) and false otherwise. @@ -196,6 +203,7 @@ impl TokenAuthority { expiry > get_time_ms(ClockType::Monotonic) } + #[tracing::instrument(level = "trace", skip(self, payload, tag, iv))] /// Decrypt ciphertext composed of payload and tag to obtain the expiry value. fn decrypt_expiry( &self, @@ -222,6 +230,7 @@ impl TokenAuthority { Ok(u64::from_le_bytes(expiry_as_bytes)) } + #[tracing::instrument(level = "trace", skip(entropy_pool))] /// Create a new AES-GCM cipher entity. fn create_cipher(entropy_pool: &mut File) -> Result { // Randomly generate a 256-bit key to be used for encryption/decryption purposes. @@ -232,6 +241,7 @@ impl TokenAuthority { Ok(Aes256Gcm::new(Key::::from_slice(&key))) } + #[tracing::instrument(level = "trace", skip(self))] /// Make sure to reinitialize the cipher under a new key before reaching /// a count of 2^32 encrypted tokens under the same cipher entity. fn check_encryption_count(&mut self) -> Result<(), Error> { @@ -258,11 +268,13 @@ impl TokenAuthority { Ok(()) } + #[tracing::instrument(level = "trace", skip(ttl_seconds))] /// Validate the token time to live against bounds. fn check_ttl(ttl_seconds: u32) -> bool { (MIN_TOKEN_TTL_SECONDS..=MAX_TOKEN_TTL_SECONDS).contains(&ttl_seconds) } + #[tracing::instrument(level = "trace", skip(ttl_as_seconds))] /// Compute expiry time in seconds by adding the time to live provided /// to the current time measured in milliseconds. fn compute_expiry(ttl_as_seconds: u32) -> u64 { @@ -289,11 +301,13 @@ struct Token { } impl Token { + #[tracing::instrument(level = "trace", skip(iv, payload, tag))] /// Create a new token struct. fn new(iv: [u8; IV_LEN], payload: [u8; PAYLOAD_LEN], tag: [u8; TAG_LEN]) -> Self { Token { iv, payload, tag } } + #[tracing::instrument(level = "trace", skip(self))] /// Encode token structure into a string using base64 encoding. fn base64_encode(&self) -> Result { let token_bytes: Vec = bincode::serialize(self)?; @@ -302,6 +316,7 @@ impl Token { Ok(base64::encode_config(token_bytes, base64::STANDARD)) } + #[tracing::instrument(level = "trace", skip(encoded_token))] /// Decode token structure from base64 string. fn base64_decode(encoded_token: &str) -> Result { let token_bytes = base64::decode_config(encoded_token, base64::STANDARD) diff --git a/src/mmds/src/token_headers.rs b/src/mmds/src/token_headers.rs index edb501d6ab5..312c974ad10 100644 --- a/src/mmds/src/token_headers.rs +++ b/src/mmds/src/token_headers.rs @@ -21,6 +21,7 @@ pub struct TokenHeaders { } impl Default for TokenHeaders { + #[tracing::instrument(level = "trace", skip())] /// Token headers are not present in the request by default. fn default() -> Self { Self { @@ -36,6 +37,7 @@ impl TokenHeaders { /// `X-metadata-token-ttl-seconds` header. const X_METADATA_TOKEN_TTL_SECONDS: &'static str = "X-metadata-token-ttl-seconds"; + #[tracing::instrument(level = "trace", skip(map))] /// Return `TokenHeaders` from headers map. pub fn try_from(map: &HashMap) -> Result { let mut headers = Self::default(); @@ -68,21 +70,25 @@ impl TokenHeaders { Ok(headers) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the `XMetadataToken` token. pub fn x_metadata_token(&self) -> Option<&String> { self.x_metadata_token.as_ref() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the `XMetadataTokenTtlSeconds` token. pub fn x_metadata_token_ttl_seconds(&self) -> Option { self.x_metadata_token_ttl_seconds } + #[tracing::instrument(level = "trace", skip(self, token))] /// Sets the `XMetadataToken` token. pub fn set_x_metadata_token(&mut self, token: String) { self.x_metadata_token = Some(token) } + #[tracing::instrument(level = "trace", skip(self, ttl))] /// Sets the `XMetadataTokenTtlSeconds` token. pub fn set_x_metadata_token_ttl_seconds(&mut self, ttl: u32) { self.x_metadata_token_ttl_seconds = Some(ttl); diff --git a/src/rebase-snap/Cargo.toml b/src/rebase-snap/Cargo.toml index f4f1032820d..879ad5c50ee 100644 --- a/src/rebase-snap/Cargo.toml +++ b/src/rebase-snap/Cargo.toml @@ -13,5 +13,6 @@ bench = false [dependencies] libc = "0.2.147" thiserror = "1.0.40" +tracing = { version = "0.1.37", features = ["max_level_debug"] } utils = { path = "../utils" } diff --git a/src/rebase-snap/src/main.rs b/src/rebase-snap/src/main.rs index 6e631abcc8b..80e8d1e4f99 100644 --- a/src/rebase-snap/src/main.rs +++ b/src/rebase-snap/src/main.rs @@ -41,6 +41,7 @@ enum RebaseSnapError { RebaseFiles(FileError), } +#[tracing::instrument(level = "trace", skip())] fn build_arg_parser<'a>() -> ArgParser<'a> { let arg_parser = ArgParser::new() .arg( @@ -59,6 +60,7 @@ fn build_arg_parser<'a>() -> ArgParser<'a> { arg_parser } +#[tracing::instrument(level = "trace", skip(args))] fn get_files(args: &Arguments) -> Result<(File, File), FileError> { // Safe to unwrap since the required arguments are checked as part of // `arg_parser.parse_from_cmdline()` @@ -78,6 +80,7 @@ fn get_files(args: &Arguments) -> Result<(File, File), FileError> { Ok((base_file, diff_file)) } +#[tracing::instrument(level = "trace", skip(base_file, diff_file))] fn rebase(base_file: &mut File, diff_file: &mut File) -> Result<(), FileError> { let mut cursor: u64 = 0; while let Some(block_start) = diff_file.seek_data(cursor).map_err(FileError::SeekData)? { @@ -113,6 +116,7 @@ fn rebase(base_file: &mut File, diff_file: &mut File) -> Result<(), FileError> { Ok(()) } +#[tracing::instrument(level = "trace", skip())] fn main() -> Result<(), RebaseSnapError> { let result = main_exec(); if let Err(e) = result { @@ -123,6 +127,7 @@ fn main() -> Result<(), RebaseSnapError> { } } +#[tracing::instrument(level = "trace", skip())] fn main_exec() -> Result<(), RebaseSnapError> { let mut arg_parser = build_arg_parser(); @@ -235,6 +240,7 @@ mod tests { assert!(get_files(arguments).is_ok()); } + #[tracing::instrument(level = "trace", skip(file, expected_content))] fn check_file_content(file: &mut File, expected_content: &[u8]) { let mut buf = vec![0u8; expected_content.len()]; file.read_exact_at(buf.as_mut_slice(), 0).unwrap(); diff --git a/src/seccompiler/Cargo.toml b/src/seccompiler/Cargo.toml index 9f9a76b639e..853624abfa6 100644 --- a/src/seccompiler/Cargo.toml +++ b/src/seccompiler/Cargo.toml @@ -22,5 +22,6 @@ libc = "0.2.147" serde = { version = "1.0.183", features = ["derive"] } serde_json = "1.0.104" thiserror = "1.0.44" +tracing = { version = "0.1.37", features = ["max_level_debug"] } utils = { path = "../utils" } diff --git a/src/seccompiler/src/backend.rs b/src/seccompiler/src/backend.rs index e2cd3b75b06..ae9da6306e0 100644 --- a/src/seccompiler/src/backend.rs +++ b/src/seccompiler/src/backend.rs @@ -84,6 +84,7 @@ const SECCOMP_DATA_ARG_SIZE: u8 = 8; pub(crate) struct Comment; impl<'de> Deserialize<'de> for Comment { + #[tracing::instrument(level = "trace", skip(_deserializer))] fn deserialize(_deserializer: D) -> std::result::Result where D: Deserializer<'de>, @@ -133,6 +134,7 @@ pub(crate) enum TargetArchError { } impl TargetArch { + #[tracing::instrument(level = "trace", skip(self))] /// Get the arch audit value. fn get_audit_value(self) -> u32 { match self { @@ -141,6 +143,7 @@ impl TargetArch { } } + #[tracing::instrument(level = "trace", skip(self))] /// Get the string representation. fn to_string(self) -> &'static str { match self { @@ -152,6 +155,7 @@ impl TargetArch { impl TryInto for &str { type Error = TargetArchError; + #[tracing::instrument(level = "trace", skip(self))] fn try_into(self) -> std::result::Result { match self.to_lowercase().as_str() { "x86_64" => Ok(TargetArch::x86_64), @@ -162,6 +166,7 @@ impl TryInto for &str { } impl From for &str { + #[tracing::instrument(level = "trace", skip(target_arch))] fn from(target_arch: TargetArch) -> Self { target_arch.to_string() } @@ -265,6 +270,7 @@ pub(crate) struct SeccompFilter { } impl SeccompCondition { + #[tracing::instrument(level = "trace", skip(self))] /// Validates the SeccompCondition data pub fn validate(&self) -> Result<(), FilterError> { // Checks that the given argument number is valid. @@ -275,6 +281,7 @@ impl SeccompCondition { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Splits the [`SeccompCondition`] into 32 bit chunks and offsets. /// /// Returns most significant half, least significant half of the `value` field of @@ -298,6 +305,7 @@ impl SeccompCondition { (msb, lsb, msb_offset, lsb_offset) } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the `eq` (equal) condition into BPF statements. /// /// # Arguments @@ -330,6 +338,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the `ge` (greater than or equal) condition into BPF statements. /// /// # Arguments @@ -354,6 +363,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the `gt` (greater than) condition into BPF statements. /// /// # Arguments @@ -378,6 +388,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the `le` (less than or equal) condition into BPF statements. /// /// # Arguments @@ -402,6 +413,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the `lt` (less than) condition into BPF statements. /// /// # Arguments @@ -426,6 +438,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset, mask))] /// Translates the `masked_eq` (masked equal) condition into BPF statements. /// /// The `masked_eq` condition is `true` if the result of logical `AND` between the given value @@ -457,6 +470,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the `ne` (not equal) condition into BPF statements. /// /// # Arguments @@ -480,6 +494,7 @@ impl SeccompCondition { bpf } + #[tracing::instrument(level = "trace", skip(self, offset))] /// Translates the [`SeccompCondition`] into BPF statements. /// /// # Arguments @@ -506,6 +521,7 @@ impl SeccompCondition { } impl From for u32 { + #[tracing::instrument(level = "trace", skip(action))] /// Return codes of the BPF program for each action. /// /// # Arguments @@ -527,6 +543,7 @@ impl From for u32 { } impl SeccompRule { + #[tracing::instrument(level = "trace", skip(conditions, action))] /// Creates a new rule. Rules with 0 conditions always match. /// /// # Arguments @@ -540,6 +557,7 @@ impl SeccompRule { Self { conditions, action } } + #[tracing::instrument(level = "trace", skip(condition, accumulator, rule_len, offset))] /// Appends a condition of the rule to an accumulator. /// /// The length of the rule and offset to the next rule are updated. @@ -588,6 +606,7 @@ impl SeccompRule { } impl From for BpfProgram { + #[tracing::instrument(level = "trace", skip(rule))] /// Translates a rule into BPF statements. /// /// Each rule starts with 2 jump statements: @@ -629,6 +648,7 @@ impl From for BpfProgram { } impl SeccompFilter { + #[tracing::instrument(level = "trace", skip(rules, default_action, target_arch))] /// Creates a new filter with a set of rules and a default action. /// /// # Arguments @@ -652,6 +672,7 @@ impl SeccompFilter { Ok(instance) } + #[tracing::instrument(level = "trace", skip(self))] /// Performs semantic checks on the SeccompFilter. fn validate(&self) -> Result<(), FilterError> { for (syscall_number, syscall_rules) in self.rules.iter() { @@ -686,6 +707,10 @@ impl SeccompFilter { Ok(()) } + #[tracing::instrument( + level = "trace", + skip(syscall_number, chain, default_action, accumulator, filter_len) + )] /// Appends a chain of rules to an accumulator, updating the length of the filter. /// /// # Arguments @@ -741,6 +766,7 @@ impl SeccompFilter { impl TryInto for SeccompFilter { type Error = FilterError; + #[tracing::instrument(level = "trace", skip(self))] fn try_into(self) -> Result { // Initialize the result with the precursory architecture check. let mut result = VALIDATE_ARCHITECTURE(self.target_arch); @@ -795,6 +821,7 @@ impl TryInto for SeccompFilter { } } +#[tracing::instrument(level = "trace", skip(code, k, jt, jf))] /// Builds a `jump` BPF instruction. /// /// # Arguments @@ -809,6 +836,7 @@ fn BPF_JUMP(code: u16, k: u32, jt: u8, jf: u8) -> sock_filter { sock_filter { code, jt, jf, k } } +#[tracing::instrument(level = "trace", skip(code, k))] /// Builds a "statement" BPF instruction. /// /// # Arguments @@ -826,6 +854,7 @@ fn BPF_STMT(code: u16, k: u32) -> sock_filter { } } +#[tracing::instrument(level = "trace", skip(target_arch))] /// Builds a sequence of BPF instructions that validate the underlying architecture. #[allow(non_snake_case)] #[inline(always)] @@ -838,6 +867,7 @@ fn VALIDATE_ARCHITECTURE(target_arch: TargetArch) -> Vec { ] } +#[tracing::instrument(level = "trace", skip())] /// Builds a sequence of BPF instructions that are followed by syscall examination. #[allow(non_snake_case)] #[inline(always)] @@ -866,12 +896,14 @@ mod tests { } // Builds the (syscall, rules) tuple for allowing a syscall with certain arguments. + #[tracing::instrument(level = "trace", skip(syscall_number, rules))] fn allow_syscall_if(syscall_number: i64, rules: Vec) -> (i64, Vec) { (syscall_number, rules) } impl SeccompCondition { // Creates a new `SeccompCondition`. + #[tracing::instrument(level = "trace", skip(arg_number, arg_len, operator, value))] pub fn new( arg_number: u8, arg_len: SeccompCmpArgLen, @@ -913,6 +945,7 @@ mod tests { libc::SYS_futex, ]; + #[tracing::instrument(level = "trace", skip(bpf_filter))] fn install_filter(bpf_filter: BpfProgram) { unsafe { { @@ -935,6 +968,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(rules, validation_fn, should_fail))] fn validate_seccomp_filter( rules: Vec<(i64, Vec)>, validation_fn: fn(), @@ -1470,6 +1504,7 @@ mod tests { assert_eq!(bpfprog, instructions); } + #[tracing::instrument(level = "trace", skip(arg_len))] fn create_test_bpf_filter(arg_len: ArgLen) -> SeccompFilter { SeccompFilter::new( vec![ diff --git a/src/seccompiler/src/compiler.rs b/src/seccompiler/src/compiler.rs index c4f0682620b..d261bb6556f 100644 --- a/src/seccompiler/src/compiler.rs +++ b/src/seccompiler/src/compiler.rs @@ -51,6 +51,7 @@ pub(crate) struct JsonFile(pub BTreeMap); // Implement a custom deserializer, that returns an error for duplicate thread keys. impl<'de> Deserialize<'de> for JsonFile { + #[tracing::instrument(level = "trace", skip(deserializer))] fn deserialize(deserializer: D) -> result::Result where D: de::Deserializer<'de>, @@ -61,10 +62,12 @@ impl<'de> Deserialize<'de> for JsonFile { impl<'d> Visitor<'d> for JsonFileVisitor { type Value = BTreeMap; + #[tracing::instrument(level = "trace", skip(self, f))] fn expecting(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> { f.write_str("a map of filters") } + #[tracing::instrument(level = "trace", skip(self, access))] fn visit_map(self, mut access: M) -> result::Result where M: MapAccess<'d>, @@ -98,6 +101,7 @@ pub(crate) struct SyscallRule { } impl SyscallRule { + #[tracing::instrument(level = "trace", skip(self))] /// Perform semantic checks after deserialization. fn validate(&self) -> Result<(), CompilationError> { // Validate all `SeccompCondition`s. @@ -126,6 +130,7 @@ pub(crate) struct Filter { } impl Filter { + #[tracing::instrument(level = "trace", skip(self))] /// Perform semantic checks after deserialization. fn validate(&self) -> Result<(), CompilationError> { // Doesn't make sense to have equal default and on-match actions. @@ -154,6 +159,7 @@ pub(crate) struct Compiler { } impl Compiler { + #[tracing::instrument(level = "trace", skip(arch))] /// Create a new `Compiler` instance, for the given target architecture. pub fn new(arch: TargetArch) -> Self { Self { @@ -162,6 +168,7 @@ impl Compiler { } } + #[tracing::instrument(level = "trace", skip(self, filters))] /// Perform semantic checks after deserialization. fn validate_filters(&self, filters: &BTreeMap) -> Result<(), CompilationError> { // Validate all `Filter`s. @@ -172,6 +179,7 @@ impl Compiler { .map_or(Ok(()), Err) } + #[tracing::instrument(level = "trace", skip(self, filters, is_basic))] /// Main compilation function. pub fn compile_blob( &self, @@ -194,6 +202,7 @@ impl Compiler { Ok(bpf_map) } + #[tracing::instrument(level = "trace", skip(self, filter))] /// Transforms the deserialized `Filter` into a `SeccompFilter` (IR language). fn make_seccomp_filter(&self, filter: Filter) -> Result { let mut rule_map: SeccompRuleMap = SeccompRuleMap::new(); @@ -218,6 +227,7 @@ impl Compiler { .map_err(CompilationError::Filter) } + #[tracing::instrument(level = "trace", skip(self, filter))] /// Transforms the deserialized `Filter` into a basic `SeccompFilter` (IR language). /// This filter will drop any argument checks and any rule-level action. /// All rules will trigger the filter-level `filter_action`. @@ -261,6 +271,7 @@ mod tests { }; impl Filter { + #[tracing::instrument(level = "trace", skip(default_action, filter_action, filter))] pub fn new( default_action: SeccompAction, filter_action: SeccompAction, @@ -275,6 +286,7 @@ mod tests { } impl SyscallRule { + #[tracing::instrument(level = "trace", skip(syscall, conditions))] pub fn new(syscall: String, conditions: Option>) -> SyscallRule { SyscallRule { syscall, @@ -284,10 +296,12 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(syscall_number, action))] fn match_syscall(syscall_number: i64, action: SeccompAction) -> (i64, Vec) { (syscall_number, vec![SeccompRule::new(vec![], action)]) } + #[tracing::instrument(level = "trace", skip(syscall_number, rules))] fn match_syscall_if(syscall_number: i64, rules: Vec) -> (i64, Vec) { (syscall_number, rules) } diff --git a/src/seccompiler/src/lib.rs b/src/seccompiler/src/lib.rs index dcaf0dec373..6efd8f8d8c0 100644 --- a/src/seccompiler/src/lib.rs +++ b/src/seccompiler/src/lib.rs @@ -51,6 +51,7 @@ pub enum InstallationError { Prctl(i32), } +#[tracing::instrument(level = "trace", skip(reader, bytes_limit))] /// Deserialize a BPF file into a collection of usable BPF filters. /// Has an optional `bytes_limit` that is passed to bincode to constrain the maximum amount of /// memory that we can allocate while performing the deserialization. @@ -79,6 +80,7 @@ pub fn deserialize_binary( .collect()) } +#[tracing::instrument(level = "trace", skip(bpf_filter))] /// Helper function for installing a BPF filter. pub fn apply_filter(bpf_filter: BpfProgramRef) -> std::result::Result<(), InstallationError> { // If the program is empty, don't install the filter. diff --git a/src/seccompiler/src/seccompiler_bin.rs b/src/seccompiler/src/seccompiler_bin.rs index 9908a090927..2d8d42379b2 100644 --- a/src/seccompiler/src/seccompiler_bin.rs +++ b/src/seccompiler/src/seccompiler_bin.rs @@ -79,6 +79,7 @@ struct Arguments { is_basic: bool, } +#[tracing::instrument(level = "trace", skip())] fn build_arg_parser() -> ArgParser<'static> { ArgParser::new() .arg( @@ -109,6 +110,7 @@ fn build_arg_parser() -> ArgParser<'static> { )) } +#[tracing::instrument(level = "trace", skip(arguments))] fn get_argument_values(arguments: &ArgumentsBag) -> Result { let arch_string = arguments.single_value("target-arch"); if arch_string.is_none() { @@ -138,6 +140,7 @@ fn get_argument_values(arguments: &ArgumentsBag) -> Result Result<(), SeccompError> { let input_file = File::open(&args.input_file) .map_err(|err| SeccompError::FileOpen(PathBuf::from(&args.input_file), err))?; @@ -169,6 +172,7 @@ enum SeccompilerError { Error(SeccompError), } +#[tracing::instrument(level = "trace", skip())] fn main() -> core::result::Result<(), SeccompilerError> { let result = main_exec(); if let Err(e) = result { @@ -179,6 +183,7 @@ fn main() -> core::result::Result<(), SeccompilerError> { } } +#[tracing::instrument(level = "trace", skip())] fn main_exec() -> core::result::Result<(), SeccompilerError> { let mut arg_parser = build_arg_parser(); diff --git a/src/seccompiler/src/syscall_table/aarch64.rs b/src/seccompiler/src/syscall_table/aarch64.rs index af56b90552a..3b57079051b 100644 --- a/src/seccompiler/src/syscall_table/aarch64.rs +++ b/src/seccompiler/src/syscall_table/aarch64.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; +#[tracing::instrument(level = "trace", skip(map))] pub(crate) fn make_syscall_table(map: &mut HashMap) { map.insert("accept4".to_string(), 242); map.insert("accept".to_string(), 202); diff --git a/src/seccompiler/src/syscall_table/mod.rs b/src/seccompiler/src/syscall_table/mod.rs index 94c861636bc..8eda38691ee 100644 --- a/src/seccompiler/src/syscall_table/mod.rs +++ b/src/seccompiler/src/syscall_table/mod.rs @@ -19,6 +19,7 @@ pub(crate) struct SyscallTable { const MAP_CAPACITY: usize = 351; impl SyscallTable { + #[tracing::instrument(level = "trace", skip(arch))] pub fn new(arch: TargetArch) -> Self { let mut instance = Self { arch, @@ -30,11 +31,13 @@ impl SyscallTable { instance } + #[tracing::instrument(level = "trace", skip(self, sys_name))] /// Returns the arch-specific syscall number based on the given name. pub fn get_syscall_nr(&self, sys_name: &str) -> Option { self.map.get(sys_name).copied() } + #[tracing::instrument(level = "trace", skip(self))] /// Populates the arch-specific syscall map. fn populate_map(&mut self) { match self.arch { diff --git a/src/seccompiler/src/syscall_table/x86_64.rs b/src/seccompiler/src/syscall_table/x86_64.rs index 2ff471755af..dd5e5e2a59e 100644 --- a/src/seccompiler/src/syscall_table/x86_64.rs +++ b/src/seccompiler/src/syscall_table/x86_64.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; +#[tracing::instrument(level = "trace", skip(map))] pub(crate) fn make_syscall_table(map: &mut HashMap) { map.insert("accept4".to_string(), 288); map.insert("accept".to_string(), 43); diff --git a/src/snapshot/Cargo.toml b/src/snapshot/Cargo.toml index 058efa139d8..8d0ff3cfe6c 100644 --- a/src/snapshot/Cargo.toml +++ b/src/snapshot/Cargo.toml @@ -14,6 +14,7 @@ libc = "0.2.117" versionize = "0.1.10" versionize_derive = "0.1.5" thiserror = "1.0.32" +tracing = { version = "0.1.37", features = ["max_level_debug"] } [dev-dependencies] criterion = { version = "0.5.0", default-features = false } diff --git a/src/snapshot/benches/version_map.rs b/src/snapshot/benches/version_map.rs index ea3c38b86d7..042a2eb67b4 100644 --- a/src/snapshot/benches/version_map.rs +++ b/src/snapshot/benches/version_map.rs @@ -25,11 +25,13 @@ struct Dummy { b: [u64; 32], } +#[tracing::instrument(level = "trace", skip(snapshot_mem, vm))] #[inline] fn restore(mut snapshot_mem: &[u8], vm: VersionMap) { Snapshot::unchecked_load::<&[u8], Test>(&mut snapshot_mem, vm).unwrap(); } +#[tracing::instrument(level = "trace", skip(snapshot_mem, vm))] #[inline] fn save(mut snapshot_mem: &mut W, vm: VersionMap) { let state = Test { @@ -52,6 +54,7 @@ fn save(mut snapshot_mem: &mut W, vm: VersionMap) { .unwrap(); } +#[tracing::instrument(level = "trace", skip(c))] pub fn criterion_benchmark(c: &mut Criterion) { let mut snapshot_mem = vec![0u8; 1024 * 1024 * 128]; let mut vm = VersionMap::new(); diff --git a/src/snapshot/src/lib.rs b/src/snapshot/src/lib.rs index 187fe58e3be..d680abd326d 100644 --- a/src/snapshot/src/lib.rs +++ b/src/snapshot/src/lib.rs @@ -86,6 +86,7 @@ pub struct Snapshot { } // Parse a magic_id and return the format version. +#[tracing::instrument(level = "trace", skip(magic_id))] fn get_format_version(magic_id: u64) -> Result { let magic_arch = magic_id & BASE_MAGIC_ID_MASK; if magic_arch == BASE_MAGIC_ID { @@ -94,11 +95,13 @@ fn get_format_version(magic_id: u64) -> Result { Err(Error::InvalidMagic(magic_id)) } +#[tracing::instrument(level = "trace", skip(format_version))] fn build_magic_id(format_version: u16) -> u64 { BASE_MAGIC_ID | u64::from(format_version) } impl Snapshot { + #[tracing::instrument(level = "trace", skip(version_map, target_version))] /// Creates a new instance which can only be used to save a new snapshot. pub fn new(version_map: VersionMap, target_version: u16) -> Snapshot { Snapshot { @@ -108,6 +111,7 @@ impl Snapshot { } } + #[tracing::instrument(level = "trace", skip(reader, version_map))] /// Fetches snapshot data version. pub fn get_data_version(mut reader: &mut T, version_map: &VersionMap) -> Result where @@ -133,6 +137,7 @@ impl Snapshot { Ok(hdr.data_version) } + #[tracing::instrument(level = "trace", skip(reader, version_map))] /// Attempts to load an existing snapshot without CRC validation. pub fn unchecked_load( mut reader: &mut T, @@ -142,6 +147,7 @@ impl Snapshot { O::deserialize(&mut reader, &version_map, data_version).map_err(Error::Versionize) } + #[tracing::instrument(level = "trace", skip(reader, snapshot_len, version_map))] /// Attempts to load an existing snapshot and validate CRC. pub fn load( reader: &mut T, @@ -176,6 +182,7 @@ impl Snapshot { Ok(object) } + #[tracing::instrument(level = "trace", skip(self, writer, object))] /// Saves a snapshot and include a CRC64 checksum. pub fn save(&mut self, writer: &mut T, object: &O) -> Result<(), Error> where @@ -194,6 +201,7 @@ impl Snapshot { // TODO Remove `skip(crc_writer)` when https://github.com/firecracker-microvm/versionize/pull/59 // is merged and included. + #[tracing::instrument(level = "trace", skip(self, writer, object))] /// Save a snapshot with no CRC64 checksum included. pub fn save_without_crc(&mut self, mut writer: &mut T, object: &O) -> Result<(), Error> where @@ -235,6 +243,7 @@ impl Snapshot { // defined structures. // This version map allows us to change the underlying storage format - // for example the way we encode vectors or moving to something else than bincode. + #[tracing::instrument(level = "trace", skip())] fn format_version_map() -> VersionMap { // Firecracker snapshot format version 1. VersionMap::new() @@ -276,15 +285,19 @@ mod tests { } impl Test { + #[tracing::instrument(level = "trace", skip())] fn field2_default(_: u16) -> u64 { 20 } + #[tracing::instrument(level = "trace", skip())] fn field3_default(_: u16) -> String { "default".to_owned() } + #[tracing::instrument(level = "trace", skip())] fn field4_default(_: u16) -> Vec { vec![1, 2, 3, 4] } + #[tracing::instrument(level = "trace", skip(self, target_version))] fn field4_serialize(&mut self, target_version: u16) -> VersionizeResult<()> { // Fail if semantic serialization is called for the latest version. assert_ne!(target_version, Test::version()); @@ -297,6 +310,7 @@ mod tests { } Ok(()) } + #[tracing::instrument(level = "trace", skip(self, source_version))] fn field4_deserialize(&mut self, source_version: u16) -> VersionizeResult<()> { // Fail if semantic deserialization is called for the latest version. assert_ne!(source_version, Test::version()); @@ -304,6 +318,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, target_version))] fn field3_serialize(&mut self, target_version: u16) -> VersionizeResult<()> { // Fail if semantic serialization is called for the previous versions only. assert!(target_version < 3); @@ -311,6 +326,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, source_version))] fn field3_deserialize(&mut self, source_version: u16) -> VersionizeResult<()> { // Fail if semantic deserialization is called for the latest version. assert!(source_version < 3); diff --git a/src/snapshot/tests/test.rs b/src/snapshot/tests/test.rs index 94c1510c306..7ee4b0d6d34 100644 --- a/src/snapshot/tests/test.rs +++ b/src/snapshot/tests/test.rs @@ -13,6 +13,7 @@ pub enum TestState { } impl TestState { + #[tracing::instrument(level = "trace", skip(self, target_version))] fn default_state_two(&self, target_version: u16) -> VersionizeResult { match target_version { 1 => Ok(TestState::One(2)), @@ -34,6 +35,7 @@ pub struct A { } impl A { + #[tracing::instrument(level = "trace", skip(_source_version))] fn default_c(_source_version: u16) -> String { "some_string".to_owned() } diff --git a/src/utils/Cargo.toml b/src/utils/Cargo.toml index 8730af0ab49..69f81658bbb 100644 --- a/src/utils/Cargo.toml +++ b/src/utils/Cargo.toml @@ -17,6 +17,7 @@ versionize = "0.1.10" versionize_derive = "0.1.5" vmm-sys-util = "0.11.0" vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-bitmap"] } +tracing = { version = "0.1.37", features = ["max_level_debug"] } net_gen = { path = "../net_gen" } diff --git a/src/utils/src/arg_parser.rs b/src/utils/src/arg_parser.rs index 3a736e048c6..38c317b7768 100644 --- a/src/utils/src/arg_parser.rs +++ b/src/utils/src/arg_parser.rs @@ -38,22 +38,26 @@ pub struct ArgParser<'a> { } impl<'a> ArgParser<'a> { + #[tracing::instrument(level = "trace", skip())] /// Create a new ArgParser instance. pub fn new() -> Self { ArgParser::default() } + #[tracing::instrument(level = "trace", skip(self, argument))] /// Add an argument with its associated `Argument` in `arguments`. pub fn arg(mut self, argument: Argument<'a>) -> Self { self.arguments.insert_arg(argument); self } + #[tracing::instrument(level = "trace", skip(self))] /// Parse the command line arguments. pub fn parse_from_cmdline(&mut self) -> Result<()> { self.arguments.parse_from_cmdline() } + #[tracing::instrument(level = "trace", skip(self))] /// Concatenate the `help` information of every possible argument /// in a message that represents the correct command line usage /// for the application. @@ -80,6 +84,7 @@ impl<'a> ArgParser<'a> { help_builder.join("\n") } + #[tracing::instrument(level = "trace", skip(self))] /// Return a reference to `arguments` field. pub fn arguments(&self) -> &Arguments { &self.arguments @@ -87,6 +92,7 @@ impl<'a> ArgParser<'a> { // Filter arguments by whether or not it is required. // Align arguments by setting width to length of the longest argument. + #[tracing::instrument(level = "trace", skip(self, is_required))] fn format_arguments(&self, is_required: bool) -> String { let filtered_arguments = self .arguments @@ -124,6 +130,7 @@ pub struct Argument<'a> { } impl<'a> Argument<'a> { + #[tracing::instrument(level = "trace", skip(name))] /// Create a new `Argument` that keeps the necessary information for an argument. pub fn new(name: &'a str) -> Argument<'a> { Argument { @@ -139,24 +146,28 @@ impl<'a> Argument<'a> { } } + #[tracing::instrument(level = "trace", skip(self, required))] /// Set if the argument *must* be provided by user. pub fn required(mut self, required: bool) -> Self { self.required = required; self } + #[tracing::instrument(level = "trace", skip(self, other_arg))] /// Add `other_arg` as a required parameter when `self` is specified. pub fn requires(mut self, other_arg: &'a str) -> Self { self.requires = Some(other_arg); self } + #[tracing::instrument(level = "trace", skip(self, args))] /// Add `other_arg` as a forbidden parameter when `self` is specified. pub fn forbids(mut self, args: Vec<&'a str>) -> Self { self.forbids = args; self } + #[tracing::instrument(level = "trace", skip(self, takes_value))] /// If `takes_value` is true, then the user *must* provide a value for the /// argument, otherwise that argument is a flag. pub fn takes_value(mut self, takes_value: bool) -> Self { @@ -164,6 +175,7 @@ impl<'a> Argument<'a> { self } + #[tracing::instrument(level = "trace", skip(self, allow_multiple))] /// If `allow_multiple` is true, then the user can provide multiple values for the /// argument (e.g --arg val1 --arg val2). It sets the `takes_value` option to true, /// so the user must provides at least one value. @@ -175,6 +187,7 @@ impl<'a> Argument<'a> { self } + #[tracing::instrument(level = "trace", skip(self, default_value))] /// Keep a default value which will be used if the user didn't provide a value for /// the argument. pub fn default_value(mut self, default_value: &'a str) -> Self { @@ -182,6 +195,7 @@ impl<'a> Argument<'a> { self } + #[tracing::instrument(level = "trace", skip(self, help))] /// Set the information that will be displayed for the argument when user passes /// `--help` flag. pub fn help(mut self, help: &'a str) -> Self { @@ -189,6 +203,7 @@ impl<'a> Argument<'a> { self } + #[tracing::instrument(level = "trace", skip(self, arg_width))] fn format_help(&self, arg_width: usize) -> String { let mut help_builder = vec![]; @@ -212,6 +227,7 @@ impl<'a> Argument<'a> { help_builder.concat() } + #[tracing::instrument(level = "trace", skip(self))] fn format_name(&self) -> String { if self.takes_value { format!(" --{name} <{name}>", name = self.name) @@ -230,6 +246,7 @@ pub enum Value { } impl Value { + #[tracing::instrument(level = "trace", skip(self))] fn as_single_value(&self) -> Option<&String> { match self { Value::Single(s) => Some(s), @@ -237,10 +254,12 @@ impl Value { } } + #[tracing::instrument(level = "trace", skip(self))] fn as_flag(&self) -> bool { matches!(self, Value::Flag) } + #[tracing::instrument(level = "trace", skip(self))] fn as_multiple(&self) -> Option<&[String]> { match self { Value::Multiple(v) => Some(v), @@ -250,6 +269,7 @@ impl Value { } impl fmt::Display for Value { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Value::Flag => write!(f, "true"), @@ -269,11 +289,13 @@ pub struct Arguments<'a> { } impl<'a> Arguments<'a> { + #[tracing::instrument(level = "trace", skip(self, argument))] /// Add an argument with its associated `Argument` in `args`. fn insert_arg(&mut self, argument: Argument<'a>) { self.args.insert(argument.name, argument); } + #[tracing::instrument(level = "trace", skip(self, arg_name))] /// Get the value for the argument specified by `arg_name`. fn value_of(&self, arg_name: &'static str) -> Option<&Value> { self.args.get(arg_name).and_then(|argument| { @@ -284,6 +306,7 @@ impl<'a> Arguments<'a> { }) } + #[tracing::instrument(level = "trace", skip(self, arg_name))] /// Return the value of an argument if the argument exists and has the type /// String. Otherwise return None. pub fn single_value(&self, arg_name: &'static str) -> Option<&String> { @@ -291,6 +314,7 @@ impl<'a> Arguments<'a> { .and_then(|arg_value| arg_value.as_single_value()) } + #[tracing::instrument(level = "trace", skip(self, arg_name))] /// Return whether an `arg_name` argument of type flag exists. pub fn flag_present(&self, arg_name: &'static str) -> bool { match self.value_of(arg_name) { @@ -299,6 +323,7 @@ impl<'a> Arguments<'a> { } } + #[tracing::instrument(level = "trace", skip(self, arg_name))] /// Return the value of an argument if the argument exists and has the type /// vector. Otherwise return None. pub fn multiple_values(&self, arg_name: &'static str) -> Option<&[String]> { @@ -306,6 +331,7 @@ impl<'a> Arguments<'a> { .and_then(|arg_value| arg_value.as_multiple()) } + #[tracing::instrument(level = "trace", skip(self))] /// Get the extra arguments (all arguments after `--`). pub fn extra_args(&self) -> Vec { self.extra_args.clone() @@ -313,6 +339,7 @@ impl<'a> Arguments<'a> { // Split `args` in two slices: one with the actual arguments of the process and the other with // the extra arguments, meaning all parameters specified after `--`. + #[tracing::instrument(level = "trace", skip(args))] fn split_args(args: &[String]) -> (&[String], &[String]) { if let Some(index) = args.iter().position(|arg| arg == ARG_SEPARATOR) { return (&args[..index], &args[index + 1..]); @@ -321,6 +348,7 @@ impl<'a> Arguments<'a> { (args, &[]) } + #[tracing::instrument(level = "trace", skip(self))] /// Collect the command line arguments and the values provided for them. pub fn parse_from_cmdline(&mut self) -> Result<()> { let args: Vec = env::args().collect(); @@ -328,6 +356,7 @@ impl<'a> Arguments<'a> { self.parse(&args) } + #[tracing::instrument(level = "trace", skip(self, args))] /// Clear split between the actual arguments of the process, the extra arguments if any /// and the `--help` and `--version` arguments if present. pub fn parse(&mut self, args: &[String]) -> Result<()> { @@ -361,6 +390,7 @@ impl<'a> Arguments<'a> { // Check if `required`, `requires` and `forbids` field rules are indeed followed by every // argument. + #[tracing::instrument(level = "trace", skip(self, args))] fn validate_requirements(&self, args: &[String]) -> Result<()> { for argument in self.args.values() { // The arguments that are marked `required` must be provided by user. @@ -390,6 +420,7 @@ impl<'a> Arguments<'a> { } // Does a general validation of `arg` command line argument. + #[tracing::instrument(level = "trace", skip(self, arg))] fn validate_arg(&self, arg: &str) -> Result<()> { if !arg.starts_with(ARG_PREFIX) { return Err(Error::UnexpectedArgument(arg.to_string())); @@ -409,6 +440,7 @@ impl<'a> Arguments<'a> { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, args))] /// Validate the arguments provided by user and their values. Insert those /// values in the `Argument` instances of the corresponding arguments. fn populate_args(&mut self, args: &[String]) -> Result<()> { @@ -463,6 +495,7 @@ mod tests { use super::*; use crate::arg_parser::Value; + #[tracing::instrument(level = "trace", skip())] fn build_arg_parser() -> ArgParser<'static> { ArgParser::new() .arg( diff --git a/src/utils/src/kernel_version.rs b/src/utils/src/kernel_version.rs index 1dd513f4417..bc5cbf368e7 100644 --- a/src/utils/src/kernel_version.rs +++ b/src/utils/src/kernel_version.rs @@ -22,6 +22,7 @@ pub struct KernelVersion { } impl KernelVersion { + #[tracing::instrument(level = "trace", skip(major, minor, patch))] pub fn new(major: u16, minor: u16, patch: u16) -> Self { Self { major, @@ -30,6 +31,7 @@ impl KernelVersion { } } + #[tracing::instrument(level = "trace", skip())] pub fn get() -> Result { let mut name: utsname = utsname { sysname: [0; 65], @@ -55,6 +57,7 @@ impl KernelVersion { )?) } + #[tracing::instrument(level = "trace", skip(release))] fn parse(release: String) -> Result { let mut tokens = release.split('.'); @@ -76,11 +79,13 @@ impl KernelVersion { } impl std::fmt::Display for KernelVersion { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}.{}.{}", self.major, self.minor, self.patch) } } +#[tracing::instrument(level = "trace", skip())] pub fn min_kernel_version_for_io_uring() -> KernelVersion { KernelVersion::new(5, 10, 51) } diff --git a/src/utils/src/lib.rs b/src/utils/src/lib.rs index ce05ea72d34..1d197b33145 100644 --- a/src/utils/src/lib.rs +++ b/src/utils/src/lib.rs @@ -23,6 +23,7 @@ pub mod vm_memory; use std::result::Result; +#[tracing::instrument(level = "trace", skip())] /// Return the default page size of the platform, in bytes. pub fn get_page_size() -> Result { // SAFETY: Safe because the parameters are valid. diff --git a/src/utils/src/net/ipv4addr.rs b/src/utils/src/net/ipv4addr.rs index 9237d4004c9..be758285860 100644 --- a/src/utils/src/net/ipv4addr.rs +++ b/src/utils/src/net/ipv4addr.rs @@ -3,6 +3,7 @@ use std::net::Ipv4Addr; +#[tracing::instrument(level = "trace", skip(ipv4_addr))] /// Checks if an IPv4 address is RFC 3927 compliant. /// # Examples /// diff --git a/src/utils/src/net/mac.rs b/src/utils/src/net/mac.rs index 448b26df641..e9ac8794a6e 100644 --- a/src/utils/src/net/mac.rs +++ b/src/utils/src/net/mac.rs @@ -30,6 +30,7 @@ pub struct MacAddr { } impl fmt::Display for MacAddr { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let b = &self.bytes; write!( @@ -41,12 +42,14 @@ impl fmt::Display for MacAddr { } impl From<[u8; 6]> for MacAddr { + #[tracing::instrument(level = "trace", skip(bytes))] fn from(bytes: [u8; 6]) -> Self { Self { bytes } } } impl From for [u8; 6] { + #[tracing::instrument(level = "trace", skip(mac))] fn from(mac: MacAddr) -> Self { mac.bytes } @@ -54,6 +57,7 @@ impl From for [u8; 6] { impl FromStr for MacAddr { type Err = String; + #[tracing::instrument(level = "trace", skip(s))] /// Try to turn a `&str` into a `MacAddr` object. The method will return the `str` that failed /// to be parsed. /// # Arguments @@ -87,6 +91,7 @@ impl FromStr for MacAddr { } impl MacAddr { + #[tracing::instrument(level = "trace", skip(src))] /// Create a `MacAddr` from a slice. /// Does not check whether `src.len()` == `MAC_ADDR_LEN`. /// # Arguments @@ -109,6 +114,7 @@ impl MacAddr { MacAddr { bytes } } + #[tracing::instrument(level = "trace", skip(self))] /// Return the underlying content of this `MacAddr` in bytes. /// # Example /// @@ -124,6 +130,7 @@ impl MacAddr { } impl Serialize for MacAddr { + #[tracing::instrument(level = "trace", skip(self, serializer))] fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -133,6 +140,7 @@ impl Serialize for MacAddr { } impl<'de> Deserialize<'de> for MacAddr { + #[tracing::instrument(level = "trace", skip(deserializer))] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/src/utils/src/signal.rs b/src/utils/src/signal.rs index c20981cd531..abecfab8d00 100644 --- a/src/utils/src/signal.rs +++ b/src/utils/src/signal.rs @@ -9,11 +9,13 @@ extern "C" { fn __libc_current_sigrtmax() -> c_int; } +#[tracing::instrument(level = "trace", skip())] pub fn sigrtmin() -> c_int { // SAFETY: Function has no invariants that can be broken. unsafe { __libc_current_sigrtmin() } } +#[tracing::instrument(level = "trace", skip())] pub fn sigrtmax() -> c_int { // SAFETY: Function has no invariants that can be broken. unsafe { __libc_current_sigrtmax() } diff --git a/src/utils/src/sm.rs b/src/utils/src/sm.rs index 6e64e8f1ef4..f37079c23cb 100644 --- a/src/utils/src/sm.rs +++ b/src/utils/src/sm.rs @@ -16,6 +16,7 @@ pub struct StateMachine { function: Option>, } impl Debug for StateMachine { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("StateMachine") .field("function", &self.function.map(|f| f as usize)) @@ -28,6 +29,7 @@ impl Debug for StateMachine { type StateFn = fn(&mut T) -> StateMachine; impl StateMachine { + #[tracing::instrument(level = "trace", skip(function))] /// Creates a new state wrapper. /// /// # Arguments @@ -37,6 +39,7 @@ impl StateMachine { StateMachine { function } } + #[tracing::instrument(level = "trace", skip(function))] /// Creates a new state wrapper that has further possible transitions. /// /// # Arguments @@ -46,6 +49,7 @@ impl StateMachine { StateMachine::new(Some(function)) } + #[tracing::instrument(level = "trace", skip())] /// Creates a new state wrapper that has no further transitions. The state machine /// will finish after running this handler. /// @@ -56,6 +60,7 @@ impl StateMachine { StateMachine::new(None) } + #[tracing::instrument(level = "trace", skip(machine, starting_state_fn))] /// Runs a state machine for `T` starting from the provided state. /// /// # Arguments @@ -87,6 +92,7 @@ mod tests { } impl DummyMachine { + #[tracing::instrument(level = "trace", skip())] fn new() -> Self { DummyMachine { private_data_s1: false, @@ -98,6 +104,7 @@ mod tests { // DummyMachine functions here. // Simple state-machine: start->s1->s2->s3->done. + #[tracing::instrument(level = "trace", skip(self))] fn run(&mut self) { // Verify the machine has not run yet. assert!(!self.private_data_s1); @@ -113,6 +120,7 @@ mod tests { assert!(self.private_data_s3); } + #[tracing::instrument(level = "trace", skip(self))] fn s1(&mut self) -> StateMachine { // Verify private data mutates along with the states. assert!(!self.private_data_s1); @@ -120,6 +128,7 @@ mod tests { StateMachine::next(Self::s2) } + #[tracing::instrument(level = "trace", skip(self))] fn s2(&mut self) -> StateMachine { // Verify private data mutates along with the states. assert!(!self.private_data_s2); @@ -127,6 +136,7 @@ mod tests { StateMachine::next(Self::s3) } + #[tracing::instrument(level = "trace", skip(self))] fn s3(&mut self) -> StateMachine { // Verify private data mutates along with the states. assert!(!self.private_data_s3); diff --git a/src/utils/src/time.rs b/src/utils/src/time.rs index bff4855481e..09a09e8744c 100644 --- a/src/utils/src/time.rs +++ b/src/utils/src/time.rs @@ -22,6 +22,7 @@ pub enum ClockType { } impl From for libc::clockid_t { + #[tracing::instrument(level = "trace", skip(clock_type))] fn from(clock_type: ClockType) -> Self { match clock_type { ClockType::Monotonic => libc::CLOCK_MONOTONIC, @@ -52,6 +53,7 @@ pub struct LocalTime { } impl LocalTime { + #[tracing::instrument(level = "trace", skip())] /// Returns the [LocalTime](struct.LocalTime.html) structure for the calling moment. pub fn now() -> LocalTime { let mut timespec = libc::timespec { @@ -91,6 +93,7 @@ impl LocalTime { } impl fmt::Display for LocalTime { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -116,6 +119,7 @@ pub struct TimestampUs { } impl Default for TimestampUs { + #[tracing::instrument(level = "trace", skip())] fn default() -> TimestampUs { TimestampUs { time_us: get_time_us(ClockType::Monotonic), @@ -124,6 +128,7 @@ impl Default for TimestampUs { } } +#[tracing::instrument(level = "trace", skip())] /// Returns a timestamp in nanoseconds from a monotonic clock. /// /// Uses `_rdstc` on `x86_64` and [`get_time`](fn.get_time.html) on other architectures. @@ -139,6 +144,7 @@ pub fn timestamp_cycles() -> u64 { } } +#[tracing::instrument(level = "trace", skip(clock_type))] /// Returns a timestamp in nanoseconds based on the provided clock type. /// /// # Arguments @@ -156,6 +162,7 @@ pub fn get_time_ns(clock_type: ClockType) -> u64 { + u64::try_from(time_struct.tv_nsec).unwrap() } +#[tracing::instrument(level = "trace", skip(clock_type))] /// Returns a timestamp in microseconds based on the provided clock type. /// /// # Arguments @@ -165,6 +172,7 @@ pub fn get_time_us(clock_type: ClockType) -> u64 { get_time_ns(clock_type) / 1000 } +#[tracing::instrument(level = "trace", skip(clock_type))] /// Returns a timestamp in milliseconds based on the provided clock type. /// /// # Arguments @@ -174,6 +182,7 @@ pub fn get_time_ms(clock_type: ClockType) -> u64 { get_time_ns(clock_type) / NANOS_PER_MILLISECOND } +#[tracing::instrument(level = "trace", skip(value))] /// Converts a timestamp in seconds to an equivalent one in nanoseconds. /// Returns `None` if the conversion overflows. /// diff --git a/src/utils/src/validators.rs b/src/utils/src/validators.rs index 3f956b66e93..0b1b23c8ad0 100644 --- a/src/utils/src/validators.rs +++ b/src/utils/src/validators.rs @@ -14,6 +14,7 @@ pub enum Error { InvalidLen(usize, usize, usize), // (length, min, max) } +#[tracing::instrument(level = "trace", skip(input))] /// Checks that the instance id only contains alphanumeric chars and hyphens /// and that the size is between 1 and 64 characters. pub fn validate_instance_id(input: &str) -> Result<(), Error> { diff --git a/src/utils/src/vm_memory.rs b/src/utils/src/vm_memory.rs index cd748e38f07..b24e31be7ce 100644 --- a/src/utils/src/vm_memory.rs +++ b/src/utils/src/vm_memory.rs @@ -24,6 +24,10 @@ pub type GuestMmapRegion = vm_memory::MmapRegion>; const GUARD_PAGE_COUNT: usize = 1; +#[tracing::instrument( + level = "trace", + skip(maybe_file_offset, size, prot, flags, track_dirty_pages) +)] /// Build a `MmapRegion` surrounded by guard pages. /// /// Initially, we map a `PROT_NONE` guard region of size: @@ -109,6 +113,7 @@ fn build_guarded_region( } } +#[tracing::instrument(level = "trace", skip(regions, track_dirty_pages))] /// Helper for creating the guest memory. pub fn create_guest_memory( regions: &[(Option, GuestAddress, usize)], @@ -133,6 +138,7 @@ pub fn create_guest_memory( GuestMemoryMmap::from_regions(mmap_regions) } +#[tracing::instrument(level = "trace", skip(mem, addr, len))] pub fn mark_dirty_mem(mem: &GuestMemoryMmap, addr: GuestAddress, len: usize) { let _ = mem.try_access(len, addr, |_total, count, caddr, region| { if let Some(bitmap) = region.bitmap() { @@ -246,6 +252,7 @@ pub trait WriteVolatile: Debug { // "an upstream crate could implement AsRawFd for &mut [u8]`. impl ReadVolatile for std::fs::File { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read_volatile( &mut self, buf: &mut VolatileSlice, @@ -255,6 +262,7 @@ impl ReadVolatile for std::fs::File { } impl ReadVolatile for std::os::unix::net::UnixStream { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read_volatile( &mut self, buf: &mut VolatileSlice, @@ -263,6 +271,7 @@ impl ReadVolatile for std::os::unix::net::UnixStream { } } +#[tracing::instrument(level = "trace", skip(raw_fd, buf))] /// Tries to do a single `read` syscall on the provided file descriptor, storing the data raed in /// the given [`VolatileSlice`]. /// @@ -292,6 +301,7 @@ fn read_volatile_raw_fd( } impl WriteVolatile for std::fs::File { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_volatile( &mut self, buf: &VolatileSlice, @@ -301,6 +311,7 @@ impl WriteVolatile for std::fs::File { } impl WriteVolatile for std::os::unix::net::UnixStream { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_volatile( &mut self, buf: &VolatileSlice, @@ -309,6 +320,7 @@ impl WriteVolatile for std::os::unix::net::UnixStream { } } +#[tracing::instrument(level = "trace", skip(raw_fd, buf))] /// Tries to do a single `write` syscall on the provided file descriptor, attempting to write the /// data stored in the given [`VolatileSlice`]. /// @@ -333,6 +345,7 @@ fn write_volatile_raw_fd( } impl WriteVolatile for &mut [u8] { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_volatile( &mut self, buf: &VolatileSlice, @@ -348,6 +361,7 @@ impl WriteVolatile for &mut [u8] { Ok(read) } + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_all_volatile( &mut self, buf: &VolatileSlice, @@ -365,6 +379,7 @@ impl WriteVolatile for &mut [u8] { } impl ReadVolatile for &[u8] { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read_volatile( &mut self, buf: &mut VolatileSlice, @@ -380,6 +395,7 @@ impl ReadVolatile for &[u8] { Ok(written) } + #[tracing::instrument(level = "trace", skip(self, buf))] fn read_exact_volatile( &mut self, buf: &mut VolatileSlice, @@ -399,6 +415,7 @@ impl ReadVolatile for &[u8] { pub mod test_utils { use super::*; + #[tracing::instrument(level = "trace", skip(regions, track_dirty_pages))] /// Test helper used to initialize the guest memory without adding guard pages. /// This is needed because the default `create_guest_memory` /// uses MmapRegionBuilder::build_raw() for setting up the memory with guard pages, which would @@ -431,6 +448,7 @@ pub mod test_utils { GuestMemoryMmap::from_regions(mmap_regions) } + #[tracing::instrument(level = "trace", skip(regions, track_dirty_pages))] /// Test helper used to initialize the guest memory, without the option of file-backed mmap. /// It is just a little syntactic sugar that helps deduplicate test code. pub fn create_anon_guest_memory( @@ -460,6 +478,7 @@ mod tests { } impl AddrOp { + #[tracing::instrument(level = "trace", skip(self, addr))] fn apply_on_addr(&self, addr: *mut u8) { match self { AddrOp::Read => { @@ -474,6 +493,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(function, expect_sigsegv))] fn fork_and_run(function: &dyn Fn(), expect_sigsegv: bool) { let pid = unsafe { libc::fork() }; match pid { @@ -500,6 +520,7 @@ mod tests { }; } + #[tracing::instrument(level = "trace", skip(region))] fn validate_guard_region(region: &GuestMmapRegion) { let page_size = get_page_size().unwrap(); @@ -522,6 +543,7 @@ mod tests { fork_and_run(&|| AddrOp::Write.apply_on_addr(right_border), true); } + #[tracing::instrument(level = "trace", skip(region))] fn loop_guard_region_to_sigsegv(region: &GuestMmapRegion) { let page_size = get_page_size().unwrap(); let right_page_guard = region.as_ptr() as usize + region.size(); diff --git a/src/vmm/Cargo.toml b/src/vmm/Cargo.toml index 11601b4914f..0a47fdb3e22 100644 --- a/src/vmm/Cargo.toml +++ b/src/vmm/Cargo.toml @@ -29,6 +29,9 @@ versionize_derive = "0.1.5" vm-allocator = "0.1.0" vm-fdt = "0.2.0" vm-superio = "0.7.0" +tracing = { version = "0.1.37", features = ["max_level_debug"] } +tracing-subscriber = "0.3.17" +tracing-flame = "0.2.0" log = { version = "0.4.17", features = ["serde"] } dumbo = { path = "../dumbo" } diff --git a/src/vmm/benches/cpu_templates.rs b/src/vmm/benches/cpu_templates.rs index 75060a58675..768e0593a3d 100644 --- a/src/vmm/benches/cpu_templates.rs +++ b/src/vmm/benches/cpu_templates.rs @@ -11,16 +11,19 @@ use criterion::{criterion_group, criterion_main, Criterion}; use vmm::cpu_config::templates::test_utils::{build_test_template, TEST_TEMPLATE_JSON}; use vmm::cpu_config::templates::CustomCpuTemplate; +#[tracing::instrument(level = "trace", skip(cpu_template))] #[inline] pub fn bench_serialize_cpu_template(cpu_template: &CustomCpuTemplate) { let _ = serde_json::to_string(cpu_template); } +#[tracing::instrument(level = "trace", skip(cpu_template_str))] #[inline] pub fn bench_deserialize_cpu_template(cpu_template_str: &str) { let _ = serde_json::from_str::(cpu_template_str); } +#[tracing::instrument(level = "trace", skip(c))] pub fn cpu_template_benchmark(c: &mut Criterion) { println!( "Deserialization test - Template size (JSON string): [{}] bytes.", diff --git a/src/vmm/src/arch/aarch64/cache_info.rs b/src/vmm/src/arch/aarch64/cache_info.rs index 8d61b63a8d3..49724b9d0a4 100644 --- a/src/vmm/src/arch/aarch64/cache_info.rs +++ b/src/vmm/src/arch/aarch64/cache_info.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use std::{fs, io}; -use log::warn; +use logger::warn; // Based on https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/kernel/cacheinfo.c#L29. const MAX_CACHE_LEVEL: u8 = 7; @@ -51,6 +51,7 @@ struct HostCacheStore { #[cfg(not(test))] impl Default for CacheEngine { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { CacheEngine { store: Box::new(HostCacheStore { @@ -61,6 +62,7 @@ impl Default for CacheEngine { } impl CacheStore for HostCacheStore { + #[tracing::instrument(level = "trace", skip(self, index, file_name))] fn get_by_key(&self, index: u8, file_name: &str) -> Result { readln_special(&PathBuf::from(format!( "{}/index{}/{}", @@ -72,6 +74,7 @@ impl CacheStore for HostCacheStore { } impl CacheEntry { + #[tracing::instrument(level = "trace", skip(index, store))] fn from_index(index: u8, store: &dyn CacheStore) -> Result { let mut err_str = String::new(); let mut cache: CacheEntry = CacheEntry::default(); @@ -139,6 +142,7 @@ impl CacheEntry { } impl Default for CacheEntry { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { CacheEntry { level: 0, @@ -160,6 +164,7 @@ pub(crate) enum CacheType { } impl CacheType { + #[tracing::instrument(level = "trace", skip(string))] fn try_from(string: &str) -> Result { match string.trim() { "Instruction" => Ok(Self::Instruction), @@ -173,6 +178,7 @@ impl CacheType { } // The below are auxiliary functions used for constructing the FDT. + #[tracing::instrument(level = "trace", skip(self))] pub fn of_cache_size(&self) -> &str { match self { Self::Instruction => "i-cache-size", @@ -181,6 +187,7 @@ impl CacheType { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn of_cache_line_size(&self) -> &str { match self { Self::Instruction => "i-cache-line-size", @@ -189,6 +196,7 @@ impl CacheType { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn of_cache_type(&self) -> Option<&'static str> { match self { Self::Instruction => None, @@ -197,6 +205,7 @@ impl CacheType { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn of_cache_sets(&self) -> &str { match self { Self::Instruction => "i-cache-sets", @@ -206,11 +215,13 @@ impl CacheType { } } +#[tracing::instrument(level = "trace", skip(file_path))] fn readln_special>(file_path: &T) -> Result { let line = fs::read_to_string(file_path)?; Ok(line.trim_end().to_string()) } +#[tracing::instrument(level = "trace", skip(cache_size_pretty))] fn to_bytes(cache_size_pretty: &mut String) -> Result { match cache_size_pretty.pop() { Some('K') => Ok(cache_size_pretty.parse::().map_err(|err| { @@ -239,6 +250,7 @@ fn to_bytes(cache_size_pretty: &mut String) -> Result { // Expected input is a list of 32-bit comma separated hex values, // without the 0x prefix. // +#[tracing::instrument(level = "trace", skip(mask_str))] fn mask_str2bit_count(mask_str: &str) -> Result { let split_mask_iter = mask_str.split(','); let mut bit_count: u16 = 0; @@ -263,6 +275,7 @@ fn mask_str2bit_count(mask_str: &str) -> Result { Ok(bit_count) } +#[tracing::instrument(level = "trace", skip(cache_l1, cache_non_l1, cache))] fn append_cache_level( cache_l1: &mut Vec, cache_non_l1: &mut Vec, @@ -275,6 +288,7 @@ fn append_cache_level( } } +#[tracing::instrument(level = "trace", skip(cache_l1, cache_non_l1))] pub(crate) fn read_cache_config( cache_l1: &mut Vec, cache_non_l1: &mut Vec, @@ -324,6 +338,7 @@ mod tests { } impl Default for CacheEngine { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { CacheEngine { store: Box::new(MockCacheStore { @@ -334,6 +349,7 @@ mod tests { } impl CacheEngine { + #[tracing::instrument(level = "trace", skip(map))] fn new(map: &HashMap) -> Self { CacheEngine { store: Box::new(MockCacheStore { @@ -344,6 +360,7 @@ mod tests { } impl CacheStore for MockCacheStore { + #[tracing::instrument(level = "trace", skip(self, index, file_name))] fn get_by_key(&self, index: u8, file_name: &str) -> Result { let key = format!("index{}/{}", index, file_name); if let Some(val) = self.dummy_fs.get(&key) { @@ -356,6 +373,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn create_default_store() -> HashMap { let mut cache_struct = HashMap::new(); cache_struct.insert("index0/level".to_string(), "1".to_string()); diff --git a/src/vmm/src/arch/aarch64/fdt.rs b/src/vmm/src/arch/aarch64/fdt.rs index 4ffd7f4f2a6..75f501cb00d 100644 --- a/src/vmm/src/arch/aarch64/fdt.rs +++ b/src/vmm/src/arch/aarch64/fdt.rs @@ -62,6 +62,10 @@ pub enum FdtError { WriteFdtToMemory(GuestMemoryError), } +#[tracing::instrument( + level = "trace", + skip(guest_mem, vcpu_mpidr, cmdline, device_info, gic_device, initrd) +)] /// Creates the flattened device tree for this aarch64 microVM. pub fn create_fdt( guest_mem: &GuestMemoryMmap, @@ -110,6 +114,7 @@ pub fn create_fdt Result<(), FdtError> { // Since the L1 caches are not shareable among CPUs and they are direct attributes of the // cpu in the device tree, we process the L1 and non-L1 caches separately. @@ -214,6 +219,7 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> Result<(), FdtEr Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, guest_mem))] fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Result<(), FdtError> { let mem_size = guest_mem.last_addr().raw_value() - super::layout::DRAM_MEM_START + 1; // See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960 @@ -228,6 +234,7 @@ fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Resul Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, cmdline, initrd))] fn create_chosen_node( fdt: &mut FdtWriter, cmdline: CString, @@ -254,6 +261,7 @@ fn create_chosen_node( Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, gic_device))] fn create_gic_node(fdt: &mut FdtWriter, gic_device: &GICDevice) -> Result<(), FdtError> { let interrupt = fdt.begin_node("intc")?; fdt.property_string("compatible", gic_device.fdt_compatibility())?; @@ -280,6 +288,7 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &GICDevice) -> Result<(), Fd Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt))] fn create_clock_node(fdt: &mut FdtWriter) -> Result<(), FdtError> { // The Advanced Peripheral Bus (APB) is part of the Advanced Microcontroller Bus Architecture // (AMBA) protocol family. It defines a low-cost interface that is optimized for minimal power @@ -295,6 +304,7 @@ fn create_clock_node(fdt: &mut FdtWriter) -> Result<(), FdtError> { Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt))] fn create_timer_node(fdt: &mut FdtWriter) -> Result<(), FdtError> { // See // https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/interrupt-controller/arch_timer.txt @@ -317,6 +327,7 @@ fn create_timer_node(fdt: &mut FdtWriter) -> Result<(), FdtError> { Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt))] fn create_psci_node(fdt: &mut FdtWriter) -> Result<(), FdtError> { let compatible = "arm,psci-0.2"; @@ -331,6 +342,7 @@ fn create_psci_node(fdt: &mut FdtWriter) -> Result<(), FdtError> { Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, dev_info))] fn create_virtio_node( fdt: &mut FdtWriter, dev_info: &T, @@ -349,6 +361,7 @@ fn create_virtio_node( Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, dev_info))] fn create_serial_node( fdt: &mut FdtWriter, dev_info: &T, @@ -368,6 +381,7 @@ fn create_serial_node( Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, dev_info))] fn create_rtc_node( fdt: &mut FdtWriter, dev_info: &T, @@ -388,6 +402,7 @@ fn create_rtc_node( Ok(()) } +#[tracing::instrument(level = "trace", skip(fdt, dev_info))] fn create_devices_node( fdt: &mut FdtWriter, dev_info: &HashMap<(DeviceType, String), T, S>, @@ -434,18 +449,22 @@ mod tests { } impl DeviceInfoForFDT for MMIODeviceInfo { + #[tracing::instrument(level = "trace", skip(self))] fn addr(&self) -> u64 { self.addr } + #[tracing::instrument(level = "trace", skip(self))] fn irq(&self) -> u32 { self.irq } + #[tracing::instrument(level = "trace", skip(self))] fn length(&self) -> u64 { LEN } } // The `load` function from the `device_tree` will mistakenly check the actual size // of the buffer with the allocated size. This works around that. + #[tracing::instrument(level = "trace", skip(buf, pos, val))] fn set_size(buf: &mut [u8], pos: usize, val: usize) { buf[pos] = ((val >> 24) & 0xff) as u8; buf[pos + 1] = ((val >> 16) & 0xff) as u8; diff --git a/src/vmm/src/arch/aarch64/gic/gicv2/mod.rs b/src/vmm/src/arch/aarch64/gic/gicv2/mod.rs index 22aaa4b4b74..ebf894321e7 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv2/mod.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv2/mod.rs @@ -14,6 +14,7 @@ pub struct GICv2(super::GIC); impl std::ops::Deref for GICv2 { type Target = super::GIC; + #[tracing::instrument(level = "trace", skip(self))] fn deref(&self) -> &Self::Target { &self.0 } @@ -50,14 +51,17 @@ impl GICv2 { pub const VERSION: u32 = kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V2; + #[tracing::instrument(level = "trace", skip(self))] pub fn fdt_compatibility(&self) -> &str { "arm,gic-400" } + #[tracing::instrument(level = "trace", skip(self))] pub fn fdt_maint_irq(&self) -> u32 { GICv2::ARCH_GIC_V2_MAINT_IRQ } + #[tracing::instrument(level = "trace", skip(fd, vcpu_count))] /// Create the GIC device object pub fn create_device(fd: DeviceFd, vcpu_count: u64) -> Self { GICv2(super::GIC { @@ -72,14 +76,17 @@ impl GICv2 { }) } + #[tracing::instrument(level = "trace", skip(self, mpidrs))] pub fn save_device(&self, mpidrs: &[u64]) -> Result { regs::save_state(&self.fd, mpidrs) } + #[tracing::instrument(level = "trace", skip(self, mpidrs, state))] pub fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<(), GicError> { regs::restore_state(&self.fd, mpidrs, state) } + #[tracing::instrument(level = "trace", skip(gic_device))] pub fn init_device_attributes(gic_device: &Self) -> Result<(), GicError> { // Setting up the distributor attribute. // We are placing the GIC below 1GB so we need to substract the size of the distributor. @@ -103,6 +110,7 @@ impl GICv2 { Ok(()) } + #[tracing::instrument(level = "trace", skip(vm))] /// Initialize a GIC device pub fn init_device(vm: &VmFd) -> Result { let mut gic_device = kvm_bindings::kvm_create_device { @@ -115,6 +123,7 @@ impl GICv2 { .map_err(GicError::CreateGIC) } + #[tracing::instrument(level = "trace", skip(vm, vcpu_count))] /// Method to initialize the GIC device pub fn create(vm: &VmFd, vcpu_count: u64) -> Result { let vgic_fd = Self::init_device(vm)?; @@ -128,6 +137,7 @@ impl GICv2 { Ok(device) } + #[tracing::instrument(level = "trace", skip(gic_device))] /// Finalize the setup of a GIC device pub fn finalize_device(gic_device: &Self) -> Result<(), GicError> { // On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020). @@ -158,6 +168,7 @@ impl GICv2 { Ok(()) } + #[tracing::instrument(level = "trace", skip(fd, group, attr, addr, flags))] /// Set a GIC device attribute pub fn set_device_attribute( fd: &DeviceFd, diff --git a/src/vmm/src/arch/aarch64/gic/gicv2/regs/dist_regs.rs b/src/vmm/src/arch/aarch64/gic/gicv2/regs/dist_regs.rs index 910871403a3..551b4e8f23f 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv2/regs/dist_regs.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv2/regs/dist_regs.rs @@ -57,6 +57,7 @@ pub struct SharedIrqReg { } impl MmioReg for SharedIrqReg { + #[tracing::instrument(level = "trace", skip(self))] fn range(&self) -> Range { // The ARM® TrustZone® implements a protection logic which contains a // read-as-zero/write-ignore (RAZ/WI) policy. @@ -93,6 +94,7 @@ impl DistReg { } impl MmioReg for DistReg { + #[tracing::instrument(level = "trace", skip(self))] fn range(&self) -> Range { match self { DistReg::Simple(reg) => reg.range(), @@ -107,19 +109,23 @@ impl VgicRegEngine for DistRegEngine { type Reg = DistReg; type RegChunk = u32; + #[tracing::instrument(level = "trace", skip())] fn group() -> u32 { KVM_DEV_ARM_VGIC_GRP_DIST_REGS } + #[tracing::instrument(level = "trace", skip())] fn mpidr_mask() -> u64 { 0 } } +#[tracing::instrument(level = "trace", skip(fd))] pub(crate) fn get_dist_regs(fd: &DeviceFd) -> Result>, GicError> { DistRegEngine::get_regs_data(fd, Box::new(VGIC_DIST_REGS.iter()), 0) } +#[tracing::instrument(level = "trace", skip(fd, state))] pub(crate) fn set_dist_regs(fd: &DeviceFd, state: &[GicRegState]) -> Result<(), GicError> { DistRegEngine::set_regs_data(fd, Box::new(VGIC_DIST_REGS.iter()), state, 0) } diff --git a/src/vmm/src/arch/aarch64/gic/gicv2/regs/icc_regs.rs b/src/vmm/src/arch/aarch64/gic/gicv2/regs/icc_regs.rs index 3092ed53585..38d5f8f8f56 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv2/regs/icc_regs.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv2/regs/icc_regs.rs @@ -37,10 +37,12 @@ impl VgicRegEngine for VgicSysRegEngine { type Reg = SimpleReg; type RegChunk = u64; + #[tracing::instrument(level = "trace", skip())] fn group() -> u32 { KVM_DEV_ARM_VGIC_GRP_CPU_REGS } + #[tracing::instrument(level = "trace", skip(offset, val, cpuid))] fn kvm_device_attr(offset: u64, val: &mut Self::RegChunk, cpuid: u64) -> kvm_device_attr { kvm_device_attr { group: Self::group(), @@ -54,6 +56,7 @@ impl VgicRegEngine for VgicSysRegEngine { } } +#[tracing::instrument(level = "trace", skip(fd, mpidr))] pub(crate) fn get_icc_regs(fd: &DeviceFd, mpidr: u64) -> Result { let main_icc_regs = VgicSysRegEngine::get_regs_data(fd, Box::new(MAIN_VGIC_ICC_REGS.iter()), mpidr)?; @@ -64,6 +67,7 @@ pub(crate) fn get_icc_regs(fd: &DeviceFd, mpidr: u64) -> Result Result { let mut vcpu_states = Vec::with_capacity(mpidrs.len()); @@ -25,6 +26,7 @@ pub fn save_state(fd: &DeviceFd, mpidrs: &[u64]) -> Result { }) } +#[tracing::instrument(level = "trace", skip(fd, mpidrs, state))] /// Restore the state of the GIC device. pub fn restore_state(fd: &DeviceFd, mpidrs: &[u64], state: &GicState) -> Result<(), GicError> { dist_regs::set_dist_regs(fd, &state.dist)?; diff --git a/src/vmm/src/arch/aarch64/gic/gicv3/mod.rs b/src/vmm/src/arch/aarch64/gic/gicv3/mod.rs index d0e5dd33962..2d8bc1125f2 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv3/mod.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv3/mod.rs @@ -13,6 +13,7 @@ pub struct GICv3(super::GIC); impl std::ops::Deref for GICv3 { type Target = super::GIC; + #[tracing::instrument(level = "trace", skip(self))] fn deref(&self) -> &Self::Target { &self.0 } @@ -28,21 +29,25 @@ impl GICv3 { // Device trees specific constants const ARCH_GIC_V3_MAINT_IRQ: u32 = 9; + #[tracing::instrument(level = "trace", skip())] /// Get the address of the GIC distributor. fn get_dist_addr() -> u64 { super::layout::MAPPED_IO_START - GICv3::KVM_VGIC_V3_DIST_SIZE } + #[tracing::instrument(level = "trace", skip())] /// Get the size of the GIC distributor. fn get_dist_size() -> u64 { GICv3::KVM_VGIC_V3_DIST_SIZE } + #[tracing::instrument(level = "trace", skip(vcpu_count))] /// Get the address of the GIC redistributors. fn get_redists_addr(vcpu_count: u64) -> u64 { GICv3::get_dist_addr() - GICv3::get_redists_size(vcpu_count) } + #[tracing::instrument(level = "trace", skip(vcpu_count))] /// Get the size of the GIC redistributors. fn get_redists_size(vcpu_count: u64) -> u64 { vcpu_count * GICv3::KVM_VGIC_V3_REDIST_SIZE @@ -50,14 +55,17 @@ impl GICv3 { pub const VERSION: u32 = kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3; + #[tracing::instrument(level = "trace", skip(self))] pub fn fdt_compatibility(&self) -> &str { "arm,gic-v3" } + #[tracing::instrument(level = "trace", skip(self))] pub fn fdt_maint_irq(&self) -> u32 { GICv3::ARCH_GIC_V3_MAINT_IRQ } + #[tracing::instrument(level = "trace", skip(fd, vcpu_count))] /// Create the GIC device object pub fn create_device(fd: DeviceFd, vcpu_count: u64) -> Self { GICv3(super::GIC { @@ -72,14 +80,17 @@ impl GICv3 { }) } + #[tracing::instrument(level = "trace", skip(self, mpidrs))] pub fn save_device(&self, mpidrs: &[u64]) -> Result { regs::save_state(&self.fd, mpidrs) } + #[tracing::instrument(level = "trace", skip(self, mpidrs, state))] pub fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<(), GicError> { regs::restore_state(&self.fd, mpidrs, state) } + #[tracing::instrument(level = "trace", skip(gic_device))] pub fn init_device_attributes(gic_device: &Self) -> Result<(), GicError> { // Setting up the distributor attribute. // We are placing the GIC below 1GB so we need to substract the size of the distributor. @@ -104,6 +115,7 @@ impl GICv3 { Ok(()) } + #[tracing::instrument(level = "trace", skip(vm))] /// Initialize a GIC device pub fn init_device(vm: &VmFd) -> Result { let mut gic_device = kvm_bindings::kvm_create_device { @@ -116,6 +128,7 @@ impl GICv3 { .map_err(GicError::CreateGIC) } + #[tracing::instrument(level = "trace", skip(vm, vcpu_count))] /// Method to initialize the GIC device pub fn create(vm: &VmFd, vcpu_count: u64) -> Result { let vgic_fd = Self::init_device(vm)?; @@ -129,6 +142,7 @@ impl GICv3 { Ok(device) } + #[tracing::instrument(level = "trace", skip(gic_device))] /// Finalize the setup of a GIC device pub fn finalize_device(gic_device: &Self) -> Result<(), GicError> { // On arm there are 3 types of interrupts: SGI (0-15), PPI (16-31), SPI (32-1020). @@ -159,6 +173,7 @@ impl GICv3 { Ok(()) } + #[tracing::instrument(level = "trace", skip(fd, group, attr, addr, flags))] /// Set a GIC device attribute pub fn set_device_attribute( fd: &DeviceFd, @@ -180,6 +195,7 @@ impl GICv3 { } } +#[tracing::instrument(level = "trace", skip(fd))] /// Function that flushes /// RDIST pending tables into guest RAM. /// diff --git a/src/vmm/src/arch/aarch64/gic/gicv3/regs/dist_regs.rs b/src/vmm/src/arch/aarch64/gic/gicv3/regs/dist_regs.rs index 5a0d4a9ec76..b423eea363c 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv3/regs/dist_regs.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv3/regs/dist_regs.rs @@ -60,6 +60,7 @@ pub struct SharedIrqReg { } impl MmioReg for SharedIrqReg { + #[tracing::instrument(level = "trace", skip(self))] fn range(&self) -> Range { // The ARM® TrustZone® implements a protection logic which contains a // read-as-zero/write-ignore (RAZ/WI) policy. @@ -96,6 +97,7 @@ impl DistReg { } impl MmioReg for DistReg { + #[tracing::instrument(level = "trace", skip(self))] fn range(&self) -> Range { match self { DistReg::Simple(reg) => reg.range(), @@ -110,19 +112,23 @@ impl VgicRegEngine for DistRegEngine { type Reg = DistReg; type RegChunk = u32; + #[tracing::instrument(level = "trace", skip())] fn group() -> u32 { KVM_DEV_ARM_VGIC_GRP_DIST_REGS } + #[tracing::instrument(level = "trace", skip())] fn mpidr_mask() -> u64 { 0 } } +#[tracing::instrument(level = "trace", skip(fd))] pub(crate) fn get_dist_regs(fd: &DeviceFd) -> Result>, GicError> { DistRegEngine::get_regs_data(fd, Box::new(VGIC_DIST_REGS.iter()), 0) } +#[tracing::instrument(level = "trace", skip(fd, state))] pub(crate) fn set_dist_regs(fd: &DeviceFd, state: &[GicRegState]) -> Result<(), GicError> { DistRegEngine::set_regs_data(fd, Box::new(VGIC_DIST_REGS.iter()), state, 0) } diff --git a/src/vmm/src/arch/aarch64/gic/gicv3/regs/icc_regs.rs b/src/vmm/src/arch/aarch64/gic/gicv3/regs/icc_regs.rs index 4dae3f669ea..7585cabf7ac 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv3/regs/icc_regs.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv3/regs/icc_regs.rs @@ -79,22 +79,26 @@ impl VgicRegEngine for VgicSysRegEngine { type Reg = SimpleReg; type RegChunk = u64; + #[tracing::instrument(level = "trace", skip())] fn group() -> u32 { KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS } + #[tracing::instrument(level = "trace", skip())] #[allow(clippy::cast_sign_loss)] // bit mask fn mpidr_mask() -> u64 { KVM_DEV_ARM_VGIC_V3_MPIDR_MASK as u64 } } +#[tracing::instrument(level = "trace", skip(fd, mpidr))] fn num_priority_bits(fd: &DeviceFd, mpidr: u64) -> Result { let reg_val = &VgicSysRegEngine::get_reg_data(fd, &SYS_ICC_CTLR_EL1, mpidr)?.chunks[0]; Ok(((reg_val & ICC_CTLR_EL1_PRIBITS_MASK) >> ICC_CTLR_EL1_PRIBITS_SHIFT) + 1) } +#[tracing::instrument(level = "trace", skip(reg, num_priority_bits))] fn is_ap_reg_available(reg: &SimpleReg, num_priority_bits: u64) -> bool { // As per ARMv8 documentation: // https://static.docs.arm.com/ihi0069/c/IHI0069C_gic_architecture_specification.pdf @@ -118,6 +122,7 @@ fn is_ap_reg_available(reg: &SimpleReg, num_priority_bits: u64) -> bool { true } +#[tracing::instrument(level = "trace", skip(fd, mpidr))] pub(crate) fn get_icc_regs(fd: &DeviceFd, mpidr: u64) -> Result { let main_icc_regs = VgicSysRegEngine::get_regs_data(fd, Box::new(MAIN_VGIC_ICC_REGS.iter()), mpidr)?; @@ -138,6 +143,7 @@ pub(crate) fn get_icc_regs(fd: &DeviceFd, mpidr: u64) -> Result Result { // Flush redistributors pending tables to guest RAM. @@ -29,6 +30,7 @@ pub fn save_state(fd: &DeviceFd, mpidrs: &[u64]) -> Result { }) } +#[tracing::instrument(level = "trace", skip(fd, mpidrs, state))] /// Restore the state of the GIC device. pub fn restore_state(fd: &DeviceFd, mpidrs: &[u64], state: &GicState) -> Result<(), GicError> { dist_regs::set_dist_regs(fd, &state.dist)?; diff --git a/src/vmm/src/arch/aarch64/gic/gicv3/regs/redist_regs.rs b/src/vmm/src/arch/aarch64/gic/gicv3/regs/redist_regs.rs index c857307410b..0e8663154fa 100644 --- a/src/vmm/src/arch/aarch64/gic/gicv3/regs/redist_regs.rs +++ b/src/vmm/src/arch/aarch64/gic/gicv3/regs/redist_regs.rs @@ -56,20 +56,24 @@ impl VgicRegEngine for RedistRegEngine { type Reg = SimpleReg; type RegChunk = u32; + #[tracing::instrument(level = "trace", skip())] fn group() -> u32 { KVM_DEV_ARM_VGIC_GRP_REDIST_REGS } + #[tracing::instrument(level = "trace", skip())] #[allow(clippy::cast_sign_loss)] // bit mask fn mpidr_mask() -> u64 { KVM_DEV_ARM_VGIC_V3_MPIDR_MASK as u64 } } +#[tracing::instrument(level = "trace", skip())] fn redist_regs() -> Box> { Box::new(VGIC_RDIST_REGS.iter().chain(VGIC_SGI_REGS)) } +#[tracing::instrument(level = "trace", skip(fd, mpidr))] pub(crate) fn get_redist_regs( fd: &DeviceFd, mpidr: u64, @@ -77,6 +81,7 @@ pub(crate) fn get_redist_regs( RedistRegEngine::get_regs_data(fd, redist_regs(), mpidr) } +#[tracing::instrument(level = "trace", skip(fd, mpidr, data))] pub(crate) fn set_redist_regs( fd: &DeviceFd, mpidr: u64, diff --git a/src/vmm/src/arch/aarch64/gic/mod.rs b/src/vmm/src/arch/aarch64/gic/mod.rs index 524b3e67979..3dc5db33cf0 100644 --- a/src/vmm/src/arch/aarch64/gic/mod.rs +++ b/src/vmm/src/arch/aarch64/gic/mod.rs @@ -25,16 +25,19 @@ pub struct GIC { vcpu_count: u64, } impl GIC { + #[tracing::instrument(level = "trace", skip(self))] /// Returns the file descriptor of the GIC device pub fn device_fd(&self) -> &DeviceFd { &self.fd } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an array with GIC device properties pub fn device_properties(&self) -> &[u64] { &self.properties } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the number of vCPUs this GIC handles pub fn vcpu_count(&self) -> u64 { self.vcpu_count @@ -78,6 +81,7 @@ pub enum GICDevice { V3(GICv3), } impl GICDevice { + #[tracing::instrument(level = "trace", skip(self))] /// Returns the file descriptor of the GIC device pub fn device_fd(&self) -> &DeviceFd { match self { @@ -86,6 +90,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an array with GIC device properties pub fn device_properties(&self) -> &[u64] { match self { @@ -94,6 +99,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the number of vCPUs this GIC handles pub fn vcpu_count(&self) -> u64 { match self { @@ -102,6 +108,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the fdt compatibility property of the device pub fn fdt_compatibility(&self) -> &str { match self { @@ -110,6 +117,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the maint_irq fdt property of the device pub fn fdt_maint_irq(&self) -> u32 { match self { @@ -118,6 +126,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the GIC version of the device pub fn version(&self) -> u32 { match self { @@ -126,6 +135,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(gic_device))] /// Setup the device-specific attributes pub fn init_device_attributes(gic_device: &Self) -> Result<(), GicError> { match gic_device { @@ -134,6 +144,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self, mpidrs))] /// Method to save the state of the GIC device. pub fn save_device(&self, mpidrs: &[u64]) -> Result { match self { @@ -142,6 +153,7 @@ impl GICDevice { } } + #[tracing::instrument(level = "trace", skip(self, mpidrs, state))] /// Method to restore the state of the GIC device. pub fn restore_device(&self, mpidrs: &[u64], state: &GicState) -> Result<(), GicError> { match self { @@ -151,6 +163,7 @@ impl GICDevice { } } +#[tracing::instrument(level = "trace", skip(vm, vcpu_count, version))] /// Create a GIC device. /// /// If "version" parameter is "None" the function will try to create by default a GICv3 device. diff --git a/src/vmm/src/arch/aarch64/gic/regs.rs b/src/vmm/src/arch/aarch64/gic/regs.rs index c2e0a303d75..3e6b9b620f6 100644 --- a/src/vmm/src/arch/aarch64/gic/regs.rs +++ b/src/vmm/src/arch/aarch64/gic/regs.rs @@ -41,6 +41,7 @@ pub struct GicVcpuState { } impl Versionize for GicRegState { + #[tracing::instrument(level = "trace", skip(self, writer, version_map, app_version))] fn serialize( &self, writer: &mut W, @@ -52,6 +53,7 @@ impl Versionize for GicRegState { Versionize::serialize(chunks, writer, version_map, app_version) } + #[tracing::instrument(level = "trace", skip(reader, version_map, app_version))] fn deserialize( reader: &mut R, version_map: &VersionMap, @@ -62,6 +64,7 @@ impl Versionize for GicRegState { Ok(Self { chunks }) } + #[tracing::instrument(level = "trace", skip())] fn version() -> u16 { 1 } @@ -184,6 +187,7 @@ impl SimpleReg { } impl MmioReg for SimpleReg { + #[tracing::instrument(level = "trace", skip(self))] fn range(&self) -> Range { self.offset..self.offset + u64::from(self.size) } diff --git a/src/vmm/src/arch/aarch64/mod.rs b/src/vmm/src/arch/aarch64/mod.rs index db28f984083..aa937f34f8d 100644 --- a/src/vmm/src/arch/aarch64/mod.rs +++ b/src/vmm/src/arch/aarch64/mod.rs @@ -37,6 +37,7 @@ pub const MMIO_MEM_START: u64 = layout::MAPPED_IO_START; /// The size of the memory area reserved for MMIO devices. pub const MMIO_MEM_SIZE: u64 = layout::DRAM_MEM_START - layout::MAPPED_IO_START; //>> 1GB +#[tracing::instrument(level = "trace", skip(size))] /// Returns a Vec of the valid memory addresses for aarch64. /// See [`layout`](layout) module for a drawing of the specific memory model for this platform. pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> { @@ -44,6 +45,17 @@ pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> { vec![(GuestAddress(layout::DRAM_MEM_START), dram_size)] } +#[tracing::instrument( + level = "trace", + skip( + guest_mem, + cmdline_cstring, + vcpu_mpidr, + device_info, + gic_device, + initrd + ) +)] /// Configures the system and should be called once per vm before starting vcpu threads. /// For aarch64, we only setup the FDT. /// @@ -74,11 +86,13 @@ pub fn configure_system u64 { layout::DRAM_MEM_START } +#[tracing::instrument(level = "trace", skip(guest_mem, initrd_size))] /// Returns the memory address where the initrd could be loaded. pub fn initrd_load_addr( guest_mem: &GuestMemoryMmap, @@ -98,6 +112,7 @@ pub fn initrd_load_addr( } // Auxiliary function to get the address where the device tree blob is loaded. +#[tracing::instrument(level = "trace", skip(mem))] fn get_fdt_addr(mem: &GuestMemoryMmap) -> u64 { // If the memory allocated is smaller than the size allocated for the FDT, // we return the start of the DRAM so that diff --git a/src/vmm/src/arch/aarch64/regs.rs b/src/vmm/src/arch/aarch64/regs.rs index d832e92d4f3..fa19fa9fb33 100644 --- a/src/vmm/src/arch/aarch64/regs.rs +++ b/src/vmm/src/arch/aarch64/regs.rs @@ -155,6 +155,7 @@ impl RegSize { } impl From for RegSize { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: u64) -> Self { match value { RegSize::U8_SIZE => RegSize::U8, @@ -172,6 +173,7 @@ impl From for RegSize { } impl From for u64 { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: RegSize) -> Self { match value { RegSize::U8 => RegSize::U8_SIZE, @@ -187,6 +189,7 @@ impl From for u64 { } } +#[tracing::instrument(level = "trace", skip(reg_id))] /// Returns register size in bytes pub fn reg_size(reg_id: u64) -> u64 { 2_u64.pow(((reg_id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT) as u32) @@ -202,22 +205,26 @@ struct Aarch64RegisterVecInner { } impl Aarch64RegisterVecInner { + #[tracing::instrument(level = "trace", skip(self))] /// Returns the number of elements in the vector. fn len(&self) -> usize { self.ids.len() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns true if the vector contains no elements. fn is_empty(&self) -> bool { self.ids.is_empty() } + #[tracing::instrument(level = "trace", skip(self, reg))] /// Appends a register to the vector, copying register data. fn push(&mut self, reg: Aarch64RegisterRef<'_>) { self.ids.push(reg.id); self.data.extend_from_slice(reg.data); } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an iterator over stored registers. fn iter(&self) -> impl Iterator { Aarch64RegisterVecIterator { @@ -228,6 +235,7 @@ impl Aarch64RegisterVecInner { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an iterator over stored registers that allows register modifications. fn iter_mut(&mut self) -> impl Iterator { Aarch64RegisterVecIteratorMut { @@ -248,26 +256,31 @@ pub struct Aarch64RegisterVec { } impl Aarch64RegisterVec { + #[tracing::instrument(level = "trace", skip(self))] /// Returns the number of elements in the vector. pub fn len(&self) -> usize { self.inner.len() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns true if the vector contains no elements. pub fn is_empty(&self) -> bool { self.inner.is_empty() } + #[tracing::instrument(level = "trace", skip(self, reg))] /// Appends a register to the vector, copying register data. pub fn push(&mut self, reg: Aarch64RegisterRef<'_>) { self.inner.push(reg); } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an iterator over stored registers. pub fn iter(&self) -> impl Iterator { self.inner.iter() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an iterator over stored registers that allows register modifications. pub fn iter_mut(&mut self) -> impl Iterator { self.inner.iter_mut() @@ -275,6 +288,7 @@ impl Aarch64RegisterVec { } impl Versionize for Aarch64RegisterVec { + #[tracing::instrument(level = "trace", skip(self, writer, version_map, target_version))] fn serialize( &self, writer: &mut W, @@ -284,6 +298,7 @@ impl Versionize for Aarch64RegisterVec { self.inner.serialize(writer, version_map, target_version) } + #[tracing::instrument(level = "trace", skip(reader, version_map, source_version))] fn deserialize( reader: &mut R, version_map: &VersionMap, @@ -316,6 +331,7 @@ impl Versionize for Aarch64RegisterVec { } } + #[tracing::instrument(level = "trace", skip())] fn version() -> u16 { Aarch64RegisterVecInner::version() } @@ -333,6 +349,7 @@ pub struct Aarch64RegisterVecIterator<'a> { impl<'a> Iterator for Aarch64RegisterVecIterator<'a> { type Item = Aarch64RegisterRef<'a>; + #[tracing::instrument(level = "trace", skip(self))] fn next(&mut self) -> Option { if self.index < self.ids.len() { let id = self.ids[self.index]; @@ -362,6 +379,7 @@ pub struct Aarch64RegisterVecIteratorMut<'a> { impl<'a> Iterator for Aarch64RegisterVecIteratorMut<'a> { type Item = Aarch64RegisterRefMut<'a>; + #[tracing::instrument(level = "trace", skip(self))] fn next(&mut self) -> Option { if self.index < self.ids.len() { let id = self.ids[self.index]; @@ -389,6 +407,7 @@ pub struct Aarch64RegisterRef<'a> { } impl<'a> Aarch64RegisterRef<'a> { + #[tracing::instrument(level = "trace", skip(id, data))] /// Creates new register reference with provided id and data. /// Register size in `id` should be equal to the /// length of the slice. Otherwise this method @@ -403,11 +422,13 @@ impl<'a> Aarch64RegisterRef<'a> { Self { id, data } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns register size in bytes pub fn size(&self) -> RegSize { reg_size(self.id).into() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a register value. /// Type `T` must be of the same length as an /// underlying data slice. Otherwise this method @@ -416,6 +437,7 @@ impl<'a> Aarch64RegisterRef<'a> { T::from_slice(self.data) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns register data as a byte slice pub fn as_slice(&self) -> &[u8] { self.data @@ -431,6 +453,7 @@ pub struct Aarch64RegisterRefMut<'a> { } impl<'a> Aarch64RegisterRefMut<'a> { + #[tracing::instrument(level = "trace", skip(id, data))] /// Creates new register reference with provided id and data. /// Register size in `id` should be equal to the /// length of the slice. Otherwise this method @@ -445,11 +468,13 @@ impl<'a> Aarch64RegisterRefMut<'a> { Self { id, data } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns register size in bytes pub fn size(&self) -> RegSize { reg_size(self.id).into() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a register value. /// Type `T` must be of the same length as an /// underlying data slice. Otherwise this method @@ -458,6 +483,7 @@ impl<'a> Aarch64RegisterRefMut<'a> { T::from_slice(self.data) } + #[tracing::instrument(level = "trace", skip(self, value))] /// Sets the register value. /// Type `T` must be of the same length as an /// underlying data slice. Otherwise this method @@ -482,6 +508,7 @@ pub struct Aarch64RegisterOld { impl<'a> TryFrom> for Aarch64RegisterOld { type Error = &'static str; + #[tracing::instrument(level = "trace", skip(value))] fn try_from(value: Aarch64RegisterRef) -> Result { let reg = match value.size() { RegSize::U32 => Self { @@ -505,6 +532,7 @@ impl<'a> TryFrom> for Aarch64RegisterOld { impl<'a> TryFrom<&Aarch64RegisterOld> for Aarch64RegisterRef<'a> { type Error = &'static str; + #[tracing::instrument(level = "trace", skip(value))] fn try_from(value: &Aarch64RegisterOld) -> Result { // # Safety: // `self.data` is a valid memory and slice size is valid for this type. diff --git a/src/vmm/src/arch/aarch64/vcpu.rs b/src/vmm/src/arch/aarch64/vcpu.rs index d9ab10b886f..1dfebb75e91 100644 --- a/src/vmm/src/arch/aarch64/vcpu.rs +++ b/src/vmm/src/arch/aarch64/vcpu.rs @@ -40,6 +40,7 @@ pub enum VcpuError { GetMidrEl1(String), } +#[tracing::instrument(level = "trace", skip(regs))] /// Extract the Manufacturer ID from a VCPU state's registers. /// The ID is found between bits 24-31 of MIDR_EL1 register. /// @@ -56,6 +57,7 @@ pub fn get_manufacturer_id_from_state(regs: &Aarch64RegisterVec) -> Result Result { @@ -72,6 +74,7 @@ pub fn get_manufacturer_id_from_host() -> Result { Ok(manufacturer_id >> 24) } +#[tracing::instrument(level = "trace", skip(vcpufd, cpu_id, boot_ip, mem))] /// Configure relevant boot registers for a given vCPU. /// /// # Arguments @@ -116,6 +119,7 @@ pub fn setup_boot_regs( Ok(()) } +#[tracing::instrument(level = "trace", skip(vcpufd))] /// Read the MPIDR - Multiprocessor Affinity Register. pub fn get_mpidr(vcpufd: &VcpuFd) -> Result { // MPIDR register is 64 bit wide on aarch64 @@ -126,6 +130,7 @@ pub fn get_mpidr(vcpufd: &VcpuFd) -> Result { } } +#[tracing::instrument(level = "trace", skip(vcpufd, state))] /// Saves the states of the system registers into `state`. /// /// # Arguments @@ -135,6 +140,7 @@ pub fn get_all_registers(vcpufd: &VcpuFd, state: &mut Aarch64RegisterVec) -> Res get_registers(vcpufd, &get_all_registers_ids(vcpufd)?, state) } +#[tracing::instrument(level = "trace", skip(vcpufd, ids, regs))] /// Saves states of registers into `state`. /// /// # Arguments @@ -157,6 +163,7 @@ pub fn get_registers( Ok(()) } +#[tracing::instrument(level = "trace", skip(vcpufd))] /// Returns all registers ids, including core and system pub fn get_all_registers_ids(vcpufd: &VcpuFd) -> Result, VcpuError> { // Call KVM_GET_REG_LIST to get all registers available to the guest. For ArmV8 there are @@ -168,6 +175,7 @@ pub fn get_all_registers_ids(vcpufd: &VcpuFd) -> Result, VcpuError> { Ok(reg_list.as_slice().to_vec()) } +#[tracing::instrument(level = "trace", skip(vcpufd, regs))] /// Set the state of the system registers. /// /// # Arguments @@ -182,6 +190,7 @@ pub fn set_registers(vcpufd: &VcpuFd, regs: &Aarch64RegisterVec) -> Result<(), V Ok(()) } +#[tracing::instrument(level = "trace", skip(vcpufd))] /// Get the multistate processor. /// /// # Arguments @@ -191,6 +200,7 @@ pub fn get_mpstate(vcpufd: &VcpuFd) -> Result { vcpufd.get_mp_state().map_err(VcpuError::GetMp) } +#[tracing::instrument(level = "trace", skip(vcpufd, state))] /// Set the state of the system registers. /// /// # Arguments diff --git a/src/vmm/src/arch/mod.rs b/src/vmm/src/arch/mod.rs index 83b373af445..78eb7cc38ba 100644 --- a/src/vmm/src/arch/mod.rs +++ b/src/vmm/src/arch/mod.rs @@ -56,6 +56,7 @@ pub struct InitrdConfig { pub const PAGE_SIZE: usize = 4096; impl fmt::Display for DeviceType { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } diff --git a/src/vmm/src/arch/x86_64/cpu_model.rs b/src/vmm/src/arch/x86_64/cpu_model.rs index befaa3953bf..63fbfcef3fc 100644 --- a/src/vmm/src/arch/x86_64/cpu_model.rs +++ b/src/vmm/src/arch/x86_64/cpu_model.rs @@ -20,6 +20,7 @@ pub struct CpuModel { } impl CpuModel { + #[tracing::instrument(level = "trace", skip())] /// Get CPU model from current machine. pub fn get_cpu_model() -> Self { // SAFETY: This operation is safe as long as the processor implements this CPUID function. @@ -28,6 +29,7 @@ impl CpuModel { CpuModel::from(&eax) } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the current CPU model is Intel Cascade Lake or later. pub fn is_at_least_cascade_lake(&self) -> bool { let cascade_lake = CpuModel { @@ -43,6 +45,7 @@ impl CpuModel { } impl From<&u32> for CpuModel { + #[tracing::instrument(level = "trace", skip(eax))] fn from(eax: &u32) -> Self { CpuModel { extended_family: ((eax >> 20) & 0xff) as u8, @@ -55,6 +58,7 @@ impl From<&u32> for CpuModel { } impl From<&CpuModel> for u32 { + #[tracing::instrument(level = "trace", skip(cpu_model))] fn from(cpu_model: &CpuModel) -> Self { u32::from(cpu_model.extended_family) << 20 | u32::from(cpu_model.extended_model) << 16 @@ -65,12 +69,14 @@ impl From<&CpuModel> for u32 { } impl PartialOrd for CpuModel { + #[tracing::instrument(level = "trace", skip(self, other))] fn partial_cmp(&self, other: &Self) -> Option { Some(u32::from(self).cmp(&u32::from(other))) } } impl Ord for CpuModel { + #[tracing::instrument(level = "trace", skip(self, other))] fn cmp(&self, other: &Self) -> Ordering { u32::from(self).cmp(&u32::from(other)) } diff --git a/src/vmm/src/arch/x86_64/gdt.rs b/src/vmm/src/arch/x86_64/gdt.rs index c7fcbf31bf0..0c4ed649bc8 100644 --- a/src/vmm/src/arch/x86_64/gdt.rs +++ b/src/vmm/src/arch/x86_64/gdt.rs @@ -9,6 +9,7 @@ use kvm_bindings::kvm_segment; +#[tracing::instrument(level = "trace", skip(flags, base, limit))] /// Constructor for a conventional segment GDT (or LDT) entry. Derived from the kernel's segment.h. pub fn gdt_entry(flags: u16, base: u32, limit: u32) -> u64 { ((u64::from(base) & 0xff00_0000u64) << (56 - 24)) @@ -18,48 +19,59 @@ pub fn gdt_entry(flags: u16, base: u32, limit: u32) -> u64 { | (u64::from(limit) & 0x0000_ffffu64) } +#[tracing::instrument(level = "trace", skip(entry))] fn get_base(entry: u64) -> u64 { (((entry) & 0xFF00_0000_0000_0000) >> 32) | (((entry) & 0x0000_00FF_0000_0000) >> 16) | (((entry) & 0x0000_0000_FFFF_0000) >> 16) } +#[tracing::instrument(level = "trace", skip(entry))] fn get_limit(entry: u64) -> u32 { ((((entry) & 0x000F_0000_0000_0000) >> 32) | ((entry) & 0x0000_0000_0000_FFFF)) as u32 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_g(entry: u64) -> u8 { ((entry & 0x0080_0000_0000_0000) >> 55) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_db(entry: u64) -> u8 { ((entry & 0x0040_0000_0000_0000) >> 54) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_l(entry: u64) -> u8 { ((entry & 0x0020_0000_0000_0000) >> 53) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_avl(entry: u64) -> u8 { ((entry & 0x0010_0000_0000_0000) >> 52) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_p(entry: u64) -> u8 { ((entry & 0x0000_8000_0000_0000) >> 47) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_dpl(entry: u64) -> u8 { ((entry & 0x0000_6000_0000_0000) >> 45) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_s(entry: u64) -> u8 { ((entry & 0x0000_1000_0000_0000) >> 44) as u8 } +#[tracing::instrument(level = "trace", skip(entry))] fn get_type(entry: u64) -> u8 { ((entry & 0x0000_0F00_0000_0000) >> 40) as u8 } +#[tracing::instrument(level = "trace", skip(entry, table_index))] /// Automatically build the kvm struct for SET_SREGS from the kernel bit fields. /// /// # Arguments diff --git a/src/vmm/src/arch/x86_64/interrupts.rs b/src/vmm/src/arch/x86_64/interrupts.rs index ea42ce8cb44..9e66aee76ac 100644 --- a/src/vmm/src/arch/x86_64/interrupts.rs +++ b/src/vmm/src/arch/x86_64/interrupts.rs @@ -26,22 +26,26 @@ const APIC_LVT1: usize = 0x360; const APIC_MODE_NMI: u32 = 0x4; const APIC_MODE_EXTINT: u32 = 0x7; +#[tracing::instrument(level = "trace", skip(klapic, reg_offset))] fn get_klapic_reg(klapic: &kvm_lapic_state, reg_offset: usize) -> u32 { let range = reg_offset..reg_offset + 4; let reg = klapic.regs.get(range).expect("get_klapic_reg range"); byte_order::read_le_u32_from_i8(reg) } +#[tracing::instrument(level = "trace", skip(klapic, reg_offset, value))] fn set_klapic_reg(klapic: &mut kvm_lapic_state, reg_offset: usize, value: u32) { let range = reg_offset..reg_offset + 4; let reg = klapic.regs.get_mut(range).expect("set_klapic_reg range"); byte_order::write_le_u32_to_i8(reg, value) } +#[tracing::instrument(level = "trace", skip(reg, mode))] fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 { ((reg) & !0x700) | ((mode) << 8) } +#[tracing::instrument(level = "trace", skip(vcpu))] /// Configures LAPICs. LAPIC0 is set for external interrupts, LAPIC1 is set for NMI. /// /// # Arguments diff --git a/src/vmm/src/arch/x86_64/mod.rs b/src/vmm/src/arch/x86_64/mod.rs index 6d6db07a051..96691205531 100644 --- a/src/vmm/src/arch/x86_64/mod.rs +++ b/src/vmm/src/arch/x86_64/mod.rs @@ -51,6 +51,7 @@ pub const MMIO_MEM_START: u64 = FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE; /// The size of the memory area reserved for MMIO devices. pub const MMIO_MEM_SIZE: u64 = MEM_32BIT_GAP_SIZE; +#[tracing::instrument(level = "trace", skip(size))] /// Returns a Vec of the valid memory addresses. /// These should be used to configure the GuestMemoryMmap structure for the platform. /// For x86_64 all addresses are valid from the start of the kernel except a @@ -69,11 +70,13 @@ pub fn arch_memory_regions(size: usize) -> Vec<(GuestAddress, usize)> { } } +#[tracing::instrument(level = "trace", skip())] /// Returns the memory address where the kernel could be loaded. pub fn get_kernel_start() -> u64 { layout::HIMEM_START } +#[tracing::instrument(level = "trace", skip(guest_mem, initrd_size))] /// Returns the memory address where the initrd could be loaded. pub fn initrd_load_addr( guest_mem: &GuestMemoryMmap, @@ -93,6 +96,10 @@ pub fn initrd_load_addr( Ok(align_to_pagesize(lowmem_size - initrd_size) as u64) } +#[tracing::instrument( + level = "trace", + skip(guest_mem, cmdline_addr, cmdline_size, initrd, num_cpus) +)] /// Configures the system and should be called once per vm before starting vcpu threads. /// /// # Arguments @@ -175,6 +182,7 @@ pub fn configure_system( .map_err(|_| ConfigurationError::ZeroPageSetup) } +#[tracing::instrument(level = "trace", skip(params, addr, size, mem_type))] /// Add an e820 region to the e820 map. /// Returns Ok(()) if successful, or an error if there is no space left in the map. fn add_e820_entry( diff --git a/src/vmm/src/arch/x86_64/mptable.rs b/src/vmm/src/arch/x86_64/mptable.rs index a5161bb8a20..01c08d1681b 100644 --- a/src/vmm/src/arch/x86_64/mptable.rs +++ b/src/vmm/src/arch/x86_64/mptable.rs @@ -106,6 +106,7 @@ const CPU_STEPPING: u32 = 0x600; const CPU_FEATURE_APIC: u32 = 0x200; const CPU_FEATURE_FPU: u32 = 0x001; +#[tracing::instrument(level = "trace", skip(v))] fn compute_checksum(v: &T) -> u8 { // SAFETY: Safe because we are only reading the bytes within the size of the `T` reference `v`. let v_slice = unsafe { @@ -119,11 +120,13 @@ fn compute_checksum(v: &T) -> u8 { checksum } +#[tracing::instrument(level = "trace", skip(v))] fn mpf_intel_compute_checksum(v: &mpspec::mpf_intel) -> u8 { let checksum = compute_checksum(v).wrapping_sub(v.checksum); (!checksum).wrapping_add(1) } +#[tracing::instrument(level = "trace", skip(num_cpus))] fn compute_mp_size(num_cpus: u8) -> usize { mem::size_of::() + mem::size_of::() @@ -134,6 +137,7 @@ fn compute_mp_size(num_cpus: u8) -> usize { + mem::size_of::() * 2 } +#[tracing::instrument(level = "trace", skip(mem, num_cpus))] /// Performs setup of the MP table for the given `num_cpus`. pub fn setup_mptable(mem: &GuestMemoryMmap, num_cpus: u8) -> Result<(), MptableError> { if u32::from(num_cpus) > MAX_SUPPORTED_CPUS { @@ -301,6 +305,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip(type_))] fn table_entry_size(type_: u8) -> usize { match u32::from(type_) { mpspec::MP_PROCESSOR => mem::size_of::(), @@ -373,12 +378,14 @@ mod tests { #[derive(Debug)] struct Sum(u8); impl io::Write for Sum { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write(&mut self, buf: &[u8]) -> io::Result { for v in buf.iter() { self.0 = self.0.wrapping_add(*v); } Ok(buf.len()) } + #[tracing::instrument(level = "trace", skip(self))] fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/src/vmm/src/arch/x86_64/msr.rs b/src/vmm/src/arch/x86_64/msr.rs index 7550f6d6801..c757e947379 100644 --- a/src/vmm/src/arch/x86_64/msr.rs +++ b/src/vmm/src/arch/x86_64/msr.rs @@ -43,6 +43,7 @@ struct MsrRange { } impl MsrRange { + #[tracing::instrument(level = "trace", skip(self, msr))] /// Returns whether `msr` is contained in this MSR range. fn contains(&self, msr: u32) -> bool { self.base <= msr && msr < self.base + self.nmsrs @@ -243,6 +244,7 @@ static SERIALIZABLE_MSR_RANGES: &[MsrRange] = &[ MSR_RANGE!(MSR_KVM_ASYNC_PF_INT), ]; +#[tracing::instrument(level = "trace", skip(index))] /// Specifies whether a particular MSR should be included in vcpu serialization. /// /// # Arguments @@ -258,6 +260,7 @@ pub fn msr_should_serialize(index: u32) -> bool { .any(|range| range.contains(index)) } +#[tracing::instrument(level = "trace", skip(kvm_fd))] /// Returns the list of serializable MSR indices. /// /// # Arguments @@ -394,6 +397,7 @@ static UNDUMPABLE_MSR_RANGES: &[MsrRange] = &[ MSR_RANGE!(HV_X64_MSR_SYNDBG_OPTIONS), ]; +#[tracing::instrument(level = "trace", skip(index))] /// Specifies whether a particular MSR should be dumped. /// /// # Arguments @@ -416,6 +420,7 @@ static UNDUMPABLE_MSR_RANGES_AMD: &[MsrRange] = &[ MSR_RANGE!(MSR_IA32_ARCH_CAPABILITIES), ]; +#[tracing::instrument(level = "trace", skip(index))] /// Specifies whether a particular MSR should be dumped on AMD /// /// # Arguments @@ -427,6 +432,7 @@ pub fn msr_should_dump_amd(index: u32) -> bool { .any(|range| range.contains(index)) } +#[tracing::instrument(level = "trace", skip(kvm_fd))] /// Returns the list of dumpable MSR indices. /// /// # Arguments @@ -450,6 +456,7 @@ pub fn get_msrs_to_dump(kvm_fd: &Kvm) -> Result { Ok(msr_index_list) } +#[tracing::instrument(level = "trace", skip())] /// Creates and populates required MSR entries for booting Linux on X86_64. pub fn create_boot_msr_entries() -> Vec { let msr_entry_default = |msr| kvm_msr_entry { @@ -478,6 +485,7 @@ pub fn create_boot_msr_entries() -> Vec { ] } +#[tracing::instrument(level = "trace", skip(vcpu, msr_entries))] /// Configure Model Specific Registers (MSRs) required to boot Linux for a given x86_64 vCPU. /// /// # Arguments @@ -509,6 +517,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip())] fn create_vcpu() -> VcpuFd { let kvm = Kvm::new().unwrap(); let vm = kvm.create_vm().unwrap(); diff --git a/src/vmm/src/arch/x86_64/regs.rs b/src/vmm/src/arch/x86_64/regs.rs index 41d37389ef7..0d979b94d87 100644 --- a/src/vmm/src/arch/x86_64/regs.rs +++ b/src/vmm/src/arch/x86_64/regs.rs @@ -55,6 +55,7 @@ pub enum RegsError { #[error("Failed to setup FPU: {0}")] pub struct SetupFpuError(utils::errno::Error); +#[tracing::instrument(level = "trace", skip(vcpu))] /// Configure Floating-Point Unit (FPU) registers for a given CPU. /// /// # Arguments @@ -79,6 +80,7 @@ pub fn setup_fpu(vcpu: &VcpuFd) -> Result<(), SetupFpuError> { #[error("Failed to setup registers: {0}")] pub struct SetupRegistersError(utils::errno::Error); +#[tracing::instrument(level = "trace", skip(vcpu, boot_ip))] /// Configure base registers for a given CPU. /// /// # Arguments @@ -125,6 +127,7 @@ pub enum SetupSpecialRegistersError { SetSpecialRegisters(utils::errno::Error), } +#[tracing::instrument(level = "trace", skip(mem, vcpu))] /// Configures the special registers and system page tables for a given CPU. /// /// # Arguments @@ -164,6 +167,7 @@ const X86_CR0_PE: u64 = 0x1; const X86_CR0_PG: u64 = 0x8000_0000; const X86_CR4_PAE: u64 = 0x20; +#[tracing::instrument(level = "trace", skip(table, guest_mem))] fn write_gdt_table(table: &[u64], guest_mem: &GuestMemoryMmap) -> Result<(), RegsError> { let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET); for (index, entry) in table.iter().enumerate() { @@ -177,6 +181,7 @@ fn write_gdt_table(table: &[u64], guest_mem: &GuestMemoryMmap) -> Result<(), Reg Ok(()) } +#[tracing::instrument(level = "trace", skip(val, guest_mem))] fn write_idt_value(val: u64, guest_mem: &GuestMemoryMmap) -> Result<(), RegsError> { let boot_idt_addr = GuestAddress(BOOT_IDT_OFFSET); guest_mem @@ -184,6 +189,7 @@ fn write_idt_value(val: u64, guest_mem: &GuestMemoryMmap) -> Result<(), RegsErro .map_err(|_| RegsError::WriteIDT) } +#[tracing::instrument(level = "trace", skip(mem, sregs))] fn configure_segments_and_sregs( mem: &GuestMemoryMmap, sregs: &mut kvm_sregs, @@ -223,6 +229,7 @@ fn configure_segments_and_sregs( Ok(()) } +#[tracing::instrument(level = "trace", skip(mem, sregs))] fn setup_page_tables(mem: &GuestMemoryMmap, sregs: &mut kvm_sregs) -> Result<(), RegsError> { // Puts PML4 right after zero page but aligned to 4k. let boot_pml4_addr = GuestAddress(PML4_START); @@ -256,6 +263,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip(mem_size))] fn create_guest_mem(mem_size: Option) -> GuestMemoryMmap { let page_size = 0x10000usize; let mem_size = mem_size.unwrap_or(page_size as u64) as usize; @@ -274,11 +282,13 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(gm, offset))] fn read_u64(gm: &GuestMemoryMmap, offset: u64) -> u64 { let read_addr = GuestAddress(offset); gm.read_obj(read_addr).unwrap() } + #[tracing::instrument(level = "trace", skip(gm, sregs))] fn validate_segments_and_sregs(gm: &GuestMemoryMmap, sregs: &kvm_sregs) { assert_eq!(0x0, read_u64(gm, BOOT_GDT_OFFSET)); assert_eq!(0xaf_9b00_0000_ffff, read_u64(gm, BOOT_GDT_OFFSET + 8)); @@ -299,6 +309,7 @@ mod tests { assert!(sregs.efer & EFER_LME != 0 && sregs.efer & EFER_LMA != 0); } + #[tracing::instrument(level = "trace", skip(gm, sregs))] fn validate_page_tables(gm: &GuestMemoryMmap, sregs: &kvm_sregs) { assert_eq!(0xa003, read_u64(gm, PML4_START)); assert_eq!(0xb003, read_u64(gm, PDPTE_START)); diff --git a/src/vmm/src/arch_gen/x86/mpspec.rs b/src/vmm/src/arch_gen/x86/mpspec.rs index a4771b57da3..ce5ae4e00eb 100644 --- a/src/vmm/src/arch_gen/x86/mpspec.rs +++ b/src/vmm/src/arch_gen/x86/mpspec.rs @@ -79,6 +79,7 @@ fn bindgen_test_layout_mpf_intel() { 4usize, concat!("Alignment of ", stringify!(mpf_intel)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_signature() { assert_eq!( unsafe { @@ -96,6 +97,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_signature(); + #[tracing::instrument(level = "trace", skip())] fn test_field_physptr() { assert_eq!( unsafe { @@ -113,6 +115,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_physptr(); + #[tracing::instrument(level = "trace", skip())] fn test_field_length() { assert_eq!( unsafe { @@ -130,6 +133,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_length(); + #[tracing::instrument(level = "trace", skip())] fn test_field_specification() { assert_eq!( unsafe { @@ -147,6 +151,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_specification(); + #[tracing::instrument(level = "trace", skip())] fn test_field_checksum() { assert_eq!( unsafe { @@ -164,6 +169,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_checksum(); + #[tracing::instrument(level = "trace", skip())] fn test_field_feature1() { assert_eq!( unsafe { @@ -181,6 +187,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_feature1(); + #[tracing::instrument(level = "trace", skip())] fn test_field_feature2() { assert_eq!( unsafe { @@ -198,6 +205,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_feature2(); + #[tracing::instrument(level = "trace", skip())] fn test_field_feature3() { assert_eq!( unsafe { @@ -215,6 +223,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_feature3(); + #[tracing::instrument(level = "trace", skip())] fn test_field_feature4() { assert_eq!( unsafe { @@ -232,6 +241,7 @@ fn bindgen_test_layout_mpf_intel() { ); } test_field_feature4(); + #[tracing::instrument(level = "trace", skip())] fn test_field_feature5() { assert_eq!( unsafe { @@ -277,6 +287,7 @@ fn bindgen_test_layout_mpc_table() { 4usize, concat!("Alignment of ", stringify!(mpc_table)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_signature() { assert_eq!( unsafe { @@ -294,6 +305,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_signature(); + #[tracing::instrument(level = "trace", skip())] fn test_field_length() { assert_eq!( unsafe { @@ -311,6 +323,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_length(); + #[tracing::instrument(level = "trace", skip())] fn test_field_spec() { assert_eq!( unsafe { @@ -328,6 +341,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_spec(); + #[tracing::instrument(level = "trace", skip())] fn test_field_checksum() { assert_eq!( unsafe { @@ -345,6 +359,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_checksum(); + #[tracing::instrument(level = "trace", skip())] fn test_field_oem() { assert_eq!( unsafe { @@ -362,6 +377,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_oem(); + #[tracing::instrument(level = "trace", skip())] fn test_field_productid() { assert_eq!( unsafe { @@ -379,6 +395,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_productid(); + #[tracing::instrument(level = "trace", skip())] fn test_field_oemptr() { assert_eq!( unsafe { @@ -396,6 +413,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_oemptr(); + #[tracing::instrument(level = "trace", skip())] fn test_field_oemsize() { assert_eq!( unsafe { @@ -413,6 +431,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_oemsize(); + #[tracing::instrument(level = "trace", skip())] fn test_field_oemcount() { assert_eq!( unsafe { @@ -430,6 +449,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_oemcount(); + #[tracing::instrument(level = "trace", skip())] fn test_field_lapic() { assert_eq!( unsafe { @@ -447,6 +467,7 @@ fn bindgen_test_layout_mpc_table() { ); } test_field_lapic(); + #[tracing::instrument(level = "trace", skip())] fn test_field_reserved() { assert_eq!( unsafe { @@ -488,6 +509,7 @@ fn bindgen_test_layout_mpc_cpu() { 4usize, concat!("Alignment of ", stringify!(mpc_cpu)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_type() { assert_eq!( unsafe { @@ -505,6 +527,7 @@ fn bindgen_test_layout_mpc_cpu() { ); } test_field_type(); + #[tracing::instrument(level = "trace", skip())] fn test_field_apicid() { assert_eq!( unsafe { @@ -522,6 +545,7 @@ fn bindgen_test_layout_mpc_cpu() { ); } test_field_apicid(); + #[tracing::instrument(level = "trace", skip())] fn test_field_apicver() { assert_eq!( unsafe { @@ -539,6 +563,7 @@ fn bindgen_test_layout_mpc_cpu() { ); } test_field_apicver(); + #[tracing::instrument(level = "trace", skip())] fn test_field_cpuflag() { assert_eq!( unsafe { @@ -556,6 +581,7 @@ fn bindgen_test_layout_mpc_cpu() { ); } test_field_cpuflag(); + #[tracing::instrument(level = "trace", skip())] fn test_field_cpufeature() { assert_eq!( unsafe { @@ -573,6 +599,7 @@ fn bindgen_test_layout_mpc_cpu() { ); } test_field_cpufeature(); + #[tracing::instrument(level = "trace", skip())] fn test_field_featureflag() { assert_eq!( unsafe { @@ -590,6 +617,7 @@ fn bindgen_test_layout_mpc_cpu() { ); } test_field_featureflag(); + #[tracing::instrument(level = "trace", skip())] fn test_field_reserved() { assert_eq!( unsafe { @@ -627,6 +655,7 @@ fn bindgen_test_layout_mpc_bus() { 1usize, concat!("Alignment of ", stringify!(mpc_bus)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_type() { assert_eq!( unsafe { @@ -644,6 +673,7 @@ fn bindgen_test_layout_mpc_bus() { ); } test_field_type(); + #[tracing::instrument(level = "trace", skip())] fn test_field_busid() { assert_eq!( unsafe { @@ -661,6 +691,7 @@ fn bindgen_test_layout_mpc_bus() { ); } test_field_busid(); + #[tracing::instrument(level = "trace", skip())] fn test_field_bustype() { assert_eq!( unsafe { @@ -700,6 +731,7 @@ fn bindgen_test_layout_mpc_ioapic() { 4usize, concat!("Alignment of ", stringify!(mpc_ioapic)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_type() { assert_eq!( unsafe { @@ -717,6 +749,7 @@ fn bindgen_test_layout_mpc_ioapic() { ); } test_field_type(); + #[tracing::instrument(level = "trace", skip())] fn test_field_apicid() { assert_eq!( unsafe { @@ -734,6 +767,7 @@ fn bindgen_test_layout_mpc_ioapic() { ); } test_field_apicid(); + #[tracing::instrument(level = "trace", skip())] fn test_field_apicver() { assert_eq!( unsafe { @@ -751,6 +785,7 @@ fn bindgen_test_layout_mpc_ioapic() { ); } test_field_apicver(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -768,6 +803,7 @@ fn bindgen_test_layout_mpc_ioapic() { ); } test_field_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_apicaddr() { assert_eq!( unsafe { @@ -809,6 +845,7 @@ fn bindgen_test_layout_mpc_intsrc() { 2usize, concat!("Alignment of ", stringify!(mpc_intsrc)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_type() { assert_eq!( unsafe { @@ -826,6 +863,7 @@ fn bindgen_test_layout_mpc_intsrc() { ); } test_field_type(); + #[tracing::instrument(level = "trace", skip())] fn test_field_irqtype() { assert_eq!( unsafe { @@ -843,6 +881,7 @@ fn bindgen_test_layout_mpc_intsrc() { ); } test_field_irqtype(); + #[tracing::instrument(level = "trace", skip())] fn test_field_irqflag() { assert_eq!( unsafe { @@ -860,6 +899,7 @@ fn bindgen_test_layout_mpc_intsrc() { ); } test_field_irqflag(); + #[tracing::instrument(level = "trace", skip())] fn test_field_srcbus() { assert_eq!( unsafe { @@ -877,6 +917,7 @@ fn bindgen_test_layout_mpc_intsrc() { ); } test_field_srcbus(); + #[tracing::instrument(level = "trace", skip())] fn test_field_srcbusirq() { assert_eq!( unsafe { @@ -894,6 +935,7 @@ fn bindgen_test_layout_mpc_intsrc() { ); } test_field_srcbusirq(); + #[tracing::instrument(level = "trace", skip())] fn test_field_dstapic() { assert_eq!( unsafe { @@ -911,6 +953,7 @@ fn bindgen_test_layout_mpc_intsrc() { ); } test_field_dstapic(); + #[tracing::instrument(level = "trace", skip())] fn test_field_dstirq() { assert_eq!( unsafe { @@ -957,6 +1000,7 @@ fn bindgen_test_layout_mpc_lintsrc() { 2usize, concat!("Alignment of ", stringify!(mpc_lintsrc)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_type() { assert_eq!( unsafe { @@ -974,6 +1018,7 @@ fn bindgen_test_layout_mpc_lintsrc() { ); } test_field_type(); + #[tracing::instrument(level = "trace", skip())] fn test_field_irqtype() { assert_eq!( unsafe { @@ -991,6 +1036,7 @@ fn bindgen_test_layout_mpc_lintsrc() { ); } test_field_irqtype(); + #[tracing::instrument(level = "trace", skip())] fn test_field_irqflag() { assert_eq!( unsafe { @@ -1008,6 +1054,7 @@ fn bindgen_test_layout_mpc_lintsrc() { ); } test_field_irqflag(); + #[tracing::instrument(level = "trace", skip())] fn test_field_srcbusid() { assert_eq!( unsafe { @@ -1025,6 +1072,7 @@ fn bindgen_test_layout_mpc_lintsrc() { ); } test_field_srcbusid(); + #[tracing::instrument(level = "trace", skip())] fn test_field_srcbusirq() { assert_eq!( unsafe { @@ -1042,6 +1090,7 @@ fn bindgen_test_layout_mpc_lintsrc() { ); } test_field_srcbusirq(); + #[tracing::instrument(level = "trace", skip())] fn test_field_destapic() { assert_eq!( unsafe { @@ -1059,6 +1108,7 @@ fn bindgen_test_layout_mpc_lintsrc() { ); } test_field_destapic(); + #[tracing::instrument(level = "trace", skip())] fn test_field_destapiclint() { assert_eq!( unsafe { @@ -1098,6 +1148,7 @@ fn bindgen_test_layout_mpc_oemtable() { 2usize, concat!("Alignment of ", stringify!(mpc_oemtable)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_signature() { assert_eq!( unsafe { @@ -1115,6 +1166,7 @@ fn bindgen_test_layout_mpc_oemtable() { ); } test_field_signature(); + #[tracing::instrument(level = "trace", skip())] fn test_field_length() { assert_eq!( unsafe { @@ -1132,6 +1184,7 @@ fn bindgen_test_layout_mpc_oemtable() { ); } test_field_length(); + #[tracing::instrument(level = "trace", skip())] fn test_field_rev() { assert_eq!( unsafe { @@ -1149,6 +1202,7 @@ fn bindgen_test_layout_mpc_oemtable() { ); } test_field_rev(); + #[tracing::instrument(level = "trace", skip())] fn test_field_checksum() { assert_eq!( unsafe { @@ -1166,6 +1220,7 @@ fn bindgen_test_layout_mpc_oemtable() { ); } test_field_checksum(); + #[tracing::instrument(level = "trace", skip())] fn test_field_mpc() { assert_eq!( unsafe { diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index 5e63d95e004..11299af6090 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -17,7 +17,7 @@ use linux_loader::loader::elf::Elf as Loader; #[cfg(target_arch = "aarch64")] use linux_loader::loader::pe::PE as Loader; use linux_loader::loader::KernelLoader; -use log::error; +use logger::error; use seccompiler::BpfThreadMap; use snapshot::Persist; use userfaultfd::Uffd; @@ -141,11 +141,23 @@ pub enum StartMicrovmError { /// It's convenient to automatically convert `linux_loader::cmdline::Error`s /// to `StartMicrovmError`s. impl std::convert::From for StartMicrovmError { + #[tracing::instrument(level = "trace", skip(err))] fn from(err: linux_loader::cmdline::Error) -> StartMicrovmError { StartMicrovmError::KernelCmdline(err.to_string()) } } +#[tracing::instrument( + level = "trace", + skip( + instance_info, + event_manager, + guest_memory, + uffd, + track_dirty_pages, + vcpu_count + ) +)] #[cfg_attr(target_arch = "aarch64", allow(unused))] fn create_vmm_and_vcpus( instance_info: &InstanceInfo, @@ -234,6 +246,10 @@ fn create_vmm_and_vcpus( Ok((vmm, vcpus)) } +#[tracing::instrument( + level = "trace", + skip(instance_info, vm_resources, event_manager, seccomp_filters) +)] /// Builds and starts a microVM based on the current Firecracker VmResources configuration. /// /// The built microVM and all the created vCPUs start off in the paused state. @@ -344,6 +360,10 @@ pub fn build_microvm_for_boot( Ok(vmm) } +#[tracing::instrument( + level = "trace", + skip(instance_info, vm_resources, event_manager, seccomp_filters) +)] /// Builds and boots a microVM based on the current Firecracker VmResources configuration. /// /// This is the default build recipe, one could build other microVM flavors by using the @@ -420,6 +440,19 @@ pub enum BuildMicrovmFromSnapshotError { SeccompFiltersInternal(#[from] seccompiler::InstallationError), } +#[tracing::instrument( + level = "trace", + skip( + instance_info, + event_manager, + microvm_state, + guest_memory, + uffd, + track_dirty_pages, + seccomp_filters, + vm_resources + ) +)] /// Builds and starts a microVM based on the provided MicrovmState. /// /// An `Arc` reference of the built `Vmm` is also plugged in the `EventManager`, while another @@ -526,6 +559,7 @@ pub fn build_microvm_from_snapshot( Ok(vmm) } +#[tracing::instrument(level = "trace", skip(mem_size_mib, track_dirty_pages))] /// Creates GuestMemory of `mem_size_mib` MiB in size. pub fn create_guest_memory( mem_size_mib: usize, @@ -544,6 +578,7 @@ pub fn create_guest_memory( .map_err(StartMicrovmError::GuestMemoryMmap) } +#[tracing::instrument(level = "trace", skip(boot_config, guest_memory))] fn load_kernel( boot_config: &BootConfig, guest_memory: &GuestMemoryMmap, @@ -574,6 +609,7 @@ fn load_kernel( Ok(entry_addr.kernel_load) } +#[tracing::instrument(level = "trace", skip(boot_cfg, vm_memory))] fn load_initrd_from_config( boot_cfg: &BootConfig, vm_memory: &GuestMemoryMmap, @@ -589,6 +625,7 @@ fn load_initrd_from_config( }) } +#[tracing::instrument(level = "trace", skip(vm_memory, image))] /// Loads the initrd from a file into the given memory slice. /// /// * `vm_memory` - The guest memory the initrd is written to. @@ -637,6 +674,7 @@ where }) } +#[tracing::instrument(level = "trace", skip(guest_memory, track_dirty_pages))] pub(crate) fn setup_kvm_vm( guest_memory: &GuestMemoryMmap, track_dirty_pages: bool, @@ -652,6 +690,7 @@ pub(crate) fn setup_kvm_vm( Ok(vm) } +#[tracing::instrument(level = "trace", skip(vm))] /// Sets up the irqchip for a x86_64 microVM. #[cfg(target_arch = "x86_64")] pub fn setup_interrupt_controller(vm: &mut Vm) -> Result<(), StartMicrovmError> { @@ -660,6 +699,7 @@ pub fn setup_interrupt_controller(vm: &mut Vm) -> Result<(), StartMicrovmError> .map_err(StartMicrovmError::Internal) } +#[tracing::instrument(level = "trace", skip(vm, vcpu_count))] /// Sets up the irqchip for a aarch64 microVM. #[cfg(target_arch = "aarch64")] pub fn setup_interrupt_controller(vm: &mut Vm, vcpu_count: u8) -> Result<(), StartMicrovmError> { @@ -668,6 +708,7 @@ pub fn setup_interrupt_controller(vm: &mut Vm, vcpu_count: u8) -> Result<(), Sta .map_err(StartMicrovmError::Internal) } +#[tracing::instrument(level = "trace", skip(event_manager, input, out))] /// Sets up the serial device. pub fn setup_serial_device( event_manager: &mut EventManager, @@ -691,6 +732,7 @@ pub fn setup_serial_device( Ok(serial) } +#[tracing::instrument(level = "trace", skip(event_manager, vmm, cmdline))] #[cfg(target_arch = "aarch64")] fn attach_legacy_devices_aarch64( event_manager: &mut EventManager, @@ -723,6 +765,7 @@ fn attach_legacy_devices_aarch64( .map_err(VmmError::RegisterMMIODevice) } +#[tracing::instrument(level = "trace", skip(vm, vcpu_count, exit_evt))] fn create_vcpus(vm: &Vm, vcpu_count: u8, exit_evt: &EventFd) -> Result, VmmError> { let mut vcpus = Vec::with_capacity(vcpu_count as usize); for cpu_idx in 0..vcpu_count { @@ -737,6 +780,10 @@ fn create_vcpus(vm: &Vm, vcpu_count: u8, exit_evt: &EventFd) -> Result Ok(vcpus) } +#[tracing::instrument( + level = "trace", + skip(vmm, vcpus, vm_config, entry_addr, initrd, boot_cmdline) +)] /// Configures the system for booting Linux. #[cfg_attr(target_arch = "aarch64", allow(unused))] pub fn configure_system_for_boot( @@ -835,6 +882,7 @@ pub fn configure_system_for_boot( Ok(()) } +#[tracing::instrument(level = "trace", skip(event_manager, vmm, id, device, cmdline))] /// Attaches a VirtioDevice device to the device manager and event manager. fn attach_virtio_device( event_manager: &mut EventManager, @@ -855,6 +903,7 @@ fn attach_virtio_device( .map(|_| ()) } +#[tracing::instrument(level = "trace", skip(vmm, request_ts))] pub(crate) fn attach_boot_timer_device( vmm: &mut Vmm, request_ts: TimestampUs, @@ -870,6 +919,7 @@ pub(crate) fn attach_boot_timer_device( Ok(()) } +#[tracing::instrument(level = "trace", skip(vmm, cmdline, entropy_device, event_manager))] fn attach_entropy_device( vmm: &mut Vmm, cmdline: &mut LoaderKernelCmdline, @@ -885,6 +935,7 @@ fn attach_entropy_device( attach_virtio_device(event_manager, vmm, id, entropy_device.clone(), cmdline) } +#[tracing::instrument(level = "trace", skip(vmm, cmdline, blocks, event_manager))] fn attach_block_devices<'a, I: Iterator>> + Debug>( vmm: &mut Vmm, cmdline: &mut LoaderKernelCmdline, @@ -913,6 +964,7 @@ fn attach_block_devices<'a, I: Iterator>> + Debug>( Ok(()) } +#[tracing::instrument(level = "trace", skip(vmm, cmdline, net_devices, event_manager))] fn attach_net_devices<'a, I: Iterator>> + Debug>( vmm: &mut Vmm, cmdline: &mut LoaderKernelCmdline, @@ -927,6 +979,7 @@ fn attach_net_devices<'a, I: Iterator>> + Debug>( Ok(()) } +#[tracing::instrument(level = "trace", skip(vmm, cmdline, unix_vsock, event_manager))] fn attach_unixsock_vsock_device( vmm: &mut Vmm, cmdline: &mut LoaderKernelCmdline, @@ -938,6 +991,7 @@ fn attach_unixsock_vsock_device( attach_virtio_device(event_manager, vmm, id, unix_vsock.clone(), cmdline) } +#[tracing::instrument(level = "trace", skip(vmm, cmdline, balloon, event_manager))] fn attach_balloon_device( vmm: &mut Vmm, cmdline: &mut LoaderKernelCmdline, @@ -950,6 +1004,7 @@ fn attach_balloon_device( } // Adds `O_NONBLOCK` to the stdout flags. +#[tracing::instrument(level = "trace", skip())] pub(crate) fn set_stdout_nonblocking() { // SAFETY: Call is safe since parameters are valid. let flags = unsafe { libc::fcntl(libc::STDOUT_FILENO, libc::F_GETFL, 0) }; @@ -996,6 +1051,10 @@ pub mod tests { } impl CustomBlockConfig { + #[tracing::instrument( + level = "trace", + skip(drive_id, is_root_device, partuuid, is_read_only, cache_type) + )] pub(crate) fn new( drive_id: String, is_root_device: bool, @@ -1013,6 +1072,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn default_mmio_device_manager() -> MMIODeviceManager { MMIODeviceManager::new( crate::arch::MMIO_MEM_START, @@ -1022,6 +1082,7 @@ pub mod tests { .unwrap() } + #[tracing::instrument(level = "trace", skip(cmdline, slug))] fn cmdline_contains(cmdline: &Cmdline, slug: &str) -> bool { // The following unwraps can never fail; the only way any of these methods // would return an `Err` is if one of the following conditions is met: @@ -1041,6 +1102,7 @@ pub mod tests { .contains(slug) } + #[tracing::instrument(level = "trace", skip())] pub(crate) fn default_kernel_cmdline() -> Cmdline { linux_loader::cmdline::Cmdline::try_from( DEFAULT_KERNEL_CMDLINE, @@ -1049,6 +1111,7 @@ pub mod tests { .unwrap() } + #[tracing::instrument(level = "trace", skip())] pub(crate) fn default_vmm() -> Vmm { let guest_memory = create_guest_memory(128, false).unwrap(); @@ -1100,6 +1163,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(vmm, cmdline, event_manager, custom_block_cfgs))] pub(crate) fn insert_block_devices( vmm: &mut Vmm, cmdline: &mut Cmdline, @@ -1133,6 +1197,7 @@ pub mod tests { block_files } + #[tracing::instrument(level = "trace", skip(vmm, cmdline, event_manager, net_config))] pub(crate) fn insert_net_device( vmm: &mut Vmm, cmdline: &mut Cmdline, @@ -1146,6 +1211,10 @@ pub mod tests { assert!(res.is_ok()); } + #[tracing::instrument( + level = "trace", + skip(vmm, cmdline, event_manager, net_config, mmds_version) + )] pub(crate) fn insert_net_device_with_mmds( vmm: &mut Vmm, cmdline: &mut Cmdline, @@ -1166,6 +1235,7 @@ pub mod tests { attach_net_devices(vmm, cmdline, net_builder.iter(), event_manager).unwrap(); } + #[tracing::instrument(level = "trace", skip(vmm, cmdline, event_manager, vsock_config))] pub(crate) fn insert_vsock_device( vmm: &mut Vmm, cmdline: &mut Cmdline, @@ -1184,6 +1254,7 @@ pub mod tests { .is_some()); } + #[tracing::instrument(level = "trace", skip(vmm, cmdline, event_manager, entropy_config))] pub(crate) fn insert_entropy_device( vmm: &mut Vmm, cmdline: &mut Cmdline, @@ -1201,6 +1272,7 @@ pub mod tests { .is_some()); } + #[tracing::instrument(level = "trace", skip(vmm, cmdline, event_manager, balloon_config))] pub(crate) fn insert_balloon_device( vmm: &mut Vmm, cmdline: &mut Cmdline, @@ -1219,20 +1291,24 @@ pub mod tests { .is_some()); } + #[tracing::instrument(level = "trace", skip())] fn make_test_bin() -> Vec { let mut fake_bin = Vec::new(); fake_bin.resize(1_000_000, 0xAA); fake_bin } + #[tracing::instrument(level = "trace", skip(at, size))] fn create_guest_mem_at(at: GuestAddress, size: usize) -> GuestMemoryMmap { utils::vm_memory::test_utils::create_guest_memory_unguarded(&[(at, size)], false).unwrap() } + #[tracing::instrument(level = "trace", skip(size))] pub(crate) fn create_guest_mem_with_size(size: usize) -> GuestMemoryMmap { create_guest_mem_at(GuestAddress(0x0), size) } + #[tracing::instrument(level = "trace", skip(mem))] fn is_dirty_tracking_enabled(mem: &GuestMemoryMmap) -> bool { mem.iter().all(|r| r.bitmap().is_some()) } diff --git a/src/vmm/src/cpu_config/aarch64/custom_cpu_template.rs b/src/vmm/src/cpu_config/aarch64/custom_cpu_template.rs index e4b2f8a44c7..80efbf832dc 100644 --- a/src/vmm/src/cpu_config/aarch64/custom_cpu_template.rs +++ b/src/vmm/src/cpu_config/aarch64/custom_cpu_template.rs @@ -16,6 +16,7 @@ use crate::cpu_config::templates::{ use crate::cpu_config::templates_serde::*; impl GetCpuTemplate for Option { + #[tracing::instrument(level = "trace", skip(self))] fn get_cpu_template(&self) -> Result, GetCpuTemplateError> { match self { Some(template_type) => match template_type { @@ -41,6 +42,7 @@ pub struct CustomCpuTemplate { } impl CustomCpuTemplate { + #[tracing::instrument(level = "trace", skip(self))] /// Get a list of register IDs that are modified by the CPU template. pub fn reg_list(&self) -> Vec { self.reg_modifiers @@ -49,6 +51,7 @@ impl CustomCpuTemplate { .collect() } + #[tracing::instrument(level = "trace", skip(self))] /// Validate the correctness of the template. pub fn validate(&self) -> Result<(), serde_json::Error> { for modifier in self.reg_modifiers.iter() { diff --git a/src/vmm/src/cpu_config/aarch64/mod.rs b/src/vmm/src/cpu_config/aarch64/mod.rs index 16f24587be5..2dcd9a03251 100644 --- a/src/vmm/src/cpu_config/aarch64/mod.rs +++ b/src/vmm/src/cpu_config/aarch64/mod.rs @@ -25,6 +25,7 @@ pub struct CpuConfiguration { } impl CpuConfiguration { + #[tracing::instrument(level = "trace", skip(self, template))] /// Creates new guest CPU config based on the provided template pub fn apply_template( mut self, @@ -47,6 +48,7 @@ impl CpuConfiguration { Ok(self) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns ids of registers that are changed /// by this template pub fn register_ids(&self) -> Vec { diff --git a/src/vmm/src/cpu_config/aarch64/static_cpu_templates/mod.rs b/src/vmm/src/cpu_config/aarch64/static_cpu_templates/mod.rs index 68762699576..e9822a741e5 100644 --- a/src/vmm/src/cpu_config/aarch64/static_cpu_templates/mod.rs +++ b/src/vmm/src/cpu_config/aarch64/static_cpu_templates/mod.rs @@ -25,6 +25,7 @@ pub enum StaticCpuTemplate { } impl StaticCpuTemplate { + #[tracing::instrument(level = "trace", skip(self))] /// Check if no template specified pub fn is_none(&self) -> bool { self == &StaticCpuTemplate::None @@ -32,6 +33,7 @@ impl StaticCpuTemplate { } impl std::fmt::Display for StaticCpuTemplate { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { StaticCpuTemplate::V1N1 => write!(f, "V1N1"), diff --git a/src/vmm/src/cpu_config/aarch64/static_cpu_templates/v1n1.rs b/src/vmm/src/cpu_config/aarch64/static_cpu_templates/v1n1.rs index 72ee10690dc..d1a0693b6f4 100644 --- a/src/vmm/src/cpu_config/aarch64/static_cpu_templates/v1n1.rs +++ b/src/vmm/src/cpu_config/aarch64/static_cpu_templates/v1n1.rs @@ -10,6 +10,7 @@ use crate::cpu_config::templates::RegisterValueFilter; // Arm Armv8-A Architecture Registers documentation // https://developer.arm.com/documentation/ddi0595/2021-12/AArch64-Registers?lang=en +#[tracing::instrument(level = "trace", skip())] /// Template to mask Neoverse-V1 as Neoverse-N1 /// Masks: dgh, asimdfhm, bf16, dcpodp, flagm, i8mm, sha3, sha512, sm3, sm4 /// sve, svebf16, svei8mm, uscat, fcma, jscvt, dit, ilrcpc, rng diff --git a/src/vmm/src/cpu_config/aarch64/test_utils.rs b/src/vmm/src/cpu_config/aarch64/test_utils.rs index 3cf93513d04..3b211a80d90 100644 --- a/src/vmm/src/cpu_config/aarch64/test_utils.rs +++ b/src/vmm/src/cpu_config/aarch64/test_utils.rs @@ -31,6 +31,7 @@ pub const TEST_INVALID_TEMPLATE_JSON: &str = r#"{ ] }"#; +#[tracing::instrument(level = "trace", skip())] /// Builds a sample custom CPU template pub fn build_test_template() -> CustomCpuTemplate { CustomCpuTemplate { diff --git a/src/vmm/src/cpu_config/templates.rs b/src/vmm/src/cpu_config/templates.rs index 74a52d19295..4ce603bb3e3 100644 --- a/src/vmm/src/cpu_config/templates.rs +++ b/src/vmm/src/cpu_config/templates.rs @@ -66,6 +66,7 @@ pub enum CpuTemplateType { } impl From<&Option> for StaticCpuTemplate { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: &Option) -> Self { match value { Some(CpuTemplateType::Static(template)) => *template, @@ -77,6 +78,7 @@ impl From<&Option> for StaticCpuTemplate { impl<'a> TryFrom<&'a [u8]> for CustomCpuTemplate { type Error = serde_json::Error; + #[tracing::instrument(level = "trace", skip(value))] fn try_from(value: &[u8]) -> Result { let template: CustomCpuTemplate = serde_json::from_slice(value)?; template.validate()?; @@ -87,6 +89,7 @@ impl<'a> TryFrom<&'a [u8]> for CustomCpuTemplate { impl TryFrom<&str> for CustomCpuTemplate { type Error = serde_json::Error; + #[tracing::instrument(level = "trace", skip(value))] fn try_from(value: &str) -> Result { CustomCpuTemplate::try_from(value.as_bytes()) } @@ -108,6 +111,7 @@ impl RegisterValueFilter where V: Numeric + Debug, { + #[tracing::instrument(level = "trace", skip(self, value))] /// Applies filter to the value #[inline] pub fn apply(&self, value: V) -> V { @@ -166,6 +170,7 @@ impl Serialize for RegisterValueFilter where V: Numeric + Debug, { + #[tracing::instrument(level = "trace", skip(self, serializer))] /// Serialize combination of value and filter into a single tri state string fn serialize(&self, serializer: S) -> Result where @@ -197,6 +202,7 @@ impl<'de, V> Deserialize<'de> for RegisterValueFilter where V: Numeric + Debug, { + #[tracing::instrument(level = "trace", skip(deserializer))] /// Deserialize a composite bitmap string into a value pair /// input string: "010x" /// result: { diff --git a/src/vmm/src/cpu_config/templates_serde.rs b/src/vmm/src/cpu_config/templates_serde.rs index c640c1d18e2..dc69e6d985c 100644 --- a/src/vmm/src/cpu_config/templates_serde.rs +++ b/src/vmm/src/cpu_config/templates_serde.rs @@ -6,6 +6,7 @@ use std::fmt::Debug; use serde::de::Error as SerdeError; use serde::{Deserialize, Deserializer, Serializer}; +#[tracing::instrument(level = "trace", skip(number, serializer))] /// Serializes number to hex pub fn serialize_to_hex_str(number: &N, serializer: S) -> Result where diff --git a/src/vmm/src/cpu_config/test_utils.rs b/src/vmm/src/cpu_config/test_utils.rs index de2e952522e..4f7a81674d3 100644 --- a/src/vmm/src/cpu_config/test_utils.rs +++ b/src/vmm/src/cpu_config/test_utils.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use crate::cpu_config::templates::CustomCpuTemplate; // Get a static CPU template stored as a JSON file. +#[tracing::instrument(level = "trace", skip(filename))] pub fn get_json_template(filename: &str) -> CustomCpuTemplate { let json_path = [ env!("CARGO_MANIFEST_DIR"), diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/amd/mod.rs b/src/vmm/src/cpu_config/x86_64/cpuid/amd/mod.rs index f6bba245ee3..c21747ddb44 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/amd/mod.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/amd/mod.rs @@ -19,12 +19,14 @@ pub use normalize::{ pub struct AmdCpuid(pub std::collections::BTreeMap); impl CpuidTrait for AmdCpuid { + #[tracing::instrument(level = "trace", skip(self, key))] /// Gets a given sub-leaf. #[inline] fn get(&self, key: &CpuidKey) -> Option<&CpuidEntry> { self.0.get(key) } + #[tracing::instrument(level = "trace", skip(self, key))] /// Gets a given sub-leaf. #[inline] fn get_mut(&mut self, key: &CpuidKey) -> Option<&mut CpuidEntry> { @@ -33,6 +35,7 @@ impl CpuidTrait for AmdCpuid { } impl From for AmdCpuid { + #[tracing::instrument(level = "trace", skip(kvm_cpuid))] #[inline] fn from(kvm_cpuid: kvm_bindings::CpuId) -> Self { let map = kvm_cpuid diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs b/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs index db79acd884c..a5366059466 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs @@ -107,6 +107,7 @@ impl super::AmdCpuid { const DEFAULT_BRAND_STRING: &[u8; BRAND_STRING_LENGTH] = b"AMD EPYC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + #[tracing::instrument(level = "trace", skip(self, cpu_index, cpu_count, cpus_per_core))] /// Applies required modifications to CPUID respective of a vCPU. /// /// # Errors @@ -135,6 +136,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Passthrough cache topology. /// /// # Errors @@ -202,6 +204,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Update largest extended fn entry. #[allow(clippy::unwrap_used, clippy::unwrap_in_result)] fn update_largest_extended_fn_entry(&mut self) -> Result<(), NormalizeCpuidError> { @@ -219,6 +222,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Updated extended feature fn entry. fn update_extended_feature_fn_entry(&mut self) -> Result<(), NormalizeCpuidError> { // set the Topology Extension bit since we use the Extended Cache Topology leaf @@ -234,6 +238,7 @@ impl super::AmdCpuid { } // Update structured extended feature entry. + #[tracing::instrument(level = "trace", skip(self))] fn update_structured_extended_entry(&mut self) -> Result<(), NormalizeCpuidError> { let leaf_7_subleaf_0 = self .get_mut(&CpuidKey::subleaf(0x7, 0x0)) @@ -247,6 +252,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, cpu_count))] /// Update AMD feature entry. #[allow(clippy::unwrap_used, clippy::unwrap_in_result)] fn update_amd_feature_entry(&mut self, cpu_count: u8) -> Result<(), FeatureEntryError> { @@ -285,6 +291,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, cpu_count, cpus_per_core))] /// Update extended cache topology entry. #[allow(clippy::unwrap_in_result, clippy::unwrap_used)] fn update_extended_cache_topology_entry( @@ -348,6 +355,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, cpu_index, cpus_per_core))] /// Update extended apic id entry #[allow(clippy::unwrap_used, clippy::unwrap_in_result)] fn update_extended_apic_id_entry( @@ -422,6 +430,7 @@ impl super::AmdCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Update brand string entry fn update_brand_string_entry(&mut self) -> Result<(), NormalizeCpuidError> { self.apply_brand_string(Self::DEFAULT_BRAND_STRING) diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/common.rs b/src/vmm/src/cpu_config/x86_64/cpuid/common.rs index 8f2ac15ee10..226c8913615 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/common.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/common.rs @@ -13,6 +13,7 @@ pub enum GetCpuidError { InvalidSubleaf(u32), } +#[tracing::instrument(level = "trace", skip(leaf, subleaf))] /// Extract entry from the cpuid. /// /// # Errors @@ -36,6 +37,7 @@ pub fn get_cpuid(leaf: u32, subleaf: u32) -> Result Result<[u8; 12], GetCpuidError> { }) } +#[tracing::instrument(level = "trace", skip(cpuid))] /// Returns MSRs to be saved based on CPUID features that are enabled. pub(crate) fn msrs_to_save_by_cpuid(cpuid: &kvm_bindings::CpuId) -> std::collections::HashSet { /// Memory Protection Extensions diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/intel/mod.rs b/src/vmm/src/cpu_config/x86_64/cpuid/intel/mod.rs index 48e393d5cee..44acb4538e5 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/intel/mod.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/intel/mod.rs @@ -21,12 +21,14 @@ use super::{CpuidEntry, CpuidKey, CpuidRegisters, CpuidTrait, KvmCpuidFlags}; pub struct IntelCpuid(pub std::collections::BTreeMap); impl CpuidTrait for IntelCpuid { + #[tracing::instrument(level = "trace", skip(self, key))] /// Gets a given sub-leaf. #[inline] fn get(&self, key: &CpuidKey) -> Option<&CpuidEntry> { self.0.get(key) } + #[tracing::instrument(level = "trace", skip(self, key))] /// Gets a given sub-leaf. #[inline] fn get_mut(&mut self, key: &CpuidKey) -> Option<&mut CpuidEntry> { @@ -35,6 +37,7 @@ impl CpuidTrait for IntelCpuid { } impl From for IntelCpuid { + #[tracing::instrument(level = "trace", skip(kvm_cpuid))] #[inline] fn from(kvm_cpuid: kvm_bindings::CpuId) -> Self { let map = kvm_cpuid diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/intel/normalize.rs b/src/vmm/src/cpu_config/x86_64/cpuid/intel/normalize.rs index c4d6ddd95c2..e7cac7fb8ec 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/intel/normalize.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/intel/normalize.rs @@ -75,6 +75,7 @@ pub const DEFAULT_BRAND_STRING_BASE: &[u8; 28] = b"Intel(R) Xeon(R) Processor @" // `normalize`. #[allow(clippy::multiple_inherent_impl)] impl super::IntelCpuid { + #[tracing::instrument(level = "trace", skip(self, _cpu_index, cpu_count, cpus_per_core))] /// Applies required modifications to CPUID respective of a vCPU. /// /// # Errors @@ -100,6 +101,7 @@ impl super::IntelCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, cpu_count, cpus_per_core))] /// Update deterministic cache entry #[allow(clippy::unwrap_in_result)] fn update_deterministic_cache_entry( @@ -184,6 +186,7 @@ impl super::IntelCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Update power management entry fn update_power_management_entry(&mut self) -> Result<(), NormalizeCpuidError> { let leaf_6 = self @@ -206,6 +209,7 @@ impl super::IntelCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Update structured extended feature flags enumeration leaf fn update_extended_feature_flags_entry(&mut self) -> Result<(), NormalizeCpuidError> { let leaf_7_0 = self @@ -222,6 +226,7 @@ impl super::IntelCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Update performance monitoring entry fn update_performance_monitoring_entry(&mut self) -> Result<(), NormalizeCpuidError> { let leaf_a = self @@ -236,6 +241,7 @@ impl super::IntelCpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn update_brand_string_entry(&mut self) -> Result<(), NormalizeCpuidError> { // Get host brand string. let host_brand_string: [u8; BRAND_STRING_LENGTH] = host_brand_string(); @@ -263,6 +269,7 @@ pub enum DefaultBrandStringError { Overflow, } +#[tracing::instrument(level = "trace", skip(host_brand_string))] /// Normalize brand string to a generic Xeon(R) processor, with the actual CPU frequency /// /// # Errors diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs b/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs index 69131171c13..9df14853684 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs @@ -68,11 +68,13 @@ pub const VENDOR_ID_AMD_STR: &str = unsafe { std::str::from_utf8_unchecked(VENDO /// To store the brand string we have 3 leaves, each with 4 registers, each with 4 bytes. pub const BRAND_STRING_LENGTH: usize = 3 * 4 * 4; +#[tracing::instrument(level = "trace", skip(leaf))] /// Mimic of [`std::arch::x86_64::__cpuid`] that wraps [`cpuid_count`]. fn cpuid(leaf: u32) -> std::arch::x86_64::CpuidResult { cpuid_count(leaf, 0) } +#[tracing::instrument(level = "trace", skip(leaf, subleaf))] /// Safe wrapper around [`std::arch::x86_64::__cpuid_count`]. fn cpuid_count(leaf: u32, subleaf: u32) -> std::arch::x86_64::CpuidResult { // JUSTIFICATION: There is no safe alternative. @@ -80,6 +82,7 @@ fn cpuid_count(leaf: u32, subleaf: u32) -> std::arch::x86_64::CpuidResult { unsafe { std::arch::x86_64::__cpuid_count(leaf, subleaf) } } +#[tracing::instrument(level = "trace", skip())] /// Gets the Intel default brand. // As we pass through host frequency, we require CPUID and thus `cfg(cpuid)`. /// Gets host brand string. @@ -245,6 +248,7 @@ pub trait CpuidTrait { } impl CpuidTrait for kvm_bindings::CpuId { + #[tracing::instrument(level = "trace", skip(self, leaf, subleaf))] /// Gets a given sub-leaf. #[allow(clippy::transmute_ptr_to_ptr, clippy::unwrap_used)] #[inline] @@ -265,6 +269,7 @@ impl CpuidTrait for kvm_bindings::CpuId { }) } + #[tracing::instrument(level = "trace", skip(self, leaf, subleaf))] /// Gets a given sub-leaf. #[allow(clippy::transmute_ptr_to_ptr, clippy::unwrap_used)] #[inline] @@ -323,6 +328,7 @@ pub enum Cpuid { } impl Cpuid { + #[tracing::instrument(level = "trace", skip(self))] /// Returns `Some(&mut IntelCpuid)` if `Self == Self::Intel(_)` else returns `None`. #[inline] #[must_use] @@ -333,6 +339,7 @@ impl Cpuid { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns `Some(&IntelCpuid)` if `Self == Self::Intel(_)` else returns `None`. #[inline] #[must_use] @@ -343,6 +350,7 @@ impl Cpuid { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns `Some(&AmdCpuid)` if `Self == Self::Amd(_)` else returns `None`. #[inline] #[must_use] @@ -353,6 +361,7 @@ impl Cpuid { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns `Some(&mut AmdCpuid)` if `Self == Self::Amd(_)` else returns `None`. #[inline] #[must_use] @@ -363,6 +372,7 @@ impl Cpuid { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns imumutable reference to inner BTreeMap. #[inline] #[must_use] @@ -373,6 +383,7 @@ impl Cpuid { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns mutable reference to inner BTreeMap. #[inline] #[must_use] @@ -385,6 +396,7 @@ impl Cpuid { } impl CpuidTrait for Cpuid { + #[tracing::instrument(level = "trace", skip(self, key))] /// Gets a given sub-leaf. #[inline] fn get(&self, key: &CpuidKey) -> Option<&CpuidEntry> { @@ -394,6 +406,7 @@ impl CpuidTrait for Cpuid { } } + #[tracing::instrument(level = "trace", skip(self, key))] /// Gets a given sub-leaf. #[inline] fn get_mut(&mut self, key: &CpuidKey) -> Option<&mut CpuidEntry> { @@ -407,6 +420,7 @@ impl CpuidTrait for Cpuid { impl TryFrom for Cpuid { type Error = CpuidTryFromKvmCpuid; + #[tracing::instrument(level = "trace", skip(kvm_cpuid))] #[inline] fn try_from(kvm_cpuid: kvm_bindings::CpuId) -> Result { let vendor_id = kvm_cpuid @@ -424,6 +438,7 @@ impl TryFrom for Cpuid { impl TryFrom for kvm_bindings::CpuId { type Error = utils::fam::Error; + #[tracing::instrument(level = "trace", skip(cpuid))] fn try_from(cpuid: Cpuid) -> Result { let entries = cpuid .inner() @@ -454,6 +469,7 @@ pub struct CpuidKey { } impl CpuidKey { + #[tracing::instrument(level = "trace", skip(leaf))] /// `CpuidKey { leaf, subleaf: 0 }` #[inline] #[must_use] @@ -461,6 +477,7 @@ impl CpuidKey { Self { leaf, subleaf: 0 } } + #[tracing::instrument(level = "trace", skip(leaf, subleaf))] /// `CpuidKey { leaf, subleaf }` #[inline] #[must_use] @@ -470,6 +487,7 @@ impl CpuidKey { } impl std::cmp::PartialOrd for CpuidKey { + #[tracing::instrument(level = "trace", skip(self, other))] #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some( @@ -481,6 +499,7 @@ impl std::cmp::PartialOrd for CpuidKey { } impl std::cmp::Ord for CpuidKey { + #[tracing::instrument(level = "trace", skip(self, other))] #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.leaf @@ -508,6 +527,7 @@ impl KvmCpuidFlags { #[allow(clippy::derivable_impls)] impl Default for KvmCpuidFlags { + #[tracing::instrument(level = "trace", skip())] #[inline] fn default() -> Self { Self(0) @@ -585,6 +605,7 @@ pub struct CpuidRegisters { } impl From for CpuidRegisters { + #[tracing::instrument(level = "trace", skip(eax, ebx, ecx, edx))] #[inline] fn from( core::arch::x86_64::CpuidResult { eax, ebx, ecx, edx }: core::arch::x86_64::CpuidResult, @@ -599,6 +620,7 @@ mod tests { use super::*; + #[tracing::instrument(level = "trace", skip())] fn build_intel_leaf0_for_cpuid() -> (CpuidKey, CpuidEntry) { ( CpuidKey { @@ -618,6 +640,7 @@ mod tests { ) } + #[tracing::instrument(level = "trace", skip())] fn build_intel_leaf0_for_kvmcpuid() -> kvm_bindings::kvm_cpuid_entry2 { kvm_bindings::kvm_cpuid_entry2 { function: 0x0, @@ -632,6 +655,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn build_amd_leaf0_for_cpuid() -> (CpuidKey, CpuidEntry) { ( CpuidKey { @@ -651,6 +675,7 @@ mod tests { ) } + #[tracing::instrument(level = "trace", skip())] fn build_amd_leaf0_for_kvmcpuid() -> kvm_bindings::kvm_cpuid_entry2 { kvm_bindings::kvm_cpuid_entry2 { function: 0x0, @@ -665,6 +690,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn build_sample_leaf_for_cpuid() -> (CpuidKey, CpuidEntry) { ( CpuidKey { @@ -683,6 +709,7 @@ mod tests { ) } + #[tracing::instrument(level = "trace", skip())] fn build_sample_leaf_for_kvmcpuid() -> kvm_bindings::kvm_cpuid_entry2 { kvm_bindings::kvm_cpuid_entry2 { function: 0x1, @@ -696,6 +723,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn build_sample_intel_cpuid() -> Cpuid { Cpuid::Intel(IntelCpuid(BTreeMap::from([ build_intel_leaf0_for_cpuid(), @@ -703,6 +731,7 @@ mod tests { ]))) } + #[tracing::instrument(level = "trace", skip())] fn build_sample_intel_kvmcpuid() -> kvm_bindings::CpuId { kvm_bindings::CpuId::from_entries(&[ build_intel_leaf0_for_kvmcpuid(), @@ -711,6 +740,7 @@ mod tests { .unwrap() } + #[tracing::instrument(level = "trace", skip())] fn build_sample_amd_cpuid() -> Cpuid { Cpuid::Amd(AmdCpuid(BTreeMap::from([ build_amd_leaf0_for_cpuid(), @@ -718,6 +748,7 @@ mod tests { ]))) } + #[tracing::instrument(level = "trace", skip())] fn build_sample_amd_kvmcpuid() -> kvm_bindings::CpuId { kvm_bindings::CpuId::from_entries(&[ build_amd_leaf0_for_kvmcpuid(), diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/normalize.rs b/src/vmm/src/cpu_config/x86_64/cpuid/normalize.rs index fb3de1d585f..bd2b3f8945c 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/normalize.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/normalize.rs @@ -111,6 +111,7 @@ pub enum ExtendedCacheFeaturesError { #[error("Given value is greater than maximum storable value in bit range.")] pub struct CheckedAssignError; +#[tracing::instrument(level = "trace", skip(x, bit, y))] /// Sets a given bit to a true or false (1 or 0). #[allow(clippy::integer_arithmetic, clippy::arithmetic_side_effects)] pub fn set_bit(x: &mut u32, bit: u8, y: bool) { @@ -118,6 +119,7 @@ pub fn set_bit(x: &mut u32, bit: u8, y: bool) { *x = (*x & !(1 << bit)) | ((u32::from(u8::from(y))) << bit); } +#[tracing::instrument(level = "trace", skip(x, range, y))] /// Sets a given range to a given value. #[allow(clippy::integer_arithmetic, clippy::arithmetic_side_effects)] pub fn set_range( @@ -144,6 +146,7 @@ pub fn set_range( 33.. => Err(CheckedAssignError), } } +#[tracing::instrument(level = "trace", skip(x, range))] /// Gets a given range within a given value. #[allow(clippy::integer_arithmetic, clippy::arithmetic_side_effects)] pub fn get_range(x: u32, range: std::ops::Range) -> u32 { @@ -186,6 +189,7 @@ const fn mask(range: std::ops::Range) -> u32 { // `normalize`. #[allow(clippy::multiple_inherent_impl)] impl super::Cpuid { + #[tracing::instrument(level = "trace", skip(self, cpu_index, cpu_count, cpu_bits))] /// Applies required modifications to CPUID respective of a vCPU. /// /// # Errors @@ -225,6 +229,7 @@ impl super::Cpuid { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Pass-through the vendor ID from the host. This is used to prevent modification of the vendor /// ID via custom CPU templates. fn update_vendor_id(&mut self) -> Result<(), VendorIdError> { @@ -242,6 +247,7 @@ impl super::Cpuid { } // Update feature information entry + #[tracing::instrument(level = "trace", skip(self, cpu_index, cpu_count))] fn update_feature_info_entry( &mut self, cpu_index: u8, @@ -325,6 +331,10 @@ impl super::Cpuid { Ok(()) } + #[tracing::instrument( + level = "trace", + skip(self, cpu_index, cpu_count, cpu_bits, cpus_per_core) + )] /// Update extended topology entry fn update_extended_topology_entry( &mut self, @@ -467,6 +477,7 @@ impl super::Cpuid { } // Update extended cache features entry + #[tracing::instrument(level = "trace", skip(self))] fn update_extended_cache_features(&mut self) -> Result<(), ExtendedCacheFeaturesError> { // Leaf 0x800000005 indicates L1 Cache and TLB Information. let guest_leaf_0x80000005 = self diff --git a/src/vmm/src/cpu_config/x86_64/custom_cpu_template.rs b/src/vmm/src/cpu_config/x86_64/custom_cpu_template.rs index f082a7efbfe..dcbe9e86713 100644 --- a/src/vmm/src/cpu_config/x86_64/custom_cpu_template.rs +++ b/src/vmm/src/cpu_config/x86_64/custom_cpu_template.rs @@ -18,6 +18,7 @@ use crate::cpu_config::x86_64::cpuid::{KvmCpuidFlags, VENDOR_ID_AMD, VENDOR_ID_I use crate::cpu_config::x86_64::static_cpu_templates::{c3, t2, t2a, t2cl, t2s, StaticCpuTemplate}; impl GetCpuTemplate for Option { + #[tracing::instrument(level = "trace", skip(self))] fn get_cpu_template(&self) -> Result, GetCpuTemplateError> { use GetCpuTemplateError::*; @@ -131,6 +132,7 @@ pub struct CustomCpuTemplate { } impl CustomCpuTemplate { + #[tracing::instrument(level = "trace", skip(self))] /// Get a list of MSR indices that are modified by the CPU template. pub fn get_msr_index_list(&self) -> Vec { self.msr_modifiers @@ -139,6 +141,7 @@ impl CustomCpuTemplate { .collect() } + #[tracing::instrument(level = "trace", skip(self))] /// Validate the correctness of the template. pub fn validate(&self) -> Result<(), serde_json::Error> { Ok(()) @@ -160,6 +163,7 @@ pub struct RegisterModifier { pub bitmap: RegisterValueFilter, } +#[tracing::instrument(level = "trace", skip(deserializer))] fn deserialize_kvm_cpuid_flags<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -168,6 +172,7 @@ where Ok(KvmCpuidFlags(flag)) } +#[tracing::instrument(level = "trace", skip(deserializer))] fn deserialize_cpuid_register<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -187,6 +192,7 @@ where }) } +#[tracing::instrument(level = "trace", skip(cpuid_reg, serializer))] fn serialize_cpuid_register(cpuid_reg: &CpuidRegister, serializer: S) -> Result where S: Serializer, diff --git a/src/vmm/src/cpu_config/x86_64/mod.rs b/src/vmm/src/cpu_config/x86_64/mod.rs index 33c0984bfa2..d78e0179a2e 100644 --- a/src/vmm/src/cpu_config/x86_64/mod.rs +++ b/src/vmm/src/cpu_config/x86_64/mod.rs @@ -45,6 +45,7 @@ pub struct CpuConfiguration { } impl CpuConfiguration { + #[tracing::instrument(level = "trace", skip(self, template))] /// Modifies provided config with changes from template pub fn apply_template( self, @@ -114,6 +115,7 @@ mod tests { use crate::cpu_config::templates::RegisterValueFilter; use crate::cpu_config::x86_64::cpuid::{CpuidEntry, IntelCpuid, KvmCpuidFlags}; + #[tracing::instrument(level = "trace", skip())] fn build_test_template() -> CustomCpuTemplate { CustomCpuTemplate { cpuid_modifiers: vec![CpuidLeafModifier { @@ -170,6 +172,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn build_supported_cpuid() -> Cpuid { Cpuid::Intel(IntelCpuid(BTreeMap::from([( CpuidKey { @@ -180,6 +183,7 @@ mod tests { )]))) } + #[tracing::instrument(level = "trace", skip())] fn empty_cpu_config() -> CpuConfiguration { CpuConfiguration { cpuid: Cpuid::Intel(IntelCpuid(BTreeMap::new())), @@ -187,6 +191,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn supported_cpu_config() -> CpuConfiguration { CpuConfiguration { cpuid: build_supported_cpuid(), @@ -194,6 +199,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn unsupported_cpu_config() -> CpuConfiguration { CpuConfiguration { cpuid: build_supported_cpuid(), diff --git a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/c3.rs b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/c3.rs index 3a6e89cc505..69557e4515a 100644 --- a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/c3.rs +++ b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/c3.rs @@ -7,6 +7,7 @@ use crate::cpu_config::x86_64::custom_cpu_template::{ CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, }; +#[tracing::instrument(level = "trace", skip())] /// C3 CPU template. /// /// Mask CPUID to make exposed CPU features as close as possbile to AWS C3 instance. diff --git a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/mod.rs b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/mod.rs index a267a8b9739..64b1b8e844a 100644 --- a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/mod.rs +++ b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/mod.rs @@ -45,6 +45,7 @@ pub enum StaticCpuTemplate { } impl StaticCpuTemplate { + #[tracing::instrument(level = "trace", skip(self))] /// Check if no template specified pub fn is_none(&self) -> bool { self == &StaticCpuTemplate::None diff --git a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2.rs b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2.rs index 731c699f79c..cf1ada48efb 100644 --- a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2.rs +++ b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2.rs @@ -7,6 +7,7 @@ use crate::cpu_config::x86_64::custom_cpu_template::{ CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, }; +#[tracing::instrument(level = "trace", skip())] /// T2 template /// /// Mask CPUID to make exposed CPU features as close as possbile to AWS T2 instance. diff --git a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2a.rs b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2a.rs index 4259bfb5e3d..4c0265c04e8 100644 --- a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2a.rs +++ b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2a.rs @@ -7,6 +7,7 @@ use crate::cpu_config::x86_64::custom_cpu_template::{ CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, }; +#[tracing::instrument(level = "trace", skip())] /// T2A template /// /// Provide instruction set feature partity with Intel Cascade Lake or later using T2CL template. diff --git a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2cl.rs b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2cl.rs index d296d94a0d7..cc744f58565 100644 --- a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2cl.rs +++ b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2cl.rs @@ -7,6 +7,7 @@ use crate::cpu_config::x86_64::custom_cpu_template::{ CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, RegisterModifier, }; +#[tracing::instrument(level = "trace", skip())] /// T2CL template /// /// Mask CPUID to make exposed CPU features as close as possbile to Intel Cascade Lake and provide diff --git a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2s.rs b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2s.rs index 293419ad321..012a163cdfc 100644 --- a/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2s.rs +++ b/src/vmm/src/cpu_config/x86_64/static_cpu_templates/t2s.rs @@ -7,6 +7,7 @@ use crate::cpu_config::x86_64::custom_cpu_template::{ CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, RegisterModifier, }; +#[tracing::instrument(level = "trace", skip())] /// T2S template /// /// Mask CPUID to make exposed CPU features as close as possbile to AWS T2 instance and allow diff --git a/src/vmm/src/cpu_config/x86_64/test_utils.rs b/src/vmm/src/cpu_config/x86_64/test_utils.rs index 50f1b7f0c7e..71e9ea46a6e 100644 --- a/src/vmm/src/cpu_config/x86_64/test_utils.rs +++ b/src/vmm/src/cpu_config/x86_64/test_utils.rs @@ -109,6 +109,7 @@ pub const TEST_INVALID_TEMPLATE_JSON: &str = r#"{ ] }"#; +#[tracing::instrument(level = "trace", skip())] /// Builds a sample custom CPU template pub fn build_test_template() -> CustomCpuTemplate { CustomCpuTemplate { diff --git a/src/vmm/src/device_manager/legacy.rs b/src/vmm/src/device_manager/legacy.rs index ef6d802aaa9..f25e1a1b883 100644 --- a/src/vmm/src/device_manager/legacy.rs +++ b/src/vmm/src/device_manager/legacy.rs @@ -71,6 +71,7 @@ impl PortIODeviceManager { /// i8042 keyboard data register size. const I8042_KDB_DATA_REGISTER_SIZE: u64 = 0x5; + #[tracing::instrument(level = "trace", skip(serial, i8042_reset_evfd))] /// Create a new DeviceManager handling legacy devices (uart, i8042). pub fn new( serial: Arc>, @@ -103,6 +104,7 @@ impl PortIODeviceManager { }) } + #[tracing::instrument(level = "trace", skip(self, vm_fd))] /// Register supported legacy devices. pub fn register_devices(&mut self, vm_fd: &VmFd) -> Result<(), LegacyDeviceError> { let serial_2_4 = Arc::new(Mutex::new(BusDevice::Serial(SerialDevice { diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index 87a6811e098..5aed9228808 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -11,7 +11,7 @@ use std::sync::{Arc, Mutex}; use kvm_ioctls::{IoEventAddress, VmFd}; use linux_loader::cmdline as kernel_cmdline; -use log::info; +use logger::info; #[cfg(target_arch = "x86_64")] use utils::vm_memory::GuestAddress; use versionize::{VersionMap, Versionize, VersionizeResult}; @@ -91,6 +91,7 @@ pub struct MMIODeviceManager { } impl MMIODeviceManager { + #[tracing::instrument(level = "trace", skip(mmio_base, mmio_size))] /// Create a new DeviceManager handling mmio devices (virtio net, block). pub fn new( mmio_base: u64, @@ -106,6 +107,7 @@ impl MMIODeviceManager { }) } + #[tracing::instrument(level = "trace", skip(self, irq_count))] /// Allocates resources for a new device to be added. fn allocate_mmio_resources(&mut self, irq_count: u32) -> Result { let irqs = (0..irq_count) @@ -124,6 +126,7 @@ impl MMIODeviceManager { Ok(device_info) } + #[tracing::instrument(level = "trace", skip(self, identifier, device_info, device))] /// Register a device at some MMIO address. fn register_mmio_device( &mut self, @@ -138,6 +141,7 @@ impl MMIODeviceManager { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, vm, device_id, mmio_device, device_info))] /// Register a virtio-over-MMIO device to be used via MMIO transport at a specific slot. pub fn register_mmio_virtio( &mut self, @@ -173,6 +177,7 @@ impl MMIODeviceManager { ) } + #[tracing::instrument(level = "trace", skip(cmdline, device_info))] /// Append a registered virtio-over-MMIO device to the kernel cmdline. #[cfg(target_arch = "x86_64")] pub fn add_virtio_device_to_cmdline( @@ -194,6 +199,7 @@ impl MMIODeviceManager { .map_err(MmioError::Cmdline) } + #[tracing::instrument(level = "trace", skip(self, vm, device_id, mmio_device, _cmdline))] /// Allocate slot and register an already created virtio-over-MMIO device. Also Adds the device /// to the boot cmdline. pub fn register_mmio_virtio_for_boot( @@ -210,6 +216,7 @@ impl MMIODeviceManager { Ok(device_info) } + #[tracing::instrument(level = "trace", skip(self, vm, serial, device_info_opt))] #[cfg(target_arch = "aarch64")] /// Register an early console at the specified MMIO configuration if given as parameter, /// otherwise allocate a new MMIO resources for it. @@ -244,6 +251,7 @@ impl MMIODeviceManager { self.register_mmio_device(identifier, device_info, serial) } + #[tracing::instrument(level = "trace", skip(self, cmdline))] #[cfg(target_arch = "aarch64")] /// Append the registered early console to the kernel cmdline. pub fn add_mmio_serial_to_cmdline( @@ -259,6 +267,7 @@ impl MMIODeviceManager { .map_err(MmioError::Cmdline) } + #[tracing::instrument(level = "trace", skip(self, rtc, device_info_opt))] #[cfg(target_arch = "aarch64")] /// Create and register a MMIO RTC device at the specified MMIO configuration if /// given as parameter, otherwise allocate a new MMIO resources for it. @@ -285,6 +294,7 @@ impl MMIODeviceManager { ) } + #[tracing::instrument(level = "trace", skip(self, device))] /// Register a boot timer device. pub fn register_mmio_boot_timer(&mut self, device: BootTimer) -> Result<(), MmioError> { // Attach a new boot timer device. @@ -298,11 +308,13 @@ impl MMIODeviceManager { ) } + #[tracing::instrument(level = "trace", skip(self))] /// Gets the information of the devices registered up to some point in time. pub fn get_device_info(&self) -> &HashMap<(DeviceType, String), MMIODeviceInfo> { &self.id_to_dev_info } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(target_arch = "x86_64")] /// Gets the number of interrupts used by the devices registered. pub fn used_irqs_count(&self) -> usize { @@ -313,6 +325,7 @@ impl MMIODeviceManager { irq_number } + #[tracing::instrument(level = "trace", skip(self, device_type, device_id))] /// Gets the specified device. pub fn get_device( &self, @@ -330,6 +343,7 @@ impl MMIODeviceManager { None } + #[tracing::instrument(level = "trace", skip(self, f))] /// Run fn for each registered device. pub fn for_each_device(&self, mut f: F) -> Result<(), E> where @@ -345,6 +359,7 @@ impl MMIODeviceManager { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, f))] /// Run fn for each registered virtio device. pub fn for_each_virtio_device(&self, mut f: F) -> Result<(), E> where @@ -366,6 +381,7 @@ impl MMIODeviceManager { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, virtio_type, id, f))] /// Run fn `f()` for the virtio device matching `virtio_type` and `id`. pub fn with_virtio_device_with_id( &self, @@ -396,6 +412,7 @@ impl MMIODeviceManager { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Artificially kick devices as if they had external events. pub fn kick_devices(&self) { info!("Artificially kick devices."); @@ -458,12 +475,15 @@ impl MMIODeviceManager { #[cfg(target_arch = "aarch64")] impl DeviceInfoForFDT for MMIODeviceInfo { + #[tracing::instrument(level = "trace", skip(self))] fn addr(&self) -> u64 { self.addr } + #[tracing::instrument(level = "trace", skip(self))] fn irq(&self) -> u32 { self.irqs[0] } + #[tracing::instrument(level = "trace", skip(self))] fn length(&self) -> u64 { self.len } @@ -484,6 +504,7 @@ mod tests { const QUEUE_SIZES: &[u16] = &[64]; impl MMIODeviceManager { + #[tracing::instrument(level = "trace", skip(self, vm, guest_mem, device, cmdline, dev_id))] fn register_virtio_test_device( &mut self, vm: &VmFd, @@ -509,6 +530,7 @@ mod tests { } impl DummyDevice { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> Self { DummyDevice { dummy: 0, @@ -520,59 +542,73 @@ mod tests { } impl crate::devices::virtio::VirtioDevice for DummyDevice { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { 0 } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { 0 } + #[tracing::instrument(level = "trace", skip(self))] fn set_acked_features(&mut self, _: u64) {} + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { 0 } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_evts } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.interrupt_evt } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { Arc::new(AtomicUsize::new(0)) } + #[tracing::instrument(level = "trace", skip(self, page, value))] fn ack_features_by_page(&mut self, page: u32, value: u32) { let _ = page; let _ = value; } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn read_config(&self, offset: u64, data: &mut [u8]) { let _ = offset; let _ = data; } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn write_config(&mut self, offset: u64, data: &[u8]) { let _ = offset; let _ = data; } + #[tracing::instrument(level = "trace", skip(self))] fn activate(&mut self, _: GuestMemoryMmap) -> Result<(), ActivateError> { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { false } diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/persist.rs index 42564ffaa82..b78b80b18ce 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/persist.rs @@ -8,7 +8,7 @@ use std::sync::{Arc, Mutex}; use event_manager::{MutEventSubscriber, SubscriberOps}; use kvm_ioctls::VmFd; -use log::{error, warn}; +use logger::{error, warn}; use mmds::data_store::MmdsVersion; use snapshot::Persist; use utils::vm_memory::GuestMemoryMmap; @@ -148,6 +148,7 @@ pub enum MmdsVersionState { } impl From for MmdsVersion { + #[tracing::instrument(level = "trace", skip(state))] fn from(state: MmdsVersionState) -> Self { match state { MmdsVersionState::V1 => MmdsVersion::V1, @@ -157,6 +158,7 @@ impl From for MmdsVersion { } impl From for MmdsVersionState { + #[tracing::instrument(level = "trace", skip(version))] fn from(version: MmdsVersion) -> Self { match version { MmdsVersion::V1 => MmdsVersionState::V1, @@ -201,6 +203,7 @@ pub enum SharedDeviceType { } impl DeviceStates { + #[tracing::instrument(level = "trace", skip(self, target_version))] fn balloon_serialize(&mut self, target_version: u16) -> VersionizeResult<()> { if target_version < 2 && self.balloon_device.is_some() { return Err(VersionizeError::Semantic( @@ -211,6 +214,7 @@ impl DeviceStates { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, target_version))] fn mmds_version_serialize(&mut self, target_version: u16) -> VersionizeResult<()> { if target_version < 3 && self.mmds_version.is_some() { warn!( @@ -222,6 +226,7 @@ impl DeviceStates { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, target_version))] fn entropy_serialize(&mut self, target_version: u16) -> VersionizeResult<()> { if target_version < 4 && self.entropy_device.is_some() { return Err(VersionizeError::Semantic( @@ -242,6 +247,7 @@ pub struct MMIODevManagerConstructorArgs<'a> { pub instance_id: &'a str, } impl fmt::Debug for MMIODevManagerConstructorArgs<'_> { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MMIODevManagerConstructorArgs") .field("mem", &self.mem) @@ -259,6 +265,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { type ConstructorArgs = MMIODevManagerConstructorArgs<'a>; type Error = DevicePersistError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { let mut states = DeviceStates { balloon_device: None, @@ -384,6 +391,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { states } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, @@ -641,6 +649,7 @@ mod tests { use crate::vmm_config::vsock::VsockDeviceConfig; impl PartialEq for ConnectedBalloonState { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &ConnectedBalloonState) -> bool { // Actual device state equality is checked by the device's tests. self.transport_state == other.transport_state && self.device_info == other.device_info @@ -648,6 +657,7 @@ mod tests { } impl PartialEq for ConnectedBlockState { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &ConnectedBlockState) -> bool { // Actual device state equality is checked by the device's tests. self.transport_state == other.transport_state && self.device_info == other.device_info @@ -655,6 +665,7 @@ mod tests { } impl PartialEq for ConnectedNetState { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &ConnectedNetState) -> bool { // Actual device state equality is checked by the device's tests. self.transport_state == other.transport_state && self.device_info == other.device_info @@ -662,6 +673,7 @@ mod tests { } impl PartialEq for ConnectedVsockState { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &ConnectedVsockState) -> bool { // Actual device state equality is checked by the device's tests. self.transport_state == other.transport_state && self.device_info == other.device_info @@ -669,6 +681,7 @@ mod tests { } impl PartialEq for DeviceStates { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &DeviceStates) -> bool { self.balloon_device == other.balloon_device && self.block_devices == other.block_devices @@ -678,6 +691,7 @@ mod tests { } impl MMIODeviceManager { + #[tracing::instrument(level = "trace", skip(self))] fn soft_clone(&self) -> Self { let dummy_mmio_base = 0; let dummy_irq_range = (0, 0); @@ -696,6 +710,7 @@ mod tests { } impl PartialEq for MMIODeviceManager { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &MMIODeviceManager) -> bool { // We only care about the device hashmap. if self.id_to_dev_info.len() != other.id_to_dev_info.len() { diff --git a/src/vmm/src/devices/bus.rs b/src/vmm/src/devices/bus.rs index b5d91545d2b..fc2329732d7 100644 --- a/src/vmm/src/devices/bus.rs +++ b/src/vmm/src/devices/bus.rs @@ -25,18 +25,21 @@ struct BusRange(u64, u64); impl Eq for BusRange {} impl PartialEq for BusRange { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &BusRange) -> bool { self.0 == other.0 } } impl Ord for BusRange { + #[tracing::instrument(level = "trace", skip(self, other))] fn cmp(&self, other: &BusRange) -> Ordering { self.0.cmp(&other.0) } } impl PartialOrd for BusRange { + #[tracing::instrument(level = "trace", skip(self, other))] fn partial_cmp(&self, other: &BusRange) -> Option { self.0.partial_cmp(&other.0) } @@ -79,7 +82,9 @@ pub struct DummyDevice; #[cfg(test)] impl DummyDevice { + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] pub fn bus_write(&mut self, _offset: u64, _data: &[u8]) {} + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] pub fn bus_read(&mut self, _offset: u64, _data: &[u8]) {} } @@ -89,12 +94,14 @@ pub struct ConstantDevice; #[cfg(test)] impl ConstantDevice { + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_read(&mut self, offset: u64, data: &mut [u8]) { for (i, v) in data.iter_mut().enumerate() { *v = (offset as u8) + (i as u8); } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn bus_write(&mut self, offset: u64, data: &[u8]) { for (i, v) in data.iter().enumerate() { assert_eq!(*v, (offset as u8) + (i as u8)) @@ -103,12 +110,14 @@ impl ConstantDevice { } impl BusDevice { + #[tracing::instrument(level = "trace", skip(self))] pub fn i8042_device_ref(&self) -> Option<&I8042Device> { match self { Self::I8042Device(x) => Some(x), _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(target_arch = "aarch64")] pub fn rtc_device_ref(&self) -> Option<&RTCDevice> { match self { @@ -116,18 +125,21 @@ impl BusDevice { _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] pub fn boot_timer_ref(&self) -> Option<&BootTimer> { match self { Self::BootTimer(x) => Some(x), _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] pub fn mmio_transport_ref(&self) -> Option<&MmioTransport> { match self { Self::MmioTransport(x) => Some(x), _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] pub fn serial_ref(&self) -> Option<&SerialDevice> { match self { Self::Serial(x) => Some(x), @@ -135,12 +147,14 @@ impl BusDevice { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn i8042_device_mut(&mut self) -> Option<&mut I8042Device> { match self { Self::I8042Device(x) => Some(x), _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(target_arch = "aarch64")] pub fn rtc_device_mut(&mut self) -> Option<&mut RTCDevice> { match self { @@ -148,18 +162,21 @@ impl BusDevice { _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] pub fn boot_timer_mut(&mut self) -> Option<&mut BootTimer> { match self { Self::BootTimer(x) => Some(x), _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] pub fn mmio_transport_mut(&mut self) -> Option<&mut MmioTransport> { match self { Self::MmioTransport(x) => Some(x), _ => None, } } + #[tracing::instrument(level = "trace", skip(self))] pub fn serial_mut(&mut self) -> Option<&mut SerialDevice> { match self { Self::Serial(x) => Some(x), @@ -167,6 +184,7 @@ impl BusDevice { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn read(&mut self, offset: u64, data: &mut [u8]) { match self { Self::I8042Device(x) => x.bus_read(offset, data), @@ -182,6 +200,7 @@ impl BusDevice { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn write(&mut self, offset: u64, data: &[u8]) { match self { Self::I8042Device(x) => x.bus_write(offset, data), @@ -199,12 +218,14 @@ impl BusDevice { } impl MutEventSubscriber for BusDevice { + #[tracing::instrument(level = "trace", skip(self, event, ops))] fn process(&mut self, event: Events, ops: &mut EventOps) { match self { Self::Serial(serial) => serial.process(event, ops), _ => panic!(), } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { match self { Self::Serial(serial) => serial.init(ops), @@ -214,6 +235,7 @@ impl MutEventSubscriber for BusDevice { } impl Bus { + #[tracing::instrument(level = "trace", skip())] /// Constructs an a bus with an empty address space. pub fn new() -> Bus { Bus { @@ -221,6 +243,7 @@ impl Bus { } } + #[tracing::instrument(level = "trace", skip(self, addr))] fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex)> { // for when we switch to rustc 1.17: self.devices.range(..addr).iter().rev().next() for (range, dev) in self.devices.iter().rev() { @@ -231,6 +254,7 @@ impl Bus { None } + #[tracing::instrument(level = "trace", skip(self, addr))] /// Returns the device found at some address. pub fn get_device(&self, addr: u64) -> Option<(u64, &Mutex)> { if let Some((BusRange(start, len), dev)) = self.first_before(addr) { @@ -242,6 +266,7 @@ impl Bus { None } + #[tracing::instrument(level = "trace", skip(self, device, base, len))] /// Puts the given device at the given address space. pub fn insert( &mut self, @@ -277,6 +302,7 @@ impl Bus { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, addr, data))] /// Reads data from the device that owns the range containing `addr` and puts it into `data`. /// /// Returns true on success, otherwise `data` is untouched. @@ -292,6 +318,7 @@ impl Bus { } } + #[tracing::instrument(level = "trace", skip(self, addr, data))] /// Writes `data` to the device that owns the range containing `addr`. /// /// Returns true on success, otherwise `data` is untouched. diff --git a/src/vmm/src/devices/legacy/i8042.rs b/src/vmm/src/devices/legacy/i8042.rs index 2524386ef0e..10a603b2406 100644 --- a/src/vmm/src/devices/legacy/i8042.rs +++ b/src/vmm/src/devices/legacy/i8042.rs @@ -8,8 +8,7 @@ use std::io; use std::num::Wrapping; -use log::warn; -use logger::{IncMetric, METRICS}; +use logger::{warn, IncMetric, METRICS}; use utils::eventfd::EventFd; /// Errors thrown by the i8042 device. @@ -85,6 +84,7 @@ pub struct I8042Device { } impl I8042Device { + #[tracing::instrument(level = "trace", skip(reset_evt, kbd_interrupt_evt))] /// Constructs an i8042 device that will signal the given event when the guest requests it. pub fn new(reset_evt: EventFd, kbd_interrupt_evt: EventFd) -> I8042Device { I8042Device { @@ -100,6 +100,7 @@ impl I8042Device { } } + #[tracing::instrument(level = "trace", skip(self))] /// Signal a ctrl-alt-del (reset) event. #[inline] pub fn trigger_ctrl_alt_del(&mut self) -> Result<(), I8042Error> { @@ -114,6 +115,7 @@ impl I8042Device { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn trigger_kbd_interrupt(&self) -> Result<(), I8042Error> { if (self.control & CB_KBD_INT) == 0 { warn!("Failed to trigger i8042 kbd interrupt (disabled by guest OS)"); @@ -124,6 +126,7 @@ impl I8042Device { .map_err(I8042Error::KbdInterruptFailure) } + #[tracing::instrument(level = "trace", skip(self, key))] fn trigger_key(&mut self, key: u16) -> Result<(), I8042Error> { if key & 0xff00 != 0 { // Check if there is enough room in the buffer, before pushing an extended (2-byte) key. @@ -140,6 +143,7 @@ impl I8042Device { } } + #[tracing::instrument(level = "trace", skip(self, byte))] #[inline] fn push_byte(&mut self, byte: u8) -> Result<(), I8042Error> { self.status |= SB_OUT_DATA_AVAIL; @@ -151,6 +155,7 @@ impl I8042Device { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] #[inline] fn pop_byte(&mut self) -> Option { if self.buf_len() == 0 { @@ -164,6 +169,7 @@ impl I8042Device { Some(res) } + #[tracing::instrument(level = "trace", skip(self))] #[inline] fn flush_buf(&mut self) { self.bhead = Wrapping(0usize); @@ -171,6 +177,7 @@ impl I8042Device { self.status &= !SB_OUT_DATA_AVAIL; } + #[tracing::instrument(level = "trace", skip(self))] #[inline] fn buf_len(&self) -> usize { (self.btail - self.bhead).0 @@ -178,6 +185,7 @@ impl I8042Device { } impl I8042Device { + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_read(&mut self, offset: u64, data: &mut [u8]) { // All our ports are byte-wide. We don't know how to handle any wider data. if data.len() != 1 { @@ -213,6 +221,7 @@ impl I8042Device { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_write(&mut self, offset: u64, data: &[u8]) { // All our ports are byte-wide. We don't know how to handle any wider data. if data.len() != 1 { @@ -228,7 +237,7 @@ impl I8042Device { // our exit event fd. Meaning Firecracker will be exiting as soon as the VMM // thread wakes up to handle this event. if let Err(err) = self.reset_evt.write(1) { - log::error!("Failed to trigger i8042 reset event: {:?}", err); + logger::error!("Failed to trigger i8042 reset event: {:?}", err); METRICS.i8042.error_count.inc(); } METRICS.i8042.reset_count.inc(); @@ -311,6 +320,7 @@ mod tests { use super::*; impl PartialEq for I8042Error { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &I8042Error) -> bool { self.to_string() == other.to_string() } @@ -430,6 +440,7 @@ mod tests { EventFd::new(libc::EFD_NONBLOCK).unwrap(), ); + #[tracing::instrument(level = "trace", skip(i8042, key))] fn expect_key(i8042: &mut I8042Device, key: u16) { let mut data = [1]; diff --git a/src/vmm/src/devices/legacy/mod.rs b/src/vmm/src/devices/legacy/mod.rs index 78f4025c29f..4a9cbd0baae 100644 --- a/src/vmm/src/devices/legacy/mod.rs +++ b/src/vmm/src/devices/legacy/mod.rs @@ -33,6 +33,7 @@ pub struct EventFdTrigger(EventFd); impl Trigger for EventFdTrigger { type E = io::Error; + #[tracing::instrument(level = "trace", skip(self))] fn trigger(&self) -> io::Result<()> { self.write(1) } @@ -40,22 +41,26 @@ impl Trigger for EventFdTrigger { impl Deref for EventFdTrigger { type Target = EventFd; + #[tracing::instrument(level = "trace", skip(self))] fn deref(&self) -> &Self::Target { &self.0 } } impl EventFdTrigger { + #[tracing::instrument(level = "trace", skip(self))] /// Clone an `EventFdTrigger`. pub fn try_clone(&self) -> io::Result { Ok(EventFdTrigger((**self).try_clone()?)) } + #[tracing::instrument(level = "trace", skip(evt))] /// Create an `EventFdTrigger`. pub fn new(evt: EventFd) -> Self { Self(evt) } + #[tracing::instrument(level = "trace", skip(self))] /// Get the associated event fd out of an `EventFdTrigger`. pub fn get_event(&self) -> EventFd { self.0.try_clone().unwrap() diff --git a/src/vmm/src/devices/legacy/rtc_pl031.rs b/src/vmm/src/devices/legacy/rtc_pl031.rs index a6b720fadc7..348bc467392 100644 --- a/src/vmm/src/devices/legacy/rtc_pl031.rs +++ b/src/vmm/src/devices/legacy/rtc_pl031.rs @@ -12,12 +12,14 @@ pub struct RTCDevice(pub vm_superio::Rtc<&'static RTCDeviceMetrics>); impl std::ops::Deref for RTCDevice { type Target = vm_superio::Rtc<&'static RTCDeviceMetrics>; + #[tracing::instrument(level = "trace", skip(self))] fn deref(&self) -> &Self::Target { &self.0 } } impl std::ops::DerefMut for RTCDevice { + #[tracing::instrument(level = "trace", skip(self))] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -25,6 +27,7 @@ impl std::ops::DerefMut for RTCDevice { // Implements Bus functions for AMBA PL031 RTC device impl RTCDevice { + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_read(&mut self, offset: u64, data: &mut [u8]) { if data.len() == 4 { // read() function from RTC implementation expects a slice of @@ -39,6 +42,7 @@ impl RTCDevice { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_write(&mut self, offset: u64, data: &[u8]) { if data.len() == 4 { // write() function from RTC implementation expects a slice of diff --git a/src/vmm/src/devices/legacy/serial.rs b/src/vmm/src/devices/legacy/serial.rs index ff67817093d..e1a064626f7 100644 --- a/src/vmm/src/devices/legacy/serial.rs +++ b/src/vmm/src/devices/legacy/serial.rs @@ -12,8 +12,7 @@ use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, RawFd}; use event_manager::{EventOps, Events, MutEventSubscriber}; -use log::{error, warn}; -use logger::{IncMetric, METRICS}; +use logger::{error, warn, IncMetric, METRICS}; use utils::epoll::EventSet; use vm_superio::serial::{Error as SerialError, SerialEvents}; use vm_superio::{Serial, Trigger}; @@ -38,6 +37,7 @@ pub trait RawIOHandler { impl RawIOHandler for Serial { // This is not used for anything and is basically just a dummy implementation for `raw_input`. + #[tracing::instrument(level = "trace", skip(self, data))] fn raw_input(&mut self, data: &[u8]) -> Result<(), RawIOError> { // Fail fast if the serial is serviced with more data than it can buffer. if data.len() > self.fifo_capacity() { @@ -61,18 +61,22 @@ pub struct SerialEventsWrapper { } impl SerialEvents for SerialEventsWrapper { + #[tracing::instrument(level = "trace", skip(self))] fn buffer_read(&self) { METRICS.uart.read_count.inc(); } + #[tracing::instrument(level = "trace", skip(self))] fn out_byte(&self) { METRICS.uart.write_count.inc(); } + #[tracing::instrument(level = "trace", skip(self))] fn tx_lost_byte(&self) { METRICS.uart.missed_write_count.inc(); } + #[tracing::instrument(level = "trace", skip(self))] fn in_buffer_empty(&self) { match self .buffer_ready_event_fd @@ -94,12 +98,14 @@ pub enum SerialOut { Stdout(std::io::Stdout), } impl std::io::Write for SerialOut { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write(&mut self, buf: &[u8]) -> std::io::Result { match self { Self::Sink(sink) => sink.write(buf), Self::Stdout(stdout) => stdout.write(buf), } } + #[tracing::instrument(level = "trace", skip(self))] fn flush(&mut self) -> std::io::Result<()> { match self { Self::Sink(sink) => sink.flush(), @@ -118,6 +124,7 @@ pub struct SerialWrapper } impl SerialWrapper { + #[tracing::instrument(level = "trace", skip(self, ops))] fn handle_ewouldblock(&self, ops: &mut EventOps) { let buffer_ready_fd = self.buffer_ready_evt_fd(); let input_fd = self.serial_input_fd(); @@ -140,6 +147,7 @@ impl SerialWrapper io::Result { let avail_cap = self.serial.fifo_capacity(); if avail_cap == 0 { @@ -161,6 +169,7 @@ impl SerialWrapper RawFd { self.serial @@ -170,11 +179,13 @@ impl SerialWrapper RawFd { self.input.as_ref().map_or(-1, |input| input.as_raw_fd()) } + #[tracing::instrument(level = "trace", skip(self))] fn consume_buffer_ready_event(&self) -> io::Result { self.serial .events() @@ -190,8 +201,10 @@ pub type SerialDevice = SerialWrapper impl MutEventSubscriber for SerialWrapper { + #[tracing::instrument(level = "trace", skip(self, event, ops))] /// Handle events on the serial input fd. fn process(&mut self, event: Events, ops: &mut EventOps) { + #[tracing::instrument(level = "trace", skip(ops, source))] #[inline] fn unregister_source(ops: &mut EventOps, source: &T) { match ops.remove(Events::new(source, EventSet::IN)) { @@ -259,6 +272,7 @@ impl MutEventSubscriber } } + #[tracing::instrument(level = "trace", skip(self, ops))] /// Initial registration of pollable objects. /// If serial input is present, register the serial input FD as readable. fn init(&mut self, ops: &mut EventOps) { @@ -284,6 +298,7 @@ impl MutEventSubscriber } } +#[tracing::instrument(level = "trace", skip(fd))] /// Checks whether the given file descriptor is a FIFO pipe. fn is_fifo(fd: RawFd) -> bool { let mut stat = std::mem::MaybeUninit::::uninit(); @@ -305,6 +320,7 @@ fn is_fifo(fd: RawFd) -> bool { impl SerialWrapper { + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_read(&mut self, offset: u64, data: &mut [u8]) { if data.len() != 1 { METRICS.uart.missed_read_count.inc(); @@ -313,6 +329,7 @@ impl data[0] = self.serial.read(offset as u8); } + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_write(&mut self, offset: u64, data: &[u8]) { if data.len() != 1 { METRICS.uart.missed_write_count.inc(); diff --git a/src/vmm/src/devices/mod.rs b/src/vmm/src/devices/mod.rs index b4e46743db7..e75962d6a5b 100644 --- a/src/vmm/src/devices/mod.rs +++ b/src/vmm/src/devices/mod.rs @@ -15,18 +15,19 @@ pub mod pseudo; pub mod virtio; pub use bus::{Bus, BusDevice, BusError}; -use log::error; -use logger::{IncMetric, METRICS}; +use logger::{error, IncMetric, METRICS}; use crate::devices::virtio::{QueueError, VsockError}; // Function used for reporting error in terms of logging // but also in terms of METRICS net event fails. +#[tracing::instrument(level = "trace", skip(err))] pub(crate) fn report_net_event_fail(err: DeviceError) { error!("{:?}", err); METRICS.net.event_fails.inc(); } +#[tracing::instrument(level = "trace", skip(err))] pub(crate) fn report_balloon_event_fail(err: virtio::balloon::BalloonError) { error!("{:?}", err); METRICS.balloon.event_fails.inc(); diff --git a/src/vmm/src/devices/pseudo/boot_timer.rs b/src/vmm/src/devices/pseudo/boot_timer.rs index 2551483ea53..e3ac0e52ae9 100644 --- a/src/vmm/src/devices/pseudo/boot_timer.rs +++ b/src/vmm/src/devices/pseudo/boot_timer.rs @@ -12,6 +12,7 @@ pub struct BootTimer { } impl BootTimer { + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_write(&mut self, offset: u64, data: &[u8]) { // Only handle byte length instructions at a zero offset. if data.len() != 1 || offset != 0 { @@ -23,7 +24,7 @@ impl BootTimer { let boot_time_us = now_tm_us.time_us - self.start_ts.time_us; let boot_time_cpu_us = now_tm_us.cputime_us - self.start_ts.cputime_us; - log::info!( + logger::info!( "Guest-boot-time = {:>6} us {} ms, {:>6} CPU us {} CPU ms", boot_time_us, boot_time_us / 1000, @@ -32,10 +33,12 @@ impl BootTimer { ); } } + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] pub fn bus_read(&mut self, _offset: u64, _data: &[u8]) {} } impl BootTimer { + #[tracing::instrument(level = "trace", skip(start_ts))] /// Create a device at a certain point in time. pub fn new(start_ts: TimestampUs) -> BootTimer { BootTimer { start_ts } diff --git a/src/vmm/src/devices/virtio/balloon/device.rs b/src/vmm/src/devices/virtio/balloon/device.rs index 727c11d0e7a..5615c2d6a53 100644 --- a/src/vmm/src/devices/virtio/balloon/device.rs +++ b/src/vmm/src/devices/virtio/balloon/device.rs @@ -7,8 +7,7 @@ use std::sync::Arc; use std::time::Duration; use std::{cmp, fmt}; -use log::error; -use logger::{IncMetric, METRICS}; +use logger::{error, IncMetric, METRICS}; use serde::Serialize; use timerfd::{ClockId, SetTimeFlags, TimerFd, TimerState}; use utils::eventfd::EventFd; @@ -32,12 +31,14 @@ use crate::devices::virtio::{IrqTrigger, IrqType}; const SIZE_OF_U32: usize = std::mem::size_of::(); const SIZE_OF_STAT: usize = std::mem::size_of::(); +#[tracing::instrument(level = "trace", skip(amount_mib))] fn mib_to_pages(amount_mib: u32) -> Result { amount_mib .checked_mul(MIB_TO_4K_PAGES) .ok_or(BalloonError::TooManyPagesRequested) } +#[tracing::instrument(level = "trace", skip(amount_pages))] fn pages_to_mib(amount_pages: u32) -> u32 { amount_pages / MIB_TO_4K_PAGES } @@ -126,6 +127,7 @@ pub struct BalloonStats { } impl BalloonStats { + #[tracing::instrument(level = "trace", skip(self, stat))] fn update_with_stat(&mut self, stat: &BalloonStat) -> Result<(), BalloonError> { let val = Some(stat.val); match stat.tag { @@ -178,6 +180,7 @@ pub struct Balloon { // [rust-timerfd](https://github.com/main--/rust-timerfd) is published that includes // https://github.com/main--/rust-timerfd/pull/12. impl fmt::Debug for Balloon { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Balloon") .field("avail_features", &self.avail_features) @@ -198,6 +201,10 @@ impl fmt::Debug for Balloon { } impl Balloon { + #[tracing::instrument( + level = "trace", + skip(amount_mib, deflate_on_oom, stats_polling_interval_s, restored) + )] /// Instantiate a new balloon device. pub fn new( amount_mib: u32, @@ -253,6 +260,7 @@ impl Balloon { }) } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_inflate_queue_event(&mut self) -> Result<(), BalloonError> { self.queue_evts[INFLATE_INDEX] .read() @@ -260,6 +268,7 @@ impl Balloon { self.process_inflate() } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_deflate_queue_event(&mut self) -> Result<(), BalloonError> { self.queue_evts[DEFLATE_INDEX] .read() @@ -267,6 +276,7 @@ impl Balloon { self.process_deflate_queue() } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_stats_queue_event(&mut self) -> Result<(), BalloonError> { self.queue_evts[STATS_INDEX] .read() @@ -274,11 +284,13 @@ impl Balloon { self.process_stats_queue() } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_stats_timer_event(&mut self) -> Result<(), BalloonError> { self.stats_timer.read(); self.trigger_stats_update() } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_inflate(&mut self) -> Result<(), BalloonError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -370,6 +382,7 @@ impl Balloon { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_deflate_queue(&mut self) -> Result<(), BalloonError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -392,6 +405,7 @@ impl Balloon { } } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_stats_queue(&mut self) -> Result<(), BalloonError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -430,6 +444,7 @@ impl Balloon { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn signal_used_queue(&self) -> Result<(), BalloonError> { self.irq_trigger.trigger_irq(IrqType::Vring).map_err(|err| { METRICS.balloon.event_fails.inc(); @@ -437,17 +452,20 @@ impl Balloon { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Process device virtio queue(s). pub fn process_virtio_queues(&mut self) { let _ = self.process_inflate(); let _ = self.process_deflate_queue(); } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the ID of this balloon device. pub fn id(&self) -> &str { BALLOON_DEV_ID } + #[tracing::instrument(level = "trace", skip(self))] fn trigger_stats_update(&mut self) -> Result<(), BalloonError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -465,6 +483,7 @@ impl Balloon { } } + #[tracing::instrument(level = "trace", skip(self, amount_mib))] /// Update the target size of the balloon. pub fn update_size(&mut self, amount_mib: u32) -> Result<(), BalloonError> { if self.is_activated() { @@ -477,6 +496,7 @@ impl Balloon { } } + #[tracing::instrument(level = "trace", skip(self, interval_s))] /// Update the the statistics polling interval. pub fn update_stats_polling_interval(&mut self, interval_s: u16) -> Result<(), BalloonError> { if self.stats_polling_interval_s == interval_s { @@ -494,6 +514,7 @@ impl Balloon { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn update_timer_state(&mut self) { let timer_state = TimerState::Periodic { current: Duration::from_secs(u64::from(self.stats_polling_interval_s)), @@ -503,24 +524,29 @@ impl Balloon { .set_state(timer_state, SetTimeFlags::Default); } + #[tracing::instrument(level = "trace", skip(self))] /// Obtain the number of 4K pages the device is currently holding. pub fn num_pages(&self) -> u32 { self.config_space.num_pages } + #[tracing::instrument(level = "trace", skip(self))] /// Obtain the size of 4K pages the device is currently holding in MIB. pub fn size_mb(&self) -> u32 { pages_to_mib(self.config_space.num_pages) } + #[tracing::instrument(level = "trace", skip(self))] pub fn deflate_on_oom(&self) -> bool { self.avail_features & (1u64 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM) != 0 } + #[tracing::instrument(level = "trace", skip(self))] pub fn stats_polling_interval_s(&self) -> u16 { self.stats_polling_interval_s } + #[tracing::instrument(level = "trace", skip(self))] /// Retrieve latest stats for the balloon device. pub fn latest_stats(&mut self) -> Option<&BalloonStats> { if self.stats_enabled() { @@ -534,6 +560,7 @@ impl Balloon { } } + #[tracing::instrument(level = "trace", skip(self))] /// Return the config of the balloon device. pub fn config(&self) -> BalloonConfig { BalloonConfig { @@ -543,52 +570,64 @@ impl Balloon { } } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn stats_enabled(&self) -> bool { self.stats_polling_interval_s > 0 } + #[tracing::instrument(level = "trace", skip(self, stats_desc_index))] pub(crate) fn set_stats_desc_index(&mut self, stats_desc_index: Option) { self.stats_desc_index = stats_desc_index; } } impl VirtioDevice for Balloon { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { self.avail_features } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, acked_features))] fn set_acked_features(&mut self, acked_features: u64) { self.acked_features = acked_features; } + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { TYPE_BALLOON } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_evts } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.irq_trigger.irq_evt } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { self.irq_trigger.irq_status.clone() } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn read_config(&self, offset: u64, mut data: &mut [u8]) { let config_space_bytes = self.config_space.as_slice(); let config_len = config_space_bytes.len() as u64; @@ -606,6 +645,7 @@ impl VirtioDevice for Balloon { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn write_config(&mut self, offset: u64, data: &[u8]) { let config_space_bytes = self.config_space.as_mut_slice(); let start = usize::try_from(offset).ok(); @@ -621,6 +661,7 @@ impl VirtioDevice for Balloon { dst.copy_from_slice(data); } + #[tracing::instrument(level = "trace", skip(self, mem))] fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> { self.device_state = DeviceState::Activated(mem); if self.activate_evt.write(1).is_err() { @@ -637,6 +678,7 @@ impl VirtioDevice for Balloon { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { self.device_state.is_activated() } @@ -659,18 +701,22 @@ pub(crate) mod tests { use crate::devices::virtio::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE}; impl Balloon { + #[tracing::instrument(level = "trace", skip(self, idx, q))] pub(crate) fn set_queue(&mut self, idx: usize, q: Queue) { self.queues[idx] = q; } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn actual_pages(&self) -> u32 { self.config_space.actual_pages } + #[tracing::instrument(level = "trace", skip(self, num_pages))] pub fn update_num_pages(&mut self, num_pages: u32) { self.config_space.num_pages = num_pages; } + #[tracing::instrument(level = "trace", skip(self, actual_pages))] pub fn update_actual_pages(&mut self, actual_pages: u32) { self.config_space.actual_pages = actual_pages; } diff --git a/src/vmm/src/devices/virtio/balloon/event_handler.rs b/src/vmm/src/devices/virtio/balloon/event_handler.rs index 869cf0eb657..ba2f54af2f3 100644 --- a/src/vmm/src/devices/virtio/balloon/event_handler.rs +++ b/src/vmm/src/devices/virtio/balloon/event_handler.rs @@ -4,7 +4,7 @@ use std::os::unix::io::AsRawFd; use event_manager::{EventOps, Events, MutEventSubscriber}; -use log::{error, warn}; +use logger::{error, warn}; use utils::epoll::EventSet; use crate::devices::report_balloon_event_fail; @@ -12,6 +12,7 @@ use crate::devices::virtio::balloon::device::Balloon; use crate::devices::virtio::{VirtioDevice, DEFLATE_INDEX, INFLATE_INDEX, STATS_INDEX}; impl Balloon { + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_runtime_events(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.queue_evts[INFLATE_INDEX], EventSet::IN)) { error!("Failed to register inflate queue event: {}", err); @@ -29,14 +30,16 @@ impl Balloon { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_activate_event(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.activate_evt, EventSet::IN)) { error!("Failed to register activate event: {}", err); } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn process_activate_event(&self, ops: &mut EventOps) { - log::debug!("balloon: activate event"); + logger::debug!("balloon: activate event"); if let Err(err) = self.activate_evt.read() { error!("Failed to consume balloon activate event: {:?}", err); } @@ -48,6 +51,7 @@ impl Balloon { } impl MutEventSubscriber for Balloon { + #[tracing::instrument(level = "trace", skip(self, event, ops))] fn process(&mut self, event: Events, ops: &mut EventOps) { let source = event.fd(); let event_set = event.event_set(); @@ -95,6 +99,7 @@ impl MutEventSubscriber for Balloon { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { // This function can be called during different points in the device lifetime: // - shortly after device creation, diff --git a/src/vmm/src/devices/virtio/balloon/persist.rs b/src/vmm/src/devices/virtio/balloon/persist.rs index 3402538b729..d484e00cd05 100644 --- a/src/vmm/src/devices/virtio/balloon/persist.rs +++ b/src/vmm/src/devices/virtio/balloon/persist.rs @@ -45,6 +45,7 @@ pub struct BalloonStatsState { } impl BalloonStatsState { + #[tracing::instrument(level = "trace", skip(stats))] fn from_stats(stats: &BalloonStats) -> Self { Self { swap_in: stats.swap_in, @@ -60,6 +61,7 @@ impl BalloonStatsState { } } + #[tracing::instrument(level = "trace", skip(self))] fn create_stats(&self) -> BalloonStats { BalloonStats { target_pages: 0, @@ -104,6 +106,7 @@ impl Persist<'_> for Balloon { type ConstructorArgs = BalloonConstructorArgs; type Error = super::BalloonError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { BalloonState { stats_polling_interval_s: self.stats_polling_interval_s, @@ -117,6 +120,7 @@ impl Persist<'_> for Balloon { } } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, diff --git a/src/vmm/src/devices/virtio/balloon/test_utils.rs b/src/vmm/src/devices/virtio/balloon/test_utils.rs index bce898e10f9..d865565a3bf 100644 --- a/src/vmm/src/devices/virtio/balloon/test_utils.rs +++ b/src/vmm/src/devices/virtio/balloon/test_utils.rs @@ -11,6 +11,7 @@ use crate::devices::virtio::{ balloon::BALLOON_NUM_QUEUES, Balloon, IrqType, DEFLATE_INDEX, INFLATE_INDEX, STATS_INDEX, }; +#[tracing::instrument(level = "trace", skip(b, queue_index))] #[cfg(test)] pub fn invoke_handler_for_queue_event(b: &mut Balloon, queue_index: usize) { assert!(queue_index < BALLOON_NUM_QUEUES); @@ -27,6 +28,7 @@ pub fn invoke_handler_for_queue_event(b: &mut Balloon, queue_index: usize) { assert!(b.irq_trigger.has_pending_irq(IrqType::Vring)); } +#[tracing::instrument(level = "trace", skip(queue, idx, addr, len, flags))] pub fn set_request(queue: &VirtQueue, idx: usize, addr: u64, len: u32, flags: u16) { // Set the index of the next request. queue.avail.idx.set((idx + 1) as u16); @@ -36,6 +38,7 @@ pub fn set_request(queue: &VirtQueue, idx: usize, addr: u64, len: u32, flags: u1 queue.dtable[idx].set(addr, len, flags, 1); } +#[tracing::instrument(level = "trace", skip(queue, idx))] pub fn check_request_completion(queue: &VirtQueue, idx: usize) { // Check that the next used will be idx + 1. assert_eq!(queue.used.idx.get(), (idx + 1) as u16); diff --git a/src/vmm/src/devices/virtio/balloon/util.rs b/src/vmm/src/devices/virtio/balloon/util.rs index 490c9960af8..ab68ea6e4ba 100644 --- a/src/vmm/src/devices/virtio/balloon/util.rs +++ b/src/vmm/src/devices/virtio/balloon/util.rs @@ -7,6 +7,7 @@ use utils::vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRe use super::{RemoveRegionError, MAX_PAGE_COMPACT_BUFFER}; +#[tracing::instrument(level = "trace", skip(v))] /// This takes a vector of page frame numbers, and compacts them /// into ranges of consecutive pages. The result is a vector /// of (start_page_frame_number, range_length) pairs. @@ -35,7 +36,7 @@ pub(crate) fn compact_page_frame_numbers(v: &mut [u32]) -> Vec<(u32, u32)> { // Skip duplicate pages. This will ensure we only consider // distinct PFNs. if page_frame_number == v[pfn_index - 1] { - log::error!("Skipping duplicate PFN {}.", page_frame_number); + logger::error!("Skipping duplicate PFN {}.", page_frame_number); continue; } @@ -64,6 +65,7 @@ pub(crate) fn compact_page_frame_numbers(v: &mut [u32]) -> Vec<(u32, u32)> { result } +#[tracing::instrument(level = "trace", skip(guest_memory, range, restored))] pub(crate) fn remove_range( guest_memory: &GuestMemoryMmap, range: (GuestAddress, u64), @@ -264,6 +266,7 @@ mod tests { use crate::devices::virtio::test_utils::single_region_mem; + #[tracing::instrument(level = "trace", skip())] #[allow(clippy::let_with_type_underscore)] fn random_pfn_u32_max() -> impl Strategy> { // Create a randomly sized vec (max MAX_PAGE_COMPACT_BUFFER elements) filled with random u32 @@ -271,6 +274,7 @@ mod tests { prop::collection::vec(0..std::u32::MAX, 0..MAX_PAGE_COMPACT_BUFFER) } + #[tracing::instrument(level = "trace", skip())] #[allow(clippy::let_with_type_underscore)] fn random_pfn_100() -> impl Strategy> { // Create a randomly sized vec (max MAX_PAGE_COMPACT_BUFFER/8) filled with random u32 @@ -280,6 +284,7 @@ mod tests { // The uncompactor will output deduplicated and sorted elements as compaction algorithm // guarantees it. + #[tracing::instrument(level = "trace", skip(compacted))] fn uncompact(compacted: Vec<(u32, u32)>) -> Vec { let mut result = Vec::new(); for (start, len) in compacted { @@ -288,6 +293,7 @@ mod tests { result } + #[tracing::instrument(level = "trace", skip(v))] fn sort_and_dedup(v: &[T]) -> Vec { let mut sorted_v = v.to_vec(); sorted_v.sort_unstable(); diff --git a/src/vmm/src/devices/virtio/block/device.rs b/src/vmm/src/devices/virtio/block/device.rs index 13370b50731..47979ac38b6 100644 --- a/src/vmm/src/devices/virtio/block/device.rs +++ b/src/vmm/src/devices/virtio/block/device.rs @@ -58,12 +58,14 @@ pub enum FileEngineType { } impl Default for FileEngineType { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self::Sync } } impl FileEngineType { + #[tracing::instrument(level = "trace", skip(self))] /// Whether the Async engine is supported on the current host kernel. pub fn is_supported(&self) -> Result { match self { @@ -84,6 +86,10 @@ pub(crate) struct DiskProperties { } impl DiskProperties { + #[tracing::instrument( + level = "trace", + skip(disk_image_path, is_disk_read_only, cache_type, file_engine_type) + )] pub fn new( disk_image_path: String, is_disk_read_only: bool, @@ -119,27 +125,33 @@ impl DiskProperties { }) } + #[tracing::instrument(level = "trace", skip(self))] pub fn file_engine(&self) -> &FileEngine { &self.file_engine } + #[tracing::instrument(level = "trace", skip(self))] pub fn file_engine_mut(&mut self) -> &mut FileEngine { &mut self.file_engine } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(test)] pub fn file(&self) -> &File { self.file_engine.file() } + #[tracing::instrument(level = "trace", skip(self))] pub fn nsectors(&self) -> u64 { self.nsectors } + #[tracing::instrument(level = "trace", skip(self))] pub fn image_id(&self) -> &[u8] { &self.image_id } + #[tracing::instrument(level = "trace", skip(disk_file))] fn build_device_id(disk_file: &File) -> Result { let blk_metadata = disk_file.metadata().map_err(BlockError::GetFileMetadata)?; // This is how kvmtool does it. @@ -152,6 +164,7 @@ impl DiskProperties { Ok(device_id) } + #[tracing::instrument(level = "trace", skip(disk_file))] fn build_disk_image_id(disk_file: &File) -> [u8; VIRTIO_BLK_ID_BYTES as usize] { let mut default_id = [0; VIRTIO_BLK_ID_BYTES as usize]; match Self::build_device_id(disk_file) { @@ -169,11 +182,13 @@ impl DiskProperties { default_id } + #[tracing::instrument(level = "trace", skip(self))] /// Backing file path. pub fn file_path(&self) -> &String { &self.file_path } + #[tracing::instrument(level = "trace", skip(self))] /// Provides vec containing the virtio block configuration space /// buffer. The config space is populated with the disk size based /// on the backing file size. @@ -186,6 +201,7 @@ impl DiskProperties { config } + #[tracing::instrument(level = "trace", skip(self))] pub fn cache_type(&self) -> CacheType { self.cache_type } @@ -230,6 +246,19 @@ macro_rules! unwrap_async_file_engine_or_return { } impl Block { + #[tracing::instrument( + level = "trace", + skip( + id, + partuuid, + cache_type, + disk_image_path, + is_disk_read_only, + is_disk_root, + rate_limiter, + file_engine_type + ) + )] /// Create a new virtio block device that operates on the given file. /// /// The given file must be seekable and sizable. @@ -283,6 +312,7 @@ impl Block { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Process a single event in the VirtIO queue. /// /// This function is called by the event manager when the guest notifies us @@ -301,11 +331,13 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self))] /// Process device virtio queue(s). pub fn process_virtio_queues(&mut self) { self.process_queue(0); } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_rate_limiter_event(&mut self) { METRICS.block.rate_limiter_event_count.inc(); // Upon rate limiter event, call the rate limiter handler @@ -315,6 +347,7 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(queue, index, len, mem, irq_trigger))] fn add_used_descriptor( queue: &mut Queue, index: u16, @@ -333,6 +366,7 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self, queue_index))] /// Device specific function for peaking inside a queue and processing descriptors. pub fn process_queue(&mut self, queue_index: usize) { // This is safe since we checked in the event handler that the device is activated. @@ -395,6 +429,7 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self))] fn process_async_completion_queue(&mut self) { let engine = unwrap_async_file_engine_or_return!(&mut self.disk.file_engine); @@ -436,6 +471,7 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn process_async_completion_event(&mut self) { let engine = unwrap_async_file_engine_or_return!(&mut self.disk.file_engine); @@ -451,6 +487,7 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self, disk_image_path))] /// Update the backing file and the config space of the block device. pub fn update_disk_image(&mut self, disk_image_path: String) -> Result<(), BlockError> { let disk_properties = DiskProperties::new( @@ -469,46 +506,55 @@ impl Block { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, bytes, ops))] /// Updates the parameters for the rate limiter pub fn update_rate_limiter(&mut self, bytes: BucketUpdate, ops: BucketUpdate) { self.rate_limiter.update_buckets(bytes, ops); } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the ID of this block device. pub fn id(&self) -> &String { &self.id } + #[tracing::instrument(level = "trace", skip(self))] /// Provides backing file path of this block device. pub fn file_path(&self) -> &String { self.disk.file_path() } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the PARTUUID of this block device. pub fn partuuid(&self) -> Option<&String> { self.partuuid.as_ref() } + #[tracing::instrument(level = "trace", skip(self))] /// Specifies if this block device is read only. pub fn is_read_only(&self) -> bool { self.avail_features & (1u64 << VIRTIO_BLK_F_RO) != 0 } + #[tracing::instrument(level = "trace", skip(self))] /// Specifies if this block device is read only. pub fn is_root_device(&self) -> bool { self.root_device } + #[tracing::instrument(level = "trace", skip(self))] /// Specifies block device cache type. pub fn cache_type(&self) -> CacheType { self.disk.cache_type() } + #[tracing::instrument(level = "trace", skip(self))] /// Provides non-mutable reference to this device's rate limiter. pub fn rate_limiter(&self) -> &RateLimiter { &self.rate_limiter } + #[tracing::instrument(level = "trace", skip(self))] /// Retrieve the file engine type. pub fn file_engine_type(&self) -> FileEngineType { match self.disk.file_engine() { @@ -517,12 +563,14 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self, discard))] fn drain_and_flush(&mut self, discard: bool) { if let Err(err) = self.disk.file_engine_mut().drain_and_flush(discard) { error!("Failed to drain ops and flush block data: {:?}", err); } } + #[tracing::instrument(level = "trace", skip(self))] /// Prepare device for being snapshotted. pub fn prepare_save(&mut self) { if !self.is_activated() { @@ -537,43 +585,53 @@ impl Block { } impl VirtioDevice for Block { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { self.avail_features } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, acked_features))] fn set_acked_features(&mut self, acked_features: u64) { self.acked_features = acked_features; } + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { TYPE_BLOCK } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_evts } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.irq_trigger.irq_evt } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the current device interrupt status. fn interrupt_status(&self) -> Arc { self.irq_trigger.irq_status.clone() } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn read_config(&self, offset: u64, mut data: &mut [u8]) { let config_len = self.config_space.len() as u64; if offset >= config_len { @@ -588,6 +646,7 @@ impl VirtioDevice for Block { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn write_config(&mut self, offset: u64, data: &[u8]) { let start = usize::try_from(offset).ok(); let end = start.and_then(|s| s.checked_add(data.len())); @@ -603,6 +662,7 @@ impl VirtioDevice for Block { dst.copy_from_slice(data); } + #[tracing::instrument(level = "trace", skip(self, mem))] fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> { let event_idx = self.has_feature(u64::from(VIRTIO_RING_F_EVENT_IDX)); if event_idx { @@ -619,12 +679,14 @@ impl VirtioDevice for Block { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { self.device_state.is_activated() } } impl Drop for Block { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { match self.disk.cache_type { CacheType::Unsafe => { @@ -1377,6 +1439,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(block, vq, count))] fn add_flush_requests_batch(block: &mut Block, vq: &VirtQueue, count: u16) { let mem = vq.memory(); vq.avail.idx.set(0); @@ -1416,6 +1479,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(count, vq))] fn check_flush_requests_batch(count: u16, vq: &VirtQueue) { let used_idx = vq.used.idx.get(); assert_eq!(used_idx, count); diff --git a/src/vmm/src/devices/virtio/block/event_handler.rs b/src/vmm/src/devices/virtio/block/event_handler.rs index a766471bf9f..1be525f38e3 100644 --- a/src/vmm/src/devices/virtio/block/event_handler.rs +++ b/src/vmm/src/devices/virtio/block/event_handler.rs @@ -3,7 +3,7 @@ use std::os::unix::io::AsRawFd; use event_manager::{EventOps, Events, MutEventSubscriber}; -use log::{error, warn}; +use logger::{error, warn}; use utils::epoll::EventSet; use super::io::FileEngine; @@ -11,6 +11,7 @@ use crate::devices::virtio::block::device::Block; use crate::devices::virtio::VirtioDevice; impl Block { + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_runtime_events(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.queue_evts[0], EventSet::IN)) { error!("Failed to register queue event: {}", err); @@ -25,14 +26,16 @@ impl Block { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_activate_event(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.activate_evt, EventSet::IN)) { error!("Failed to register activate event: {}", err); } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn process_activate_event(&self, ops: &mut EventOps) { - log::debug!("block: activate event"); + logger::debug!("block: activate event"); if let Err(err) = self.activate_evt.read() { error!("Failed to consume block activate event: {:?}", err); } @@ -45,6 +48,7 @@ impl Block { impl MutEventSubscriber for Block { // Handle an event for queue or rate limiter. + #[tracing::instrument(level = "trace", skip(self, event, ops))] fn process(&mut self, event: Events, ops: &mut EventOps) { let source = event.fd(); let event_set = event.event_set(); @@ -85,6 +89,7 @@ impl MutEventSubscriber for Block { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { // This function can be called during different points in the device lifetime: // - shortly after device creation, diff --git a/src/vmm/src/devices/virtio/block/io/async_io.rs b/src/vmm/src/devices/virtio/block/io/async_io.rs index 189e145c6e2..cb56456db34 100644 --- a/src/vmm/src/devices/virtio/block/io/async_io.rs +++ b/src/vmm/src/devices/virtio/block/io/async_io.rs @@ -41,6 +41,7 @@ pub struct WrappedUserData { } impl WrappedUserData { + #[tracing::instrument(level = "trace", skip(user_data))] fn new(user_data: T) -> Self { WrappedUserData { addr: None, @@ -48,6 +49,7 @@ impl WrappedUserData { } } + #[tracing::instrument(level = "trace", skip(addr, user_data))] fn new_with_dirty_tracking(addr: GuestAddress, user_data: T) -> Self { WrappedUserData { addr: Some(addr), @@ -55,6 +57,7 @@ impl WrappedUserData { } } + #[tracing::instrument(level = "trace", skip(self, mem, count))] fn mark_dirty_mem_and_unwrap(self, mem: &GuestMemoryMmap, count: u32) -> T { if let Some(addr) = self.addr { mark_dirty_mem(mem, addr, count as usize) @@ -65,6 +68,7 @@ impl WrappedUserData { } impl AsyncFileEngine { + #[tracing::instrument(level = "trace", skip(file))] pub fn from_file(file: File) -> Result, AsyncIoError> { log_dev_preview_warning("Async file IO", Option::None); @@ -92,15 +96,18 @@ impl AsyncFileEngine { }) } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(test)] pub fn file(&self) -> &File { &self.file } + #[tracing::instrument(level = "trace", skip(self))] pub fn completion_evt(&self) -> &EventFd { &self.completion_evt } + #[tracing::instrument(level = "trace", skip(self, offset, mem, addr, count, user_data))] pub fn push_read( &mut self, offset: u64, @@ -138,6 +145,7 @@ impl AsyncFileEngine { }) } + #[tracing::instrument(level = "trace", skip(self, offset, mem, addr, count, user_data))] pub fn push_write( &mut self, offset: u64, @@ -175,6 +183,7 @@ impl AsyncFileEngine { }) } + #[tracing::instrument(level = "trace", skip(self, user_data))] pub fn push_flush(&mut self, user_data: T) -> Result<(), UserDataError> { let wrapped_user_data = WrappedUserData::new(user_data); @@ -188,6 +197,7 @@ impl AsyncFileEngine { }) } + #[tracing::instrument(level = "trace", skip(self))] pub fn kick_submission_queue(&mut self) -> Result<(), AsyncIoError> { self.ring .submit() @@ -195,6 +205,7 @@ impl AsyncFileEngine { .map_err(AsyncIoError::IoUring) } + #[tracing::instrument(level = "trace", skip(self, discard_cqes))] pub fn drain(&mut self, discard_cqes: bool) -> Result<(), AsyncIoError> { self.ring .submit_and_wait_all() @@ -209,6 +220,7 @@ impl AsyncFileEngine { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, discard_cqes))] pub fn drain_and_flush(&mut self, discard_cqes: bool) -> Result<(), AsyncIoError> { self.drain(discard_cqes)?; @@ -220,6 +232,7 @@ impl AsyncFileEngine { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn do_pop(&mut self) -> Result>>, AsyncIoError> { // SAFETY: We trust that the host kernel did not touch the operation's `user_data` field. // The `T` type is the same one used for `push`ing and since the kernel made this entry @@ -228,6 +241,7 @@ impl AsyncFileEngine { unsafe { self.ring.pop::>() }.map_err(AsyncIoError::IoUring) } + #[tracing::instrument(level = "trace", skip(self, mem))] pub fn pop(&mut self, mem: &GuestMemoryMmap) -> Result>, AsyncIoError> { let cqe = self.do_pop()?.map(|cqe| { let count = cqe.count(); diff --git a/src/vmm/src/devices/virtio/block/io/mod.rs b/src/vmm/src/devices/virtio/block/io/mod.rs index 3746c97918c..dc3153290e5 100644 --- a/src/vmm/src/devices/virtio/block/io/mod.rs +++ b/src/vmm/src/devices/virtio/block/io/mod.rs @@ -34,6 +34,7 @@ pub enum BlockIoError { } impl BlockIoError { + #[tracing::instrument(level = "trace", skip(self))] pub fn is_throttling_err(&self) -> bool { match self { BlockIoError::Async(AsyncIoError::IoUring(err)) => err.is_throttling_err(), @@ -57,6 +58,7 @@ pub enum FileEngine { } impl FileEngine { + #[tracing::instrument(level = "trace", skip(file, engine_type))] pub fn from_file( file: File, engine_type: FileEngineType, @@ -75,6 +77,7 @@ impl FileEngine { } } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(test)] pub fn file(&self) -> &File { match self { @@ -83,6 +86,7 @@ impl FileEngine { } } + #[tracing::instrument(level = "trace", skip(self, offset, mem, addr, count, user_data))] pub fn read( &mut self, offset: u64, @@ -111,6 +115,7 @@ impl FileEngine { } } + #[tracing::instrument(level = "trace", skip(self, offset, mem, addr, count, user_data))] pub fn write( &mut self, offset: u64, @@ -139,6 +144,7 @@ impl FileEngine { } } + #[tracing::instrument(level = "trace", skip(self, user_data))] pub fn flush( &mut self, user_data: T, @@ -164,6 +170,7 @@ impl FileEngine { } } + #[tracing::instrument(level = "trace", skip(self, discard))] pub fn drain(&mut self, discard: bool) -> Result<(), BlockIoError> { match self { FileEngine::Async(engine) => engine.drain(discard).map_err(BlockIoError::Async), @@ -171,6 +178,7 @@ impl FileEngine { } } + #[tracing::instrument(level = "trace", skip(self, discard))] pub fn drain_and_flush(&mut self, discard: bool) -> Result<(), BlockIoError> { match self { FileEngine::Async(engine) => { @@ -236,6 +244,7 @@ pub mod tests { }; } + #[tracing::instrument(level = "trace", skip(mem, engine, count))] fn assert_async_execution(mem: &GuestMemoryMmap, engine: &mut FileEngine<()>, count: u32) { if let FileEngine::Async(ref mut engine) = engine { engine.drain(false).unwrap(); @@ -243,11 +252,13 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn create_mem() -> GuestMemoryMmap { utils::vm_memory::test_utils::create_anon_guest_memory(&[(GuestAddress(0), MEM_LEN)], true) .unwrap() } + #[tracing::instrument(level = "trace", skip(mem, addr, len))] fn check_dirty_mem(mem: &GuestMemoryMmap, addr: GuestAddress, len: u32) { let bitmap = mem.find_region(addr).unwrap().bitmap().as_ref().unwrap(); for offset in addr.0..addr.0 + u64::from(len) { @@ -255,6 +266,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(mem, addr, len))] fn check_clean_mem(mem: &GuestMemoryMmap, addr: GuestAddress, len: u32) { let bitmap = mem.find_region(addr).unwrap().bitmap().as_ref().unwrap(); for offset in addr.0..addr.0 + u64::from(len) { diff --git a/src/vmm/src/devices/virtio/block/io/sync_io.rs b/src/vmm/src/devices/virtio/block/io/sync_io.rs index d8aa29b3f9b..d24c848894b 100644 --- a/src/vmm/src/devices/virtio/block/io/sync_io.rs +++ b/src/vmm/src/devices/virtio/block/io/sync_io.rs @@ -25,15 +25,18 @@ pub struct SyncFileEngine { unsafe impl Send for SyncFileEngine {} impl SyncFileEngine { + #[tracing::instrument(level = "trace", skip(file))] pub fn from_file(file: File) -> SyncFileEngine { SyncFileEngine { file } } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(test)] pub fn file(&self) -> &File { &self.file } + #[tracing::instrument(level = "trace", skip(self, offset, mem, addr, count))] pub fn read( &mut self, offset: u64, @@ -50,6 +53,7 @@ impl SyncFileEngine { Ok(count) } + #[tracing::instrument(level = "trace", skip(self, offset, mem, addr, count))] pub fn write( &mut self, offset: u64, @@ -66,6 +70,7 @@ impl SyncFileEngine { Ok(count) } + #[tracing::instrument(level = "trace", skip(self))] pub fn flush(&mut self) -> Result<(), SyncIoError> { // flush() first to force any cached data out of rust buffers. self.file.flush().map_err(SyncIoError::Flush)?; diff --git a/src/vmm/src/devices/virtio/block/persist.rs b/src/vmm/src/devices/virtio/block/persist.rs index 5733c762880..a2df1986cf2 100644 --- a/src/vmm/src/devices/virtio/block/persist.rs +++ b/src/vmm/src/devices/virtio/block/persist.rs @@ -34,6 +34,7 @@ pub enum CacheTypeState { } impl From for CacheTypeState { + #[tracing::instrument(level = "trace", skip(cache_type))] fn from(cache_type: CacheType) -> Self { match cache_type { CacheType::Unsafe => CacheTypeState::Unsafe, @@ -43,6 +44,7 @@ impl From for CacheTypeState { } impl From for CacheType { + #[tracing::instrument(level = "trace", skip(cache_type_state))] fn from(cache_type_state: CacheTypeState) -> Self { match cache_type_state { CacheTypeState::Unsafe => CacheType::Unsafe, @@ -65,6 +67,7 @@ pub enum FileEngineTypeState { } impl From for FileEngineTypeState { + #[tracing::instrument(level = "trace", skip(file_engine_type))] fn from(file_engine_type: FileEngineType) -> Self { match file_engine_type { FileEngineType::Sync => FileEngineTypeState::Sync, @@ -74,6 +77,7 @@ impl From for FileEngineTypeState { } impl From for FileEngineType { + #[tracing::instrument(level = "trace", skip(file_engine_type_state))] fn from(file_engine_type_state: FileEngineTypeState) -> Self { match file_engine_type_state { FileEngineTypeState::Sync => FileEngineType::Sync, @@ -106,6 +110,7 @@ pub struct BlockState { } impl BlockState { + #[tracing::instrument(level = "trace", skip(self, target_version))] fn block_cache_type_ser(&mut self, target_version: u16) -> VersionizeResult<()> { if target_version < 3 && self.cache_type != CacheTypeState::Unsafe { warn!( @@ -117,6 +122,7 @@ impl BlockState { Ok(()) } + #[tracing::instrument(level = "trace", skip(_source_version))] fn default_cache_type_flush(_source_version: u16) -> CacheTypeState { CacheTypeState::Unsafe } @@ -134,6 +140,7 @@ impl Persist<'_> for Block { type ConstructorArgs = BlockConstructorArgs; type Error = BlockError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { // Save device state. BlockState { @@ -148,6 +155,7 @@ impl Persist<'_> for Block { } } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, diff --git a/src/vmm/src/devices/virtio/block/request.rs b/src/vmm/src/devices/virtio/block/request.rs index 170ee6b5536..c90e5f449e4 100644 --- a/src/vmm/src/devices/virtio/block/request.rs +++ b/src/vmm/src/devices/virtio/block/request.rs @@ -37,6 +37,7 @@ pub enum RequestType { } impl From for RequestType { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: u32) -> Self { match value { VIRTIO_BLK_T_IN => RequestType::In, @@ -69,6 +70,7 @@ enum Status { } impl Status { + #[tracing::instrument(level = "trace", skip(data_len, transferred_data_len, data_to_mem))] fn from_data(data_len: u32, transferred_data_len: u32, data_to_mem: bool) -> Status { let num_bytes_to_mem = match data_to_mem { true => transferred_data_len, @@ -97,6 +99,7 @@ pub struct PendingRequest { } impl PendingRequest { + #[tracing::instrument(level = "trace", skip(self, status, mem))] fn write_status_and_finish(self, status: &Status, mem: &GuestMemoryMmap) -> FinishedRequest { let (num_bytes_to_mem, status_code) = match status { Status::Ok { num_bytes_to_mem } => (*num_bytes_to_mem, VIRTIO_BLK_S_OK), @@ -136,6 +139,7 @@ impl PendingRequest { } } + #[tracing::instrument(level = "trace", skip(self, mem, res))] pub fn finish(self, mem: &GuestMemoryMmap, res: Result) -> FinishedRequest { let status = match (res, self.r#type) { (Ok(transferred_data_len), RequestType::In) => { @@ -195,6 +199,7 @@ pub struct RequestHeader { unsafe impl ByteValued for RequestHeader {} impl RequestHeader { + #[tracing::instrument(level = "trace", skip(request_type, sector))] pub fn new(request_type: u32, sector: u64) -> RequestHeader { RequestHeader { request_type, @@ -202,6 +207,7 @@ impl RequestHeader { sector, } } + #[tracing::instrument(level = "trace", skip(memory, addr))] /// Reads the request header from GuestMemoryMmap starting at `addr`. /// /// Virtio 1.0 specifies that the data is transmitted by the driver in little-endian @@ -227,6 +233,7 @@ pub struct Request { } impl Request { + #[tracing::instrument(level = "trace", skip(avail_desc, mem, num_disk_sectors))] pub fn parse( avail_desc: &DescriptorChain, mem: &GuestMemoryMmap, @@ -316,6 +323,7 @@ impl Request { Ok(req) } + #[tracing::instrument(level = "trace", skip(self, rate_limiter))] pub(crate) fn rate_limit(&self, rate_limiter: &mut RateLimiter) -> bool { // If limiter.consume() fails it means there is no more TokenType::Ops // budget and rate limiting is in effect. @@ -336,10 +344,12 @@ impl Request { false } + #[tracing::instrument(level = "trace", skip(self))] fn offset(&self) -> u64 { self.sector << SECTOR_SHIFT } + #[tracing::instrument(level = "trace", skip(self, desc_idx))] fn to_pending_request(&self, desc_idx: u16) -> PendingRequest { PendingRequest { r#type: self.r#type, @@ -349,6 +359,7 @@ impl Request { } } + #[tracing::instrument(level = "trace", skip(self, disk, desc_idx, mem))] pub(crate) fn process( self, disk: &mut DiskProperties, @@ -457,6 +468,7 @@ mod tests { } impl<'a, 'b> RequestDescriptorChain<'a, 'b> { + #[tracing::instrument(level = "trace", skip(self, _e))] fn check_parse_err(&self, _e: BlockError) { let mut q = self.driver_queue.create_queue(); let memory = self.driver_queue.memory(); @@ -467,6 +479,7 @@ mod tests { )); } + #[tracing::instrument(level = "trace", skip(self, check_data))] fn check_parse(&self, check_data: bool) { let mut q = self.driver_queue.create_queue(); let memory = self.driver_queue.memory(); @@ -680,6 +693,7 @@ mod tests { ), )>; + #[tracing::instrument(level = "trace", skip())] fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { // All strategies have the same weight, there is no reson currently to skew // the rations to increase the odds of a specific request type. @@ -702,6 +716,7 @@ mod tests { } impl From for u32 { + #[tracing::instrument(level = "trace", skip(request_type))] fn from(request_type: RequestType) -> u32 { match request_type { RequestType::In => VIRTIO_BLK_T_IN, @@ -714,6 +729,7 @@ mod tests { } // Returns flags based on the request type. + #[tracing::instrument(level = "trace", skip(request_type))] fn request_type_flags(request_type: RequestType) -> u16 { match request_type { RequestType::In => VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE, @@ -724,6 +740,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] #[allow(clippy::let_with_type_underscore)] fn random_request_parse( ) -> impl Strategy, GuestMemoryMmap, Queue)> { @@ -763,6 +780,10 @@ mod tests { ) } + #[tracing::instrument( + level = "trace", + skip(sparsity, data_len, sector, request_type, virtio_request_id, coins_arr) + )] fn do_random_request_parse( sparsity: u64, data_len: u32, diff --git a/src/vmm/src/devices/virtio/block/test_utils.rs b/src/vmm/src/devices/virtio/block/test_utils.rs index 4e76d793bee..78189a89b1d 100644 --- a/src/vmm/src/devices/virtio/block/test_utils.rs +++ b/src/vmm/src/devices/virtio/block/test_utils.rs @@ -22,6 +22,7 @@ use crate::devices::virtio::IrqType; use crate::devices::virtio::{Block, CacheType, Queue, RequestHeader}; use crate::rate_limiter::RateLimiter; +#[tracing::instrument(level = "trace", skip(file_engine_type))] /// Create a default Block instance to be used in tests. pub fn default_block(file_engine_type: FileEngineType) -> Block { // Create backing file. @@ -31,6 +32,7 @@ pub fn default_block(file_engine_type: FileEngineType) -> Block { default_block_with_path(f.as_path().to_str().unwrap().to_string(), file_engine_type) } +#[tracing::instrument(level = "trace", skip())] /// Return the Async FileEngineType if supported by the host, otherwise default to Sync. pub fn default_engine_type_for_kv() -> FileEngineType { if KernelVersion::get().unwrap() >= min_kernel_version_for_io_uring() { @@ -40,6 +42,7 @@ pub fn default_engine_type_for_kv() -> FileEngineType { } } +#[tracing::instrument(level = "trace", skip(path, file_engine_type))] /// Create a default Block instance using file at the specified path to be used in tests. pub fn default_block_with_path(path: String, file_engine_type: FileEngineType) -> Block { // Rate limiting is enabled but with a high operation rate (10 million ops/s). @@ -60,18 +63,22 @@ pub fn default_block_with_path(path: String, file_engine_type: FileEngineType) - .unwrap() } +#[tracing::instrument(level = "trace", skip(blk, idx, q))] pub fn set_queue(blk: &mut Block, idx: usize, q: Queue) { blk.queues[idx] = q; } +#[tracing::instrument(level = "trace", skip(blk, rl))] pub fn set_rate_limiter(blk: &mut Block, rl: RateLimiter) { blk.rate_limiter = rl; } +#[tracing::instrument(level = "trace", skip(blk))] pub fn rate_limiter(blk: &mut Block) -> &RateLimiter { &blk.rate_limiter } +#[tracing::instrument(level = "trace", skip(b, maybe_expected_irq))] #[cfg(test)] pub fn simulate_queue_event(b: &mut Block, maybe_expected_irq: Option) { // Trigger the queue event. @@ -84,6 +91,7 @@ pub fn simulate_queue_event(b: &mut Block, maybe_expected_irq: Option) { } } +#[tracing::instrument(level = "trace", skip(b, expected_irq))] #[cfg(test)] pub fn simulate_async_completion_event(b: &mut Block, expected_irq: bool) { if let FileEngine::Async(engine) = b.disk.file_engine_mut() { @@ -99,6 +107,7 @@ pub fn simulate_async_completion_event(b: &mut Block, expected_irq: bool) { assert_eq!(b.irq_trigger.has_pending_irq(IrqType::Vring), expected_irq); } +#[tracing::instrument(level = "trace", skip(b, expected_irq))] #[cfg(test)] pub fn simulate_queue_and_async_completion_events(b: &mut Block, expected_irq: bool) { match b.disk.file_engine_mut() { @@ -123,6 +132,7 @@ pub struct RequestDescriptorChain<'a, 'b> { } impl<'a, 'b> RequestDescriptorChain<'a, 'b> { + #[tracing::instrument(level = "trace", skip(vq))] /// Creates a new [`RequestDescriptor´] chain in the given [`VirtQueue`] /// /// The header, data and status descriptors are put into the first three indices in @@ -141,6 +151,7 @@ impl<'a, 'b> RequestDescriptorChain<'a, 'b> { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn header(&self) -> RequestHeader { self.header_desc .memory() @@ -148,6 +159,7 @@ impl<'a, 'b> RequestDescriptorChain<'a, 'b> { .unwrap() } + #[tracing::instrument(level = "trace", skip(self, header))] pub fn set_header(&self, header: RequestHeader) { self.header_desc .memory() @@ -156,6 +168,7 @@ impl<'a, 'b> RequestDescriptorChain<'a, 'b> { } } +#[tracing::instrument(level = "trace", skip(vq))] /// Puts a descriptor chain of length three into the given [`VirtQueue`]. /// /// This chain follows the skeleton of a block device request, e.g. the first diff --git a/src/vmm/src/devices/virtio/device.rs b/src/vmm/src/devices/virtio/device.rs index 2b68df2530f..dd2e0d72bc0 100644 --- a/src/vmm/src/devices/virtio/device.rs +++ b/src/vmm/src/devices/virtio/device.rs @@ -9,7 +9,7 @@ use std::fmt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use log::warn; +use logger::warn; use utils::eventfd::EventFd; use utils::vm_memory::GuestMemoryMmap; @@ -25,6 +25,7 @@ pub enum DeviceState { } impl DeviceState { + #[tracing::instrument(level = "trace", skip(self))] /// Checks if the device is activated. pub fn is_activated(&self) -> bool { match self { @@ -33,6 +34,7 @@ impl DeviceState { } } + #[tracing::instrument(level = "trace", skip(self))] /// Gets the memory attached to the device if it is activated. pub fn mem(&self) -> Option<&GuestMemoryMmap> { match self { @@ -59,6 +61,7 @@ pub struct IrqTrigger { } impl IrqTrigger { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> std::io::Result { Ok(Self { irq_status: Arc::new(AtomicUsize::new(0)), @@ -66,6 +69,7 @@ impl IrqTrigger { }) } + #[tracing::instrument(level = "trace", skip(self, irq_type))] pub fn trigger_irq(&self, irq_type: IrqType) -> Result<(), std::io::Error> { let irq = match irq_type { IrqType::Config => VIRTIO_MMIO_INT_CONFIG, @@ -74,7 +78,7 @@ impl IrqTrigger { self.irq_status.fetch_or(irq as usize, Ordering::SeqCst); self.irq_evt.write(1).map_err(|err| { - log::error!("Failed to send irq to the guest: {:?}", err); + logger::error!("Failed to send irq to the guest: {:?}", err); err })?; @@ -180,6 +184,7 @@ pub trait VirtioDevice: AsAny + Send { } impl fmt::Debug for dyn VirtioDevice { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VirtioDevice type {}", self.device_type()) } @@ -190,6 +195,7 @@ pub(crate) mod tests { use super::*; impl IrqTrigger { + #[tracing::instrument(level = "trace", skip(self, irq_type))] pub fn has_pending_irq(&self, irq_type: IrqType) -> bool { if let Ok(num_irqs) = self.irq_evt.read() { if num_irqs == 0 { @@ -236,54 +242,67 @@ pub(crate) mod tests { } impl VirtioDevice for MockVirtioDevice { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, _acked_features))] fn set_acked_features(&mut self, _acked_features: u64) { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { todo!() } + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] fn read_config(&self, _offset: u64, _data: &mut [u8]) { todo!() } + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] fn write_config(&mut self, _offset: u64, _data: &[u8]) { todo!() } + #[tracing::instrument(level = "trace", skip(self, _mem))] fn activate(&mut self, _mem: GuestMemoryMmap) -> Result<(), ActivateError> { todo!() } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { todo!() } diff --git a/src/vmm/src/devices/virtio/iovec.rs b/src/vmm/src/devices/virtio/iovec.rs index 8065c027de8..114f57ee17e 100644 --- a/src/vmm/src/devices/virtio/iovec.rs +++ b/src/vmm/src/devices/virtio/iovec.rs @@ -50,6 +50,7 @@ impl<'a> IovVecSubregion<'a> { // // If the sub-region is within the range of the buffer, i.e. the offset is not past the end of // the buffer, it will return an `IovVecSubregion`. + #[tracing::instrument(level = "trace", skip(iovecs, len, offset, size))] fn new(iovecs: &'a [iovec], len: usize, mut offset: usize, mut size: usize) -> Option { // Out-of-bounds sub-region if offset >= len { @@ -92,6 +93,7 @@ impl<'a> IovVecSubregion<'a> { }) } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(test)] fn len(&self) -> usize { self.iovecs.iter().fold(0, |acc, iov| acc + iov.iov_len) @@ -103,6 +105,7 @@ impl<'a> IntoIterator for IovVecSubregion<'a> { type IntoIter = std::vec::IntoIter; + #[tracing::instrument(level = "trace", skip(self))] fn into_iter(self) -> Self::IntoIter { self.iovecs.into_iter() } @@ -122,6 +125,7 @@ pub(crate) struct IoVecBuffer { } impl IoVecBuffer { + #[tracing::instrument(level = "trace", skip(mem, head))] /// Create an `IoVecBuffer` from a `DescriptorChain` pub fn from_descriptor_chain( mem: &GuestMemoryMmap, @@ -155,26 +159,31 @@ impl IoVecBuffer { Ok(Self { vecs, len }) } + #[tracing::instrument(level = "trace", skip(self))] /// Get the total length of the memory regions covered by this `IoVecBuffer` pub fn len(&self) -> usize { self.len } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a pointer to the memory keeping the `iovec` structs pub fn as_iovec_ptr(&self) -> *const iovec { self.vecs.as_ptr() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the length of the `iovec` array. pub fn iovec_count(&self) -> usize { self.vecs.len() } + #[tracing::instrument(level = "trace", skip(self, offset, size))] /// Get a sub-region of the buffer fn sub_region(&self, offset: usize, size: usize) -> Option { IovVecSubregion::new(&self.vecs, self.len, offset, size) } + #[tracing::instrument(level = "trace", skip(self, buf, offset))] /// Reads a number of bytes from the `IoVecBuffer` starting at a given offset. /// /// This will try to fill `buf` reading bytes from the `IoVecBuffer` starting from @@ -227,6 +236,7 @@ pub(crate) struct IoVecBufferMut { } impl IoVecBufferMut { + #[tracing::instrument(level = "trace", skip(mem, head))] /// Create an `IoVecBufferMut` from a `DescriptorChain` pub fn from_descriptor_chain( mem: &GuestMemoryMmap, @@ -261,16 +271,19 @@ impl IoVecBufferMut { Ok(Self { vecs, len }) } + #[tracing::instrument(level = "trace", skip(self))] /// Get the total length of the memory regions covered by this `IoVecBuffer` pub fn len(&self) -> usize { self.len } + #[tracing::instrument(level = "trace", skip(self, offset, size))] /// Get a sub-region of the buffer fn sub_region(&self, offset: usize, size: usize) -> Option { IovVecSubregion::new(&self.vecs, self.len, offset, size) } + #[tracing::instrument(level = "trace", skip(self, buf, offset))] /// Writes a number of bytes into the `IoVecBufferMut` starting at a given offset. /// /// This will try to fill `IoVecBufferMut` writing bytes from the `buf` starting from @@ -321,6 +334,7 @@ mod tests { use crate::devices::virtio::test_utils::VirtQueue; impl<'a> From<&'a [u8]> for IoVecBuffer { + #[tracing::instrument(level = "trace", skip(buf))] fn from(buf: &'a [u8]) -> Self { Self { vecs: vec![iovec { @@ -333,6 +347,7 @@ mod tests { } impl<'a> From> for IoVecBuffer { + #[tracing::instrument(level = "trace", skip(buffer))] fn from(buffer: Vec<&'a [u8]>) -> Self { let mut len = 0; let vecs = buffer @@ -351,6 +366,7 @@ mod tests { } impl From<&mut [u8]> for IoVecBufferMut { + #[tracing::instrument(level = "trace", skip(buf))] fn from(buf: &mut [u8]) -> Self { Self { vecs: vec![iovec { @@ -362,6 +378,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn default_mem() -> GuestMemoryMmap { create_anon_guest_memory( &[ @@ -374,6 +391,7 @@ mod tests { .unwrap() } + #[tracing::instrument(level = "trace", skip(m, is_write_only))] fn chain(m: &GuestMemoryMmap, is_write_only: bool) -> (Queue, VirtQueue) { let vq = VirtQueue::new(GuestAddress(0), m, 16); @@ -398,6 +416,7 @@ mod tests { (q, vq) } + #[tracing::instrument(level = "trace", skip(mem))] fn read_only_chain(mem: &GuestMemoryMmap) -> (Queue, VirtQueue) { let v: Vec = (0..=255).collect(); mem.write_slice(&v, GuestAddress(0x20000)).unwrap(); @@ -405,6 +424,7 @@ mod tests { chain(mem, false) } + #[tracing::instrument(level = "trace", skip(mem))] fn write_only_chain(mem: &GuestMemoryMmap) -> (Queue, VirtQueue) { let v = vec![0; 256]; mem.write_slice(&v, GuestAddress(0x20000)).unwrap(); diff --git a/src/vmm/src/devices/virtio/mmio.rs b/src/vmm/src/devices/virtio/mmio.rs index b7632f88a1f..2ff3262bf0a 100644 --- a/src/vmm/src/devices/virtio/mmio.rs +++ b/src/vmm/src/devices/virtio/mmio.rs @@ -9,7 +9,7 @@ use std::fmt::Debug; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex, MutexGuard}; -use log::warn; +use logger::warn; use utils::byte_order; use utils::vm_memory::{GuestAddress, GuestMemoryMmap}; @@ -58,6 +58,7 @@ pub struct MmioTransport { } impl MmioTransport { + #[tracing::instrument(level = "trace", skip(mem, device))] /// Constructs a new MMIO transport for the given virtio device. pub fn new(mem: GuestMemoryMmap, device: Arc>) -> MmioTransport { let interrupt_status = device.lock().expect("Poisoned lock").interrupt_status(); @@ -74,20 +75,24 @@ impl MmioTransport { } } + #[tracing::instrument(level = "trace", skip(self))] /// Gets the encapsulated locked VirtioDevice. pub fn locked_device(&self) -> MutexGuard { self.device.lock().expect("Poisoned lock") } + #[tracing::instrument(level = "trace", skip(self))] /// Gets the encapsulated VirtioDevice. pub fn device(&self) -> Arc> { self.device.clone() } + #[tracing::instrument(level = "trace", skip(self, set, clr))] fn check_device_status(&self, set: u32, clr: u32) -> bool { self.device_status & (set | clr) == set } + #[tracing::instrument(level = "trace", skip(self))] fn are_queues_valid(&self) -> bool { self.locked_device() .queues() @@ -95,6 +100,7 @@ impl MmioTransport { .all(|q| q.is_valid(&self.mem)) } + #[tracing::instrument(level = "trace", skip(self, d, f))] fn with_queue(&self, d: U, f: F) -> U where F: FnOnce(&Queue) -> U, @@ -110,6 +116,7 @@ impl MmioTransport { } } + #[tracing::instrument(level = "trace", skip(self, f))] fn with_queue_mut(&mut self, f: F) -> bool { if let Some(queue) = self .locked_device() @@ -123,6 +130,7 @@ impl MmioTransport { } } + #[tracing::instrument(level = "trace", skip(self, f))] fn update_queue_field(&mut self, f: F) { if self.check_device_status( device_status::FEATURES_OK, @@ -137,6 +145,7 @@ impl MmioTransport { } } + #[tracing::instrument(level = "trace", skip(self))] fn reset(&mut self) { if self.locked_device().is_activated() { warn!("reset device while it's still in active state"); @@ -155,6 +164,7 @@ impl MmioTransport { } } + #[tracing::instrument(level = "trace", skip(self, status))] /// Update device status according to the state machine defined by VirtIO Spec 1.0. /// Please refer to VirtIO Spec 1.0, section 2.1.1 and 3.1.1. /// @@ -219,6 +229,7 @@ impl MmioTransport { } impl MmioTransport { + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_read(&mut self, offset: u64, data: &mut [u8]) { match offset { 0x00..=0xff if data.len() == 4 => { @@ -259,11 +270,14 @@ impl MmioTransport { }; } + #[tracing::instrument(level = "trace", skip(self, offset, data))] pub fn bus_write(&mut self, offset: u64, data: &[u8]) { + #[tracing::instrument(level = "trace", skip(v, x))] fn hi(v: &mut GuestAddress, x: u32) { *v = (*v & 0xffff_ffff) | (u64::from(x) << 32) } + #[tracing::instrument(level = "trace", skip(v, x))] fn lo(v: &mut GuestAddress, x: u32) { *v = (*v & !0xffff_ffff) | u64::from(x) } @@ -348,6 +362,7 @@ pub(crate) mod tests { } impl DummyDevice { + #[tracing::instrument(level = "trace", skip())] pub(crate) fn new() -> Self { DummyDevice { acked_features: 0, @@ -364,68 +379,83 @@ pub(crate) mod tests { } } + #[tracing::instrument(level = "trace", skip(self, avail_features))] fn set_avail_features(&mut self, avail_features: u64) { self.avail_features = avail_features; } } impl VirtioDevice for DummyDevice { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { self.avail_features } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, acked_features))] fn set_acked_features(&mut self, acked_features: u64) { self.acked_features = acked_features; } + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { 123 } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_evts } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.interrupt_evt } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { self.interrupt_status.clone() } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn read_config(&self, offset: u64, data: &mut [u8]) { data.copy_from_slice(&self.config_bytes[offset as usize..]); } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn write_config(&mut self, offset: u64, data: &[u8]) { for (i, item) in data.iter().enumerate() { self.config_bytes[offset as usize + i] = *item; } } + #[tracing::instrument(level = "trace", skip(self))] fn activate(&mut self, _: GuestMemoryMmap) -> Result<(), ActivateError> { self.device_activated = true; Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { self.device_activated } } + #[tracing::instrument(level = "trace", skip(d, status))] fn set_device_status(d: &mut MmioTransport, status: u32) { let mut buf = vec![0; 4]; write_le_u32(&mut buf[..], status); @@ -796,6 +826,7 @@ pub(crate) mod tests { assert_eq!(read_le_u32(&buf[..]), 1); } + #[tracing::instrument(level = "trace", skip(d))] fn activate_device(d: &mut MmioTransport) { set_device_status(d, device_status::ACKNOWLEDGE); set_device_status(d, device_status::ACKNOWLEDGE | device_status::DRIVER); diff --git a/src/vmm/src/devices/virtio/mod.rs b/src/vmm/src/devices/virtio/mod.rs index 79d159ab74c..6791da0b2b6 100644 --- a/src/vmm/src/devices/virtio/mod.rs +++ b/src/vmm/src/devices/virtio/mod.rs @@ -83,10 +83,12 @@ pub trait AsAny { } impl AsAny for T { + #[tracing::instrument(level = "trace", skip(self))] fn as_any(&self) -> &dyn Any { self } + #[tracing::instrument(level = "trace", skip(self))] fn as_mut_any(&mut self) -> &mut dyn Any { self } diff --git a/src/vmm/src/devices/virtio/net/device.rs b/src/vmm/src/devices/virtio/net/device.rs index 22abe4dd80b..2bfe0f8889f 100755 --- a/src/vmm/src/devices/virtio/net/device.rs +++ b/src/vmm/src/devices/virtio/net/device.rs @@ -14,8 +14,7 @@ use std::{cmp, mem}; use dumbo::pdu::arp::ETH_IPV4_FRAME_LEN; use dumbo::pdu::ethernet::{EthernetFrame, PAYLOAD_OFFSET}; use libc::EAGAIN; -use log::{error, warn}; -use logger::{IncMetric, METRICS}; +use logger::{error, warn, IncMetric, METRICS}; use mmds::data_store::Mmds; use mmds::ns::MmdsNetworkStack; use utils::eventfd::EventFd; @@ -64,6 +63,7 @@ const fn frame_hdr_len() -> usize { // Frames being sent/received through the network device model have a VNET header. This // function returns a slice which holds the L2 frame bytes without this header. +#[tracing::instrument(level = "trace", skip(buf))] fn frame_bytes_from_buf(buf: &[u8]) -> Result<&[u8], NetError> { if buf.len() < vnet_hdr_len() { Err(NetError::VnetHeaderMissing) @@ -72,6 +72,7 @@ fn frame_bytes_from_buf(buf: &[u8]) -> Result<&[u8], NetError> { } } +#[tracing::instrument(level = "trace", skip(buf))] fn frame_bytes_from_buf_mut(buf: &mut [u8]) -> Result<&mut [u8], NetError> { if buf.len() < vnet_hdr_len() { Err(NetError::VnetHeaderMissing) @@ -81,6 +82,7 @@ fn frame_bytes_from_buf_mut(buf: &mut [u8]) -> Result<&mut [u8], NetError> { } // This initializes to all 0 the VNET hdr part of a buf. +#[tracing::instrument(level = "trace", skip(buf))] fn init_vnet_hdr(buf: &mut [u8]) { // The buffer should be larger than vnet_hdr_len. buf[0..vnet_hdr_len()].fill(0); @@ -135,6 +137,10 @@ pub struct Net { } impl Net { + #[tracing::instrument( + level = "trace", + skip(id, tap, guest_mac, rx_rate_limiter, tx_rate_limiter) + )] /// Create a new virtio network device with the given TAP interface. pub fn new_with_tap( id: String, @@ -189,6 +195,10 @@ impl Net { }) } + #[tracing::instrument( + level = "trace", + skip(id, tap_if_name, guest_mac, rx_rate_limiter, tx_rate_limiter) + )] /// Create a new virtio network device given the interface name. pub fn new( id: String, @@ -212,26 +222,31 @@ impl Net { Self::new_with_tap(id, tap, guest_mac, rx_rate_limiter, tx_rate_limiter) } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the ID of this net device. pub fn id(&self) -> &String { &self.id } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the MAC of this net device. pub fn guest_mac(&self) -> Option<&MacAddr> { self.guest_mac.as_ref() } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the host IFACE name of this net device. pub fn iface_name(&self) -> String { self.tap.if_name_as_str().to_string() } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the MmdsNetworkStack of this net device. pub fn mmds_ns(&self) -> Option<&MmdsNetworkStack> { self.mmds_ns.as_ref() } + #[tracing::instrument(level = "trace", skip(self, ipv4_addr, mmds))] /// Configures the `MmdsNetworkStack` to allow device to forward MMDS requests. /// If the device already supports MMDS, updates the IPv4 address. pub fn configure_mmds_network_stack(&mut self, ipv4_addr: Ipv4Addr, mmds: Arc>) { @@ -242,21 +257,25 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] /// Disables the `MmdsNetworkStack` to prevent device to forward MMDS requests. pub fn disable_mmds_network_stack(&mut self) { self.mmds_ns = None } + #[tracing::instrument(level = "trace", skip(self))] /// Provides a reference to the configured RX rate limiter. pub fn rx_rate_limiter(&self) -> &RateLimiter { &self.rx_rate_limiter } + #[tracing::instrument(level = "trace", skip(self))] /// Provides a reference to the configured TX rate limiter. pub fn tx_rate_limiter(&self) -> &RateLimiter { &self.tx_rate_limiter } + #[tracing::instrument(level = "trace", skip(self, queue_type))] fn signal_used_queue(&mut self, queue_type: NetQueue) -> Result<(), DeviceError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -279,6 +298,7 @@ impl Net { } // Helper function to consume one op with `size` bytes from a rate limiter + #[tracing::instrument(level = "trace", skip(rate_limiter, size))] fn rate_limiter_consume_op(rate_limiter: &mut RateLimiter, size: u64) -> bool { if !rate_limiter.consume(1, TokenType::Ops) { return false; @@ -293,6 +313,7 @@ impl Net { } // Helper function to replenish one operation with `size` bytes from a rate limiter + #[tracing::instrument(level = "trace", skip(rate_limiter, size))] fn rate_limiter_replenish_op(rate_limiter: &mut RateLimiter, size: u64) { rate_limiter.manual_replenish(1, TokenType::Ops); rate_limiter.manual_replenish(size, TokenType::Bytes); @@ -301,6 +322,7 @@ impl Net { // Attempts to copy a single frame into the guest if there is enough // rate limiting budget. // Returns true on successful frame delivery. + #[tracing::instrument(level = "trace", skip(self))] fn rate_limited_rx_single_frame(&mut self) -> bool { if !Self::rate_limiter_consume_op(&mut self.rx_rate_limiter, self.rx_bytes_read as u64) { METRICS.net.rx_rate_limiter_throttled.inc(); @@ -319,6 +341,7 @@ impl Net { success } + #[tracing::instrument(level = "trace", skip(mem, data, head))] /// Write a slice in a descriptor chain /// /// # Errors @@ -368,6 +391,7 @@ impl Net { } // Copies a single frame from `self.rx_frame_buf` into the guest. + #[tracing::instrument(level = "trace", skip(self))] fn do_write_frame_to_guest(&mut self) -> Result<(), FrontendError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -401,6 +425,7 @@ impl Net { // Copies a single frame from `self.rx_frame_buf` into the guest. In case of an error retries // the operation if possible. Returns true if the operation was successfull. + #[tracing::instrument(level = "trace", skip(self))] fn write_frame_to_guest(&mut self) -> bool { let max_iterations = self.queues[RX_INDEX].actual_size(); for _ in 0..max_iterations { @@ -422,6 +447,10 @@ impl Net { // Tries to detour the frame to MMDS and if MMDS doesn't accept it, sends it on the host TAP. // // Returns whether MMDS consumed the frame. + #[tracing::instrument( + level = "trace", + skip(mmds_ns, rate_limiter, headers, frame_iovec, tap, guest_mac) + )] fn write_to_mmds_or_tap( mmds_ns: Option<&mut MmdsNetworkStack>, rate_limiter: &mut RateLimiter, @@ -487,6 +516,7 @@ impl Net { } // We currently prioritize packets from the MMDS over regular network packets. + #[tracing::instrument(level = "trace", skip(self))] fn read_from_mmds_or_tap(&mut self) -> Result { if let Some(ns) = self.mmds_ns.as_mut() { if let Some(len) = @@ -503,6 +533,7 @@ impl Net { self.read_tap().map_err(NetError::IO) } + #[tracing::instrument(level = "trace", skip(self))] fn process_rx(&mut self) -> Result<(), DeviceError> { // Read as many frames as possible. loop { @@ -540,6 +571,7 @@ impl Net { } // Process the deferred frame first, then continue reading from tap. + #[tracing::instrument(level = "trace", skip(self))] fn handle_deferred_frame(&mut self) -> Result<(), DeviceError> { if self.rate_limited_rx_single_frame() { self.rx_deferred_frame = false; @@ -551,6 +583,7 @@ impl Net { self.signal_used_queue(NetQueue::Rx) } + #[tracing::instrument(level = "trace", skip(self))] fn resume_rx(&mut self) -> Result<(), DeviceError> { if self.rx_deferred_frame { self.handle_deferred_frame() @@ -559,6 +592,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] fn process_tx(&mut self) -> Result<(), DeviceError> { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -624,6 +658,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self, rx_bytes, rx_ops, tx_bytes, tx_ops))] /// Updates the parameters for the rate limiters pub fn patch_rate_limiters( &mut self, @@ -636,16 +671,19 @@ impl Net { self.tx_rate_limiter.update_buckets(tx_bytes, tx_ops); } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(not(test))] fn read_tap(&mut self) -> std::io::Result { self.tap.read(&mut self.rx_frame_buf) } + #[tracing::instrument(level = "trace", skip(tap, buf))] #[cfg(not(test))] fn write_tap(tap: &mut Tap, buf: &IoVecBuffer) -> std::io::Result { tap.write_iovec(buf) } + #[tracing::instrument(level = "trace", skip(self))] /// Process a single RX queue event. /// /// This is called by the event manager responding to the guest adding a new @@ -665,6 +703,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn process_tap_rx_event(&mut self) { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -696,6 +735,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] /// Process a single TX queue event. /// /// This is called by the event manager responding to the guest adding a new @@ -714,6 +754,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn process_rx_rate_limiter_event(&mut self) { METRICS.net.rx_event_rate_limiter_count.inc(); // Upon rate limiter event, call the rate limiter handler @@ -731,6 +772,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn process_tx_rate_limiter_event(&mut self) { METRICS.net.tx_rate_limiter_event_count.inc(); // Upon rate limiter event, call the rate limiter handler @@ -747,6 +789,7 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self))] /// Process device virtio queue(s). pub fn process_virtio_queues(&mut self) { let _ = self.resume_rx(); @@ -755,42 +798,52 @@ impl Net { } impl VirtioDevice for Net { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { self.avail_features } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, acked_features))] fn set_acked_features(&mut self, acked_features: u64) { self.acked_features = acked_features; } + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { TYPE_NET } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_evts } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.irq_trigger.irq_evt } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { self.irq_trigger.irq_status.clone() } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn read_config(&self, offset: u64, mut data: &mut [u8]) { let config_space_bytes = self.config_space.as_slice(); let config_len = config_space_bytes.len() as u64; @@ -808,6 +861,7 @@ impl VirtioDevice for Net { } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn write_config(&mut self, offset: u64, data: &[u8]) { let config_space_bytes = self.config_space.as_mut_slice(); let start = usize::try_from(offset).ok(); @@ -826,6 +880,7 @@ impl VirtioDevice for Net { METRICS.net.mac_address_updates.inc(); } + #[tracing::instrument(level = "trace", skip(self, mem))] fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> { let event_idx = self.has_feature(u64::from(VIRTIO_RING_F_EVENT_IDX)); if event_idx { @@ -842,6 +897,7 @@ impl VirtioDevice for Net { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { self.device_state.is_activated() } @@ -883,6 +939,7 @@ pub mod tests { use crate::rate_limiter::{RateLimiter, TokenBucket, TokenType}; impl Net { + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn read_tap(&mut self) -> io::Result { match &self.tap.mocks.read_tap { ReadTapMock::MockFrame(frame) => { @@ -897,6 +954,7 @@ pub mod tests { } } + #[tracing::instrument(level = "trace", skip(tap, buf))] pub(crate) fn write_tap(tap: &mut Tap, buf: &IoVecBuffer) -> io::Result { match tap.mocks.write_tap { WriteTapMock::Success => tap.write_iovec(buf), @@ -1440,6 +1498,7 @@ pub mod tests { assert_eq!(&buf[..600], &frame_2[..600]); } + #[tracing::instrument(level = "trace", skip(src_mac, src_ip, dst_mac, dst_ip))] fn create_arp_request( src_mac: MacAddr, src_ip: Ipv4Addr, diff --git a/src/vmm/src/devices/virtio/net/event_handler.rs b/src/vmm/src/devices/virtio/net/event_handler.rs index b5ed3dfa7b7..5c1f2d375b6 100644 --- a/src/vmm/src/devices/virtio/net/event_handler.rs +++ b/src/vmm/src/devices/virtio/net/event_handler.rs @@ -4,14 +4,14 @@ use std::os::unix::io::AsRawFd; use event_manager::{EventOps, Events, MutEventSubscriber}; -use log::{error, warn}; -use logger::{IncMetric, METRICS}; +use logger::{error, warn, IncMetric, METRICS}; use utils::epoll::EventSet; use crate::devices::virtio::net::device::Net; use crate::devices::virtio::{VirtioDevice, RX_INDEX, TX_INDEX}; impl Net { + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_runtime_events(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.queue_evts[RX_INDEX], EventSet::IN)) { error!("Failed to register rx queue event: {}", err); @@ -33,14 +33,16 @@ impl Net { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_activate_event(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.activate_evt, EventSet::IN)) { error!("Failed to register activate event: {}", err); } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn process_activate_event(&self, ops: &mut EventOps) { - log::debug!("net: activate event"); + logger::debug!("net: activate event"); if let Err(err) = self.activate_evt.read() { error!("Failed to consume net activate event: {:?}", err); } @@ -52,6 +54,7 @@ impl Net { } impl MutEventSubscriber for Net { + #[tracing::instrument(level = "trace", skip(self, event, ops))] fn process(&mut self, event: Events, ops: &mut EventOps) { let source = event.fd(); let event_set = event.event_set(); @@ -96,6 +99,7 @@ impl MutEventSubscriber for Net { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { // This function can be called during different points in the device lifetime: // - shortly after device creation, diff --git a/src/vmm/src/devices/virtio/net/persist.rs b/src/vmm/src/devices/virtio/net/persist.rs index 8fd4c14d322..b7c78521fe1 100644 --- a/src/vmm/src/devices/virtio/net/persist.rs +++ b/src/vmm/src/devices/virtio/net/persist.rs @@ -7,7 +7,7 @@ use std::io; use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Mutex}; -use log::warn; +use logger::warn; use mmds::data_store::Mmds; use mmds::ns::MmdsNetworkStack; use mmds::persist::MmdsNetworkStackState; @@ -36,6 +36,7 @@ pub struct NetConfigSpaceState { } impl NetConfigSpaceState { + #[tracing::instrument(level = "trace", skip(self, version))] fn de_guest_mac_v2(&mut self, version: u16) -> VersionizeResult<()> { // v1.1 and older versions do not have optional MAC address. warn!("Optional MAC address will be set to older version."); @@ -45,6 +46,7 @@ impl NetConfigSpaceState { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, _target_version))] fn ser_guest_mac_v2(&mut self, _target_version: u16) -> VersionizeResult<()> { // v1.1 and older versions do not have optional MAC address. warn!("Saving to older snapshot version, optional MAC address will not be saved."); @@ -55,6 +57,7 @@ impl NetConfigSpaceState { Ok(()) } + #[tracing::instrument(level = "trace", skip())] fn def_guest_mac_old(_: u16) -> [u8; MAC_ADDR_LEN] { // v1.2 and newer don't use this field anyway Default::default() @@ -103,6 +106,7 @@ impl Persist<'_> for Net { type ConstructorArgs = NetConstructorArgs; type Error = NetPersistError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { NetState { id: self.id().clone(), @@ -118,6 +122,7 @@ impl Persist<'_> for Net { } } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, @@ -178,6 +183,7 @@ mod tests { use crate::devices::virtio::net::test_utils::{default_net, default_net_no_mmds}; use crate::devices::virtio::test_utils::default_mem; + #[tracing::instrument(level = "trace", skip(net, mmds_ds))] fn validate_save_and_restore(net: Net, mmds_ds: Option>>) { let guest_mem = default_mem(); let mut mem = vec![0; 4096]; diff --git a/src/vmm/src/devices/virtio/net/tap.rs b/src/vmm/src/devices/virtio/net/tap.rs index 23ab2646693..5bbcb6f88c5 100644 --- a/src/vmm/src/devices/virtio/net/tap.rs +++ b/src/vmm/src/devices/virtio/net/tap.rs @@ -67,6 +67,7 @@ pub struct Tap { // Returns a byte vector representing the contents of a null terminated C string which // contains if_name. +#[tracing::instrument(level = "trace", skip(if_name))] fn build_terminated_if_name(if_name: &str) -> Result<[u8; IFACE_NAME_MAX_LEN], TapError> { // Convert the string slice to bytes, and shadow the variable, // since we no longer need the &str version. @@ -86,16 +87,19 @@ fn build_terminated_if_name(if_name: &str) -> Result<[u8; IFACE_NAME_MAX_LEN], T pub struct IfReqBuilder(ifreq); impl fmt::Debug for IfReqBuilder { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "IfReqBuilder {{ .. }}") } } impl IfReqBuilder { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> Self { Self(Default::default()) } + #[tracing::instrument(level = "trace", skip(self, if_name))] pub fn if_name(mut self, if_name: &[u8; IFACE_NAME_MAX_LEN]) -> Self { // SAFETY: Since we don't call as_mut on the same union field more than once, this block is // safe. @@ -105,11 +109,13 @@ impl IfReqBuilder { self } + #[tracing::instrument(level = "trace", skip(self, flags))] pub(crate) fn flags(mut self, flags: i16) -> Self { self.0.ifr_ifru.ifru_flags = flags; self } + #[tracing::instrument(level = "trace", skip(self, socket, ioctl))] pub(crate) fn execute( mut self, socket: &F, @@ -125,6 +131,7 @@ impl IfReqBuilder { } impl Tap { + #[tracing::instrument(level = "trace", skip(if_name))] /// Create a TUN/TAP device given the interface name. /// # Arguments /// @@ -162,6 +169,7 @@ impl Tap { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Retrieve the interface's name as a str. pub fn if_name_as_str(&self) -> &str { let len = self @@ -172,6 +180,7 @@ impl Tap { std::str::from_utf8(&self.if_name[..len]).unwrap_or("") } + #[tracing::instrument(level = "trace", skip(self, flags))] /// Set the offload flags for the tap interface. pub fn set_offload(&self, flags: c_uint) -> Result<(), TapError> { // SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return. @@ -182,6 +191,7 @@ impl Tap { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, size))] /// Set the size of the vnet hdr. pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<(), TapError> { // SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return. @@ -192,6 +202,7 @@ impl Tap { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, buffer))] /// Write an `IoVecBuffer` to tap pub(crate) fn write_iovec(&mut self, buffer: &IoVecBuffer) -> Result { let iovcnt = i32::try_from(buffer.iovec_count()).unwrap(); @@ -208,22 +219,26 @@ impl Tap { } impl Read for Tap { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read(&mut self, buf: &mut [u8]) -> Result { self.tap_file.read(buf) } } impl Write for Tap { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write(&mut self, buf: &[u8]) -> Result { self.tap_file.write(buf) } + #[tracing::instrument(level = "trace", skip(self))] fn flush(&mut self) -> Result<(), IoError> { Ok(()) } } impl AsRawFd for Tap { + #[tracing::instrument(level = "trace", skip(self))] fn as_raw_fd(&self) -> RawFd { self.tap_file.as_raw_fd() } diff --git a/src/vmm/src/devices/virtio/net/test_utils.rs b/src/vmm/src/devices/virtio/net/test_utils.rs index c1d6b9247b4..817933e85d9 100644 --- a/src/vmm/src/devices/virtio/net/test_utils.rs +++ b/src/vmm/src/devices/virtio/net/test_utils.rs @@ -28,6 +28,7 @@ use crate::rate_limiter::RateLimiter; static NEXT_INDEX: AtomicUsize = AtomicUsize::new(1); +#[tracing::instrument(level = "trace", skip())] pub fn default_net() -> Net { let next_tap = NEXT_INDEX.fetch_add(1, Ordering::SeqCst); // Id is the firecracker-facing identifier, e.g. local to the FC process. We thus do not need to @@ -57,6 +58,7 @@ pub fn default_net() -> Net { net } +#[tracing::instrument(level = "trace", skip())] pub fn default_net_no_mmds() -> Net { let next_tap = NEXT_INDEX.fetch_add(1, Ordering::SeqCst); let tap_device_id = format!("net-device{}", next_tap); @@ -84,6 +86,7 @@ pub enum ReadTapMock { } impl ReadTapMock { + #[tracing::instrument(level = "trace", skip(self))] pub fn mock_frame(&self) -> Vec { if let ReadTapMock::MockFrame(frame) = self { return frame.clone(); @@ -106,16 +109,19 @@ pub struct Mocks { } impl Mocks { + #[tracing::instrument(level = "trace", skip(self, read_tap))] pub fn set_read_tap(&mut self, read_tap: ReadTapMock) { self.read_tap = read_tap; } + #[tracing::instrument(level = "trace", skip(self, write_tap))] pub fn set_write_tap(&mut self, write_tap: WriteTapMock) { self.write_tap = write_tap; } } impl Default for Mocks { + #[tracing::instrument(level = "trace", skip())] fn default() -> Mocks { Mocks { read_tap: ReadTapMock::MockFrame( @@ -148,6 +154,7 @@ pub struct TapTrafficSimulator { } impl TapTrafficSimulator { + #[tracing::instrument(level = "trace", skip(tap_index))] pub fn new(tap_index: i32) -> Self { // Create sockaddr_ll struct. // SAFETY: sockaddr_storage has no invariants and can be safely zeroed. @@ -202,6 +209,7 @@ impl TapTrafficSimulator { } } + #[tracing::instrument(level = "trace", skip(self, buf))] pub fn push_tx_packet(&self, buf: &[u8]) { // SAFETY: The call is safe since the parameters are valid. let res = unsafe { @@ -219,6 +227,7 @@ impl TapTrafficSimulator { } } + #[tracing::instrument(level = "trace", skip(self, buf))] pub fn pop_rx_packet(&self, buf: &mut [u8]) -> bool { // SAFETY: The call is safe since the parameters are valid. let ret = unsafe { @@ -238,6 +247,7 @@ impl TapTrafficSimulator { } } +#[tracing::instrument(level = "trace", skip())] pub fn create_socket() -> File { // SAFETY: This is safe since we check the return value. let socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, libc::ETH_P_ALL.to_be()) }; @@ -250,6 +260,7 @@ pub fn create_socket() -> File { } // Returns handles to virtio queues creation/activation and manipulation. +#[tracing::instrument(level = "trace", skip(mem))] pub fn virtqueues(mem: &GuestMemoryMmap) -> (VirtQueue, VirtQueue) { let rxq = VirtQueue::new(GuestAddress(0), mem, 16); let txq = VirtQueue::new(GuestAddress(0x1000), mem, 16); @@ -258,6 +269,7 @@ pub fn virtqueues(mem: &GuestMemoryMmap) -> (VirtQueue, VirtQueue) { (rxq, txq) } +#[tracing::instrument(level = "trace", skip(tap))] pub fn if_index(tap: &Tap) -> i32 { let sock = create_socket(); let ifreq = IfReqBuilder::new() @@ -269,6 +281,7 @@ pub fn if_index(tap: &Tap) -> i32 { unsafe { ifreq.ifr_ifru.ifru_ivalue } } +#[tracing::instrument(level = "trace", skip(tap))] /// Enable the tap interface. pub fn enable(tap: &Tap) { // Disable IPv6 router advertisment requests @@ -293,6 +306,7 @@ pub fn enable(tap: &Tap) { .unwrap(); } +#[tracing::instrument(level = "trace", skip(net, len))] #[cfg(test)] pub(crate) fn inject_tap_tx_frame(net: &Net, len: usize) -> Vec { assert!(len >= vnet_hdr_len()); @@ -306,6 +320,7 @@ pub(crate) fn inject_tap_tx_frame(net: &Net, len: usize) -> Vec { frame } +#[tracing::instrument(level = "trace", skip(net, idx, val))] pub fn write_element_in_queue(net: &Net, idx: usize, val: u64) -> Result<(), DeviceError> { if idx > net.queue_evts.len() { return Err(DeviceError::QueueError(QueueError::DescIndexOutOfBounds( @@ -316,6 +331,7 @@ pub fn write_element_in_queue(net: &Net, idx: usize, val: u64) -> Result<(), Dev Ok(()) } +#[tracing::instrument(level = "trace", skip(net, idx))] pub fn get_element_from_queue(net: &Net, idx: usize) -> Result { if idx > net.queue_evts.len() { return Err(DeviceError::QueueError(QueueError::DescIndexOutOfBounds( @@ -325,16 +341,19 @@ pub fn get_element_from_queue(net: &Net, idx: usize) -> Result Ok(u64::try_from(net.queue_evts[idx].as_raw_fd()).unwrap()) } +#[tracing::instrument(level = "trace", skip())] pub fn default_guest_mac() -> MacAddr { MacAddr::from_str("11:22:33:44:55:66").unwrap() } +#[tracing::instrument(level = "trace", skip(net, mac))] pub fn set_mac(net: &mut Net, mac: MacAddr) { net.guest_mac = Some(mac); net.config_space.guest_mac = mac; } // Assigns "guest virtio driver" activated queues to the net device. +#[tracing::instrument(level = "trace", skip(net, rxq, txq))] pub fn assign_queues(net: &mut Net, rxq: Queue, txq: Queue) { net.queues.clear(); net.queues.push(rxq); @@ -374,6 +393,7 @@ pub mod test { } impl fmt::Debug for TestHelper<'_> { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TestHelper") .field("event_manager", &"?") @@ -389,6 +409,7 @@ pub mod test { impl<'a> TestHelper<'a> { const QUEUE_SIZE: u16 = 16; + #[tracing::instrument(level = "trace", skip())] pub fn get_default() -> TestHelper<'a> { let mut event_manager = EventManager::new().unwrap(); let mut net = default_net(); @@ -421,10 +442,12 @@ pub mod test { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn net(&mut self) -> MutexGuard { self.net.lock().unwrap() } + #[tracing::instrument(level = "trace", skip(self))] pub fn activate_net(&mut self) { self.net.lock().unwrap().activate(self.mem.clone()).unwrap(); // Process the activate event. @@ -432,6 +455,7 @@ pub mod test { assert_eq!(ev_count, 1); } + #[tracing::instrument(level = "trace", skip(self, event))] pub fn simulate_event(&mut self, event: NetEvent) { match event { NetEvent::RxQueue => self.net().process_rx_queue_event(), @@ -442,10 +466,12 @@ pub mod test { }; } + #[tracing::instrument(level = "trace", skip(self))] pub fn data_addr(&self) -> u64 { self.txq.end().raw_value() } + #[tracing::instrument(level = "trace", skip(self, queue, addr_offset, desc_list))] pub fn add_desc_chain( &mut self, queue: NetQueue, @@ -485,6 +511,7 @@ pub mod test { event_fd.write(1).unwrap(); } + #[tracing::instrument(level = "trace", skip(self, frame_len))] /// Generate a tap frame of `frame_len` and check that it is deferred pub fn check_rx_deferred_frame(&mut self, frame_len: usize) -> Vec { self.net().tap.mocks.set_read_tap(ReadTapMock::TapFrame); @@ -506,6 +533,7 @@ pub mod test { frame } + #[tracing::instrument(level = "trace", skip(self, expected_frame))] /// Check that after adding a valid Rx queue descriptor chain a previously deferred frame /// is eventually received by the guest pub fn check_rx_queue_resume(&mut self, expected_frame: &[u8]) { @@ -531,6 +559,7 @@ pub mod test { // Generates a frame of `frame_len` and writes it to the provided descriptor chain. // Doesn't generate an error if the descriptor chain is longer than `frame_len`. + #[tracing::instrument(level = "trace", skip(self, desc_list, frame_len))] pub fn write_tx_frame(&self, desc_list: &[(u16, u32, u16)], frame_len: usize) -> Vec { let mut frame = utils::rand::rand_alphanumerics(frame_len) .as_bytes() diff --git a/src/vmm/src/devices/virtio/persist.rs b/src/vmm/src/devices/virtio/persist.rs index ed411dcd05f..24b27dcd161 100644 --- a/src/vmm/src/devices/virtio/persist.rs +++ b/src/vmm/src/devices/virtio/persist.rs @@ -60,6 +60,7 @@ impl Persist<'_> for Queue { type ConstructorArgs = (); type Error = (); + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { QueueState { max_size: self.max_size, @@ -74,6 +75,7 @@ impl Persist<'_> for Queue { } } + #[tracing::instrument(level = "trace", skip(state))] fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result { Ok(Queue { max_size: state.max_size, @@ -109,6 +111,7 @@ pub struct VirtioDeviceState { } impl VirtioDeviceState { + #[tracing::instrument(level = "trace", skip(device))] /// Construct the virtio state of a device. pub fn from_device(device: &dyn VirtioDevice) -> Self { VirtioDeviceState { @@ -121,6 +124,16 @@ impl VirtioDeviceState { } } + #[tracing::instrument( + level = "trace", + skip( + self, + mem, + expected_device_type, + expected_num_queues, + expected_queue_max_size + ) + )] /// Does sanity checking on the `self` state against expected values /// and builds queues from state. pub fn build_queues_checked( @@ -199,6 +212,7 @@ impl Persist<'_> for MmioTransport { type ConstructorArgs = MmioTransportConstructorArgs; type Error = (); + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { MmioTransportState { features_select: self.features_select, @@ -209,6 +223,7 @@ impl Persist<'_> for MmioTransport { } } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, @@ -236,6 +251,7 @@ mod tests { const DEFAULT_QUEUE_MAX_SIZE: u16 = 256; impl Default for QueueState { + #[tracing::instrument(level = "trace", skip())] fn default() -> QueueState { QueueState { max_size: DEFAULT_QUEUE_MAX_SIZE, @@ -348,6 +364,7 @@ mod tests { } impl PartialEq for MmioTransport { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &MmioTransport) -> bool { let self_dev_type = self.device().lock().unwrap().device_type(); self.acked_features_select == other.acked_features_select && @@ -362,6 +379,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(mmio_transport, mem, device))] fn generic_mmiotransport_persistence_test( mmio_transport: MmioTransport, mem: GuestMemoryMmap, @@ -385,6 +403,7 @@ mod tests { assert_eq!(restored_mmio_transport, mmio_transport); } + #[tracing::instrument(level = "trace", skip())] fn default_block() -> (MmioTransport, GuestMemoryMmap, Arc>) { let mem = default_mem(); @@ -401,6 +420,7 @@ mod tests { (mmio_transport, mem, block) } + #[tracing::instrument(level = "trace", skip())] fn default_net() -> (MmioTransport, GuestMemoryMmap, Arc>) { let mem = default_mem(); let net = Arc::new(Mutex::new(net::test_utils::default_net())); @@ -409,6 +429,7 @@ mod tests { (mmio_transport, mem, net) } + #[tracing::instrument(level = "trace", skip())] fn default_vsock() -> ( MmioTransport, GuestMemoryMmap, diff --git a/src/vmm/src/devices/virtio/queue.rs b/src/vmm/src/devices/virtio/queue.rs index 0f45ec41dd5..7dc6f888502 100644 --- a/src/vmm/src/devices/virtio/queue.rs +++ b/src/vmm/src/devices/virtio/queue.rs @@ -9,7 +9,7 @@ use std::cmp::min; use std::num::Wrapping; use std::sync::atomic::{fence, Ordering}; -use log::error; +use logger::error; use utils::vm_memory::{ Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap, }; @@ -76,6 +76,7 @@ pub struct DescriptorChain<'a> { } impl<'a> DescriptorChain<'a> { + #[tracing::instrument(level = "trace", skip(mem, desc_table, queue_size, index))] fn checked_new( mem: &GuestMemoryMmap, desc_table: GuestAddress, @@ -117,15 +118,18 @@ impl<'a> DescriptorChain<'a> { } } + #[tracing::instrument(level = "trace", skip(self))] fn is_valid(&self) -> bool { !self.has_next() || self.next < self.queue_size } + #[tracing::instrument(level = "trace", skip(self))] /// Gets if this descriptor chain has another descriptor chain linked after it. pub fn has_next(&self) -> bool { self.flags & VIRTQ_DESC_F_NEXT != 0 && self.ttl > 1 } + #[tracing::instrument(level = "trace", skip(self))] /// If the driver designated this as a write only descriptor. /// /// If this is false, this descriptor is read only. @@ -134,6 +138,7 @@ impl<'a> DescriptorChain<'a> { self.flags & VIRTQ_DESC_F_WRITE != 0 } + #[tracing::instrument(level = "trace", skip(self))] /// Gets the next descriptor in this descriptor chain, if there is one. /// /// Note that this is distinct from the next descriptor chain returned by `AvailIter`, which is @@ -159,6 +164,7 @@ impl<'a> IntoIterator for DescriptorChain<'a> { type Item = DescriptorChain<'a>; type IntoIter = DescriptorIterator<'a>; + #[tracing::instrument(level = "trace", skip(self))] fn into_iter(self) -> Self::IntoIter { DescriptorIterator(Some(self)) } @@ -167,6 +173,7 @@ impl<'a> IntoIterator for DescriptorChain<'a> { impl<'a> Iterator for DescriptorIterator<'a> { type Item = DescriptorChain<'a>; + #[tracing::instrument(level = "trace", skip(self))] fn next(&mut self) -> Option { self.0.take().map(|desc| { self.0 = desc.next_descriptor(); @@ -207,6 +214,7 @@ pub struct Queue { #[allow(clippy::len_without_is_empty)] impl Queue { + #[tracing::instrument(level = "trace", skip(max_size))] /// Constructs an empty virtio queue with the given `max_size`. pub fn new(max_size: u16) -> Queue { Queue { @@ -223,17 +231,20 @@ impl Queue { } } + #[tracing::instrument(level = "trace", skip(self))] /// Maximum size of the queue. pub fn get_max_size(&self) -> u16 { self.max_size } + #[tracing::instrument(level = "trace", skip(self))] /// Return the actual size of the queue, as the driver may not set up a /// queue as big as the device allows. pub fn actual_size(&self) -> u16 { min(self.size, self.max_size) } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Validates that the queue's representation is correct. pub fn is_valid(&self, mem: &GuestMemoryMmap) -> bool { let queue_size = u64::from(self.actual_size()); @@ -301,16 +312,19 @@ impl Queue { } } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Returns the number of yet-to-be-popped descriptor chains in the avail ring. fn len(&self, mem: &GuestMemoryMmap) -> u16 { (self.avail_idx(mem) - self.next_avail).0 } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Checks if the driver has made any descriptor chains available in the avail ring. pub fn is_empty(&self, mem: &GuestMemoryMmap) -> bool { self.len(mem) == 0 } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Pop the first available descriptor chain from the avail ring. pub fn pop<'b>(&mut self, mem: &'b GuestMemoryMmap) -> Option> { let len = self.len(mem); @@ -334,6 +348,7 @@ impl Queue { self.do_pop_unchecked(mem) } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Try to pop the first available descriptor chain from the avail ring. /// If no descriptor is available, enable notifications. pub fn pop_or_enable_notification<'b>( @@ -351,6 +366,7 @@ impl Queue { self.do_pop_unchecked(mem) } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Pop the first available descriptor chain from the avail ring. /// /// # Important @@ -400,12 +416,14 @@ impl Queue { ) } + #[tracing::instrument(level = "trace", skip(self))] /// Undo the effects of the last `self.pop()` call. /// The caller can use this, if it was unable to consume the last popped descriptor chain. pub fn undo_pop(&mut self) { self.next_avail -= Wrapping(1); } + #[tracing::instrument(level = "trace", skip(self, mem, desc_index, len))] /// Puts an available descriptor head into the used ring for use by the guest. pub fn add_used( &mut self, @@ -441,6 +459,7 @@ impl Queue { .map_err(QueueError::UsedRing) } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Fetch the available ring index (`virtq_avail->idx`) from guest memory. /// This is written by the driver, to indicate the next slot that will be filled in the avail /// ring. @@ -454,6 +473,7 @@ impl Queue { Wrapping(mem.read_obj::(addr).unwrap()) } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Get the value of the used event field of the avail ring. #[inline(always)] pub fn used_event(&self, mem: &GuestMemoryMmap) -> Wrapping { @@ -465,6 +485,7 @@ impl Queue { Wrapping(mem.read_obj::(used_event_addr).unwrap()) } + #[tracing::instrument(level = "trace", skip(self, val, mem))] /// Helper method that writes `val` to the `avail_event` field of the used ring. fn set_avail_event(&mut self, val: u16, mem: &GuestMemoryMmap) { let avail_event_addr = self @@ -474,6 +495,7 @@ impl Queue { mem.write_obj(val, avail_event_addr).unwrap(); } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Try to enable notification events from the guest driver. Returns true if notifications were /// successfully enabled. Otherwise it means that one or more descriptors can still be consumed /// from the available ring and we can't guarantee that there will be a notification. In this @@ -510,11 +532,13 @@ impl Queue { self.next_avail.0 == self.avail_idx(mem).0 } + #[tracing::instrument(level = "trace", skip(self))] /// Enable notification suppression. pub fn enable_notif_suppression(&mut self) { self.uses_notif_suppression = true; } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Check if we need to kick the guest. /// /// Please note this method has side effects: once it returns `true`, it considers the @@ -552,6 +576,7 @@ mod tests { use crate::devices::virtio::QueueError::{DescIndexOutOfBounds, UsedRing}; impl Queue { + #[tracing::instrument(level = "trace", skip(self, mem))] fn avail_event(&self, mem: &GuestMemoryMmap) -> u16 { let avail_event_addr = self .used_ring diff --git a/src/vmm/src/devices/virtio/rng/device.rs b/src/vmm/src/devices/virtio/rng/device.rs index d10e65e11f3..e1d1fff23ac 100644 --- a/src/vmm/src/devices/virtio/rng/device.rs +++ b/src/vmm/src/devices/virtio/rng/device.rs @@ -48,11 +48,13 @@ pub struct Entropy { } impl Entropy { + #[tracing::instrument(level = "trace", skip(rate_limiter))] pub fn new(rate_limiter: RateLimiter) -> Result { let queues = vec![Queue::new(RNG_QUEUE_SIZE); RNG_NUM_QUEUES]; Self::new_with_queues(queues, rate_limiter) } + #[tracing::instrument(level = "trace", skip(queues, rate_limiter))] pub fn new_with_queues( queues: Vec, rate_limiter: RateLimiter, @@ -75,10 +77,12 @@ impl Entropy { }) } + #[tracing::instrument(level = "trace", skip(self))] pub fn id(&self) -> &str { ENTROPY_DEV_ID } + #[tracing::instrument(level = "trace", skip(self))] fn signal_used_queue(&self) -> Result<(), DeviceError> { debug!("entropy: raising IRQ"); self.irq_trigger @@ -86,6 +90,7 @@ impl Entropy { .map_err(DeviceError::FailedSignalingIrq) } + #[tracing::instrument(level = "trace", skip(rate_limiter, bytes))] fn rate_limit_request(rate_limiter: &mut RateLimiter, bytes: u64) -> bool { if !rate_limiter.consume(1, TokenType::Ops) { return false; @@ -99,11 +104,13 @@ impl Entropy { true } + #[tracing::instrument(level = "trace", skip(rate_limiter, bytes))] fn rate_limit_replenish_request(rate_limiter: &mut RateLimiter, bytes: u64) { rate_limiter.manual_replenish(1, TokenType::Ops); rate_limiter.manual_replenish(bytes, TokenType::Bytes); } + #[tracing::instrument(level = "trace", skip(self, iovec))] fn handle_one(&self, iovec: &mut IoVecBufferMut) -> Result { // If guest provided us with an empty buffer just return directly if iovec.len() == 0 { @@ -120,6 +127,7 @@ impl Entropy { Ok(iovec.write_at(&rand_bytes, 0).unwrap().try_into().unwrap()) } + #[tracing::instrument(level = "trace", skip(self))] fn process_entropy_queue(&mut self) { // This is safe since we checked in the event handler that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -184,6 +192,7 @@ impl Entropy { } } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_entropy_queue_event(&mut self) { if let Err(err) = self.queue_events[RNG_QUEUE].read() { error!("Failed to read entropy queue event: {err}"); @@ -196,6 +205,7 @@ impl Entropy { } } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn process_rate_limiter_event(&mut self) { METRICS.entropy.rate_limiter_event_count.inc(); match self.rate_limiter.event_handler() { @@ -210,80 +220,100 @@ impl Entropy { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn process_virtio_queues(&mut self) { self.process_entropy_queue(); } + #[tracing::instrument(level = "trace", skip(self))] pub fn rate_limiter(&self) -> &RateLimiter { &self.rate_limiter } + #[tracing::instrument(level = "trace", skip(self, features))] pub(crate) fn set_avail_features(&mut self, features: u64) { self.avail_features = features; } + #[tracing::instrument(level = "trace", skip(self, features))] pub(crate) fn set_acked_features(&mut self, features: u64) { self.acked_features = features; } + #[tracing::instrument(level = "trace", skip(self, status))] pub(crate) fn set_irq_status(&mut self, status: usize) { self.irq_trigger.irq_status = Arc::new(AtomicUsize::new(status)); } + #[tracing::instrument(level = "trace", skip(self, mem))] pub(crate) fn set_activated(&mut self, mem: GuestMemoryMmap) { self.device_state = DeviceState::Activated(mem); } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn activate_event(&self) -> &EventFd { &self.activate_event } } impl VirtioDevice for Entropy { + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { TYPE_RNG } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[Queue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [Queue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_events } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.irq_trigger.irq_evt } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { self.irq_trigger.irq_status.clone() } + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { self.avail_features } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, acked_features))] fn set_acked_features(&mut self, acked_features: u64) { self.acked_features = acked_features; } + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] fn read_config(&self, _offset: u64, mut _data: &mut [u8]) {} + #[tracing::instrument(level = "trace", skip(self, _offset, _data))] fn write_config(&mut self, _offset: u64, _data: &[u8]) {} + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { self.device_state.is_activated() } + #[tracing::instrument(level = "trace", skip(self, mem))] fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> { self.activate_event.write(1).map_err(|err| { error!("entropy: Cannot write to activate_evt: {err}"); @@ -308,15 +338,18 @@ mod tests { use crate::devices::virtio::VIRTQ_DESC_F_WRITE; impl VirtioTestDevice for Entropy { + #[tracing::instrument(level = "trace", skip(self, queues))] fn set_queues(&mut self, queues: Vec) { self.queues = queues; } + #[tracing::instrument(level = "trace", skip())] fn num_queues() -> usize { RNG_NUM_QUEUES } } + #[tracing::instrument(level = "trace", skip())] fn default_entropy() -> Entropy { Entropy::new(RateLimiter::default()).unwrap() } diff --git a/src/vmm/src/devices/virtio/rng/event_handler.rs b/src/vmm/src/devices/virtio/rng/event_handler.rs index 1186901c136..24ccfa5c34d 100644 --- a/src/vmm/src/devices/virtio/rng/event_handler.rs +++ b/src/vmm/src/devices/virtio/rng/event_handler.rs @@ -4,13 +4,14 @@ use std::os::unix::io::AsRawFd; use event_manager::{EventOps, Events, MutEventSubscriber}; -use log::{error, warn}; +use logger::{error, warn}; use utils::epoll::EventSet; use super::{Entropy, RNG_QUEUE}; use crate::devices::virtio::VirtioDevice; impl Entropy { + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_runtime_events(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.queue_events()[RNG_QUEUE], EventSet::IN)) { error!("entropy: Failed to register queue event: {err}"); @@ -20,12 +21,14 @@ impl Entropy { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_activate_event(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(self.activate_event(), EventSet::IN)) { error!("entropy: Failed to register activate event: {err}"); } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn process_activate_event(&self, ops: &mut EventOps) { if let Err(err) = self.activate_event().read() { error!("entropy: Failed to consume activate event: {err}"); @@ -42,6 +45,7 @@ impl Entropy { } impl MutEventSubscriber for Entropy { + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut event_manager::EventOps) { // This function can be called during different points in the device lifetime: // - shortly after device creation, @@ -54,6 +58,7 @@ impl MutEventSubscriber for Entropy { } } + #[tracing::instrument(level = "trace", skip(self, events, ops))] fn process(&mut self, events: event_manager::Events, ops: &mut event_manager::EventOps) { let event_set = events.event_set(); let source = events.fd(); diff --git a/src/vmm/src/devices/virtio/rng/persist.rs b/src/vmm/src/devices/virtio/rng/persist.rs index e779473328a..3f6824dca32 100644 --- a/src/vmm/src/devices/virtio/rng/persist.rs +++ b/src/vmm/src/devices/virtio/rng/persist.rs @@ -24,6 +24,7 @@ pub struct EntropyState { pub struct EntropyConstructorArgs(GuestMemoryMmap); impl EntropyConstructorArgs { + #[tracing::instrument(level = "trace", skip(mem))] pub fn new(mem: GuestMemoryMmap) -> Self { Self(mem) } @@ -41,6 +42,7 @@ impl Persist<'_> for Entropy { type ConstructorArgs = EntropyConstructorArgs; type Error = EntropyPersistError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { EntropyState { virtio_state: VirtioDeviceState::from_device(self), @@ -48,6 +50,7 @@ impl Persist<'_> for Entropy { } } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, diff --git a/src/vmm/src/devices/virtio/test_utils.rs b/src/vmm/src/devices/virtio/test_utils.rs index 8178f2cf75e..41331d6bba3 100644 --- a/src/vmm/src/devices/virtio/test_utils.rs +++ b/src/vmm/src/devices/virtio/test_utils.rs @@ -21,6 +21,7 @@ macro_rules! check_metric_after_block { }}; } +#[tracing::instrument(level = "trace", skip(region_size))] /// Creates a [`GuestMemoryMmap`] with a single region of the given size starting at guest physical /// address 0 pub fn single_region_mem(region_size: usize) -> GuestMemoryMmap { @@ -28,6 +29,7 @@ pub fn single_region_mem(region_size: usize) -> GuestMemoryMmap { .unwrap() } +#[tracing::instrument(level = "trace", skip())] /// Creates a [`GuestMemoryMmap`] with a single region of size 65536 (= 0x10000 hex) starting at /// guest physical address 0 pub fn default_mem() -> GuestMemoryMmap { @@ -41,6 +43,7 @@ pub struct InputData { } impl InputData { + #[tracing::instrument(level = "trace", skip(self, len))] pub fn get_slice(&self, len: usize) -> &[u8] { let old_pos = self.read_pos.fetch_add(len, Ordering::AcqRel); &self.data[old_pos..old_pos + len] @@ -60,6 +63,7 @@ impl<'a, T> SomeplaceInMemory<'a, T> where T: Debug + utils::vm_memory::ByteValued, { + #[tracing::instrument(level = "trace", skip(location, mem))] fn new(location: GuestAddress, mem: &'a GuestMemoryMmap) -> Self { SomeplaceInMemory { location, @@ -69,17 +73,20 @@ where } // Reads from the actual memory location. + #[tracing::instrument(level = "trace", skip(self))] pub fn get(&self) -> T { self.mem.read_obj(self.location).unwrap() } // Writes to the actual memory location. + #[tracing::instrument(level = "trace", skip(self, val))] pub fn set(&self, val: T) { self.mem.write_obj(val, self.location).unwrap() } // This function returns a place in memory which holds a value of type U, and starts // offset bytes after the current location. + #[tracing::instrument(level = "trace", skip(self, offset))] fn map_offset(&self, offset: usize) -> SomeplaceInMemory<'a, U> { SomeplaceInMemory { location: self.location.checked_add(offset as u64).unwrap(), @@ -90,10 +97,12 @@ where // This function returns a place in memory which holds a value of type U, and starts // immediately after the end of self (which is location + sizeof(T)). + #[tracing::instrument(level = "trace", skip(self))] fn next_place(&self) -> SomeplaceInMemory<'a, U> { self.map_offset::(mem::size_of::()) } + #[tracing::instrument(level = "trace", skip(self))] fn end(&self) -> GuestAddress { self.location .checked_add(mem::size_of::() as u64) @@ -113,6 +122,7 @@ pub struct VirtqDesc<'a> { impl<'a> VirtqDesc<'a> { pub const ALIGNMENT: u64 = 16; + #[tracing::instrument(level = "trace", skip(start, mem))] fn new(start: GuestAddress, mem: &'a GuestMemoryMmap) -> Self { assert_eq!(start.0 & (Self::ALIGNMENT - 1), 0); @@ -129,14 +139,17 @@ impl<'a> VirtqDesc<'a> { } } + #[tracing::instrument(level = "trace", skip(self))] fn start(&self) -> GuestAddress { self.addr.location } + #[tracing::instrument(level = "trace", skip(self))] fn end(&self) -> GuestAddress { self.next.end() } + #[tracing::instrument(level = "trace", skip(self, addr, len, flags, next))] pub fn set(&self, addr: u64, len: u32, flags: u16, next: u16) { self.addr.set(addr); self.len.set(len); @@ -144,10 +157,12 @@ impl<'a> VirtqDesc<'a> { self.next.set(next); } + #[tracing::instrument(level = "trace", skip(self))] pub fn memory(&self) -> &'a GuestMemoryMmap { self.addr.mem } + #[tracing::instrument(level = "trace", skip(self, data))] pub fn set_data(&mut self, data: &[u8]) { assert!(self.len.get() as usize >= data.len()); let mem = self.addr.mem; @@ -156,6 +171,7 @@ impl<'a> VirtqDesc<'a> { .is_ok()); } + #[tracing::instrument(level = "trace", skip(self, expected_data))] pub fn check_data(&self, expected_data: &[u8]) { assert!(self.len.get() as usize >= expected_data.len()); let mem = self.addr.mem; @@ -181,6 +197,7 @@ impl<'a, T> VirtqRing<'a, T> where T: Debug + utils::vm_memory::ByteValued, { + #[tracing::instrument(level = "trace", skip(start, mem, qsize, alignment))] fn new(start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16, alignment: usize) -> Self { assert_eq!(start.0 & (alignment as u64 - 1), 0); @@ -210,6 +227,7 @@ where } } + #[tracing::instrument(level = "trace", skip(self))] pub fn end(&self) -> GuestAddress { self.event.end() } @@ -237,6 +255,7 @@ pub struct VirtQueue<'a> { impl<'a> VirtQueue<'a> { // We try to make sure things are aligned properly :-s + #[tracing::instrument(level = "trace", skip(start, mem, qsize))] pub fn new(start: GuestAddress, mem: &'a GuestMemoryMmap, qsize: u16) -> Self { // power of 2? assert!(qsize > 0 && qsize & (qsize - 1) == 0); @@ -269,27 +288,33 @@ impl<'a> VirtQueue<'a> { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn memory(&self) -> &'a GuestMemoryMmap { self.used.flags.mem } + #[tracing::instrument(level = "trace", skip(self))] pub fn size(&self) -> u16 { self.dtable.len() as u16 } + #[tracing::instrument(level = "trace", skip(self))] pub fn dtable_start(&self) -> GuestAddress { self.dtable.first().unwrap().start() } + #[tracing::instrument(level = "trace", skip(self))] pub fn avail_start(&self) -> GuestAddress { self.avail.flags.location } + #[tracing::instrument(level = "trace", skip(self))] pub fn used_start(&self) -> GuestAddress { self.used.flags.location } // Creates a new Queue, using the underlying memory regions represented by the VirtQueue. + #[tracing::instrument(level = "trace", skip(self))] pub fn create_queue(&self) -> Queue { let mut q = Queue::new(self.size()); @@ -302,14 +327,17 @@ impl<'a> VirtQueue<'a> { q } + #[tracing::instrument(level = "trace", skip(self))] pub fn start(&self) -> GuestAddress { self.dtable_start() } + #[tracing::instrument(level = "trace", skip(self))] pub fn end(&self) -> GuestAddress { self.used.end() } + #[tracing::instrument(level = "trace", skip(self, used_index, expected_id, expected_len))] pub fn check_used_elem(&self, used_index: u16, expected_id: u16, expected_len: u32) { let used_elem = self.used.ring[used_index as usize].get(); assert_eq!(used_elem.id, u32::from(expected_id)); @@ -329,6 +357,7 @@ pub(crate) mod test { use crate::devices::virtio::test_utils::{VirtQueue, VirtqDesc}; use crate::devices::virtio::{Queue, VirtioDevice, MAX_BUFFER_SIZE, VIRTQ_DESC_F_NEXT}; + #[tracing::instrument(level = "trace", skip())] pub fn create_virtio_mem() -> GuestMemoryMmap { utils::vm_memory::test_utils::create_guest_memory_unguarded( &[(GuestAddress(0), MAX_BUFFER_SIZE)], @@ -366,6 +395,7 @@ pub(crate) mod test { } impl fmt::Debug for VirtioTestHelper<'_, T> { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("VirtioTestHelper") .field("event_manager", &"?") @@ -383,6 +413,7 @@ pub(crate) mod test { const QUEUE_SIZE: u16 = 16; // Helper function to create a set of Virtqueues for the device + #[tracing::instrument(level = "trace", skip(mem, num_queues))] fn create_virtqueues(mem: &'a GuestMemoryMmap, num_queues: usize) -> Vec { (0..num_queues) .scan(GuestAddress(0), |next_addr, _| { @@ -395,6 +426,7 @@ pub(crate) mod test { .collect::>() } + #[tracing::instrument(level = "trace", skip(mem, device))] /// Create a new Virtio Device test helper pub fn new(mem: &'a GuestMemoryMmap, mut device: T) -> VirtioTestHelper<'a, T> { let mut event_manager = EventManager::new().unwrap(); @@ -413,11 +445,13 @@ pub(crate) mod test { } } + #[tracing::instrument(level = "trace", skip(self))] /// Get a (locked) reference to the device pub fn device(&mut self) -> MutexGuard { self.device.lock().unwrap() } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Activate the device pub fn activate_device(&mut self, mem: &'a GuestMemoryMmap) { self.device.lock().unwrap().activate(mem.clone()).unwrap(); @@ -426,6 +460,7 @@ pub(crate) mod test { assert_eq!(ev_count, 1); } + #[tracing::instrument(level = "trace", skip(self))] /// Get the start of the data region /// /// The first address that can be used for data in the guest memory mmap @@ -435,6 +470,7 @@ pub(crate) mod test { self.virtqueues.last().unwrap().end().raw_value() } + #[tracing::instrument(level = "trace", skip(self, queue, addr_offset, desc_list))] /// Add a new Descriptor in one of the device's queues /// /// This function adds in one of the queues of the device a DescriptorChain at some offset @@ -487,6 +523,7 @@ pub(crate) mod test { event_fd.write(1).unwrap(); } + #[tracing::instrument(level = "trace", skip(self, msec))] /// Emulate the device for a period of time /// /// # Arguments diff --git a/src/vmm/src/devices/virtio/vsock/csm/connection.rs b/src/vmm/src/devices/virtio/vsock/csm/connection.rs index 2eb056aa06f..e4c1737b626 100644 --- a/src/vmm/src/devices/virtio/vsock/csm/connection.rs +++ b/src/vmm/src/devices/virtio/vsock/csm/connection.rs @@ -84,8 +84,7 @@ use std::num::Wrapping; use std::os::unix::io::{AsRawFd, RawFd}; use std::time::{Duration, Instant}; -use log::{debug, error, info, warn}; -use logger::{IncMetric, METRICS}; +use logger::{debug, error, info, warn, IncMetric, METRICS}; use utils::epoll::EventSet; use utils::vm_memory::{GuestMemoryError, GuestMemoryMmap, ReadVolatile, WriteVolatile}; @@ -143,6 +142,7 @@ impl VsockChannel for VsockConnection where S: VsockConnectionBackend + Debug, { + #[tracing::instrument(level = "trace", skip(self, pkt, mem))] /// Fill in a vsock packet, to be delivered to our peer (the guest driver). /// /// As per the `VsockChannel` trait, this should only be called when there is data to be @@ -280,6 +280,7 @@ where Err(VsockError::NoData) } + #[tracing::instrument(level = "trace", skip(self, pkt, mem))] /// Deliver a guest-generated packet to this connection. /// /// This forwards the data in RW packets to the host stream, and absorbs control packets, @@ -395,6 +396,7 @@ where Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the connection has any pending packet addressed to the peer. fn has_pending_rx(&self) -> bool { !self.pending_rx.is_empty() @@ -405,6 +407,7 @@ impl AsRawFd for VsockConnection where S: VsockConnectionBackend + Debug, { + #[tracing::instrument(level = "trace", skip(self))] /// Get the file descriptor that this connection wants polled. /// /// The connection is interested in being notified about EPOLLIN / EPOLLOUT events on the @@ -418,6 +421,7 @@ impl VsockEpollListener for VsockConnection where S: VsockConnectionBackend + Debug, { + #[tracing::instrument(level = "trace", skip(self))] /// Get the event set that this connection is interested in. /// /// A connection will want to be notified when: @@ -441,6 +445,7 @@ where evset } + #[tracing::instrument(level = "trace", skip(self, evset))] /// Notify the connection about an event (or set of events) that it was interested in. fn notify(&mut self, evset: EventSet) { if evset.contains(EventSet::IN) { @@ -497,6 +502,10 @@ impl VsockConnection where S: VsockConnectionBackend + Debug, { + #[tracing::instrument( + level = "trace", + skip(stream, local_cid, peer_cid, local_port, peer_port, peer_buf_alloc) + )] /// Create a new guest-initiated connection object. pub fn new_peer_init( stream: S, @@ -524,6 +533,10 @@ where } } + #[tracing::instrument( + level = "trace", + skip(stream, local_cid, peer_cid, local_port, peer_port) + )] /// Create a new host-initiated connection object. pub fn new_local_init( stream: S, @@ -550,6 +563,7 @@ where } } + #[tracing::instrument(level = "trace", skip(self))] /// Check if there is an expiry (kill) timer set for this connection, sometime in the /// future. pub fn will_expire(&self) -> bool { @@ -559,6 +573,7 @@ where } } + #[tracing::instrument(level = "trace", skip(self))] /// Check if this connection needs to be scheduled for forceful termination, due to its /// kill timer having expired. pub fn has_expired(&self) -> bool { @@ -568,11 +583,13 @@ where } } + #[tracing::instrument(level = "trace", skip(self))] /// Get the kill timer value, if one is set. pub fn expiry(&self) -> Option { self.expiry } + #[tracing::instrument(level = "trace", skip(self))] /// Schedule the connection to be forcefully terminated ASAP (i.e. the next time the /// connection is asked to yield a packet, via `recv_pkt()`). pub fn kill(&mut self) { @@ -580,11 +597,13 @@ where self.pending_rx.insert(PendingRx::Rst); } + #[tracing::instrument(level = "trace", skip(self))] /// Return the connections state. pub fn state(&self) -> ConnState { self.state } + #[tracing::instrument(level = "trace", skip(self, buf))] /// Send some raw, untracked, data straight to the underlying connected stream. /// Returns: number of bytes written, or the error describing the write failure. /// @@ -595,6 +614,7 @@ where self.stream.write(buf).map_err(VsockCsmError::StreamWrite) } + #[tracing::instrument(level = "trace", skip(self, mem, pkt))] /// Send some raw data (a byte-slice) to the host stream. /// /// Raw data can either be sent straight to the host stream, or to our TX buffer, if the @@ -641,6 +661,7 @@ where Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the credit information the peer has last received from us is outdated. fn peer_needs_credit_update(&self) -> bool { let peer_seen_free_buf = @@ -648,18 +669,21 @@ where peer_seen_free_buf < Wrapping(defs::CONN_CREDIT_UPDATE_THRESHOLD) } + #[tracing::instrument(level = "trace", skip(self))] /// Check if we need to ask the peer for a credit update before sending any more data its /// way. fn need_credit_update_from_peer(&self) -> bool { self.peer_avail_credit() == 0 } + #[tracing::instrument(level = "trace", skip(self))] /// Get the maximum number of bytes that we can send to our peer, without overflowing its /// buffer. fn peer_avail_credit(&self) -> usize { (Wrapping(self.peer_buf_alloc) - (self.rx_cnt - self.peer_fwd_cnt)).0 as usize } + #[tracing::instrument(level = "trace", skip(self, pkt))] /// Prepare a packet header for transmission to our peer. fn init_pkt<'a>(&self, pkt: &'a mut VsockPacket) -> &'a mut VsockPacket { pkt.set_src_cid(self.local_cid) @@ -711,6 +735,7 @@ mod tests { write_state: StreamState, } impl TestStream { + #[tracing::instrument(level = "trace", skip())] fn new() -> Self { Self { fd: EventFd::new(libc::EFD_NONBLOCK).unwrap(), @@ -720,6 +745,7 @@ mod tests { write_buf: Vec::new(), } } + #[tracing::instrument(level = "trace", skip(buf))] fn new_with_read_buf(buf: &[u8]) -> Self { let mut stream = Self::new(); stream.read_buf = buf.to_vec(); @@ -728,12 +754,14 @@ mod tests { } impl AsRawFd for TestStream { + #[tracing::instrument(level = "trace", skip(self))] fn as_raw_fd(&self) -> RawFd { self.fd.as_raw_fd() } } impl Read for TestStream { + #[tracing::instrument(level = "trace", skip(self, data))] fn read(&mut self, data: &mut [u8]) -> Result { match self.read_state { StreamState::Closed => Ok(0), @@ -754,6 +782,7 @@ mod tests { } impl ReadVolatile for TestStream { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read_volatile( &mut self, buf: &mut VolatileSlice, @@ -764,6 +793,7 @@ mod tests { } impl Write for TestStream { + #[tracing::instrument(level = "trace", skip(self, data))] fn write(&mut self, data: &[u8]) -> Result { match self.write_state { StreamState::Closed => Err(IoError::new(ErrorKind::BrokenPipe, "EPIPE")), @@ -775,12 +805,14 @@ mod tests { StreamState::WouldBlock => Err(IoError::new(ErrorKind::WouldBlock, "EAGAIN")), } } + #[tracing::instrument(level = "trace", skip(self))] fn flush(&mut self) -> Result<(), IoError> { Ok(()) } } impl WriteVolatile for TestStream { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_volatile( &mut self, buf: &VolatileSlice, @@ -796,17 +828,20 @@ mod tests { where S: VsockConnectionBackend + Debug, { + #[tracing::instrument(level = "trace", skip(self))] /// Get the fwd_cnt value from the connection. pub(crate) fn fwd_cnt(&self) -> Wrapping { self.fwd_cnt } + #[tracing::instrument(level = "trace", skip(self))] /// Forcefully insert a credit update flag. pub(crate) fn insert_credit_update(&mut self) { self.pending_rx.insert(PendingRx::CreditUpdate); } } + #[tracing::instrument(level = "trace", skip(pkt, op, len))] fn init_pkt(pkt: &mut VsockPacket, op: u16, len: u32) -> &mut VsockPacket { pkt.set_src_cid(PEER_CID) .set_dst_cid(LOCAL_CID) @@ -835,10 +870,12 @@ mod tests { } impl CsmTestContext { + #[tracing::instrument(level = "trace", skip())] fn new_established() -> Self { Self::new(ConnState::Established) } + #[tracing::instrument(level = "trace", skip(conn_state))] fn new(conn_state: ConnState) -> Self { let vsock_test_ctx = TestContext::new(); let mut handler_ctx = vsock_test_ctx.create_event_handler_context(); @@ -885,10 +922,12 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(self, stream))] fn set_stream(&mut self, stream: TestStream) { self.conn.stream = stream; } + #[tracing::instrument(level = "trace", skip(self, credit))] fn set_peer_credit(&mut self, credit: u32) { assert!(credit < self.conn.peer_buf_alloc); self.conn.peer_fwd_cnt = Wrapping(0); @@ -896,31 +935,37 @@ mod tests { assert_eq!(self.conn.peer_avail_credit(), credit as usize); } + #[tracing::instrument(level = "trace", skip(self))] fn send(&mut self) { self.conn .send_pkt(&self.pkt, &self._vsock_test_ctx.mem) .unwrap(); } + #[tracing::instrument(level = "trace", skip(self))] fn recv(&mut self) { self.conn .recv_pkt(&mut self.pkt, &self._vsock_test_ctx.mem) .unwrap(); } + #[tracing::instrument(level = "trace", skip(self))] fn notify_epollin(&mut self) { self.conn.notify(EventSet::IN); assert!(self.conn.has_pending_rx()); } + #[tracing::instrument(level = "trace", skip(self))] fn notify_epollout(&mut self) { self.conn.notify(EventSet::OUT); } + #[tracing::instrument(level = "trace", skip(self, op, len))] fn init_pkt(&mut self, op: u16, len: u32) -> &mut VsockPacket { init_pkt(&mut self.pkt, op, len) } + #[tracing::instrument(level = "trace", skip(self, data))] fn init_data_pkt(&mut self, mut data: &[u8]) -> &VsockPacket { assert!(data.len() <= self.pkt.buf_size()); self.init_pkt(uapi::VSOCK_OP_RW, data.len() as u32); diff --git a/src/vmm/src/devices/virtio/vsock/csm/mod.rs b/src/vmm/src/devices/virtio/vsock/csm/mod.rs index 8237c589e03..76824011a40 100644 --- a/src/vmm/src/devices/virtio/vsock/csm/mod.rs +++ b/src/vmm/src/devices/virtio/vsock/csm/mod.rs @@ -73,6 +73,7 @@ enum PendingRx { CreditUpdate = 4, } impl PendingRx { + #[tracing::instrument(level = "trace", skip(self))] /// Transform the enum value into a bitmask, that can be used for set operations. fn into_mask(self) -> u16 { 1u16 << (self as u16) @@ -86,11 +87,13 @@ struct PendingRxSet { } impl PendingRxSet { + #[tracing::instrument(level = "trace", skip(self, it))] /// Insert an item into the set. fn insert(&mut self, it: PendingRx) { self.data |= it.into_mask(); } + #[tracing::instrument(level = "trace", skip(self, it))] /// Remove an item from the set and return: /// - true, if the item was in the set; or /// - false, if the item wasn't in the set. @@ -100,11 +103,13 @@ impl PendingRxSet { ret } + #[tracing::instrument(level = "trace", skip(self, it))] /// Check if an item is present in this set. fn contains(&self, it: PendingRx) -> bool { self.data & it.into_mask() != 0 } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the set is empty. fn is_empty(&self) -> bool { self.data == 0 @@ -113,6 +118,7 @@ impl PendingRxSet { /// Create a set containing only one item. impl From for PendingRxSet { + #[tracing::instrument(level = "trace", skip(it))] fn from(it: PendingRx) -> Self { Self { data: it.into_mask(), diff --git a/src/vmm/src/devices/virtio/vsock/csm/txbuf.rs b/src/vmm/src/devices/virtio/vsock/csm/txbuf.rs index 2b90da878ab..ad1662866f0 100644 --- a/src/vmm/src/devices/virtio/vsock/csm/txbuf.rs +++ b/src/vmm/src/devices/virtio/vsock/csm/txbuf.rs @@ -27,6 +27,7 @@ impl TxBuf { /// Total buffer size, in bytes. const SIZE: usize = defs::CONN_TX_BUF_SIZE as usize; + #[tracing::instrument(level = "trace", skip())] /// Ring-buffer constructor. pub fn new() -> Self { Self { @@ -36,12 +37,14 @@ impl TxBuf { } } + #[tracing::instrument(level = "trace", skip(self))] /// Get the used length of this buffer - number of bytes that have been pushed in, but not /// yet flushed out. pub fn len(&self) -> usize { (self.head - self.tail).0 as usize } + #[tracing::instrument(level = "trace", skip(self, src))] /// Push a byte slice onto the ring-buffer. /// /// Either the entire source slice will be pushed to the ring-buffer, or none of it, if @@ -81,6 +84,7 @@ impl TxBuf { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, sink))] /// Flush the contents of the ring-buffer to a writable stream. /// /// Return the number of bytes that have been transferred out of the ring-buffer and into @@ -129,6 +133,7 @@ impl TxBuf { Ok(written + self.flush_to(sink).unwrap_or(0)) } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the buffer holds any data that hasn't yet been flushed out. pub fn is_empty(&self) -> bool { self.len() == 0 @@ -136,6 +141,7 @@ impl TxBuf { } impl WriteVolatile for TxBuf { + #[tracing::instrument(level = "trace", skip(self, buf))] fn write_volatile( &mut self, buf: &VolatileSlice, @@ -161,6 +167,7 @@ mod tests { impl TestSink { const DEFAULT_CAPACITY: usize = 2 * TxBuf::SIZE; + #[tracing::instrument(level = "trace", skip())] fn new() -> Self { Self { data: Vec::with_capacity(Self::DEFAULT_CAPACITY), @@ -171,6 +178,7 @@ mod tests { } impl Write for TestSink { + #[tracing::instrument(level = "trace", skip(self, src))] fn write(&mut self, src: &[u8]) -> Result { if self.err.is_some() { return Err(self.err.take().unwrap()); @@ -179,19 +187,23 @@ mod tests { self.data.extend_from_slice(&src[..len_to_push]); Ok(len_to_push) } + #[tracing::instrument(level = "trace", skip(self))] fn flush(&mut self) -> Result<(), IoError> { Ok(()) } } impl TestSink { + #[tracing::instrument(level = "trace", skip(self))] fn clear(&mut self) { self.data = Vec::with_capacity(self.capacity); self.err = None; } + #[tracing::instrument(level = "trace", skip(self, err))] fn set_err(&mut self, err: IoError) { self.err = Some(err); } + #[tracing::instrument(level = "trace", skip(self, capacity))] fn set_capacity(&mut self, capacity: usize) { self.capacity = capacity; if self.data.len() > self.capacity { diff --git a/src/vmm/src/devices/virtio/vsock/device.rs b/src/vmm/src/devices/virtio/vsock/device.rs index 8ca98d92644..f7b31f57191 100644 --- a/src/vmm/src/devices/virtio/vsock/device.rs +++ b/src/vmm/src/devices/virtio/vsock/device.rs @@ -23,8 +23,7 @@ use std::fmt::Debug; use std::sync::atomic::AtomicUsize; use std::sync::Arc; -use log::{debug, error, warn}; -use logger::{IncMetric, METRICS}; +use logger::{debug, error, warn, IncMetric, METRICS}; use utils::byte_order; use utils::eventfd::EventFd; use utils::vm_memory::{Bytes, GuestMemoryMmap}; @@ -78,6 +77,7 @@ impl Vsock where B: VsockBackend + Debug, { + #[tracing::instrument(level = "trace", skip(cid, backend, queues))] /// Auxiliary function for creating a new virtio-vsock device with the given VM CID, vsock /// backend and empty virtio queues. pub fn with_queues( @@ -103,6 +103,7 @@ where }) } + #[tracing::instrument(level = "trace", skip(cid, backend))] /// Create a new virtio-vsock device with the given VM CID and vsock backend. pub fn new(cid: u64, backend: B) -> Result, VsockError> { let queues: Vec = defs::VSOCK_QUEUE_SIZES @@ -112,21 +113,25 @@ where Self::with_queues(cid, backend, queues) } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the ID of this vsock device as used in MMIO device identification. pub fn id(&self) -> &str { defs::VSOCK_DEV_ID } + #[tracing::instrument(level = "trace", skip(self))] /// Retrieve the cid associated with this vsock device. pub fn cid(&self) -> u64 { self.cid } + #[tracing::instrument(level = "trace", skip(self))] /// Access the backend behind the device. pub fn backend(&self) -> &B { &self.backend } + #[tracing::instrument(level = "trace", skip(self))] /// Signal the guest driver that we've used some virtio buffers that it had previously made /// available. pub fn signal_used_queue(&self) -> Result<(), DeviceError> { @@ -136,6 +141,7 @@ where .map_err(DeviceError::FailedSignalingIrq) } + #[tracing::instrument(level = "trace", skip(self))] /// Walk the driver-provided RX queue buffers and attempt to fill them up with any data that we /// have pending. Return `true` if descriptors have been added to the used ring, and `false` /// otherwise. @@ -189,6 +195,7 @@ where have_used } + #[tracing::instrument(level = "trace", skip(self))] /// Walk the driver-provided TX queue buffers, package them up as vsock packets, and send them /// to the backend for processing. Return `true` if descriptors have been added to the used /// ring, and `false` otherwise. @@ -233,6 +240,7 @@ where // Send TRANSPORT_RESET_EVENT to driver. According to specs, the driver shuts down established // connections and the guest_cid configuration field is fetched again. Existing listen sockets // remain but their CID is updated to reflect the current guest_cid. + #[tracing::instrument(level = "trace", skip(self))] pub fn send_transport_reset_event(&mut self) -> Result<(), DeviceError> { // This is safe since we checked in the caller function that the device is activated. let mem = self.device_state.mem().unwrap(); @@ -261,42 +269,52 @@ impl VirtioDevice for Vsock where B: VsockBackend + Debug + 'static, { + #[tracing::instrument(level = "trace", skip(self))] fn avail_features(&self) -> u64 { self.avail_features } + #[tracing::instrument(level = "trace", skip(self))] fn acked_features(&self) -> u64 { self.acked_features } + #[tracing::instrument(level = "trace", skip(self, acked_features))] fn set_acked_features(&mut self, acked_features: u64) { self.acked_features = acked_features } + #[tracing::instrument(level = "trace", skip(self))] fn device_type(&self) -> u32 { uapi::VIRTIO_ID_VSOCK } + #[tracing::instrument(level = "trace", skip(self))] fn queues(&self) -> &[VirtQueue] { &self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queues_mut(&mut self) -> &mut [VirtQueue] { &mut self.queues } + #[tracing::instrument(level = "trace", skip(self))] fn queue_events(&self) -> &[EventFd] { &self.queue_events } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_evt(&self) -> &EventFd { &self.irq_trigger.irq_evt } + #[tracing::instrument(level = "trace", skip(self))] fn interrupt_status(&self) -> Arc { self.irq_trigger.irq_status.clone() } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn read_config(&self, offset: u64, data: &mut [u8]) { match offset { 0 if data.len() == 8 => byte_order::write_le_u64(data, self.cid()), @@ -317,6 +335,7 @@ where } } + #[tracing::instrument(level = "trace", skip(self, offset, data))] fn write_config(&mut self, offset: u64, data: &[u8]) { METRICS.vsock.cfg_fails.inc(); warn!( @@ -326,6 +345,7 @@ where ); } + #[tracing::instrument(level = "trace", skip(self, mem))] fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> { if self.queues.len() != defs::VSOCK_NUM_QUEUES { METRICS.vsock.activate_fails.inc(); @@ -348,6 +368,7 @@ where Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn is_activated(&self) -> bool { self.device_state.is_activated() } diff --git a/src/vmm/src/devices/virtio/vsock/event_handler.rs b/src/vmm/src/devices/virtio/vsock/event_handler.rs index b2e539ee101..c71b0b9941f 100755 --- a/src/vmm/src/devices/virtio/vsock/event_handler.rs +++ b/src/vmm/src/devices/virtio/vsock/event_handler.rs @@ -28,8 +28,7 @@ use std::fmt::Debug; use std::os::unix::io::AsRawFd; use event_manager::{EventOps, Events, MutEventSubscriber}; -use log::{debug, error, warn}; -use logger::{IncMetric, METRICS}; +use logger::{debug, error, warn, IncMetric, METRICS}; use utils::epoll::EventSet; use super::device::{Vsock, EVQ_INDEX, RXQ_INDEX, TXQ_INDEX}; @@ -40,6 +39,7 @@ impl Vsock where B: Debug + VsockBackend + 'static, { + #[tracing::instrument(level = "trace", skip(self, evset))] pub fn handle_rxq_event(&mut self, evset: EventSet) -> bool { debug!("vsock: RX queue event"); @@ -60,6 +60,7 @@ where raise_irq } + #[tracing::instrument(level = "trace", skip(self, evset))] pub fn handle_txq_event(&mut self, evset: EventSet) -> bool { debug!("vsock: TX queue event"); @@ -86,6 +87,7 @@ where raise_irq } + #[tracing::instrument(level = "trace", skip(self, evset))] pub fn handle_evq_event(&mut self, evset: EventSet) -> bool { debug!("vsock: event queue event"); @@ -102,6 +104,7 @@ where false } + #[tracing::instrument(level = "trace", skip(self, evset))] /// Notify backend of new events. pub fn notify_backend(&mut self, evset: EventSet) -> bool { debug!("vsock: backend event"); @@ -119,6 +122,7 @@ where raise_irq } + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_runtime_events(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.queue_events[RXQ_INDEX], EventSet::IN)) { error!("Failed to register rx queue event: {}", err); @@ -134,12 +138,14 @@ where } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn register_activate_event(&self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.activate_evt, EventSet::IN)) { error!("Failed to register activate event: {}", err); } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn handle_activate_event(&self, ops: &mut EventOps) { debug!("vsock: activate event"); if let Err(err) = self.activate_evt.read() { @@ -156,6 +162,7 @@ impl MutEventSubscriber for Vsock where B: Debug + VsockBackend + 'static, { + #[tracing::instrument(level = "trace", skip(self, event, ops))] fn process(&mut self, event: Events, ops: &mut EventOps) { let source = event.fd(); let evset = event.event_set(); @@ -190,6 +197,7 @@ where } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { // This function can be called during different points in the device lifetime: // - shortly after device creation, @@ -412,6 +420,7 @@ mod tests { // function for testing error cases, so the asserts always expect is_err() to be true. When // desc_idx = 0 we are altering the header (first descriptor in the chain), and when // desc_idx = 1 we are altering the packet buffer. + #[tracing::instrument(level = "trace", skip(test_ctx, desc_idx, addr, len))] fn vsock_bof_helper(test_ctx: &mut TestContext, desc_idx: usize, addr: u64, len: u32) { use utils::vm_memory::GuestAddress; diff --git a/src/vmm/src/devices/virtio/vsock/packet.rs b/src/vmm/src/devices/virtio/vsock/packet.rs index 8481e00bb04..3d6b749832e 100644 --- a/src/vmm/src/devices/virtio/vsock/packet.rs +++ b/src/vmm/src/devices/virtio/vsock/packet.rs @@ -99,6 +99,7 @@ pub struct VsockPacket { } impl VsockPacket { + #[tracing::instrument(level = "trace", skip(desc, expected_write_only))] fn check_desc_write_only( desc: &DescriptorChain, expected_write_only: bool, @@ -113,6 +114,7 @@ impl VsockPacket { Ok(()) } + #[tracing::instrument(level = "trace", skip(hdr_desc, expected_write_only))] fn check_hdr_desc( hdr_desc: &DescriptorChain, expected_write_only: bool, @@ -132,6 +134,7 @@ impl VsockPacket { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, hdr_desc, expected_write_only))] fn init_buf( &mut self, hdr_desc: &DescriptorChain, @@ -158,6 +161,7 @@ impl VsockPacket { Ok(()) } + #[tracing::instrument(level = "trace", skip(hdr_desc))] /// Create the packet wrapper from a TX virtq chain head. /// /// The chain head is expected to hold valid packet header data. A following packet buffer @@ -202,6 +206,7 @@ impl VsockPacket { Ok(pkt) } + #[tracing::instrument(level = "trace", skip(hdr_desc))] /// Create the packet wrapper from an RX virtq chain head. /// /// There must be two descriptors in the chain, both writable: a header descriptor and a data @@ -225,11 +230,13 @@ impl VsockPacket { Ok(pkt) } + #[tracing::instrument(level = "trace", skip(self))] /// Provides in-place access to the local copy of the vsock packet header. pub fn hdr(&self) -> &VsockPacketHeader { &self.hdr } + #[tracing::instrument(level = "trace", skip(self, mem))] /// Writes the local copy of the packet header to the guest memory. pub fn commit_hdr(&self, mem: &GuestMemoryMmap) -> Result<(), VsockError> { // Reject weirdly-sized packets. @@ -239,6 +246,7 @@ impl VsockPacket { .map_err(VsockError::GuestMemoryMmap) } + #[tracing::instrument(level = "trace", skip(self))] /// Verifies packet length against `MAX_PKT_BUF_SIZE` limit. pub fn check_len(&self) -> Result<(), VsockError> { if self.len() > defs::MAX_PKT_BUF_SIZE as u32 { @@ -248,10 +256,12 @@ impl VsockPacket { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn buf_size(&self) -> usize { self.buf_size } + #[tracing::instrument(level = "trace", skip(self, mem, buf_offset, count))] /// Verifies that it is legal to write `count` bytes into the data descriptor of this /// [`VsockPacket`] at offset `buf_offset`. /// @@ -283,6 +293,7 @@ impl VsockPacket { .ok_or(VsockError::GuestMemoryBounds) } + #[tracing::instrument(level = "trace", skip(self, mem, offset, src, count))] pub fn read_at_offset_from( &mut self, mem: &GuestMemoryMmap, @@ -307,6 +318,7 @@ impl VsockPacket { } } + #[tracing::instrument(level = "trace", skip(self, mem, offset, dst, count))] pub fn write_from_offset_to( &self, mem: &GuestMemoryMmap, @@ -331,96 +343,117 @@ impl VsockPacket { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn src_cid(&self) -> u64 { u64::from_le(self.hdr.src_cid) } + #[tracing::instrument(level = "trace", skip(self, cid))] pub fn set_src_cid(&mut self, cid: u64) -> &mut Self { self.hdr.src_cid = cid.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn dst_cid(&self) -> u64 { u64::from_le(self.hdr.dst_cid) } + #[tracing::instrument(level = "trace", skip(self, cid))] pub fn set_dst_cid(&mut self, cid: u64) -> &mut Self { self.hdr.dst_cid = cid.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn src_port(&self) -> u32 { u32::from_le(self.hdr.src_port) } + #[tracing::instrument(level = "trace", skip(self, port))] pub fn set_src_port(&mut self, port: u32) -> &mut Self { self.hdr.src_port = port.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn dst_port(&self) -> u32 { u32::from_le(self.hdr.dst_port) } + #[tracing::instrument(level = "trace", skip(self, port))] pub fn set_dst_port(&mut self, port: u32) -> &mut Self { self.hdr.dst_port = port.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn len(&self) -> u32 { u32::from_le(self.hdr.len) } + #[tracing::instrument(level = "trace", skip(self, len))] pub fn set_len(&mut self, len: u32) -> &mut Self { self.hdr.len = len.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn type_(&self) -> u16 { u16::from_le(self.hdr.type_) } + #[tracing::instrument(level = "trace", skip(self, type_))] pub fn set_type(&mut self, type_: u16) -> &mut Self { self.hdr.type_ = type_.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn op(&self) -> u16 { u16::from_le(self.hdr.op) } + #[tracing::instrument(level = "trace", skip(self, op))] pub fn set_op(&mut self, op: u16) -> &mut Self { self.hdr.op = op.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn flags(&self) -> u32 { u32::from_le(self.hdr.flags) } + #[tracing::instrument(level = "trace", skip(self, flags))] pub fn set_flags(&mut self, flags: u32) -> &mut Self { self.hdr.flags = flags.to_le(); self } + #[tracing::instrument(level = "trace", skip(self, flag))] pub fn set_flag(&mut self, flag: u32) -> &mut Self { self.set_flags(self.flags() | flag); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn buf_alloc(&self) -> u32 { u32::from_le(self.hdr.buf_alloc) } + #[tracing::instrument(level = "trace", skip(self, buf_alloc))] pub fn set_buf_alloc(&mut self, buf_alloc: u32) -> &mut Self { self.hdr.buf_alloc = buf_alloc.to_le(); self } + #[tracing::instrument(level = "trace", skip(self))] pub fn fwd_cnt(&self) -> u32 { u32::from_le(self.hdr.fwd_cnt) } + #[tracing::instrument(level = "trace", skip(self, fwd_cnt))] pub fn set_fwd_cnt(&mut self, fwd_cnt: u32) -> &mut Self { self.hdr.fwd_cnt = fwd_cnt.to_le(); self @@ -467,6 +500,7 @@ mod tests { }; } + #[tracing::instrument(level = "trace", skip(len, guest_desc, mem))] fn set_pkt_len(len: u32, guest_desc: &GuestQDesc, mem: &GuestMemoryMmap) { let hdr_addr = GuestAddress(guest_desc.addr.get()); let mut hdr: VsockPacketHeader = mem.read_obj(hdr_addr).unwrap(); diff --git a/src/vmm/src/devices/virtio/vsock/persist.rs b/src/vmm/src/devices/virtio/vsock/persist.rs index 7d188b58c68..ccd30f2094c 100644 --- a/src/vmm/src/devices/virtio/vsock/persist.rs +++ b/src/vmm/src/devices/virtio/vsock/persist.rs @@ -72,12 +72,14 @@ impl Persist<'_> for VsockUnixBackend { type ConstructorArgs = VsockUdsConstructorArgs; type Error = VsockUnixBackendError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { VsockBackendState::Uds(VsockUdsState { path: self.host_sock_path.clone(), }) } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, @@ -99,6 +101,7 @@ where type ConstructorArgs = VsockConstructorArgs; type Error = VsockError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { VsockFrontendState { cid: self.cid(), @@ -106,6 +109,7 @@ where } } + #[tracing::instrument(level = "trace", skip(constructor_args, state))] fn restore( constructor_args: Self::ConstructorArgs, state: &Self::State, @@ -150,12 +154,14 @@ pub(crate) mod tests { type ConstructorArgs = VsockUdsConstructorArgs; type Error = VsockUnixBackendError; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { VsockBackendState::Uds(VsockUdsState { path: "test".to_owned(), }) } + #[tracing::instrument(level = "trace", skip(state))] fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result { match state { VsockBackendState::Uds(_) => Ok(TestBackend::new()), diff --git a/src/vmm/src/devices/virtio/vsock/test_utils.rs b/src/vmm/src/devices/virtio/vsock/test_utils.rs index db75c5fd2b5..6ffe0efafac 100644 --- a/src/vmm/src/devices/virtio/vsock/test_utils.rs +++ b/src/vmm/src/devices/virtio/vsock/test_utils.rs @@ -30,6 +30,7 @@ pub struct TestBackend { } impl TestBackend { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> Self { Self { evfd: EventFd::new(libc::EFD_NONBLOCK).unwrap(), @@ -42,24 +43,29 @@ impl TestBackend { } } + #[tracing::instrument(level = "trace", skip(self, err))] pub fn set_rx_err(&mut self, err: Option) { self.rx_err = err; } + #[tracing::instrument(level = "trace", skip(self, err))] pub fn set_tx_err(&mut self, err: Option) { self.tx_err = err; } + #[tracing::instrument(level = "trace", skip(self, prx))] pub fn set_pending_rx(&mut self, prx: bool) { self.pending_rx = prx; } } impl Default for TestBackend { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self::new() } } impl VsockChannel for TestBackend { + #[tracing::instrument(level = "trace", skip(self, pkt, mem))] fn recv_pkt(&mut self, pkt: &mut VsockPacket, mem: &GuestMemoryMmap) -> Result<(), VsockError> { let cool_buf = [0xDu8, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF]; match self.rx_err.take() { @@ -79,6 +85,7 @@ impl VsockChannel for TestBackend { } } + #[tracing::instrument(level = "trace", skip(self, _pkt, _mem))] fn send_pkt(&mut self, _pkt: &VsockPacket, _mem: &GuestMemoryMmap) -> Result<(), VsockError> { match self.tx_err.take() { None => { @@ -89,21 +96,25 @@ impl VsockChannel for TestBackend { } } + #[tracing::instrument(level = "trace", skip(self))] fn has_pending_rx(&self) -> bool { self.pending_rx } } impl AsRawFd for TestBackend { + #[tracing::instrument(level = "trace", skip(self))] fn as_raw_fd(&self) -> RawFd { self.evfd.as_raw_fd() } } impl VsockEpollListener for TestBackend { + #[tracing::instrument(level = "trace", skip(self))] fn get_polled_evset(&self) -> EventSet { EventSet::IN } + #[tracing::instrument(level = "trace", skip(self, evset))] fn notify(&mut self, evset: EventSet) { self.evset = Some(evset); } @@ -119,6 +130,7 @@ pub struct TestContext { } impl TestContext { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> Self { const CID: u64 = 52; const MEM_SIZE: usize = 1024 * 1024 * 128; @@ -131,6 +143,7 @@ impl TestContext { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn create_event_handler_context(&self) -> EventHandlerContext { const QSIZE: u16 = 256; @@ -170,6 +183,7 @@ impl TestContext { } impl Default for TestContext { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self::new() } @@ -184,21 +198,25 @@ pub struct EventHandlerContext<'a> { } impl<'a> EventHandlerContext<'a> { + #[tracing::instrument(level = "trace", skip(self, mem))] pub fn mock_activate(&mut self, mem: GuestMemoryMmap) { // Artificially activate the device. self.device.activate(mem).unwrap(); } + #[tracing::instrument(level = "trace", skip(self))] pub fn signal_txq_event(&mut self) { self.device.queue_events[TXQ_INDEX].write(1).unwrap(); self.device.handle_txq_event(EventSet::IN); } + #[tracing::instrument(level = "trace", skip(self))] pub fn signal_rxq_event(&mut self) { self.device.queue_events[RXQ_INDEX].write(1).unwrap(); self.device.handle_rxq_event(EventSet::IN); } } +#[tracing::instrument(level = "trace", skip(pkt, mem, how_much))] #[cfg(test)] pub fn read_packet_data(pkt: &VsockPacket, mem: &GuestMemoryMmap, how_much: usize) -> Vec { let mut buf = vec![0; how_much]; @@ -211,6 +229,7 @@ impl Vsock where B: VsockBackend, { + #[tracing::instrument(level = "trace", skip(vsock, idx, val))] pub fn write_element_in_queue(vsock: &Vsock, idx: usize, val: u64) { if idx > vsock.queue_events.len() - 1 { panic!("Index bigger than the number of queues of this device"); @@ -218,6 +237,7 @@ where vsock.queue_events[idx].write(val).unwrap(); } + #[tracing::instrument(level = "trace", skip(vsock, idx))] pub fn get_element_from_interest_list(vsock: &Vsock, idx: usize) -> u64 { match idx { 0..=2 => u64::try_from(vsock.queue_events[idx].as_raw_fd()).unwrap(), diff --git a/src/vmm/src/devices/virtio/vsock/unix/muxer.rs b/src/vmm/src/devices/virtio/vsock/unix/muxer.rs index 005df93a7f0..14bf53c8d99 100644 --- a/src/vmm/src/devices/virtio/vsock/unix/muxer.rs +++ b/src/vmm/src/devices/virtio/vsock/unix/muxer.rs @@ -36,8 +36,7 @@ use std::io::Read; use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::net::{UnixListener, UnixStream}; -use log::{debug, error, info, warn}; -use logger::{IncMetric, METRICS}; +use logger::{debug, error, info, warn, IncMetric, METRICS}; use utils::epoll::{ControlOperation, Epoll, EpollEvent, EventSet}; use utils::vm_memory::GuestMemoryMmap; @@ -111,6 +110,7 @@ pub struct VsockMuxer { } impl VsockChannel for VsockMuxer { + #[tracing::instrument(level = "trace", skip(self, pkt, mem))] /// Deliver a vsock packet to the guest vsock driver. /// /// Retuns: @@ -181,6 +181,7 @@ impl VsockChannel for VsockMuxer { Err(VsockError::NoData) } + #[tracing::instrument(level = "trace", skip(self, pkt, mem))] /// Deliver a guest-generated packet to its destination in the vsock backend. /// /// This absorbs unexpected packets, handles RSTs (by dropping connections), and forwards @@ -249,6 +250,7 @@ impl VsockChannel for VsockMuxer { res } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the muxer has any pending RX data, with which to fill a guest-provided RX /// buffer. fn has_pending_rx(&self) -> bool { @@ -257,6 +259,7 @@ impl VsockChannel for VsockMuxer { } impl AsRawFd for VsockMuxer { + #[tracing::instrument(level = "trace", skip(self))] /// Get the FD to be registered for polling upstream (in the main VMM epoll loop, in this /// case). /// @@ -267,6 +270,7 @@ impl AsRawFd for VsockMuxer { } impl VsockEpollListener for VsockMuxer { + #[tracing::instrument(level = "trace", skip(self))] /// Get the epoll events to be polled upstream. /// /// Since the polled FD is a nested epoll FD, we're only interested in EPOLLIN events (i.e. @@ -275,6 +279,7 @@ impl VsockEpollListener for VsockMuxer { EventSet::IN } + #[tracing::instrument(level = "trace", skip(self))] /// Notify the muxer about a pending event having occured under its nested epoll FD. fn notify(&mut self, _: EventSet) { debug!("vsock: muxer received kick"); @@ -303,6 +308,7 @@ impl VsockEpollListener for VsockMuxer { impl VsockBackend for VsockMuxer {} impl VsockMuxer { + #[tracing::instrument(level = "trace", skip(cid, host_sock_path))] /// Muxer constructor. pub fn new(cid: u64, host_sock_path: String) -> Result { // Open/bind on the host Unix socket, so we can accept host-initiated @@ -329,11 +335,13 @@ impl VsockMuxer { Ok(muxer) } + #[tracing::instrument(level = "trace", skip(self))] /// Return the file system path of the host-side Unix socket. pub fn host_sock_path(&self) -> &str { &self.host_sock_path } + #[tracing::instrument(level = "trace", skip(self, fd, event_set))] /// Handle/dispatch an epoll event to its listener. fn handle_event(&mut self, fd: RawFd, event_set: EventSet) { debug!( @@ -422,6 +430,7 @@ impl VsockMuxer { } } + #[tracing::instrument(level = "trace", skip(stream))] /// Parse a host "connect" command, and extract the destination vsock port. fn read_local_stream_port(stream: &mut UnixStream) -> Result { let mut buf = [0u8; 32]; @@ -472,6 +481,7 @@ impl VsockMuxer { .map_err(|_| VsockUnixBackendError::InvalidPortRequest) } + #[tracing::instrument(level = "trace", skip(self, key, conn))] /// Add a new connection to the active connection pool. fn add_connection( &mut self, @@ -511,6 +521,7 @@ impl VsockMuxer { }) } + #[tracing::instrument(level = "trace", skip(self, key))] /// Remove a connection from the active connection poll. fn remove_connection(&mut self, key: ConnMapKey) { if let Some(conn) = self.conn_map.remove(&key) { @@ -520,6 +531,7 @@ impl VsockMuxer { self.free_local_port(key.local_port); } + #[tracing::instrument(level = "trace", skip(self, key))] /// Schedule a connection for immediate termination. /// I.e. as soon as we can also let our peer know we're dropping the connection, by sending /// it an RST packet. @@ -541,6 +553,7 @@ impl VsockMuxer { } } + #[tracing::instrument(level = "trace", skip(self, fd, listener))] /// Register a new epoll listener under the muxer's nested epoll FD. fn add_listener( &mut self, @@ -567,6 +580,7 @@ impl VsockMuxer { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, fd))] /// Remove (and return) a previously registered epoll listener. fn remove_listener(&mut self, fd: RawFd) -> Option { let maybe_listener = self.listener_map.remove(&fd); @@ -585,6 +599,7 @@ impl VsockMuxer { maybe_listener } + #[tracing::instrument(level = "trace", skip(self))] /// Allocate a host-side port to be assigned to a new host-initiated connection. fn allocate_local_port(&mut self) -> u32 { // TODO: this doesn't seem very space-efficient. @@ -600,11 +615,13 @@ impl VsockMuxer { self.local_port_last } + #[tracing::instrument(level = "trace", skip(self, port))] /// Mark a previously used host-side port as free. fn free_local_port(&mut self, port: u32) { self.local_port_set.remove(&port); } + #[tracing::instrument(level = "trace", skip(self, pkt))] /// Handle a new connection request comming from our peer (the guest vsock driver). /// /// This will attempt to connect to a host-side Unix socket, expected to be listening at @@ -636,6 +653,7 @@ impl VsockMuxer { .unwrap_or_else(|_| self.enq_rst(pkt.dst_port(), pkt.src_port())); } + #[tracing::instrument(level = "trace", skip(self, key, mut_fn))] /// Perform an action that might mutate a connection's state. /// /// This is used as shorthand for repetitive tasks that need to be performed after a @@ -743,6 +761,7 @@ impl VsockMuxer { } } + #[tracing::instrument(level = "trace", skip(self))] /// Check if any connections have timed out, and if so, schedule them for immediate /// termination. fn sweep_killq(&mut self) { @@ -768,6 +787,7 @@ impl VsockMuxer { } } + #[tracing::instrument(level = "trace", skip(self, local_port, peer_port))] /// Enqueue an RST packet into `self.rxq`. /// /// Enqueue errors aren't propagated up the call chain, since there is nothing we can do to @@ -813,12 +833,14 @@ mod tests { } impl Drop for MuxerTestContext { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { std::fs::remove_file(self.muxer.host_sock_path.as_str()).unwrap(); } } // Create a TempFile with a given prefix and return it as a nice String + #[tracing::instrument(level = "trace", skip(fprefix))] fn get_file(fprefix: &str) -> String { let listener_path = TempFile::new_with_prefix(fprefix).unwrap(); listener_path @@ -830,6 +852,7 @@ mod tests { } impl MuxerTestContext { + #[tracing::instrument(level = "trace", skip(name))] fn new(name: &str) -> Self { let vsock_test_ctx = VsockTestContext::new(); let mut handler_ctx = vsock_test_ctx.create_event_handler_context(); @@ -848,6 +871,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(self, local_port, peer_port, op))] fn init_pkt(&mut self, local_port: u32, peer_port: u32, op: u16) -> &mut VsockPacket { self.pkt .set_type(uapi::VSOCK_TYPE_STREAM) @@ -859,6 +883,7 @@ mod tests { .set_buf_alloc(PEER_BUF_ALLOC) } + #[tracing::instrument(level = "trace", skip(self, local_port, peer_port, data))] fn init_data_pkt( &mut self, local_port: u32, @@ -876,22 +901,26 @@ mod tests { &mut self.pkt } + #[tracing::instrument(level = "trace", skip(self))] fn send(&mut self) { self.muxer .send_pkt(&self.pkt, &self._vsock_test_ctx.mem) .unwrap(); } + #[tracing::instrument(level = "trace", skip(self))] fn recv(&mut self) { self.muxer .recv_pkt(&mut self.pkt, &self._vsock_test_ctx.mem) .unwrap(); } + #[tracing::instrument(level = "trace", skip(self))] fn notify_muxer(&mut self) { self.muxer.notify(EventSet::IN); } + #[tracing::instrument(level = "trace", skip(self))] fn count_epoll_listeners(&self) -> (usize, usize) { let mut local_lsn_count = 0usize; let mut conn_lsn_count = 0usize; @@ -905,10 +934,12 @@ mod tests { (local_lsn_count, conn_lsn_count) } + #[tracing::instrument(level = "trace", skip(self, port))] fn create_local_listener(&self, port: u32) -> LocalListener { LocalListener::new(format!("{}_{}", self.muxer.host_sock_path, port)) } + #[tracing::instrument(level = "trace", skip(self, peer_port))] fn local_connect(&mut self, peer_port: u32) -> (UnixStream, u32) { let (init_local_lsn_count, init_conn_lsn_count) = self.count_epoll_listeners(); @@ -969,6 +1000,7 @@ mod tests { sock: UnixListener, } impl LocalListener { + #[tracing::instrument(level = "trace", skip(path))] fn new + Clone + Debug>(path: P) -> Self { let path_buf = path.as_ref().to_path_buf(); let sock = UnixListener::bind(path).unwrap(); @@ -978,6 +1010,7 @@ mod tests { sock, } } + #[tracing::instrument(level = "trace", skip(self))] fn accept(&mut self) -> UnixStream { let (stream, _) = self.sock.accept().unwrap(); stream.set_nonblocking(true).unwrap(); @@ -985,6 +1018,7 @@ mod tests { } } impl Drop for LocalListener { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { std::fs::remove_file(&self.path).unwrap(); } diff --git a/src/vmm/src/devices/virtio/vsock/unix/muxer_killq.rs b/src/vmm/src/devices/virtio/vsock/unix/muxer_killq.rs index cb10f4e3343..5bed456e1f2 100644 --- a/src/vmm/src/devices/virtio/vsock/unix/muxer_killq.rs +++ b/src/vmm/src/devices/virtio/vsock/unix/muxer_killq.rs @@ -54,6 +54,7 @@ pub struct MuxerKillQ { impl MuxerKillQ { const SIZE: usize = defs::MUXER_KILLQ_SIZE; + #[tracing::instrument(level = "trace", skip())] /// Trivial kill queue constructor. pub fn new() -> Self { Self { @@ -62,6 +63,7 @@ impl MuxerKillQ { } } + #[tracing::instrument(level = "trace", skip(conn_map))] /// Create a kill queue by walking the connection pool, looking for connections that are /// set to expire at some point in the future. /// Note: if more than `Self::SIZE` connections are found, the queue will be created in an @@ -89,6 +91,7 @@ impl MuxerKillQ { } } + #[tracing::instrument(level = "trace", skip(self, key, kill_time))] /// Push a connection key to the queue, scheduling it for termination at /// `CONN_SHUTDOWN_TIMEOUT_MS` from now (the push time). pub fn push(&mut self, key: ConnMapKey, kill_time: Instant) { @@ -99,6 +102,7 @@ impl MuxerKillQ { self.q.push_back(MuxerKillQItem { key, kill_time }); } + #[tracing::instrument(level = "trace", skip(self))] /// Attempt to pop an expired connection from the kill queue. /// /// This will succeed and return a connection key, only if the connection at the front of @@ -112,16 +116,19 @@ impl MuxerKillQ { None } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the kill queue is synchronized with the connection pool. pub fn is_synced(&self) -> bool { self.synced } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the kill queue is empty, obviously. pub fn is_empty(&self) -> bool { self.q.len() == 0 } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the kill queue is full. pub fn is_full(&self) -> bool { self.q.len() == Self::SIZE diff --git a/src/vmm/src/devices/virtio/vsock/unix/muxer_rxq.rs b/src/vmm/src/devices/virtio/vsock/unix/muxer_rxq.rs index b1059774511..2fd0872de75 100644 --- a/src/vmm/src/devices/virtio/vsock/unix/muxer_rxq.rs +++ b/src/vmm/src/devices/virtio/vsock/unix/muxer_rxq.rs @@ -33,6 +33,7 @@ pub struct MuxerRxQ { impl MuxerRxQ { const SIZE: usize = defs::MUXER_RXQ_SIZE; + #[tracing::instrument(level = "trace", skip())] /// Trivial RX queue constructor. pub fn new() -> Self { Self { @@ -41,6 +42,7 @@ impl MuxerRxQ { } } + #[tracing::instrument(level = "trace", skip(conn_map))] /// Attempt to build an RX queue, that is synchronized to the connection pool. /// Note: the resulting queue may still be desynchronized, if there are too many connections /// that have pending RX data. In that case, the muxer will first drain this queue, and @@ -62,6 +64,7 @@ impl MuxerRxQ { Self { q, synced } } + #[tracing::instrument(level = "trace", skip(self, rx))] /// Push a new RX item to the queue. /// /// A push will fail when: @@ -102,31 +105,37 @@ impl MuxerRxQ { false } + #[tracing::instrument(level = "trace", skip(self))] /// Peek into the front of the queue. pub fn peek(&self) -> Option { self.q.front().copied() } + #[tracing::instrument(level = "trace", skip(self))] /// Pop an RX item from the front of the queue. pub fn pop(&mut self) -> Option { self.q.pop_front() } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the RX queue is synchronized with the connection pool. pub fn is_synced(&self) -> bool { self.synced } + #[tracing::instrument(level = "trace", skip(self))] /// Get the total number of items in the queue. pub fn len(&self) -> usize { self.q.len() } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the queue is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } + #[tracing::instrument(level = "trace", skip(self))] /// Check if the queue is full. pub fn is_full(&self) -> bool { self.len() == Self::SIZE diff --git a/src/vmm/src/io_uring/bindings.rs b/src/vmm/src/io_uring/bindings.rs index ed468b30387..8fe65486d03 100644 --- a/src/vmm/src/io_uring/bindings.rs +++ b/src/vmm/src/io_uring/bindings.rs @@ -21,24 +21,29 @@ impl __IncompleteArrayField { pub const fn new() -> Self { __IncompleteArrayField(::std::marker::PhantomData, []) } + #[tracing::instrument(level = "trace", skip(self))] #[inline] pub fn as_ptr(&self) -> *const T { self as *const _ as *const T } + #[tracing::instrument(level = "trace", skip(self))] #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut T } + #[tracing::instrument(level = "trace", skip(self, len))] #[inline] pub unsafe fn as_slice(&self, len: usize) -> &[T] { ::std::slice::from_raw_parts(self.as_ptr(), len) } + #[tracing::instrument(level = "trace", skip(self, len))] #[inline] pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) } } impl ::std::fmt::Debug for __IncompleteArrayField { + #[tracing::instrument(level = "trace", skip(self, fmt))] fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { fmt.write_str("__IncompleteArrayField") } @@ -108,6 +113,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_1() { 8usize, concat!("Alignment of ", stringify!(io_uring_sqe__bindgen_ty_1)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_off() { assert_eq!( unsafe { @@ -125,6 +131,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_1() { ); } test_field_off(); + #[tracing::instrument(level = "trace", skip())] fn test_field_addr2() { assert_eq!( unsafe { @@ -144,6 +151,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_1() { test_field_addr2(); } impl Default for io_uring_sqe__bindgen_ty_1 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -170,6 +178,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_2() { 8usize, concat!("Alignment of ", stringify!(io_uring_sqe__bindgen_ty_2)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_addr() { assert_eq!( unsafe { @@ -187,6 +196,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_2() { ); } test_field_addr(); + #[tracing::instrument(level = "trace", skip())] fn test_field_splice_off_in() { assert_eq!( unsafe { @@ -206,6 +216,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_2() { test_field_splice_off_in(); } impl Default for io_uring_sqe__bindgen_ty_2 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -243,6 +254,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { 4usize, concat!("Alignment of ", stringify!(io_uring_sqe__bindgen_ty_3)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_rw_flags() { assert_eq!( unsafe { @@ -260,6 +272,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_rw_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_fsync_flags() { assert_eq!( unsafe { @@ -277,6 +290,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_fsync_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_poll_events() { assert_eq!( unsafe { @@ -294,6 +308,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_poll_events(); + #[tracing::instrument(level = "trace", skip())] fn test_field_poll32_events() { assert_eq!( unsafe { @@ -311,6 +326,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_poll32_events(); + #[tracing::instrument(level = "trace", skip())] fn test_field_sync_range_flags() { assert_eq!( unsafe { @@ -328,6 +344,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_sync_range_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_msg_flags() { assert_eq!( unsafe { @@ -345,6 +362,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_msg_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_timeout_flags() { assert_eq!( unsafe { @@ -362,6 +380,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_timeout_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_accept_flags() { assert_eq!( unsafe { @@ -379,6 +398,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_accept_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_cancel_flags() { assert_eq!( unsafe { @@ -396,6 +416,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_cancel_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_open_flags() { assert_eq!( unsafe { @@ -413,6 +434,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_open_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_statx_flags() { assert_eq!( unsafe { @@ -430,6 +452,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_statx_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_fadvise_advice() { assert_eq!( unsafe { @@ -447,6 +470,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { ); } test_field_fadvise_advice(); + #[tracing::instrument(level = "trace", skip())] fn test_field_splice_flags() { assert_eq!( unsafe { @@ -466,6 +490,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_3() { test_field_splice_flags(); } impl Default for io_uring_sqe__bindgen_ty_3 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -511,6 +536,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4__bindgen_ty_1__bindgen_ty_1() stringify!(io_uring_sqe__bindgen_ty_4__bindgen_ty_1__bindgen_ty_1) ) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_buf_index() { assert_eq!( unsafe { @@ -530,6 +556,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4__bindgen_ty_1__bindgen_ty_1() ); } test_field_buf_index(); + #[tracing::instrument(level = "trace", skip())] fn test_field_buf_group() { assert_eq!( unsafe { @@ -551,6 +578,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4__bindgen_ty_1__bindgen_ty_1() test_field_buf_group(); } impl Default for io_uring_sqe__bindgen_ty_4__bindgen_ty_1__bindgen_ty_1 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -577,6 +605,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4__bindgen_ty_1() { stringify!(io_uring_sqe__bindgen_ty_4__bindgen_ty_1) ) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_personality() { assert_eq!( unsafe { @@ -595,6 +624,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4__bindgen_ty_1() { ); } test_field_personality(); + #[tracing::instrument(level = "trace", skip())] fn test_field_splice_fd_in() { assert_eq!( unsafe { @@ -615,6 +645,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4__bindgen_ty_1() { test_field_splice_fd_in(); } impl Default for io_uring_sqe__bindgen_ty_4__bindgen_ty_1 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -635,6 +666,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4() { 8usize, concat!("Alignment of ", stringify!(io_uring_sqe__bindgen_ty_4)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field___pad2() { assert_eq!( unsafe { @@ -654,6 +686,7 @@ fn bindgen_test_layout_io_uring_sqe__bindgen_ty_4() { test_field___pad2(); } impl Default for io_uring_sqe__bindgen_ty_4 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -674,6 +707,7 @@ fn bindgen_test_layout_io_uring_sqe() { 8usize, concat!("Alignment of ", stringify!(io_uring_sqe)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_opcode() { assert_eq!( unsafe { @@ -691,6 +725,7 @@ fn bindgen_test_layout_io_uring_sqe() { ); } test_field_opcode(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -708,6 +743,7 @@ fn bindgen_test_layout_io_uring_sqe() { ); } test_field_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ioprio() { assert_eq!( unsafe { @@ -725,6 +761,7 @@ fn bindgen_test_layout_io_uring_sqe() { ); } test_field_ioprio(); + #[tracing::instrument(level = "trace", skip())] fn test_field_fd() { assert_eq!( unsafe { @@ -742,6 +779,7 @@ fn bindgen_test_layout_io_uring_sqe() { ); } test_field_fd(); + #[tracing::instrument(level = "trace", skip())] fn test_field_len() { assert_eq!( unsafe { @@ -759,6 +797,7 @@ fn bindgen_test_layout_io_uring_sqe() { ); } test_field_len(); + #[tracing::instrument(level = "trace", skip())] fn test_field_user_data() { assert_eq!( unsafe { @@ -778,6 +817,7 @@ fn bindgen_test_layout_io_uring_sqe() { test_field_user_data(); } impl Default for io_uring_sqe { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -848,6 +888,7 @@ fn bindgen_test_layout_io_uring_cqe() { 8usize, concat!("Alignment of ", stringify!(io_uring_cqe)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_user_data() { assert_eq!( unsafe { @@ -865,6 +906,7 @@ fn bindgen_test_layout_io_uring_cqe() { ); } test_field_user_data(); + #[tracing::instrument(level = "trace", skip())] fn test_field_res() { assert_eq!( unsafe { @@ -882,6 +924,7 @@ fn bindgen_test_layout_io_uring_cqe() { ); } test_field_res(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -927,6 +970,7 @@ fn bindgen_test_layout_io_sqring_offsets() { 8usize, concat!("Alignment of ", stringify!(io_sqring_offsets)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_head() { assert_eq!( unsafe { @@ -944,6 +988,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_head(); + #[tracing::instrument(level = "trace", skip())] fn test_field_tail() { assert_eq!( unsafe { @@ -961,6 +1006,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_tail(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ring_mask() { assert_eq!( unsafe { @@ -978,6 +1024,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_ring_mask(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ring_entries() { assert_eq!( unsafe { @@ -995,6 +1042,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_ring_entries(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -1012,6 +1060,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_dropped() { assert_eq!( unsafe { @@ -1029,6 +1078,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_dropped(); + #[tracing::instrument(level = "trace", skip())] fn test_field_array() { assert_eq!( unsafe { @@ -1046,6 +1096,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_array(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv1() { assert_eq!( unsafe { @@ -1063,6 +1114,7 @@ fn bindgen_test_layout_io_sqring_offsets() { ); } test_field_resv1(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv2() { assert_eq!( unsafe { @@ -1106,6 +1158,7 @@ fn bindgen_test_layout_io_cqring_offsets() { 8usize, concat!("Alignment of ", stringify!(io_cqring_offsets)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_head() { assert_eq!( unsafe { @@ -1123,6 +1176,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_head(); + #[tracing::instrument(level = "trace", skip())] fn test_field_tail() { assert_eq!( unsafe { @@ -1140,6 +1194,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_tail(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ring_mask() { assert_eq!( unsafe { @@ -1157,6 +1212,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_ring_mask(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ring_entries() { assert_eq!( unsafe { @@ -1174,6 +1230,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_ring_entries(); + #[tracing::instrument(level = "trace", skip())] fn test_field_overflow() { assert_eq!( unsafe { @@ -1191,6 +1248,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_overflow(); + #[tracing::instrument(level = "trace", skip())] fn test_field_cqes() { assert_eq!( unsafe { @@ -1208,6 +1266,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_cqes(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -1225,6 +1284,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv1() { assert_eq!( unsafe { @@ -1242,6 +1302,7 @@ fn bindgen_test_layout_io_cqring_offsets() { ); } test_field_resv1(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv2() { assert_eq!( unsafe { @@ -1286,6 +1347,7 @@ fn bindgen_test_layout_io_uring_params() { 8usize, concat!("Alignment of ", stringify!(io_uring_params)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_sq_entries() { assert_eq!( unsafe { @@ -1303,6 +1365,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_sq_entries(); + #[tracing::instrument(level = "trace", skip())] fn test_field_cq_entries() { assert_eq!( unsafe { @@ -1320,6 +1383,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_cq_entries(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -1337,6 +1401,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_sq_thread_cpu() { assert_eq!( unsafe { @@ -1354,6 +1419,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_sq_thread_cpu(); + #[tracing::instrument(level = "trace", skip())] fn test_field_sq_thread_idle() { assert_eq!( unsafe { @@ -1371,6 +1437,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_sq_thread_idle(); + #[tracing::instrument(level = "trace", skip())] fn test_field_features() { assert_eq!( unsafe { @@ -1388,6 +1455,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_features(); + #[tracing::instrument(level = "trace", skip())] fn test_field_wq_fd() { assert_eq!( unsafe { @@ -1405,6 +1473,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_wq_fd(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv() { assert_eq!( unsafe { @@ -1422,6 +1491,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_resv(); + #[tracing::instrument(level = "trace", skip())] fn test_field_sq_off() { assert_eq!( unsafe { @@ -1439,6 +1509,7 @@ fn bindgen_test_layout_io_uring_params() { ); } test_field_sq_off(); + #[tracing::instrument(level = "trace", skip())] fn test_field_cq_off() { assert_eq!( unsafe { @@ -1491,6 +1562,7 @@ fn bindgen_test_layout_io_uring_files_update() { 8usize, concat!("Alignment of ", stringify!(io_uring_files_update)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_offset() { assert_eq!( unsafe { @@ -1508,6 +1580,7 @@ fn bindgen_test_layout_io_uring_files_update() { ); } test_field_offset(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv() { assert_eq!( unsafe { @@ -1525,6 +1598,7 @@ fn bindgen_test_layout_io_uring_files_update() { ); } test_field_resv(); + #[tracing::instrument(level = "trace", skip())] fn test_field_fds() { assert_eq!( unsafe { @@ -1563,6 +1637,7 @@ fn bindgen_test_layout_io_uring_probe_op() { 4usize, concat!("Alignment of ", stringify!(io_uring_probe_op)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_op() { assert_eq!( unsafe { @@ -1580,6 +1655,7 @@ fn bindgen_test_layout_io_uring_probe_op() { ); } test_field_op(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv() { assert_eq!( unsafe { @@ -1597,6 +1673,7 @@ fn bindgen_test_layout_io_uring_probe_op() { ); } test_field_resv(); + #[tracing::instrument(level = "trace", skip())] fn test_field_flags() { assert_eq!( unsafe { @@ -1614,6 +1691,7 @@ fn bindgen_test_layout_io_uring_probe_op() { ); } test_field_flags(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv2() { assert_eq!( unsafe { @@ -1653,6 +1731,7 @@ fn bindgen_test_layout_io_uring_probe() { 4usize, concat!("Alignment of ", stringify!(io_uring_probe)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_last_op() { assert_eq!( unsafe { @@ -1670,6 +1749,7 @@ fn bindgen_test_layout_io_uring_probe() { ); } test_field_last_op(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ops_len() { assert_eq!( unsafe { @@ -1687,6 +1767,7 @@ fn bindgen_test_layout_io_uring_probe() { ); } test_field_ops_len(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv() { assert_eq!( unsafe { @@ -1704,6 +1785,7 @@ fn bindgen_test_layout_io_uring_probe() { ); } test_field_resv(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv2() { assert_eq!( unsafe { @@ -1721,6 +1803,7 @@ fn bindgen_test_layout_io_uring_probe() { ); } test_field_resv2(); + #[tracing::instrument(level = "trace", skip())] fn test_field_ops() { assert_eq!( unsafe { @@ -1769,6 +1852,7 @@ fn bindgen_test_layout_io_uring_restriction__bindgen_ty_1() { stringify!(io_uring_restriction__bindgen_ty_1) ) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_register_op() { assert_eq!( unsafe { @@ -1787,6 +1871,7 @@ fn bindgen_test_layout_io_uring_restriction__bindgen_ty_1() { ); } test_field_register_op(); + #[tracing::instrument(level = "trace", skip())] fn test_field_sqe_op() { assert_eq!( unsafe { @@ -1805,6 +1890,7 @@ fn bindgen_test_layout_io_uring_restriction__bindgen_ty_1() { ); } test_field_sqe_op(); + #[tracing::instrument(level = "trace", skip())] fn test_field_sqe_flags() { assert_eq!( unsafe { @@ -1825,6 +1911,7 @@ fn bindgen_test_layout_io_uring_restriction__bindgen_ty_1() { test_field_sqe_flags(); } impl Default for io_uring_restriction__bindgen_ty_1 { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { @@ -1845,6 +1932,7 @@ fn bindgen_test_layout_io_uring_restriction() { 4usize, concat!("Alignment of ", stringify!(io_uring_restriction)) ); + #[tracing::instrument(level = "trace", skip())] fn test_field_opcode() { assert_eq!( unsafe { @@ -1862,6 +1950,7 @@ fn bindgen_test_layout_io_uring_restriction() { ); } test_field_opcode(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv() { assert_eq!( unsafe { @@ -1879,6 +1968,7 @@ fn bindgen_test_layout_io_uring_restriction() { ); } test_field_resv(); + #[tracing::instrument(level = "trace", skip())] fn test_field_resv2() { assert_eq!( unsafe { @@ -1898,6 +1988,7 @@ fn bindgen_test_layout_io_uring_restriction() { test_field_resv2(); } impl Default for io_uring_restriction { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); unsafe { diff --git a/src/vmm/src/io_uring/mod.rs b/src/vmm/src/io_uring/mod.rs index a6bb9ba3828..33b1242309e 100644 --- a/src/vmm/src/io_uring/mod.rs +++ b/src/vmm/src/io_uring/mod.rs @@ -67,6 +67,7 @@ pub enum IoUringError { } impl IoUringError { + #[tracing::instrument(level = "trace", skip(self))] /// Return true if this error is caused by a full submission or completion queue. pub fn is_throttling_err(&self) -> bool { matches!( @@ -94,6 +95,7 @@ pub struct IoUring { } impl IoUring { + #[tracing::instrument(level = "trace", skip(num_entries, files, restrictions, eventfd))] /// Create a new instance. /// /// # Arguments @@ -158,6 +160,7 @@ impl IoUring { Ok(instance) } + #[tracing::instrument(level = "trace", skip(self, op))] /// Push an [`Operation`](operation/struct.Operation.html) onto the submission queue. /// /// # Safety @@ -187,6 +190,7 @@ impl IoUring { } } + #[tracing::instrument(level = "trace", skip(self))] /// Pop a completed entry off the completion queue. Returns `Ok(None)` if there are no entries. /// The type `T` must be the same as the `user_data` type used for `push`-ing the operation. /// @@ -208,33 +212,39 @@ impl IoUring { .map_err(IoUringError::CQueue) } + #[tracing::instrument(level = "trace", skip(self, min_complete))] fn do_submit(&mut self, min_complete: u32) -> Result { self.squeue .submit(min_complete) .map_err(IoUringError::SQueue) } + #[tracing::instrument(level = "trace", skip(self))] /// Submit all operations but don't wait for any completions. pub fn submit(&mut self) -> Result { self.do_submit(0) } + #[tracing::instrument(level = "trace", skip(self))] /// Submit all operations and wait for their completion. pub fn submit_and_wait_all(&mut self) -> Result { self.do_submit(self.num_ops) } + #[tracing::instrument(level = "trace", skip(self))] /// Return the number of operations currently on the submission queue. pub fn pending_sqes(&self) -> Result { self.squeue.pending().map_err(IoUringError::SQueue) } + #[tracing::instrument(level = "trace", skip(self))] /// A total of the number of ops in the submission and completion queues, as well as the /// in-flight ops. pub fn num_ops(&self) -> u32 { self.num_ops } + #[tracing::instrument(level = "trace", skip(self))] fn enable(&mut self) -> Result<(), IoUringError> { // SAFETY: Safe because values are valid and we check the return value. SyscallReturnCode(unsafe { @@ -250,6 +260,7 @@ impl IoUring { .map_err(IoUringError::Enable) } + #[tracing::instrument(level = "trace", skip(self, files))] fn register_files(&mut self, files: Vec<&File>) -> Result<(), IoUringError> { if files.is_empty() { // No-op. @@ -284,6 +295,7 @@ impl IoUring { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, fd))] fn register_eventfd(&self, fd: RawFd) -> Result<(), IoUringError> { // SAFETY: Safe because values are valid and we check the return value. SyscallReturnCode(unsafe { @@ -299,6 +311,7 @@ impl IoUring { .map_err(IoUringError::RegisterEventfd) } + #[tracing::instrument(level = "trace", skip(self, restrictions))] fn register_restrictions(&self, restrictions: Vec) -> Result<(), IoUringError> { if restrictions.is_empty() { // No-op. @@ -323,6 +336,7 @@ impl IoUring { .map_err(IoUringError::RegisterRestrictions) } + #[tracing::instrument(level = "trace", skip(params))] fn check_features(params: io_uring_params) -> Result<(), IoUringError> { // We require that the host kernel will never drop completed entries due to an (unlikely) // overflow in the completion queue. @@ -337,6 +351,7 @@ impl IoUring { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] fn check_operations(&self) -> Result<(), IoUringError> { let mut probes = ProbeWrapper::new(PROBE_LEN).map_err(IoUringError::Fam)?; @@ -388,6 +403,7 @@ mod tests { /// BEGIN PROPERTY BASED TESTING use super::*; + #[tracing::instrument(level = "trace", skip(ring))] fn drain_cqueue(ring: &mut IoUring) { while let Some(entry) = unsafe { ring.pop::().unwrap() } { assert!(entry.result().is_ok()); @@ -399,6 +415,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(len))] fn setup_mem_region(len: usize) -> MmapRegion { const PROT: i32 = libc::PROT_READ | libc::PROT_WRITE; const FLAGS: i32 = libc::MAP_ANONYMOUS | libc::MAP_PRIVATE; @@ -415,10 +432,12 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(region))] fn free_mem_region(region: MmapRegion) { unsafe { libc::munmap(region.as_ptr().cast::(), region.len()) }; } + #[tracing::instrument(level = "trace", skip(region))] fn read_entire_mem_region(region: &MmapRegion) -> Vec { let mut result = vec![0u8; region.len()]; let count = region.as_volatile_slice().read(&mut result[..], 0).unwrap(); @@ -426,6 +445,7 @@ mod tests { result } + #[tracing::instrument(level = "trace", skip(file_len))] #[allow(clippy::let_with_type_underscore)] fn arbitrary_rw_operation(file_len: u32) -> impl Strategy> { ( diff --git a/src/vmm/src/io_uring/operation/cqe.rs b/src/vmm/src/io_uring/operation/cqe.rs index 303076e89ec..b894ea28cdd 100644 --- a/src/vmm/src/io_uring/operation/cqe.rs +++ b/src/vmm/src/io_uring/operation/cqe.rs @@ -18,6 +18,7 @@ pub struct Cqe { } impl Cqe { + #[tracing::instrument(level = "trace", skip(inner))] /// Construct a Cqe object from a raw `io_uring_cqe`. /// /// # Safety @@ -31,11 +32,13 @@ impl Cqe { } } + #[tracing::instrument(level = "trace", skip(self))] /// Return the number of bytes successfully transferred by this operation. pub fn count(&self) -> u32 { u32::try_from(self.res).unwrap_or(0) } + #[tracing::instrument(level = "trace", skip(self))] /// Return the result associated to the IO operation. pub fn result(&self) -> Result { let res = self.res; @@ -47,6 +50,7 @@ impl Cqe { } } + #[tracing::instrument(level = "trace", skip(self, op))] /// Create a new Cqe, applying the passed function to the user_data. pub fn map_user_data U>(self, op: F) -> Cqe { Cqe { @@ -55,6 +59,7 @@ impl Cqe { } } + #[tracing::instrument(level = "trace", skip(self))] /// Consume the object and return the user_data. pub fn user_data(self) -> T { *self.user_data diff --git a/src/vmm/src/io_uring/operation/mod.rs b/src/vmm/src/io_uring/operation/mod.rs index 9f09890b569..4b3a0d7a9a8 100644 --- a/src/vmm/src/io_uring/operation/mod.rs +++ b/src/vmm/src/io_uring/operation/mod.rs @@ -31,6 +31,7 @@ pub enum OpCode { // Useful for outputting errors. impl From for &'static str { + #[tracing::instrument(level = "trace", skip(opcode))] fn from(opcode: OpCode) -> Self { match opcode { OpCode::Read => "read", @@ -54,6 +55,7 @@ pub struct Operation { // Needed for proptesting. impl fmt::Debug for Operation { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -72,6 +74,7 @@ impl fmt::Debug for Operation { #[allow(clippy::len_without_is_empty)] impl Operation { + #[tracing::instrument(level = "trace", skip(fd, addr, len, offset, user_data))] /// Construct a read operation. pub fn read(fd: FixedFd, addr: usize, len: u32, offset: u64, user_data: T) -> Self { Self { @@ -85,6 +88,7 @@ impl Operation { } } + #[tracing::instrument(level = "trace", skip(fd, addr, len, offset, user_data))] /// Construct a write operation. pub fn write(fd: FixedFd, addr: usize, len: u32, offset: u64, user_data: T) -> Self { Self { @@ -98,6 +102,7 @@ impl Operation { } } + #[tracing::instrument(level = "trace", skip(fd, user_data))] /// Construct a fsync operation. pub fn fsync(fd: FixedFd, user_data: T) -> Self { Self { @@ -111,21 +116,25 @@ impl Operation { } } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn fd(&self) -> FixedFd { self.fd } + #[tracing::instrument(level = "trace", skip(self))] /// Consumes the operation and returns the associated `user_data`. pub fn user_data(self) -> T { *self.user_data } // Needed for proptesting. + #[tracing::instrument(level = "trace", skip(self))] #[cfg(test)] pub(crate) fn set_linked(&mut self) { self.flags |= 1 << bindings::IOSQE_IO_LINK_BIT; } + #[tracing::instrument(level = "trace", skip(self))] /// Transform the operation into an `Sqe`. /// /// # Safety diff --git a/src/vmm/src/io_uring/operation/sqe.rs b/src/vmm/src/io_uring/operation/sqe.rs index 7e0542f54c4..2d593d93500 100644 --- a/src/vmm/src/io_uring/operation/sqe.rs +++ b/src/vmm/src/io_uring/operation/sqe.rs @@ -14,17 +14,20 @@ unsafe impl ByteValued for io_uring_sqe {} pub(crate) struct Sqe(pub(crate) io_uring_sqe); impl fmt::Debug for Sqe { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Sqe").finish() } } impl Sqe { + #[tracing::instrument(level = "trace", skip(inner))] /// Construct a new sqe. pub(crate) fn new(inner: io_uring_sqe) -> Self { Self(inner) } + #[tracing::instrument(level = "trace", skip(self))] /// Consume the sqe and return the `user_data`. /// /// # Safety diff --git a/src/vmm/src/io_uring/queue/completion.rs b/src/vmm/src/io_uring/queue/completion.rs index 37fe1fb0a16..7e5f1f0e674 100644 --- a/src/vmm/src/io_uring/queue/completion.rs +++ b/src/vmm/src/io_uring/queue/completion.rs @@ -38,6 +38,7 @@ pub(crate) struct CompletionQueue { } impl CompletionQueue { + #[tracing::instrument(level = "trace", skip(io_uring_fd, params))] pub(crate) fn new( io_uring_fd: RawFd, params: &bindings::io_uring_params, @@ -68,10 +69,12 @@ impl CompletionQueue { }) } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn count(&self) -> u32 { self.count } + #[tracing::instrument(level = "trace", skip(self))] /// # Safety /// Unsafe because we reconstruct the `user_data` from a raw pointer passed by the kernel. /// It's up to the caller to make sure that `T` is the correct type of the `user_data`, that @@ -100,6 +103,7 @@ impl CompletionQueue { } impl Drop for CompletionQueue { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { // SAFETY: Safe because parameters are valid. unsafe { libc::munmap(self.cqes.as_ptr().cast::(), self.cqes.size()) }; diff --git a/src/vmm/src/io_uring/queue/mmap.rs b/src/vmm/src/io_uring/queue/mmap.rs index 8b9b435d09b..177a9d332a2 100644 --- a/src/vmm/src/io_uring/queue/mmap.rs +++ b/src/vmm/src/io_uring/queue/mmap.rs @@ -12,6 +12,7 @@ pub enum MmapError { BuildMmapRegion(MmapRegionError), } +#[tracing::instrument(level = "trace", skip(size, fd, offset))] pub(crate) fn mmap(size: usize, fd: RawFd, offset: i64) -> Result { let prot = libc::PROT_READ | libc::PROT_WRITE; let flags = libc::MAP_SHARED | libc::MAP_POPULATE; diff --git a/src/vmm/src/io_uring/queue/submission.rs b/src/vmm/src/io_uring/queue/submission.rs index 5f3eca42a64..aff9374400b 100644 --- a/src/vmm/src/io_uring/queue/submission.rs +++ b/src/vmm/src/io_uring/queue/submission.rs @@ -51,6 +51,7 @@ pub(crate) struct SubmissionQueue { } impl SubmissionQueue { + #[tracing::instrument(level = "trace", skip(io_uring_fd, params))] pub(crate) fn new( io_uring_fd: RawFd, params: &bindings::io_uring_params, @@ -81,6 +82,7 @@ impl SubmissionQueue { }) } + #[tracing::instrument(level = "trace", skip(self, sqe))] /// # Safety /// Unsafe because we pass a raw `user_data` pointer to the kernel. /// It's up to the caller to make sure that this value is ever freed (not leaked). @@ -121,6 +123,7 @@ impl SubmissionQueue { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, min_complete))] pub(crate) fn submit(&mut self, min_complete: u32) -> Result { if self.to_submit == 0 && min_complete == 0 { // Nothing to submit and nothing to wait for. @@ -154,6 +157,7 @@ impl SubmissionQueue { Ok(submitted) } + #[tracing::instrument(level = "trace", skip(io_uring_fd, params))] fn mmap( io_uring_fd: RawFd, params: &bindings::io_uring_params, @@ -182,6 +186,7 @@ impl SubmissionQueue { Ok((sqe_ring, sqes)) } + #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn pending(&self) -> Result { let ring_slice = self.ring.as_volatile_slice(); // get the sqe head @@ -192,6 +197,7 @@ impl SubmissionQueue { } impl Drop for SubmissionQueue { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { // SAFETY: Safe because parameters are valid. unsafe { libc::munmap(self.ring.as_ptr().cast::(), self.ring.size()) }; diff --git a/src/vmm/src/io_uring/restriction.rs b/src/vmm/src/io_uring/restriction.rs index e010cc74815..d1fd34c0ca3 100644 --- a/src/vmm/src/io_uring/restriction.rs +++ b/src/vmm/src/io_uring/restriction.rs @@ -25,6 +25,7 @@ pub enum Restriction { } impl From<&Restriction> for bindings::io_uring_restriction { + #[tracing::instrument(level = "trace", skip(restriction))] fn from(restriction: &Restriction) -> Self { use Restriction::*; diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index 558b33cfd91..d7a6822193e 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -279,6 +279,7 @@ pub enum VmmError { /// Shorthand type for KVM dirty page bitmap. pub type DirtyBitmap = HashMap>; +#[tracing::instrument(level = "trace", skip(guest_memory))] /// Returns the size of guest memory, in MiB. pub(crate) fn mem_size_mib(guest_memory: &GuestMemoryMmap) -> u64 { guest_memory.iter().map(|region| region.len()).sum::() >> 20 @@ -362,21 +363,25 @@ pub struct Vmm { } impl Vmm { + #[tracing::instrument(level = "trace", skip(self))] /// Gets Vmm version. pub fn version(&self) -> String { self.instance_info.vmm_version.clone() } + #[tracing::instrument(level = "trace", skip(self))] /// Gets Vmm instance info. pub fn instance_info(&self) -> InstanceInfo { self.instance_info.clone() } + #[tracing::instrument(level = "trace", skip(self))] /// Provides the Vmm shutdown exit code if there is one. pub fn shutdown_exit_code(&self) -> Option { self.shutdown_exit_code } + #[tracing::instrument(level = "trace", skip(self, device_type, device_id))] /// Gets the specified bus device. pub fn get_bus_device( &self, @@ -386,6 +391,7 @@ impl Vmm { self.mmio_device_manager.get_device(device_type, device_id) } + #[tracing::instrument(level = "trace", skip(self, vcpus, vcpu_seccomp_filter))] /// Starts the microVM vcpus. /// /// # Errors @@ -435,6 +441,7 @@ impl Vmm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Sends a resume command to the vCPUs. pub fn resume_vm(&mut self) -> Result<(), VmmError> { self.mmio_device_manager.kick_devices(); @@ -459,6 +466,7 @@ impl Vmm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Sends a pause command to the vCPUs. pub fn pause_vm(&mut self) -> Result<(), VmmError> { // Send the events. @@ -481,11 +489,13 @@ impl Vmm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a reference to the inner `GuestMemoryMmap` object. pub fn guest_memory(&self) -> &GuestMemoryMmap { &self.guest_memory } + #[tracing::instrument(level = "trace", skip(self))] /// Sets RDA bit in serial console pub fn emulate_serial_init(&self) -> Result<(), EmulateSerialInitError> { // When restoring from a previously saved state, there is no serial @@ -531,6 +541,7 @@ impl Vmm { } } + #[tracing::instrument(level = "trace", skip(self))] /// Injects CTRL+ALT+DEL keystroke combo in the i8042 device. #[cfg(target_arch = "x86_64")] pub fn send_ctrl_alt_del(&mut self) -> Result<(), VmmError> { @@ -544,6 +555,7 @@ impl Vmm { .map_err(VmmError::I8042Error) } + #[tracing::instrument(level = "trace", skip(self, vm_info))] /// Saves the state of a paused Microvm. pub fn save_state(&mut self, vm_info: &VmInfo) -> Result { use self::MicrovmStateError::SaveVmState; @@ -573,6 +585,7 @@ impl Vmm { }) } + #[tracing::instrument(level = "trace", skip(self))] fn save_vcpu_states(&mut self) -> Result, MicrovmStateError> { for handle in self.vcpus_handles.iter() { handle @@ -601,6 +614,7 @@ impl Vmm { Ok(vcpu_states) } + #[tracing::instrument(level = "trace", skip(self, vcpu_states))] /// Restores vcpus kvm states. pub fn restore_vcpu_states( &mut self, @@ -633,6 +647,7 @@ impl Vmm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Dumps CPU configuration. pub fn dump_cpu_config(&mut self) -> Result, DumpCpuConfigError> { for handle in self.vcpus_handles.iter() { @@ -661,6 +676,7 @@ impl Vmm { Ok(cpu_configs) } + #[tracing::instrument(level = "trace", skip(self))] /// Retrieves the KVM dirty bitmap for each of the guest's memory regions. pub fn get_dirty_bitmap(&self) -> Result { let mut bitmap: DirtyBitmap = HashMap::new(); @@ -679,6 +695,7 @@ impl Vmm { Ok(bitmap) } + #[tracing::instrument(level = "trace", skip(self, enable))] /// Enables or disables KVM dirty page tracking. pub fn set_dirty_page_tracking(&mut self, enable: bool) -> Result<(), VmmError> { // This function _always_ results in an ioctl update. The VMM is stateless in the sense @@ -691,6 +708,7 @@ impl Vmm { .map_err(VmmError::Vm) } + #[tracing::instrument(level = "trace", skip(self, drive_id, path_on_host))] /// Updates the path of the host file backing the emulated block device with id `drive_id`. /// We update the disk image on the device and its virtio configuration. pub fn update_block_device_path( @@ -707,6 +725,7 @@ impl Vmm { .map_err(VmmError::DeviceManager) } + #[tracing::instrument(level = "trace", skip(self, drive_id, rl_bytes, rl_ops))] /// Updates the rate limiter parameters for block device with `drive_id` id. pub fn update_block_rate_limiter( &mut self, @@ -722,6 +741,10 @@ impl Vmm { .map_err(VmmError::DeviceManager) } + #[tracing::instrument( + level = "trace", + skip(self, net_id, rx_bytes, rx_ops, tx_bytes, tx_ops) + )] /// Updates the rate limiter parameters for net device with `net_id` id. pub fn update_net_rate_limiters( &mut self, @@ -739,6 +762,7 @@ impl Vmm { .map_err(VmmError::DeviceManager) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a reference to the balloon device if present. pub fn balloon_config(&self) -> Result { if let Some(busdev) = self.get_bus_device(DeviceType::Virtio(TYPE_BALLOON), BALLOON_DEV_ID) @@ -764,6 +788,7 @@ impl Vmm { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the latest balloon statistics if they are enabled. pub fn latest_balloon_stats(&self) -> Result { if let Some(busdev) = self.get_bus_device(DeviceType::Virtio(TYPE_BALLOON), BALLOON_DEV_ID) @@ -791,6 +816,7 @@ impl Vmm { } } + #[tracing::instrument(level = "trace", skip(self, amount_mib))] /// Updates configuration for the balloon device target size. pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), BalloonError> { // The balloon cannot have a target size greater than the size of @@ -824,6 +850,7 @@ impl Vmm { } } + #[tracing::instrument(level = "trace", skip(self, stats_polling_interval_s))] /// Updates configuration for the balloon device as described in `balloon_stats_update`. pub fn update_balloon_stats_config( &mut self, @@ -853,6 +880,7 @@ impl Vmm { } } + #[tracing::instrument(level = "trace", skip(self, exit_code))] /// Signals Vmm to stop and exit. pub fn stop(&mut self, exit_code: FcExitCode) { // To avoid cycles, all teardown paths take the following route: @@ -893,6 +921,7 @@ impl Vmm { } } +#[tracing::instrument(level = "trace", skip(vcpu_states))] /// Process the content of the MPIDR_EL1 register in order to be able to pass it to KVM /// /// The kernel expects to find the four affinity levels of the MPIDR in the first 32 bits of the @@ -919,6 +948,7 @@ fn construct_kvm_mpidrs(vcpu_states: &[VcpuState]) -> Vec { } impl Drop for Vmm { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { // There are two cases when `drop()` is called: // 1) before the Vmm has been mutexed and subscribed to the event @@ -965,6 +995,7 @@ impl Drop for Vmm { } impl MutEventSubscriber for Vmm { + #[tracing::instrument(level = "trace", skip(self, event))] /// Handle a read event (EPOLLIN). fn process(&mut self, event: Events, _: &mut EventOps) { let source = event.fd(); @@ -996,6 +1027,7 @@ impl MutEventSubscriber for Vmm { } } + #[tracing::instrument(level = "trace", skip(self, ops))] fn init(&mut self, ops: &mut EventOps) { if let Err(err) = ops.add(Events::new(&self.vcpus_exit_evt, EventSet::IN)) { error!("Failed to register vmm exit event: {}", err); diff --git a/src/vmm/src/memory_snapshot.rs b/src/vmm/src/memory_snapshot.rs index 76c5a9d87ee..5b97dafea97 100644 --- a/src/vmm/src/memory_snapshot.rs +++ b/src/vmm/src/memory_snapshot.rs @@ -83,6 +83,7 @@ pub enum SnapshotMemoryError { } impl SnapshotMemory for GuestMemoryMmap { + #[tracing::instrument(level = "trace", skip(self))] /// Describes GuestMemoryMmap through a GuestMemoryState struct. fn describe(&self) -> GuestMemoryState { let mut guest_memory_state = GuestMemoryState::default(); @@ -99,6 +100,7 @@ impl SnapshotMemory for GuestMemoryMmap { guest_memory_state } + #[tracing::instrument(level = "trace", skip(self, writer))] /// Dumps all contents of GuestMemoryMmap to a writer. fn dump(&self, writer: &mut T) -> Result<(), SnapshotMemoryError> { self.iter() @@ -106,6 +108,7 @@ impl SnapshotMemory for GuestMemoryMmap { .map_err(SnapshotMemoryError::WriteMemory) } + #[tracing::instrument(level = "trace", skip(self, writer, dirty_bitmap))] /// Dumps all pages of GuestMemoryMmap present in `dirty_bitmap` to a writer. fn dump_dirty( &self, @@ -167,6 +170,7 @@ impl SnapshotMemory for GuestMemoryMmap { .map_err(SnapshotMemoryError::WriteMemory) } + #[tracing::instrument(level = "trace", skip(file, state, track_dirty_pages))] /// Creates a GuestMemoryMmap backed by a `file` if present, otherwise backed /// by anonymous memory. Memory layout and ranges are described in `state` param. fn restore( diff --git a/src/vmm/src/persist.rs b/src/vmm/src/persist.rs index 6763874c0c1..56046752114 100644 --- a/src/vmm/src/persist.rs +++ b/src/vmm/src/persist.rs @@ -11,7 +11,7 @@ use std::os::unix::net::UnixStream; use std::path::Path; use std::sync::{Arc, Mutex}; -use log::{error, info, warn}; +use logger::{error, info, warn}; use seccompiler::BpfThreadMap; use semver::Version; use serde::Serialize; @@ -73,33 +73,39 @@ pub struct VmInfo { } impl VmInfo { + #[tracing::instrument(level = "trace", skip())] fn def_smt(_: u16) -> bool { warn!("SMT field not found in snapshot."); false } + #[tracing::instrument(level = "trace", skip(self, _target_version))] fn ser_smt(&mut self, _target_version: u16) -> VersionizeResult<()> { // v1.1 and older versions do not include smt info. warn!("Saving to older snapshot version, SMT information will not be saved."); Ok(()) } + #[tracing::instrument(level = "trace", skip())] fn def_cpu_template(_: u16) -> StaticCpuTemplate { warn!("CPU template field not found in snapshot."); StaticCpuTemplate::default() } + #[tracing::instrument(level = "trace", skip(self, _target_version))] fn ser_cpu_template(&mut self, _target_version: u16) -> VersionizeResult<()> { // v1.1 and older versions do not include cpu template info. warn!("Saving to older snapshot version, CPU template information will not be saved."); Ok(()) } + #[tracing::instrument(level = "trace", skip())] fn def_boot_source(_: u16) -> BootSourceConfig { warn!("Boot source information not found in snapshot."); BootSourceConfig::default() } + #[tracing::instrument(level = "trace", skip(self, _target_version))] fn ser_boot_source(&mut self, _target_version: u16) -> VersionizeResult<()> { // v1.1 and older versions do not include boot source info. warn!("Saving to older snapshot version, boot source information will not be saved."); @@ -108,6 +114,7 @@ impl VmInfo { } impl From<&VmResources> for VmInfo { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: &VmResources) -> Self { Self { mem_size_mib: value.vm_config.mem_size_mib as u64, @@ -230,6 +237,7 @@ pub enum CreateSnapshotError { TooManyDevices(usize), } +#[tracing::instrument(level = "trace", skip(vmm, vm_info, params, version_map))] /// Creates a Microvm snapshot. pub fn create_snapshot( vmm: &mut Vmm, @@ -256,6 +264,10 @@ pub fn create_snapshot( Ok(()) } +#[tracing::instrument( + level = "trace", + skip(microvm_state, snapshot_path, snapshot_data_version, version_map) +)] fn snapshot_state_to_file( microvm_state: &MicrovmState, snapshot_path: &Path, @@ -282,6 +294,7 @@ fn snapshot_state_to_file( .map_err(|err| SnapshotBackingFile("sync_all", err)) } +#[tracing::instrument(level = "trace", skip(vmm, mem_file_path, snapshot_type))] fn snapshot_memory_to_file( vmm: &Vmm, mem_file_path: &Path, @@ -315,6 +328,7 @@ fn snapshot_memory_to_file( .map_err(|err| MemoryBackingFile("sync_all", err)) } +#[tracing::instrument(level = "trace", skip(maybe_fc_version, version_map, vmm))] /// Validate the microVM version and translate it to its corresponding snapshot data format. pub fn get_snapshot_data_version( maybe_fc_version: &Option, @@ -356,6 +370,7 @@ pub fn get_snapshot_data_version( Ok(data_version) } +#[tracing::instrument(level = "trace", skip(microvm_state))] /// Validates that snapshot CPU vendor matches the host CPU vendor. /// /// # Errors @@ -390,6 +405,7 @@ pub fn validate_cpu_vendor(microvm_state: &MicrovmState) { } } +#[tracing::instrument(level = "trace", skip(microvm_state))] /// Validate that Snapshot Manufacturer ID matches /// the one from the Host /// @@ -436,6 +452,7 @@ pub enum SnapShotStateSanityCheckError { NoMemory, } +#[tracing::instrument(level = "trace", skip(microvm_state))] /// Performs sanity checks against the state file and returns specific errors. pub fn snapshot_state_sanity_check( microvm_state: &MicrovmState, @@ -490,6 +507,17 @@ pub enum RestoreFromSnapshotGuestMemoryError { Uffd(#[from] GuestMemoryFromUffdError), } +#[tracing::instrument( + level = "trace", + skip( + instance_info, + event_manager, + seccomp_filters, + params, + version_map, + vm_resources + ) +)] /// Loads a Microvm snapshot producing a 'paused' Microvm. pub fn restore_from_snapshot( instance_info: &InstanceInfo, @@ -551,6 +579,7 @@ pub enum SnapshotStateFromFileError { Load(#[from] snapshot::Error), } +#[tracing::instrument(level = "trace", skip(snapshot_path, version_map))] fn snapshot_state_from_file( snapshot_path: &Path, version_map: VersionMap, @@ -574,6 +603,7 @@ pub enum GuestMemoryFromFileError { Restore(#[from] crate::memory_snapshot::SnapshotMemoryError), } +#[tracing::instrument(level = "trace", skip(mem_file_path, mem_state, track_dirty_pages))] fn guest_memory_from_file( mem_file_path: &Path, mem_state: &GuestMemoryState, @@ -604,6 +634,10 @@ pub enum GuestMemoryFromUffdError { Send(#[from] utils::errno::Error), } +#[tracing::instrument( + level = "trace", + skip(mem_uds_path, mem_state, track_dirty_pages, enable_balloon) +)] fn guest_memory_from_uffd( mem_uds_path: &Path, mem_state: &GuestMemoryState, @@ -683,6 +717,7 @@ fn guest_memory_from_uffd( Ok((guest_memory, Some(uffd))) } +#[tracing::instrument(level = "trace", skip(device_number))] #[cfg(target_arch = "x86_64")] fn validate_devices_number(device_number: usize) -> Result<(), CreateSnapshotError> { use self::CreateSnapshotError::TooManyDevices; @@ -713,6 +748,7 @@ mod tests { use crate::vmm_config::vsock::tests::default_config; use crate::Vmm; + #[tracing::instrument(level = "trace", skip())] fn default_vmm_with_devices() -> Vmm { let mut event_manager = EventManager::new().expect("Cannot create EventManager"); let mut vmm = default_vmm(); diff --git a/src/vmm/src/rate_limiter/mod.rs b/src/vmm/src/rate_limiter/mod.rs index 001f1c5a8ac..88050ad7f3e 100644 --- a/src/vmm/src/rate_limiter/mod.rs +++ b/src/vmm/src/rate_limiter/mod.rs @@ -26,6 +26,7 @@ const TIMER_REFILL_STATE: TimerState = const NANOSEC_IN_ONE_MILLISEC: u64 = 1_000_000; // Euclid's two-thousand-year-old algorithm for finding the greatest common divisor. +#[tracing::instrument(level = "trace", skip(x, y))] fn gcd(x: u64, y: u64) -> u64 { let mut x = x; let mut y = y; @@ -74,6 +75,7 @@ pub struct TokenBucket { } impl TokenBucket { + #[tracing::instrument(level = "trace", skip(size, one_time_burst, complete_refill_time_ms))] /// Creates a `TokenBucket` wrapped in an `Option`. /// /// TokenBucket created is of `size` total capacity and takes `complete_refill_time_ms` @@ -116,6 +118,7 @@ impl TokenBucket { } // Replenishes token bucket based on elapsed time. Should only be called internally by `Self`. + #[tracing::instrument(level = "trace", skip(self))] fn auto_replenish(&mut self) { // Compute time passed since last refill/update. let now = Instant::now(); @@ -168,6 +171,7 @@ impl TokenBucket { } } + #[tracing::instrument(level = "trace", skip(self, tokens))] /// Attempts to consume `tokens` from the bucket and returns whether the action succeeded. pub fn reduce(&mut self, mut tokens: u64) -> BucketReduction { // First things first: consume the one-time-burst budget. @@ -215,6 +219,7 @@ impl TokenBucket { BucketReduction::Success } + #[tracing::instrument(level = "trace", skip(self, tokens))] /// "Manually" adds tokens to bucket. pub fn force_replenish(&mut self, tokens: u64) { // This means we are still during the burst interval. @@ -231,26 +236,31 @@ impl TokenBucket { self.budget = std::cmp::min(self.budget.saturating_add(tokens), self.size); } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the capacity of the token bucket. pub fn capacity(&self) -> u64 { self.size } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the remaining one time burst budget. pub fn one_time_burst(&self) -> u64 { self.one_time_burst } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the time in milliseconds required to to completely fill the bucket. pub fn refill_time_ms(&self) -> u64 { self.refill_time } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the current budget (one time burst allowance notwithstanding). pub fn budget(&self) -> u64 { self.budget } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the initially configured one time burst budget. pub fn initial_one_time_burst(&self) -> u64 { self.initial_one_time_burst @@ -302,12 +312,14 @@ pub struct RateLimiter { } impl PartialEq for RateLimiter { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &RateLimiter) -> bool { self.bandwidth == other.bandwidth && self.ops == other.ops } } impl fmt::Debug for RateLimiter { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -318,6 +330,17 @@ impl fmt::Debug for RateLimiter { } impl RateLimiter { + #[tracing::instrument( + level = "trace", + skip( + bytes_total_capacity, + bytes_one_time_burst, + bytes_complete_refill_time_ms, + ops_total_capacity, + ops_one_time_burst, + ops_complete_refill_time_ms + ) + )] /// Creates a new Rate Limiter that can limit on both bytes/s and ops/s. /// /// # Arguments @@ -373,12 +396,14 @@ impl RateLimiter { } // Arm the timer of the rate limiter with the provided `TimerState`. + #[tracing::instrument(level = "trace", skip(self, timer_state))] fn activate_timer(&mut self, timer_state: TimerState) { // Register the timer; don't care about its previous state self.timer_fd.set_state(timer_state, SetTimeFlags::Default); self.timer_active = true; } + #[tracing::instrument(level = "trace", skip(self, tokens, token_type))] /// Attempts to consume tokens and returns whether that is possible. /// /// If rate limiting is disabled on provided `token_type`, this function will always succeed. @@ -431,6 +456,7 @@ impl RateLimiter { } } + #[tracing::instrument(level = "trace", skip(self, tokens, token_type))] /// Adds tokens of `token_type` to their respective bucket. /// /// Can be used to *manually* add tokens to a bucket. Useful for reverting a @@ -447,6 +473,7 @@ impl RateLimiter { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns whether this rate limiter is blocked. /// /// The limiter 'blocks' when a `consume()` operation fails because there was not enough @@ -456,6 +483,7 @@ impl RateLimiter { self.timer_active } + #[tracing::instrument(level = "trace", skip(self))] /// This function needs to be called every time there is an event on the /// FD provided by this object's `AsRawFd` trait implementation. /// @@ -474,6 +502,7 @@ impl RateLimiter { } } + #[tracing::instrument(level = "trace", skip(self, bytes, ops))] /// Updates the parameters of the token buckets associated with this RateLimiter. // TODO: Please note that, right now, the buckets become full after being updated. pub fn update_buckets(&mut self, bytes: BucketUpdate, ops: BucketUpdate) { @@ -489,11 +518,13 @@ impl RateLimiter { }; } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an immutable view of the inner bandwidth token bucket. pub fn bandwidth(&self) -> Option<&TokenBucket> { self.bandwidth.as_ref() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns an immutable view of the inner ops token bucket. pub fn ops(&self) -> Option<&TokenBucket> { self.ops.as_ref() @@ -501,6 +532,7 @@ impl RateLimiter { } impl AsRawFd for RateLimiter { + #[tracing::instrument(level = "trace", skip(self))] /// Provides a FD which needs to be monitored for POLLIN events. /// /// This object's `event_handler()` method must be called on such events. @@ -513,6 +545,7 @@ impl AsRawFd for RateLimiter { } impl Default for RateLimiter { + #[tracing::instrument(level = "trace", skip())] /// Default RateLimiter is a no-op limiter with infinite budget. fn default() -> Self { // Safe to unwrap since this will not attempt to create timer_fd. @@ -556,6 +589,7 @@ mod verification { static mut LAST_SECONDS: i64 = 0; static mut LAST_NANOS: u32 = 0; + #[tracing::instrument(level = "trace", skip())] /// Stubs out `std::time::Instant::now` to return non-deterministic instances that are /// non-decreasing. The first value produced by this stub will always be 0. This is /// because generally harnesses only care about the delta between instants i1 and i2, which @@ -585,6 +619,7 @@ mod verification { to_return } + #[tracing::instrument(level = "trace", skip())] pub(super) fn next_instant_now() -> Instant { let stub = InstantStub { tv_sec: unsafe { LAST_SECONDS }, @@ -598,6 +633,7 @@ mod verification { unsafe { std::mem::transmute(stub) } } + #[tracing::instrument(level = "trace", skip(x, y))] /// Stubs out the GCD computation by over-approximating the return value as "any number that /// divides both inputs". fn gcd(x: u64, y: u64) -> u64 { @@ -612,6 +648,7 @@ mod verification { // underapproximates. } + #[tracing::instrument(level = "trace", skip(this))] /// Stubs out `TokenBucket::auto_replenish` by simply filling up the bucket by a /// non-deterministic amount. fn token_bucket_auto_replenish(this: &mut TokenBucket) { @@ -620,6 +657,7 @@ mod verification { } impl TokenBucket { + #[tracing::instrument(level = "trace", skip(self))] /// Functions checking that the general invariants of a TokenBucket are upheld fn is_valid(&self) -> bool { self.size != 0 @@ -634,6 +672,7 @@ mod verification { } impl kani::Arbitrary for TokenBucket { + #[tracing::instrument(level = "trace", skip())] fn any() -> TokenBucket { let bucket = TokenBucket::new(kani::any(), kani::any(), kani::any()); kani::assume(bucket.is_some()); @@ -789,24 +828,29 @@ pub(crate) mod tests { impl TokenBucket { // Resets the token bucket: budget set to max capacity and last-updated set to now. + #[tracing::instrument(level = "trace", skip(self))] fn reset(&mut self) { self.budget = self.size; self.last_update = Instant::now(); } + #[tracing::instrument(level = "trace", skip(self))] fn get_last_update(&self) -> &Instant { &self.last_update } + #[tracing::instrument(level = "trace", skip(self))] fn get_processed_capacity(&self) -> u64 { self.processed_capacity } + #[tracing::instrument(level = "trace", skip(self))] fn get_processed_refill_time(&self) -> u64 { self.processed_refill_time } // After a restore, we cannot be certain that the last_update field has the same value. + #[tracing::instrument(level = "trace", skip(self, other))] pub fn partial_eq(&self, other: &TokenBucket) -> bool { (other.capacity() == self.capacity()) && (other.one_time_burst() == self.one_time_burst()) @@ -816,6 +860,7 @@ pub(crate) mod tests { } impl RateLimiter { + #[tracing::instrument(level = "trace", skip(self, token_type))] fn get_token_bucket(&self, token_type: TokenType) -> Option<&TokenBucket> { match token_type { TokenType::Bytes => self.bandwidth.as_ref(), diff --git a/src/vmm/src/rate_limiter/persist.rs b/src/vmm/src/rate_limiter/persist.rs index 75806df785b..2523d70dff7 100644 --- a/src/vmm/src/rate_limiter/persist.rs +++ b/src/vmm/src/rate_limiter/persist.rs @@ -25,6 +25,7 @@ impl Persist<'_> for TokenBucket { type ConstructorArgs = (); type Error = io::Error; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { TokenBucketState { size: self.size, @@ -35,6 +36,7 @@ impl Persist<'_> for TokenBucket { } } + #[tracing::instrument(level = "trace", skip(state))] fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result { let now = Instant::now(); let last_update = now @@ -65,6 +67,7 @@ impl Persist<'_> for RateLimiter { type ConstructorArgs = (); type Error = io::Error; + #[tracing::instrument(level = "trace", skip(self))] fn save(&self) -> Self::State { RateLimiterState { ops: self.ops.as_ref().map(|ops| ops.save()), @@ -72,6 +75,7 @@ impl Persist<'_> for RateLimiter { } } + #[tracing::instrument(level = "trace", skip(state))] fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result { let rate_limiter = RateLimiter { ops: if let Some(ops) = state.ops.as_ref() { diff --git a/src/vmm/src/resources.rs b/src/vmm/src/resources.rs index 0cede36b6a2..a8f64927893 100644 --- a/src/vmm/src/resources.rs +++ b/src/vmm/src/resources.rs @@ -19,7 +19,7 @@ use crate::vmm_config::boot_source::{ use crate::vmm_config::drive::*; use crate::vmm_config::entropy::*; use crate::vmm_config::instance_info::InstanceInfo; -use crate::vmm_config::logger::{init_logger, LoggerConfig, LoggerConfigError}; +use crate::vmm_config::logger::{InitLoggerError, LoggerConfig}; use crate::vmm_config::machine_config::{ MachineConfig, MachineConfigUpdate, VmConfig, VmConfigError, }; @@ -48,7 +48,7 @@ pub enum ResourcesError { InvalidJson(serde_json::Error), /// Logger configuration error. #[error("Logger error: {0}")] - Logger(LoggerConfigError), + Logger(InitLoggerError), /// Metrics system configuration error. #[error("Metrics error: {0}")] Metrics(MetricsConfigError), @@ -128,18 +128,25 @@ pub struct VmResources { } impl VmResources { + #[tracing::instrument( + level = "trace", + skip(config_json, instance_info, mmds_size_limit, metadata_json) + )] /// Configures Vmm resources as described by the `config_json` param. pub fn from_json( config_json: &str, instance_info: &InstanceInfo, mmds_size_limit: usize, metadata_json: Option<&str>, - ) -> Result { + ) -> Result<(Self, Option), ResourcesError> { let vmm_config = serde_json::from_str::(config_json)?; - if let Some(logger) = vmm_config.logger { - init_logger(logger, instance_info)?; - } + let flame_guard = if let Some(logger) = vmm_config.logger { + let (_logger_handles, flame_guard) = logger.init()?; + flame_guard + } else { + None + }; if let Some(metrics) = vmm_config.metrics { init_metrics(metrics)?; @@ -184,7 +191,7 @@ impl VmResources { resources.locked_mmds_or_default().put_data( serde_json::from_str(data).expect("MMDS error: metadata provided not valid json"), )?; - log::info!("Successfully added metadata to mmds from file"); + logger::info!("Successfully added metadata to mmds from file"); } if let Some(mmds_config) = vmm_config.mmds_config { @@ -195,9 +202,10 @@ impl VmResources { resources.build_entropy_device(entropy_device_config)?; } - Ok(resources) + Ok((resources, flame_guard)) } + #[tracing::instrument(level = "trace", skip(self))] /// If not initialised, create the mmds data store with the default config. pub fn mmds_or_default(&mut self) -> &Arc> { self.mmds @@ -206,12 +214,14 @@ impl VmResources { )))) } + #[tracing::instrument(level = "trace", skip(self))] /// If not initialised, create the mmds data store with the default config. pub fn locked_mmds_or_default(&mut self) -> MutexGuard<'_, Mmds> { let mmds = self.mmds_or_default(); mmds.lock().expect("Poisoned lock") } + #[tracing::instrument(level = "trace", skip(self, device))] /// Updates the resources from a restored device (used for configuring resources when /// restoring from a snapshot). pub fn update_from_restored_device(&mut self, device: SharedDeviceType) { @@ -237,22 +247,26 @@ impl VmResources { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns whether dirty page tracking is enabled or not. pub fn track_dirty_pages(&self) -> bool { self.vm_config.track_dirty_pages } + #[tracing::instrument(level = "trace", skip(self, dirty_page_tracking))] /// Configures the dirty page tracking functionality of the microVM. pub fn set_track_dirty_pages(&mut self, dirty_page_tracking: bool) { self.vm_config.track_dirty_pages = dirty_page_tracking; } + #[tracing::instrument(level = "trace", skip(self, cpu_template))] /// Add a custom CPU template to the VM resources /// to configure vCPUs. pub fn set_custom_cpu_template(&mut self, cpu_template: CustomCpuTemplate) { self.vm_config.set_custom_cpu_template(cpu_template); } + #[tracing::instrument(level = "trace", skip(self, update))] /// Updates the configuration of the microVM. pub fn update_vm_config(&mut self, update: &MachineConfigUpdate) -> Result<(), VmConfigError> { self.vm_config.update(update)?; @@ -275,6 +289,7 @@ impl VmResources { // Repopulate the MmdsConfig based on information from the data store // and the associated net devices. + #[tracing::instrument(level = "trace", skip(self))] fn mmds_config(&self) -> Option { // If the data store is not initialised, we can be sure that the user did not configure // mmds. @@ -311,16 +326,19 @@ impl VmResources { mmds_config } + #[tracing::instrument(level = "trace", skip(self))] /// Gets a reference to the boot source configuration. pub fn boot_source_config(&self) -> &BootSourceConfig { &self.boot_source.config } + #[tracing::instrument(level = "trace", skip(self))] /// Gets a reference to the boot source builder. pub fn boot_source_builder(&self) -> Option<&BootConfig> { self.boot_source.builder.as_ref() } + #[tracing::instrument(level = "trace", skip(self, config))] /// Sets a balloon device to be attached when the VM starts. pub fn set_balloon_device( &mut self, @@ -335,6 +353,7 @@ impl VmResources { self.balloon.set(config) } + #[tracing::instrument(level = "trace", skip(self, boot_source_cfg))] /// Obtains the boot source hooks (kernel fd, command line creation and validation). pub fn build_boot_source( &mut self, @@ -345,11 +364,13 @@ impl VmResources { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, boot_source_cfg))] /// Set the boot source configuration (contains raw kernel config details). pub fn set_boot_source_config(&mut self, boot_source_cfg: BootSourceConfig) { self.boot_source.config = boot_source_cfg; } + #[tracing::instrument(level = "trace", skip(self, block_device_config))] /// Inserts a block to be attached when the VM starts. // Only call this function as part of user configuration. // If the drive_id does not exist, a new Block Device Config is added to the list. @@ -360,6 +381,7 @@ impl VmResources { self.block.insert(block_device_config) } + #[tracing::instrument(level = "trace", skip(self, body))] /// Builds a network device to be attached when the VM starts. pub fn build_net_device( &mut self, @@ -369,11 +391,13 @@ impl VmResources { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, config))] /// Sets a vsock device to be attached when the VM starts. pub fn set_vsock_device(&mut self, config: VsockDeviceConfig) -> Result<(), VsockConfigError> { self.vsock.insert(config) } + #[tracing::instrument(level = "trace", skip(self, body))] /// Builds an entropy device to be attached when the VM starts. pub fn build_entropy_device( &mut self, @@ -382,6 +406,7 @@ impl VmResources { self.entropy.insert(body) } + #[tracing::instrument(level = "trace", skip(self, config, instance_id))] /// Setter for mmds config. pub fn set_mmds_config( &mut self, @@ -394,6 +419,7 @@ impl VmResources { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, version, instance_id))] /// Updates MMDS version. pub fn set_mmds_version( &mut self, @@ -411,6 +437,7 @@ impl VmResources { // Updates MMDS Network Stack for network interfaces to allow forwarding // requests to MMDS (or not). + #[tracing::instrument(level = "trace", skip(self, config))] fn set_mmds_network_stack_config( &mut self, config: &MmdsConfig, @@ -458,6 +485,7 @@ impl VmResources { } impl From<&VmResources> for VmmConfig { + #[tracing::instrument(level = "trace", skip(resources))] fn from(resources: &VmResources) -> Self { VmmConfig { balloon_device: resources.balloon.get_config().ok(), @@ -482,7 +510,6 @@ mod tests { use std::os::linux::fs::MetadataExt; use std::str::FromStr; - use logger::{LevelFilter, LOGGER}; use serde_json::{Map, Value}; use utils::net::mac::MacAddr; use utils::tempfile::TempFile; @@ -501,6 +528,7 @@ mod tests { use crate::vmm_config::RateLimiterConfig; use crate::HTTP_MAX_PAYLOAD_SIZE; + #[tracing::instrument(level = "trace", skip())] fn default_net_cfg() -> NetworkInterfaceConfig { NetworkInterfaceConfig { iface_id: "net_if1".to_string(), @@ -518,6 +546,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn default_net_builder() -> NetBuilder { let mut net_builder = NetBuilder::new(); net_builder.build(default_net_cfg()).unwrap(); @@ -525,6 +554,7 @@ mod tests { net_builder } + #[tracing::instrument(level = "trace", skip())] fn default_block_cfg() -> (BlockDeviceConfig, TempFile) { let tmp_file = TempFile::new().unwrap(); ( @@ -542,6 +572,7 @@ mod tests { ) } + #[tracing::instrument(level = "trace", skip())] fn default_blocks() -> BlockBuilder { let mut blocks = BlockBuilder::new(); let (cfg, _file) = default_block_cfg(); @@ -549,6 +580,7 @@ mod tests { blocks } + #[tracing::instrument(level = "trace", skip())] fn default_boot_cfg() -> BootSource { let kernel_cmdline = linux_loader::cmdline::Cmdline::try_from(DEFAULT_KERNEL_CMDLINE, 4096).unwrap(); @@ -563,6 +595,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip())] fn default_vm_resources() -> VmResources { VmResources { vm_config: VmConfig::default(), @@ -579,6 +612,7 @@ mod tests { } impl PartialEq for BootConfig { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &Self) -> bool { self.cmdline.eq(&other.cmdline) && self.kernel_file.metadata().unwrap().st_ino() @@ -856,18 +890,15 @@ mod tests { rootfs_file.as_path().to_str().unwrap() ); - match VmResources::from_json( - json.as_str(), - &default_instance_info, - HTTP_MAX_PAYLOAD_SIZE, - None, - ) { - Err(ResourcesError::Logger(LoggerConfigError::InitializationFailure { .. })) => (), - _ => unreachable!(), - } - - // The previous call enables the logger. We need to disable it. - LOGGER.set_max_level(LevelFilter::Off); + assert!(matches!( + VmResources::from_json( + json.as_str(), + &default_instance_info, + HTTP_MAX_PAYLOAD_SIZE, + None, + ), + Err(ResourcesError::Logger(InitLoggerError::File(_))), + )); // Invalid path for metrics pipe. json = format!( @@ -1030,7 +1061,7 @@ mod tests { kernel_file.as_path().to_str().unwrap(), rootfs_file.as_path().to_str().unwrap(), ); - let resources = VmResources::from_json( + let (resources, _flame_guard) = VmResources::from_json( json.as_str(), &default_instance_info, 1200, @@ -1118,7 +1149,7 @@ mod tests { rootfs_file.as_path().to_str().unwrap(), ); - let vm_resources = VmResources::from_json( + let (vm_resources, _flame_guard) = VmResources::from_json( json.as_str(), &default_instance_info, HTTP_MAX_PAYLOAD_SIZE, @@ -1178,7 +1209,7 @@ mod tests { ); { - let resources = VmResources::from_json( + let (resources, _flame_guard) = VmResources::from_json( json.as_str(), &InstanceInfo::default(), HTTP_MAX_PAYLOAD_SIZE, @@ -1193,7 +1224,7 @@ mod tests { { // In this case the mmds data store will be initialised but the config still None. - let resources = VmResources::from_json( + let (resources, _flame_guard) = VmResources::from_json( json.as_str(), &InstanceInfo::default(), HTTP_MAX_PAYLOAD_SIZE, @@ -1253,7 +1284,7 @@ mod tests { kernel_file.as_path().to_str().unwrap(), rootfs_file.as_path().to_str().unwrap(), ); - let resources = VmResources::from_json( + let (resources, _flame_guard) = VmResources::from_json( json.as_str(), &InstanceInfo::default(), HTTP_MAX_PAYLOAD_SIZE, @@ -1312,7 +1343,7 @@ mod tests { kernel_file.as_path().to_str().unwrap(), rootfs_file.as_path().to_str().unwrap(), ); - let resources = VmResources::from_json( + let (resources, _flame_guard) = VmResources::from_json( json.as_str(), &InstanceInfo::default(), HTTP_MAX_PAYLOAD_SIZE, diff --git a/src/vmm/src/rpc_interface.rs b/src/vmm/src/rpc_interface.rs index 255aa8242e8..f28e8c521ef 100644 --- a/src/vmm/src/rpc_interface.rs +++ b/src/vmm/src/rpc_interface.rs @@ -4,8 +4,7 @@ use std::fmt::{self, Debug}; use std::sync::{Arc, Mutex, MutexGuard}; -use log::{error, info, warn}; -use logger::*; +use logger::{error, info, warn, *}; use mmds::data_store::{self, Mmds}; use seccompiler::BpfThreadMap; use serde_json::Value; @@ -34,7 +33,7 @@ use crate::vmm_config::boot_source::{BootSourceConfig, BootSourceConfigError}; use crate::vmm_config::drive::{BlockDeviceConfig, BlockDeviceUpdateConfig, DriveError}; use crate::vmm_config::entropy::{EntropyDeviceConfig, EntropyDeviceError}; use crate::vmm_config::instance_info::InstanceInfo; -use crate::vmm_config::logger::{LoggerConfig, LoggerConfigError}; +use crate::vmm_config::logger::{LoggerConfig, LoggerHandles}; use crate::vmm_config::machine_config::{MachineConfig, MachineConfigUpdate, VmConfigError}; use crate::vmm_config::metrics::{MetricsConfig, MetricsConfigError}; use crate::vmm_config::mmds::{MmdsConfig, MmdsConfigError}; @@ -162,7 +161,7 @@ pub enum VmmActionError { LoadSnapshot(LoadSnapshotError), /// The action `ConfigureLogger` failed because of bad user input. #[error("{0}")] - Logger(LoggerConfigError), + Logger(crate::vmm_config::logger::UpdateLoggerError), /// One of the actions `GetVmConfiguration` or `UpdateVmConfiguration` failed because of bad /// input. #[error("{0}")] @@ -260,7 +259,7 @@ trait MmdsRequestHandler { } /// Enables pre-boot setup and instantiation of a Firecracker VMM. -pub struct PrebootApiController<'a> { +pub struct PrebootApiController<'a, F, G> { seccomp_filters: &'a BpfThreadMap, instance_info: InstanceInfo, vm_resources: &'a mut VmResources, @@ -272,10 +271,13 @@ pub struct PrebootApiController<'a> { // Some PrebootApiRequest errors are irrecoverable and Firecracker // should cleanly teardown if they occur. fatal_error: Option, + /// Handles that allow re-configuring the logger. + logger_handles: LoggerHandles, } // TODO Remove when `EventManager` implements `std::fmt::Debug`. -impl<'a> fmt::Debug for PrebootApiController<'a> { +impl<'a, F, G> fmt::Debug for PrebootApiController<'a, F, G> { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PrebootApiController") .field("seccomp_filters", &self.seccomp_filters) @@ -289,7 +291,8 @@ impl<'a> fmt::Debug for PrebootApiController<'a> { } } -impl MmdsRequestHandler for PrebootApiController<'_> { +impl MmdsRequestHandler for PrebootApiController<'_, F, G> { + #[tracing::instrument(level = "trace", skip(self))] fn mmds(&mut self) -> MutexGuard<'_, Mmds> { self.vm_resources.locked_mmds_or_default() } @@ -314,13 +317,26 @@ pub type ApiRequest = Box; /// Shorthand type for a response containing a boxed Result. pub type ApiResponse = Box>; -impl<'a> PrebootApiController<'a> { +impl<'a, F: Fn(&tracing::Metadata<'_>) -> bool, G: Fn(&tracing::Metadata<'_>) -> bool> + PrebootApiController<'a, F, G> +{ + #[tracing::instrument( + level = "trace", + skip( + seccomp_filters, + instance_info, + vm_resources, + event_manager, + logger_handles + ) + )] /// Constructor for the PrebootApiController. pub fn new( seccomp_filters: &'a BpfThreadMap, instance_info: InstanceInfo, vm_resources: &'a mut VmResources, event_manager: &'a mut EventManager, + logger_handles: LoggerHandles, ) -> Self { Self { seccomp_filters, @@ -330,9 +346,25 @@ impl<'a> PrebootApiController<'a> { built_vmm: None, boot_path: false, fatal_error: None, + logger_handles, } } + #[tracing::instrument( + level = "trace", + skip( + seccomp_filters, + event_manager, + instance_info, + from_api, + to_api, + api_event_fd, + boot_timer_enabled, + mmds_size_limit, + metadata_json, + logger_handles + ) + )] /// Default implementation for the function that builds and starts a microVM. /// /// Returns a populated `VmResources` object and a running `Vmm` object. @@ -347,6 +379,7 @@ impl<'a> PrebootApiController<'a> { boot_timer_enabled: bool, mmds_size_limit: usize, metadata_json: Option<&str>, + logger_handles: LoggerHandles, ) -> Result<(VmResources, Arc>), FcExitCode> { let mut vm_resources = VmResources::default(); // Silence false clippy warning. Clippy suggests using @@ -379,6 +412,7 @@ impl<'a> PrebootApiController<'a> { instance_info, &mut vm_resources, event_manager, + logger_handles, ); // Configure and start microVM through successive API calls. @@ -413,6 +447,7 @@ impl<'a> PrebootApiController<'a> { Ok((vm_resources, vmm)) } + #[tracing::instrument(level = "trace", skip(self, request))] /// Handles the incoming preboot request and provides a response for it. /// Returns a built/running `Vmm` after handling a successful `StartMicroVm` request. pub fn handle_preboot_request( @@ -424,11 +459,10 @@ impl<'a> PrebootApiController<'a> { match request { // Supported operations allowed pre-boot. ConfigureBootSource(config) => self.set_boot_source(config), - ConfigureLogger(logger_cfg) => { - vmm_config::logger::init_logger(logger_cfg, &self.instance_info) - .map(|()| VmmData::Empty) - .map_err(VmmActionError::Logger) - } + ConfigureLogger(logger_cfg) => logger_cfg + .update(&self.logger_handles) + .map(|()| VmmData::Empty) + .map_err(VmmActionError::Logger), ConfigureMetrics(metrics_cfg) => vmm_config::metrics::init_metrics(metrics_cfg) .map(|()| VmmData::Empty) .map_err(VmmActionError::Metrics), @@ -477,6 +511,7 @@ impl<'a> PrebootApiController<'a> { } } + #[tracing::instrument(level = "trace", skip(self))] fn balloon_config(&mut self) -> Result { self.vm_resources .balloon @@ -485,6 +520,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::BalloonConfig) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn insert_block_device(&mut self, cfg: BlockDeviceConfig) -> Result { self.boot_path = true; self.vm_resources @@ -493,6 +529,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::DriveConfig) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn insert_net_device( &mut self, cfg: NetworkInterfaceConfig, @@ -504,6 +541,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::NetworkConfig) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn set_balloon_device(&mut self, cfg: BalloonDeviceConfig) -> Result { self.boot_path = true; self.vm_resources @@ -512,6 +550,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::BalloonConfig) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn set_boot_source(&mut self, cfg: BootSourceConfig) -> Result { self.boot_path = true; self.vm_resources @@ -520,6 +559,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::BootSource) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn set_mmds_config(&mut self, cfg: MmdsConfig) -> Result { self.boot_path = true; self.vm_resources @@ -528,6 +568,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::MmdsConfig) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn update_vm_config(&mut self, cfg: MachineConfigUpdate) -> Result { self.boot_path = true; self.vm_resources @@ -536,6 +577,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::MachineConfig) } + #[tracing::instrument(level = "trace", skip(self, cpu_template))] fn set_custom_cpu_template( &mut self, cpu_template: CustomCpuTemplate, @@ -544,6 +586,7 @@ impl<'a> PrebootApiController<'a> { Ok(VmmData::Empty) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn set_vsock_device(&mut self, cfg: VsockDeviceConfig) -> Result { self.boot_path = true; self.vm_resources @@ -552,6 +595,7 @@ impl<'a> PrebootApiController<'a> { .map_err(VmmActionError::VsockConfig) } + #[tracing::instrument(level = "trace", skip(self, cfg))] fn set_entropy_device(&mut self, cfg: EntropyDeviceConfig) -> Result { self.boot_path = true; self.vm_resources.build_entropy_device(cfg)?; @@ -560,6 +604,7 @@ impl<'a> PrebootApiController<'a> { // On success, this command will end the pre-boot stage and this controller // will be replaced by a runtime controller. + #[tracing::instrument(level = "trace", skip(self))] fn start_microvm(&mut self) -> Result { build_and_boot_microvm( &self.instance_info, @@ -576,6 +621,7 @@ impl<'a> PrebootApiController<'a> { // On success, this command will end the pre-boot stage and this controller // will be replaced by a runtime controller. + #[tracing::instrument(level = "trace", skip(self, load_params))] fn load_snapshot( &mut self, load_params: &LoadSnapshotParams, @@ -645,12 +691,14 @@ pub struct RuntimeApiController { } impl MmdsRequestHandler for RuntimeApiController { + #[tracing::instrument(level = "trace", skip(self))] fn mmds(&mut self) -> MutexGuard<'_, Mmds> { self.vm_resources.locked_mmds_or_default() } } impl RuntimeApiController { + #[tracing::instrument(level = "trace", skip(self, request))] /// Handles the incoming runtime `VmmAction` request and provides a response for it. pub fn handle_request(&mut self, request: VmmAction) -> Result { use self::VmmAction::*; @@ -723,11 +771,13 @@ impl RuntimeApiController { } } + #[tracing::instrument(level = "trace", skip(vm_resources, vmm))] /// Creates a new `RuntimeApiController`. pub fn new(vm_resources: VmResources, vmm: Arc>) -> Self { Self { vmm, vm_resources } } + #[tracing::instrument(level = "trace", skip(self))] /// Pauses the microVM by pausing the vCPUs. pub fn pause(&mut self) -> Result { let pause_start_us = utils::time::get_time_us(utils::time::ClockType::Monotonic); @@ -741,6 +791,7 @@ impl RuntimeApiController { Ok(VmmData::Empty) } + #[tracing::instrument(level = "trace", skip(self))] /// Resumes the microVM by resuming the vCPUs. pub fn resume(&mut self) -> Result { let resume_start_us = utils::time::get_time_us(utils::time::ClockType::Monotonic); @@ -754,6 +805,7 @@ impl RuntimeApiController { Ok(VmmData::Empty) } + #[tracing::instrument(level = "trace", skip(self))] /// Write the metrics on user demand (flush). We use the word `flush` here to highlight the fact /// that the metrics will be written immediately. /// Defer to inner Vmm. We'll move to a variant where the Vmm simply exposes functionality like @@ -768,6 +820,7 @@ impl RuntimeApiController { .map_err(VmmActionError::InternalVmm) } + #[tracing::instrument(level = "trace", skip(self))] /// Injects CTRL+ALT+DEL keystroke combo to the inner Vmm (if present). #[cfg(target_arch = "x86_64")] fn send_ctrl_alt_del(&mut self) -> Result { @@ -779,6 +832,7 @@ impl RuntimeApiController { .map_err(VmmActionError::InternalVmm) } + #[tracing::instrument(level = "trace", skip(self, create_params))] fn create_snapshot( &mut self, create_params: &CreateSnapshotParams, @@ -830,6 +884,7 @@ impl RuntimeApiController { Ok(VmmData::Empty) } + #[tracing::instrument(level = "trace", skip(self, new_cfg))] /// Updates block device properties: /// - path of the host file backing the emulated block device, update the disk image on the /// device and its virtio configuration @@ -856,6 +911,7 @@ impl RuntimeApiController { Ok(VmmData::Empty) } + #[tracing::instrument(level = "trace", skip(self, new_cfg))] /// Updates configuration for an emulated net device as described in `new_cfg`. fn update_net_rate_limiters( &mut self, @@ -880,26 +936,20 @@ impl RuntimeApiController { #[cfg(test)] mod tests { use std::io; - use std::path::PathBuf; - use mmds::data_store::MmdsVersion; use seccompiler::BpfThreadMap; use super::*; - use crate::cpu_config::templates::test_utils::build_test_template; - use crate::cpu_config::templates::{CpuTemplateType, StaticCpuTemplate}; + use crate::cpu_config::templates::StaticCpuTemplate; use crate::devices::virtio::balloon::{BalloonConfig, BalloonError}; use crate::devices::virtio::rng::EntropyError; use crate::devices::virtio::VsockError; use crate::vmm_config::balloon::BalloonBuilder; - use crate::vmm_config::drive::{CacheType, FileEngineType}; - use crate::vmm_config::logger::LoggerLevel; use crate::vmm_config::machine_config::VmConfig; - use crate::vmm_config::snapshot::{MemBackendConfig, MemBackendType}; use crate::vmm_config::vsock::VsockBuilder; - use crate::HTTP_MAX_PAYLOAD_SIZE; impl PartialEq for VmmActionError { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &VmmActionError) -> bool { use VmmActionError::*; matches!( @@ -948,6 +998,7 @@ mod tests { } impl MockVmRes { + #[tracing::instrument(level = "trace", skip(self))] pub fn balloon_config(&mut self) -> Result { if self.force_errors { return Err(BalloonError::DeviceNotFound); @@ -956,14 +1007,17 @@ mod tests { Ok(BalloonConfig::default()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn track_dirty_pages(&self) -> bool { self.vm_config.track_dirty_pages } + #[tracing::instrument(level = "trace", skip(self, dirty_page_tracking))] pub fn set_track_dirty_pages(&mut self, dirty_page_tracking: bool) { self.vm_config.track_dirty_pages = dirty_page_tracking; } + #[tracing::instrument(level = "trace", skip(self, update))] pub fn update_vm_config( &mut self, update: &MachineConfigUpdate, @@ -977,6 +1031,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn set_balloon_device( &mut self, _: BalloonDeviceConfig, @@ -988,6 +1043,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, boot_source))] pub fn build_boot_source( &mut self, boot_source: BootSourceConfig, @@ -1002,10 +1058,12 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn boot_source_config(&self) -> &BootSourceConfig { &self.boot_src } + #[tracing::instrument(level = "trace", skip(self))] pub fn set_block_device(&mut self, _: BlockDeviceConfig) -> Result<(), DriveError> { if self.force_errors { return Err(DriveError::RootBlockDeviceAlreadyAdded); @@ -1014,6 +1072,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn build_net_device( &mut self, _: NetworkInterfaceConfig, @@ -1025,6 +1084,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn set_vsock_device(&mut self, _: VsockDeviceConfig) -> Result<(), VsockConfigError> { if self.force_errors { return Err(VsockConfigError::CreateVsockDevice( @@ -1035,6 +1095,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn build_entropy_device( &mut self, _: EntropyDeviceConfig, @@ -1048,6 +1109,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, mmds_config))] pub fn set_mmds_config( &mut self, mmds_config: MmdsConfig, @@ -1063,6 +1125,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// If not initialised, create the mmds data store with the default config. pub fn mmds_or_default(&mut self) -> &Arc> { self.mmds @@ -1071,12 +1134,14 @@ mod tests { )))) } + #[tracing::instrument(level = "trace", skip(self))] /// If not initialised, create the mmds data store with the default config. pub fn locked_mmds_or_default(&mut self) -> MutexGuard<'_, Mmds> { let mmds = self.mmds_or_default(); mmds.lock().expect("Poisoned lock") } + #[tracing::instrument(level = "trace", skip(self, cpu_template))] /// Update the CPU configuration for the guest. pub fn set_custom_cpu_template(&mut self, cpu_template: CustomCpuTemplate) { self.vm_config.set_custom_cpu_template(cpu_template); @@ -1084,12 +1149,14 @@ mod tests { } impl From<&MockVmRes> for VmmConfig { + #[tracing::instrument(level = "trace", skip())] fn from(_: &MockVmRes) -> Self { VmmConfig::default() } } impl From<&MockVmRes> for VmInfo { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: &MockVmRes) -> Self { Self { mem_size_mib: value.vm_config.mem_size_mib as u64, @@ -1118,6 +1185,7 @@ mod tests { } impl MockVmm { + #[tracing::instrument(level = "trace", skip(self))] pub fn resume_vm(&mut self) -> Result<(), VmmError> { if self.force_errors { return Err(VmmError::VcpuResume); @@ -1126,6 +1194,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn pause_vm(&mut self) -> Result<(), VmmError> { if self.force_errors { return Err(VmmError::VcpuPause); @@ -1134,6 +1203,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(target_arch = "x86_64")] pub fn send_ctrl_alt_del(&mut self) -> Result<(), VmmError> { if self.force_errors { @@ -1145,6 +1215,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn balloon_config(&mut self) -> Result { if self.force_errors { return Err(BalloonError::DeviceNotFound); @@ -1153,6 +1224,7 @@ mod tests { Ok(BalloonConfig::default()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn latest_balloon_stats(&mut self) -> Result { if self.force_errors { return Err(BalloonError::DeviceNotFound); @@ -1161,6 +1233,7 @@ mod tests { Ok(BalloonStats::default()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn update_balloon_config(&mut self, _: u32) -> Result<(), BalloonError> { if self.force_errors { return Err(BalloonError::DeviceNotFound); @@ -1169,6 +1242,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn update_balloon_stats_config(&mut self, _: u16) -> Result<(), BalloonError> { if self.force_errors { return Err(BalloonError::DeviceNotFound); @@ -1177,6 +1251,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn update_block_device_path(&mut self, _: &str, _: String) -> Result<(), VmmError> { if self.force_errors { return Err(VmmError::DeviceManager( @@ -1187,6 +1262,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn update_block_rate_limiter( &mut self, _: &str, @@ -1196,6 +1272,7 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn update_net_rate_limiters( &mut self, _: &str, @@ -1213,10 +1290,12 @@ mod tests { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] pub fn instance_info(&self) -> InstanceInfo { InstanceInfo::default() } + #[tracing::instrument(level = "trace", skip(self))] pub fn version(&self) -> String { String::default() } @@ -1224,6 +1303,7 @@ mod tests { // Need to redefine this since the non-test one uses real VmResources // and real Vmm instead of our mocks. + #[tracing::instrument(level = "trace", skip())] pub fn build_and_boot_microvm( _: &InstanceInfo, _: &VmResources, @@ -1235,6 +1315,7 @@ mod tests { // Need to redefine this since the non-test one uses real Vmm // instead of our mocks. + #[tracing::instrument(level = "trace", skip())] pub fn create_snapshot( _: &mut Vmm, _: &VmInfo, @@ -1246,6 +1327,7 @@ mod tests { // Need to redefine this since the non-test one uses real Vmm // instead of our mocks. + #[tracing::instrument(level = "trace", skip())] pub fn restore_from_snapshot( _: &InstanceInfo, _: &mut EventManager, @@ -1257,277 +1339,6 @@ mod tests { Ok(Arc::new(Mutex::new(MockVmm::default()))) } - fn default_preboot<'a>( - vm_resources: &'a mut VmResources, - event_manager: &'a mut EventManager, - seccomp_filters: &'a BpfThreadMap, - ) -> PrebootApiController<'a> { - let instance_info = InstanceInfo::default(); - PrebootApiController::new(seccomp_filters, instance_info, vm_resources, event_manager) - } - - fn check_preboot_request(request: VmmAction, check_success: F) - where - F: FnOnce(Result, &MockVmRes), - { - let mut vm_resources = MockVmRes::default(); - let mut evmgr = EventManager::new().unwrap(); - let seccomp_filters = BpfThreadMap::new(); - let mut preboot = default_preboot(&mut vm_resources, &mut evmgr, &seccomp_filters); - let res = preboot.handle_preboot_request(request); - check_success(res, &vm_resources); - } - - fn check_preboot_request_with_mmds( - request: VmmAction, - mmds: Arc>, - check_success: F, - ) where - F: FnOnce(Result, &MockVmRes), - { - let mut vm_resources = MockVmRes { - mmds: Some(mmds), - mmds_size_limit: HTTP_MAX_PAYLOAD_SIZE, - ..Default::default() - }; - let mut evmgr = EventManager::new().unwrap(); - let seccomp_filters = BpfThreadMap::new(); - let mut preboot = default_preboot(&mut vm_resources, &mut evmgr, &seccomp_filters); - let res = preboot.handle_preboot_request(request); - check_success(res, &vm_resources); - } - - // Forces error and validates error kind against expected. - fn check_preboot_request_err(request: VmmAction, expected_err: VmmActionError) { - let mut vm_resources = MockVmRes { - force_errors: true, - ..Default::default() - }; - let mut evmgr = EventManager::new().unwrap(); - let seccomp_filters = BpfThreadMap::new(); - let mut preboot = default_preboot(&mut vm_resources, &mut evmgr, &seccomp_filters); - let err = preboot.handle_preboot_request(request).unwrap_err(); - assert_eq!(err, expected_err); - } - - #[test] - fn test_preboot_config_boot_src() { - let req = VmmAction::ConfigureBootSource(BootSourceConfig::default()); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vm_res.boot_cfg_set) - }); - - let req = VmmAction::ConfigureBootSource(BootSourceConfig::default()); - check_preboot_request_err( - req, - VmmActionError::BootSource(BootSourceConfigError::InvalidKernelCommandLine( - String::new(), - )), - ); - } - - #[test] - fn test_preboot_get_vm_config() { - let req = VmmAction::GetVmMachineConfig; - let expected_cfg = MachineConfig::default(); - check_preboot_request(req, |result, _| { - assert_eq!(result, Ok(VmmData::MachineConfiguration(expected_cfg))) - }); - - let req = VmmAction::ConfigureBootSource(BootSourceConfig::default()); - check_preboot_request_err( - req, - VmmActionError::BootSource(BootSourceConfigError::InvalidKernelCommandLine( - String::new(), - )), - ); - } - - #[test] - fn test_preboot_get_balloon_config() { - let req = VmmAction::GetBalloonConfig; - let expected_cfg = BalloonDeviceConfig::default(); - check_preboot_request(req, |result, _| { - assert_eq!(result, Ok(VmmData::BalloonConfig(expected_cfg))) - }); - } - - #[test] - fn test_preboot_put_cpu_config() { - // Start testing - Provide VMM vCPU configuration in preparation for `InstanceStart` - let req = VmmAction::PutCpuConfiguration(build_test_template()); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert_eq!( - vm_res.vm_config.cpu_template, - Some(CpuTemplateType::Custom(build_test_template())) - ); - }); - } - - #[test] - fn test_preboot_set_vm_config() { - let req = - VmmAction::UpdateVmConfiguration(MachineConfigUpdate::from(MachineConfig::default())); - let expected_cfg = MachineConfig::default(); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert_eq!(MachineConfig::from(&vm_res.vm_config), expected_cfg); - }); - - let req = - VmmAction::UpdateVmConfiguration(MachineConfigUpdate::from(MachineConfig::default())); - check_preboot_request_err( - req, - VmmActionError::MachineConfig(VmConfigError::InvalidVcpuCount), - ); - } - - #[test] - fn test_preboot_set_balloon_dev() { - let req = VmmAction::SetBalloonDevice(BalloonDeviceConfig::default()); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vm_res.balloon_set) - }); - - let req = VmmAction::SetBalloonDevice(BalloonDeviceConfig::default()); - check_preboot_request_err( - req, - VmmActionError::BalloonConfig(BalloonConfigError::DeviceNotFound), - ); - } - - #[test] - fn test_preboot_insert_block_dev() { - let req = VmmAction::InsertBlockDevice(BlockDeviceConfig { - path_on_host: String::new(), - is_root_device: false, - partuuid: None, - cache_type: CacheType::Unsafe, - is_read_only: false, - drive_id: String::new(), - rate_limiter: None, - file_engine_type: FileEngineType::default(), - }); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vm_res.block_set) - }); - - let req = VmmAction::InsertBlockDevice(BlockDeviceConfig { - path_on_host: String::new(), - is_root_device: false, - partuuid: None, - cache_type: CacheType::Unsafe, - is_read_only: false, - drive_id: String::new(), - rate_limiter: None, - file_engine_type: FileEngineType::default(), - }); - check_preboot_request_err( - req, - VmmActionError::DriveConfig(DriveError::RootBlockDeviceAlreadyAdded), - ); - } - - #[test] - fn test_preboot_insert_net_dev() { - let req = VmmAction::InsertNetworkDevice(NetworkInterfaceConfig { - iface_id: String::new(), - host_dev_name: String::new(), - guest_mac: None, - rx_rate_limiter: None, - tx_rate_limiter: None, - }); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vm_res.net_set) - }); - - let req = VmmAction::InsertNetworkDevice(NetworkInterfaceConfig { - iface_id: String::new(), - host_dev_name: String::new(), - guest_mac: None, - rx_rate_limiter: None, - tx_rate_limiter: None, - }); - check_preboot_request_err( - req, - VmmActionError::NetworkConfig(NetworkInterfaceError::GuestMacAddressInUse( - String::new(), - )), - ); - } - - #[test] - fn test_preboot_set_vsock_dev() { - let req = VmmAction::SetVsockDevice(VsockDeviceConfig { - vsock_id: Some(String::new()), - guest_cid: 0, - uds_path: String::new(), - }); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vm_res.vsock_set) - }); - - let req = VmmAction::SetVsockDevice(VsockDeviceConfig { - vsock_id: Some(String::new()), - guest_cid: 0, - uds_path: String::new(), - }); - check_preboot_request_err( - req, - VmmActionError::VsockConfig(VsockConfigError::CreateVsockDevice( - VsockError::BufDescMissing, - )), - ); - } - - #[test] - fn test_preboot_set_entropy_device() { - let req = VmmAction::SetEntropyDevice(EntropyDeviceConfig::default()); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vm_res.entropy_set); - }); - } - - #[test] - fn test_preboot_set_mmds_config() { - let req = VmmAction::SetMmdsConfiguration(MmdsConfig { - ipv4_address: None, - version: MmdsVersion::V2, - network_interfaces: Vec::new(), - }); - check_preboot_request(req, |result, vm_res| { - assert_eq!(result, Ok(VmmData::Empty)); - assert_eq!( - vm_res.mmds.as_ref().unwrap().lock().unwrap().version(), - MmdsVersion::V2 - ); - }); - - let req = VmmAction::SetMmdsConfiguration(MmdsConfig { - ipv4_address: None, - version: MmdsVersion::default(), - network_interfaces: Vec::new(), - }); - check_preboot_request_err( - req, - VmmActionError::MmdsConfig(MmdsConfigError::InvalidIpv4Addr), - ); - } - - #[test] - fn test_preboot_get_mmds() { - check_preboot_request(VmmAction::GetMMDS, |result, _| { - assert_eq!(result, Ok(VmmData::MmdsValue(Value::Null))); - }); - } - #[test] fn test_runtime_get_mmds() { check_runtime_request(VmmAction::GetMMDS, |result, _| { @@ -1535,42 +1346,6 @@ mod tests { }); } - #[test] - fn test_preboot_put_mmds() { - let mmds = Arc::new(Mutex::new(Mmds::default())); - - check_preboot_request_with_mmds( - VmmAction::PutMMDS(Value::String("string".to_string())), - mmds.clone(), - |result, _| { - assert_eq!(result, Ok(VmmData::Empty)); - }, - ); - check_preboot_request_with_mmds(VmmAction::GetMMDS, mmds.clone(), |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue(Value::String("string".to_string()))) - ); - }); - - let filling = (0..51300).map(|_| "X").collect::(); - let data = "{\"key\": \"".to_string() + &filling + "\"}"; - - check_preboot_request_with_mmds( - VmmAction::PutMMDS(serde_json::from_str(&data).unwrap()), - mmds.clone(), - |result, _| { - assert!(matches!(result, Err(VmmActionError::MmdsLimitExceeded(_)))); - }, - ); - check_preboot_request_with_mmds(VmmAction::GetMMDS, mmds, |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue(Value::String("string".to_string()))) - ); - }); - } - #[test] fn test_runtime_put_mmds() { let mmds = Arc::new(Mutex::new(Mmds::default())); @@ -1607,236 +1382,7 @@ mod tests { }); } - #[test] - fn test_preboot_patch_mmds() { - let mmds = Arc::new(Mutex::new(Mmds::default())); - // MMDS data store is not yet initialized. - check_preboot_request_err( - VmmAction::PatchMMDS(Value::String("string".to_string())), - VmmActionError::Mmds(data_store::Error::NotInitialized), - ); - - check_preboot_request_with_mmds( - VmmAction::PutMMDS( - serde_json::from_str(r#"{"key1": "value1", "key2": "val2"}"#).unwrap(), - ), - mmds.clone(), - |result, _| { - assert_eq!(result, Ok(VmmData::Empty)); - }, - ); - check_preboot_request_with_mmds(VmmAction::GetMMDS, mmds.clone(), |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue( - serde_json::from_str(r#"{"key1": "value1", "key2": "val2"}"#).unwrap() - )) - ); - }); - - check_preboot_request_with_mmds( - VmmAction::PatchMMDS( - serde_json::from_str(r#"{"key1": null, "key2": "value2"}"#).unwrap(), - ), - mmds.clone(), - |result, _| { - assert_eq!(result, Ok(VmmData::Empty)); - }, - ); - - check_preboot_request_with_mmds(VmmAction::GetMMDS, mmds.clone(), |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue( - serde_json::from_str(r#"{"key2": "value2"}"#).unwrap() - )) - ); - }); - - let filling = (0..HTTP_MAX_PAYLOAD_SIZE).map(|_| "X").collect::(); - let data = "{\"key\": \"".to_string() + &filling + "\"}"; - - check_preboot_request_with_mmds( - VmmAction::PatchMMDS(serde_json::from_str(&data).unwrap()), - mmds.clone(), - |result, _| { - assert!(matches!(result, Err(VmmActionError::MmdsLimitExceeded(_)))); - }, - ); - check_preboot_request_with_mmds(VmmAction::GetMMDS, mmds, |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue( - serde_json::from_str(r#"{"key2": "value2"}"#).unwrap() - )) - ); - }); - } - - #[test] - fn test_runtime_patch_mmds() { - let mmds = Arc::new(Mutex::new(Mmds::default())); - // MMDS data store is not yet initialized. - check_runtime_request_err( - VmmAction::PatchMMDS(Value::String("string".to_string())), - VmmActionError::Mmds(data_store::Error::NotInitialized), - ); - - check_runtime_request_with_mmds( - VmmAction::PutMMDS( - serde_json::from_str(r#"{"key1": "value1", "key2": "val2"}"#).unwrap(), - ), - mmds.clone(), - |result, _| { - assert_eq!(result, Ok(VmmData::Empty)); - }, - ); - check_runtime_request_with_mmds(VmmAction::GetMMDS, mmds.clone(), |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue( - serde_json::from_str(r#"{"key1": "value1", "key2": "val2"}"#).unwrap() - )) - ); - }); - - check_runtime_request_with_mmds( - VmmAction::PatchMMDS( - serde_json::from_str(r#"{"key1": null, "key2": "value2"}"#).unwrap(), - ), - mmds.clone(), - |result, _| { - assert_eq!(result, Ok(VmmData::Empty)); - }, - ); - - check_runtime_request_with_mmds(VmmAction::GetMMDS, mmds.clone(), |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue( - serde_json::from_str(r#"{"key2": "value2"}"#).unwrap() - )) - ); - }); - - let filling = (0..HTTP_MAX_PAYLOAD_SIZE).map(|_| "X").collect::(); - let data = "{\"key\": \"".to_string() + &filling + "\"}"; - - check_runtime_request_with_mmds( - VmmAction::PatchMMDS(serde_json::from_str(&data).unwrap()), - mmds.clone(), - |result, _| { - assert!(matches!(result, Err(VmmActionError::MmdsLimitExceeded(_)))); - }, - ); - check_runtime_request_with_mmds(VmmAction::GetMMDS, mmds, |result, _| { - assert_eq!( - result, - Ok(VmmData::MmdsValue( - serde_json::from_str(r#"{"key2": "value2"}"#).unwrap() - )) - ); - }); - } - - #[test] - fn test_preboot_load_snapshot() { - let mut vm_resources = MockVmRes::default(); - let mut evmgr = EventManager::new().unwrap(); - let seccomp_filters = BpfThreadMap::new(); - let mut preboot = default_preboot(&mut vm_resources, &mut evmgr, &seccomp_filters); - - // Without resume. - let req = VmmAction::LoadSnapshot(LoadSnapshotParams { - snapshot_path: PathBuf::new(), - mem_backend: MemBackendConfig { - backend_type: MemBackendType::File, - backend_path: PathBuf::new(), - }, - enable_diff_snapshots: false, - resume_vm: false, - }); - // Request should succeed. - preboot.handle_preboot_request(req).unwrap(); - // Should have built default mock vmm. - let vmm = preboot.built_vmm.take().unwrap(); - assert_eq!(*vmm.lock().unwrap(), MockVmm::default()); - - // With resume. - let req = VmmAction::LoadSnapshot(LoadSnapshotParams { - snapshot_path: PathBuf::new(), - mem_backend: MemBackendConfig { - backend_type: MemBackendType::File, - backend_path: PathBuf::new(), - }, - enable_diff_snapshots: false, - resume_vm: true, - }); - // Request should succeed. - preboot.handle_preboot_request(req).unwrap(); - let vmm = preboot.built_vmm.as_ref().unwrap().lock().unwrap(); - // Should have built mock vmm then called resume on it. - assert!(vmm.resume_called); - // Extra sanity check - pause was never called. - assert!(!vmm.pause_called); - } - - #[test] - fn test_preboot_disallowed() { - check_preboot_request_err( - VmmAction::FlushMetrics, - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::Pause, - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::Resume, - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::GetBalloonStats, - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::UpdateBalloon(BalloonUpdateConfig { amount_mib: 0 }), - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::UpdateBalloonStatistics(BalloonUpdateStatsConfig { - stats_polling_interval_s: 0, - }), - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::UpdateBlockDevice(BlockDeviceUpdateConfig::default()), - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::UpdateNetworkInterface(NetworkInterfaceUpdateConfig { - iface_id: String::new(), - rx_rate_limiter: None, - tx_rate_limiter: None, - }), - VmmActionError::OperationNotSupportedPreBoot, - ); - check_preboot_request_err( - VmmAction::CreateSnapshot(CreateSnapshotParams { - snapshot_type: SnapshotType::Full, - snapshot_path: PathBuf::new(), - mem_file_path: PathBuf::new(), - version: None, - }), - VmmActionError::OperationNotSupportedPreBoot, - ); - #[cfg(target_arch = "x86_64")] - check_preboot_request_err( - VmmAction::SendCtrlAltDel, - VmmActionError::OperationNotSupportedPreBoot, - ); - } - + #[tracing::instrument(level = "trace", skip(request, check_success))] fn check_runtime_request(request: VmmAction, check_success: F) where F: FnOnce(Result, &MockVmm), @@ -1847,6 +1393,7 @@ mod tests { check_success(res, &vmm.lock().unwrap()); } + #[tracing::instrument(level = "trace", skip(request, mmds, check_success))] fn check_runtime_request_with_mmds( request: VmmAction, mmds: Arc>, @@ -1864,17 +1411,6 @@ mod tests { check_success(res, &vmm.lock().unwrap()); } - // Forces error and validates error kind against expected. - fn check_runtime_request_err(request: VmmAction, expected_err: VmmActionError) { - let vmm = Arc::new(Mutex::new(MockVmm { - force_errors: true, - ..Default::default() - })); - let mut runtime = RuntimeApiController::new(MockVmRes::default(), vmm); - let err = runtime.handle_request(request).unwrap_err(); - assert_eq!(err, expected_err); - } - #[test] fn test_runtime_get_vm_config() { let req = VmmAction::GetVmMachineConfig; @@ -1885,333 +1421,4 @@ mod tests { ); }); } - - #[test] - fn test_runtime_pause() { - let req = VmmAction::Pause; - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.pause_called) - }); - - let req = VmmAction::Pause; - check_runtime_request_err(req, VmmActionError::InternalVmm(VmmError::VcpuPause)); - } - - #[test] - fn test_runtime_resume() { - let req = VmmAction::Resume; - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.resume_called) - }); - - let req = VmmAction::Resume; - check_runtime_request_err(req, VmmActionError::InternalVmm(VmmError::VcpuResume)); - } - - #[cfg(target_arch = "x86_64")] - #[test] - fn test_runtime_ctrl_alt_del() { - let req = VmmAction::SendCtrlAltDel; - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.send_ctrl_alt_del_called) - }); - - let req = VmmAction::SendCtrlAltDel; - check_runtime_request_err( - req, - VmmActionError::InternalVmm(VmmError::I8042Error( - crate::devices::legacy::I8042DeviceError::InternalBufferFull, - )), - ); - } - - #[test] - fn test_runtime_balloon_config() { - let req = VmmAction::GetBalloonConfig; - check_runtime_request(req, |result, vmm| { - assert_eq!( - result, - Ok(VmmData::BalloonConfig(BalloonDeviceConfig::default())) - ); - assert!(vmm.balloon_config_called) - }); - - let req = VmmAction::GetBalloonConfig; - check_runtime_request_err( - req, - VmmActionError::BalloonConfig(BalloonConfigError::DeviceNotFound), - ); - } - - #[test] - fn test_runtime_latest_balloon_stats() { - let req = VmmAction::GetBalloonStats; - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::BalloonStats(BalloonStats::default()))); - assert!(vmm.latest_balloon_stats_called) - }); - - let req = VmmAction::GetBalloonStats; - check_runtime_request_err( - req, - VmmActionError::BalloonConfig(BalloonConfigError::DeviceNotFound), - ); - } - - #[test] - fn test_runtime_update_balloon_config() { - let req = VmmAction::UpdateBalloon(BalloonUpdateConfig { amount_mib: 0 }); - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.update_balloon_config_called) - }); - - let req = VmmAction::UpdateBalloon(BalloonUpdateConfig { amount_mib: 0 }); - check_runtime_request_err( - req, - VmmActionError::BalloonConfig(BalloonConfigError::DeviceNotFound), - ); - } - - #[test] - fn test_runtime_update_balloon_stats_config() { - let req = VmmAction::UpdateBalloonStatistics(BalloonUpdateStatsConfig { - stats_polling_interval_s: 0, - }); - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.update_balloon_stats_config_called) - }); - - let req = VmmAction::UpdateBalloonStatistics(BalloonUpdateStatsConfig { - stats_polling_interval_s: 0, - }); - check_runtime_request_err( - req, - VmmActionError::BalloonConfig(BalloonConfigError::DeviceNotFound), - ); - } - - #[test] - fn test_runtime_update_block_device_path() { - let req = VmmAction::UpdateBlockDevice(BlockDeviceUpdateConfig { - path_on_host: Some(String::new()), - ..Default::default() - }); - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.update_block_device_path_called) - }); - - let req = VmmAction::UpdateBlockDevice(BlockDeviceUpdateConfig { - path_on_host: Some(String::new()), - ..Default::default() - }); - check_runtime_request_err( - req, - VmmActionError::DriveConfig(DriveError::DeviceUpdate(VmmError::DeviceManager( - crate::device_manager::mmio::MmioError::InvalidDeviceType, - ))), - ); - } - - #[test] - fn test_runtime_update_net_rate_limiters() { - let req = VmmAction::UpdateNetworkInterface(NetworkInterfaceUpdateConfig { - iface_id: String::new(), - rx_rate_limiter: None, - tx_rate_limiter: None, - }); - check_runtime_request(req, |result, vmm| { - assert_eq!(result, Ok(VmmData::Empty)); - assert!(vmm.update_net_rate_limiters_called) - }); - - let req = VmmAction::UpdateNetworkInterface(NetworkInterfaceUpdateConfig { - iface_id: String::new(), - rx_rate_limiter: None, - tx_rate_limiter: None, - }); - check_runtime_request_err( - req, - VmmActionError::NetworkConfig(NetworkInterfaceError::DeviceUpdate( - VmmError::DeviceManager(crate::device_manager::mmio::MmioError::InvalidDeviceType), - )), - ); - } - - #[test] - fn test_runtime_disallowed() { - check_runtime_request_err( - VmmAction::ConfigureBootSource(BootSourceConfig::default()), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::ConfigureLogger(LoggerConfig { - log_path: PathBuf::new(), - level: LoggerLevel::Debug, - show_level: false, - show_log_origin: false, - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::ConfigureMetrics(MetricsConfig { - metrics_path: PathBuf::new(), - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::InsertBlockDevice(BlockDeviceConfig { - path_on_host: String::new(), - is_root_device: false, - partuuid: None, - cache_type: CacheType::Unsafe, - is_read_only: false, - drive_id: String::new(), - rate_limiter: None, - file_engine_type: FileEngineType::default(), - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::InsertNetworkDevice(NetworkInterfaceConfig { - iface_id: String::new(), - host_dev_name: String::new(), - guest_mac: None, - rx_rate_limiter: None, - tx_rate_limiter: None, - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::SetVsockDevice(VsockDeviceConfig { - vsock_id: Some(String::new()), - guest_cid: 0, - uds_path: String::new(), - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::SetBalloonDevice(BalloonDeviceConfig::default()), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::SetVsockDevice(VsockDeviceConfig { - vsock_id: Some(String::new()), - guest_cid: 0, - uds_path: String::new(), - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::SetMmdsConfiguration(MmdsConfig { - ipv4_address: None, - version: MmdsVersion::default(), - network_interfaces: Vec::new(), - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::UpdateVmConfiguration(MachineConfigUpdate::from(MachineConfig::default())), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::LoadSnapshot(LoadSnapshotParams { - snapshot_path: PathBuf::new(), - mem_backend: MemBackendConfig { - backend_type: MemBackendType::File, - backend_path: PathBuf::new(), - }, - enable_diff_snapshots: false, - resume_vm: false, - }), - VmmActionError::OperationNotSupportedPostBoot, - ); - check_runtime_request_err( - VmmAction::SetEntropyDevice(EntropyDeviceConfig::default()), - VmmActionError::OperationNotSupportedPostBoot, - ); - } - - fn verify_load_snap_disallowed_after_boot_resources(res: VmmAction, res_name: &str) { - let mut vm_resources = MockVmRes::default(); - let mut evmgr = EventManager::new().unwrap(); - let seccomp_filters = BpfThreadMap::new(); - let mut preboot = default_preboot(&mut vm_resources, &mut evmgr, &seccomp_filters); - - preboot.handle_preboot_request(res).unwrap(); - - // Load snapshot should no longer be allowed. - let req = VmmAction::LoadSnapshot(LoadSnapshotParams { - snapshot_path: PathBuf::new(), - mem_backend: MemBackendConfig { - backend_type: MemBackendType::File, - backend_path: PathBuf::new(), - }, - enable_diff_snapshots: false, - resume_vm: false, - }); - let err = preboot.handle_preboot_request(req); - assert_eq!( - err, - Err(VmmActionError::LoadSnapshot( - LoadSnapshotError::LoadSnapshotNotAllowed - )), - "LoadSnapshot should be disallowed after {}", - res_name - ); - } - - #[test] - fn test_preboot_load_snap_disallowed_after_boot_resources() { - // Verify LoadSnapshot not allowed after configuring various boot-specific resources. - let req = VmmAction::ConfigureBootSource(BootSourceConfig::default()); - verify_load_snap_disallowed_after_boot_resources(req, "ConfigureBootSource"); - - let req = VmmAction::InsertBlockDevice(BlockDeviceConfig { - path_on_host: String::new(), - is_root_device: false, - partuuid: None, - cache_type: CacheType::Unsafe, - is_read_only: false, - drive_id: String::new(), - rate_limiter: None, - file_engine_type: FileEngineType::default(), - }); - verify_load_snap_disallowed_after_boot_resources(req, "InsertBlockDevice"); - - let req = VmmAction::InsertNetworkDevice(NetworkInterfaceConfig { - iface_id: String::new(), - host_dev_name: String::new(), - guest_mac: None, - rx_rate_limiter: None, - tx_rate_limiter: None, - }); - verify_load_snap_disallowed_after_boot_resources(req, "InsertNetworkDevice"); - - let req = VmmAction::SetBalloonDevice(BalloonDeviceConfig::default()); - verify_load_snap_disallowed_after_boot_resources(req, "SetBalloonDevice"); - - let req = VmmAction::SetVsockDevice(VsockDeviceConfig { - vsock_id: Some(String::new()), - guest_cid: 0, - uds_path: String::new(), - }); - verify_load_snap_disallowed_after_boot_resources(req, "SetVsockDevice"); - - let req = - VmmAction::UpdateVmConfiguration(MachineConfigUpdate::from(MachineConfig::default())); - verify_load_snap_disallowed_after_boot_resources(req, "SetVmConfiguration"); - - let req = VmmAction::SetMmdsConfiguration(MmdsConfig { - ipv4_address: None, - version: MmdsVersion::default(), - network_interfaces: Vec::new(), - }); - verify_load_snap_disallowed_after_boot_resources(req, "SetMmdsConfiguration"); - } } diff --git a/src/vmm/src/seccomp_filters.rs b/src/vmm/src/seccomp_filters.rs index aabdc1ef2c1..6f940eb5b2a 100644 --- a/src/vmm/src/seccomp_filters.rs +++ b/src/vmm/src/seccomp_filters.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use seccompiler::BpfThreadMap; +#[tracing::instrument(level = "trace", skip())] /// Retrieve empty seccomp filters. pub fn get_empty_filters() -> BpfThreadMap { let mut map = BpfThreadMap::new(); diff --git a/src/vmm/src/signal_handler.rs b/src/vmm/src/signal_handler.rs index 9c4f4f04009..7c58348f586 100644 --- a/src/vmm/src/signal_handler.rs +++ b/src/vmm/src/signal_handler.rs @@ -4,8 +4,7 @@ use libc::{ c_int, c_void, siginfo_t, SIGBUS, SIGHUP, SIGILL, SIGPIPE, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ, }; -use log::error; -use logger::{IncMetric, StoreMetric, METRICS}; +use logger::{error, IncMetric, StoreMetric, METRICS}; use utils::signal::register_signal_handler; use crate::FcExitCode; @@ -19,6 +18,7 @@ const SI_OFF_SYSCALL: isize = 6; const SYS_SECCOMP_CODE: i32 = 1; +#[tracing::instrument(level = "trace", skip(exit_code))] #[inline] fn exit_with_code(exit_code: FcExitCode) { // Write the metrics before exiting. @@ -59,6 +59,7 @@ macro_rules! generate_handler { }; } +#[tracing::instrument(level = "trace", skip(si_code, info))] fn log_sigsys_err(si_code: c_int, info: *mut siginfo_t) { if si_code != SYS_SECCOMP_CODE { // We received a SIGSYS for a reason other than `bad syscall`. @@ -75,6 +76,7 @@ fn log_sigsys_err(si_code: c_int, info: *mut siginfo_t) { ); } +#[tracing::instrument(level = "trace", skip(_si_code, _info))] fn empty_fn(_si_code: c_int, _info: *mut siginfo_t) {} generate_handler!( @@ -132,6 +134,7 @@ generate_handler!( empty_fn ); +#[tracing::instrument(level = "trace", skip(num, info, _unused))] #[inline(always)] extern "C" fn sigpipe_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) { // Just record the metric and allow the process to continue, the EPIPE error needs @@ -152,6 +155,7 @@ extern "C" fn sigpipe_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_ error!("Received signal {}, code {}.", si_signo, si_code); } +#[tracing::instrument(level = "trace", skip())] /// Registers all the required signal handlers. /// /// Custom handlers are installed for: `SIGBUS`, `SIGSEGV`, `SIGSYS` @@ -249,6 +253,7 @@ mod tests { assert!(METRICS.signals.sigill.fetch() >= 1); } + #[tracing::instrument(level = "trace", skip())] fn make_test_seccomp_bpf_filter() -> Vec { // Create seccomp filter that allows all syscalls, except for `SYS_mkdirat`. // For some reason, directly calling `SYS_kill` with SIGSYS, like we do with the diff --git a/src/vmm/src/utilities/mock_devices/mod.rs b/src/vmm/src/utilities/mock_devices/mod.rs index f18c5b7eba7..7a7ef92d0b5 100644 --- a/src/vmm/src/utilities/mock_devices/mod.rs +++ b/src/vmm/src/utilities/mock_devices/mod.rs @@ -10,12 +10,14 @@ use std::os::unix::io::{AsRawFd, RawFd}; pub struct MockSerialInput(pub File); impl io::Read for MockSerialInput { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } } impl AsRawFd for MockSerialInput { + #[tracing::instrument(level = "trace", skip(self))] fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } diff --git a/src/vmm/src/utilities/mock_resources/mod.rs b/src/vmm/src/utilities/mock_resources/mod.rs index a048d924532..87303e762fe 100644 --- a/src/vmm/src/utilities/mock_resources/mod.rs +++ b/src/vmm/src/utilities/mock_resources/mod.rs @@ -19,6 +19,7 @@ pub const NOISY_KERNEL_IMAGE: &str = "test_noisy_elf.bin"; #[cfg(target_arch = "aarch64")] pub const NOISY_KERNEL_IMAGE: &str = "test_pe.bin"; +#[tracing::instrument(level = "trace", skip(kernel_image))] pub fn kernel_image_path(kernel_image: Option<&str>) -> String { let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("src/utilities/mock_resources"); @@ -40,6 +41,7 @@ macro_rules! generate_from { pub struct MockBootSourceConfig(BootSourceConfig); impl MockBootSourceConfig { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> MockBootSourceConfig { MockBootSourceConfig(BootSourceConfig { kernel_image_path: kernel_image_path(None), @@ -48,11 +50,13 @@ impl MockBootSourceConfig { }) } + #[tracing::instrument(level = "trace", skip(self))] pub fn with_default_boot_args(mut self) -> Self { self.0.boot_args = Some(DEFAULT_BOOT_ARGS.to_string()); self } + #[tracing::instrument(level = "trace", skip(self, kernel_image))] #[cfg(target_arch = "x86_64")] pub fn with_kernel(mut self, kernel_image: &str) -> Self { self.0.kernel_image_path = kernel_image_path(Some(kernel_image)); @@ -61,6 +65,7 @@ impl MockBootSourceConfig { } impl Default for MockBootSourceConfig { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self::new() } @@ -70,21 +75,25 @@ impl Default for MockBootSourceConfig { pub struct MockVmResources(VmResources); impl MockVmResources { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> MockVmResources { MockVmResources::default() } + #[tracing::instrument(level = "trace", skip(self, boot_source_cfg))] pub fn with_boot_source(mut self, boot_source_cfg: BootSourceConfig) -> Self { self.0.build_boot_source(boot_source_cfg).unwrap(); self } + #[tracing::instrument(level = "trace", skip(self, vm_config))] pub fn with_vm_config(mut self, vm_config: MachineConfig) -> Self { let machine_config = MachineConfigUpdate::from(vm_config); self.0.update_vm_config(&machine_config).unwrap(); self } + #[tracing::instrument(level = "trace", skip(self, cpu_template))] pub fn set_cpu_template(&mut self, cpu_template: CustomCpuTemplate) { self.0.vm_config.set_custom_cpu_template(cpu_template); } @@ -94,10 +103,12 @@ impl MockVmResources { pub struct MockVmConfig(MachineConfig); impl MockVmConfig { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> MockVmConfig { MockVmConfig::default() } + #[tracing::instrument(level = "trace", skip(self))] pub fn with_dirty_page_tracking(mut self) -> Self { self.0.track_dirty_pages = true; self diff --git a/src/vmm/src/utilities/test_utils/mod.rs b/src/vmm/src/utilities/test_utils/mod.rs index 9d757007019..6b28be5aa77 100644 --- a/src/vmm/src/utilities/test_utils/mod.rs +++ b/src/vmm/src/utilities/test_utils/mod.rs @@ -12,6 +12,7 @@ use crate::vmm_config::boot_source::BootSourceConfig; use crate::vmm_config::instance_info::InstanceInfo; use crate::{EventManager, Vmm}; +#[tracing::instrument(level = "trace", skip(_kernel_image, is_diff, boot_microvm))] pub fn create_vmm( _kernel_image: Option<&str>, is_diff: bool, @@ -52,14 +53,17 @@ pub fn create_vmm( (vmm, event_manager) } +#[tracing::instrument(level = "trace", skip(kernel_image))] pub fn default_vmm(kernel_image: Option<&str>) -> (Arc>, EventManager) { create_vmm(kernel_image, false, true) } +#[tracing::instrument(level = "trace", skip(kernel_image))] pub fn default_vmm_no_boot(kernel_image: Option<&str>) -> (Arc>, EventManager) { create_vmm(kernel_image, false, false) } +#[tracing::instrument(level = "trace", skip(kernel_image))] #[cfg(target_arch = "x86_64")] pub fn dirty_tracking_vmm(kernel_image: Option<&str>) -> (Arc>, EventManager) { create_vmm(kernel_image, true, true) diff --git a/src/vmm/src/vmm_config/balloon.rs b/src/vmm/src/vmm_config/balloon.rs index 20272daecb8..ac26a978a48 100644 --- a/src/vmm/src/vmm_config/balloon.rs +++ b/src/vmm/src/vmm_config/balloon.rs @@ -53,6 +53,7 @@ pub struct BalloonDeviceConfig { } impl From for BalloonDeviceConfig { + #[tracing::instrument(level = "trace", skip(state))] fn from(state: BalloonConfig) -> Self { BalloonDeviceConfig { amount_mib: state.amount_mib, @@ -90,11 +91,13 @@ pub struct BalloonBuilder { } impl BalloonBuilder { + #[tracing::instrument(level = "trace", skip())] /// Creates an empty Balloon Store. pub fn new() -> Self { Self { inner: None } } + #[tracing::instrument(level = "trace", skip(self, cfg))] /// Inserts a Balloon device in the store. /// If an entry already exists, it will overwrite it. pub fn set(&mut self, cfg: BalloonDeviceConfig) -> Result<(), BalloonConfigError> { @@ -110,16 +113,19 @@ impl BalloonBuilder { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, balloon))] /// Inserts an existing balloon device. pub fn set_device(&mut self, balloon: MutexBalloon) { self.inner = Some(balloon); } + #[tracing::instrument(level = "trace", skip(self))] /// Provides a reference to the Balloon if present. pub fn get(&self) -> Option<&MutexBalloon> { self.inner.as_ref() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the same structure that was used to configure the device. pub fn get_config(&self) -> Result { self.get() @@ -131,6 +137,7 @@ impl BalloonBuilder { #[cfg(test)] impl Default for BalloonBuilder { + #[tracing::instrument(level = "trace", skip())] fn default() -> BalloonBuilder { let mut balloon = BalloonBuilder::new(); assert!(balloon.set(BalloonDeviceConfig::default()).is_ok()); @@ -142,6 +149,7 @@ impl Default for BalloonBuilder { pub(crate) mod tests { use super::*; + #[tracing::instrument(level = "trace", skip())] pub(crate) fn default_config() -> BalloonDeviceConfig { BalloonDeviceConfig { amount_mib: 0, diff --git a/src/vmm/src/vmm_config/boot_source.rs b/src/vmm/src/vmm_config/boot_source.rs index 623326e0d5a..84869df5227 100644 --- a/src/vmm/src/vmm_config/boot_source.rs +++ b/src/vmm/src/vmm_config/boot_source.rs @@ -72,6 +72,7 @@ pub struct BootConfig { } impl BootConfig { + #[tracing::instrument(level = "trace", skip(cfg))] /// Creates the BootConfig based on a given configuration. pub fn new(cfg: &BootSourceConfig) -> Result { use self::BootSourceConfigError::{ diff --git a/src/vmm/src/vmm_config/drive.rs b/src/vmm/src/vmm_config/drive.rs index 7af40d46609..8ac5cd33073 100644 --- a/src/vmm/src/vmm_config/drive.rs +++ b/src/vmm/src/vmm_config/drive.rs @@ -68,6 +68,7 @@ pub struct BlockDeviceConfig { } impl From<&Block> for BlockDeviceConfig { + #[tracing::instrument(level = "trace", skip(block))] fn from(block: &Block) -> Self { let rl: RateLimiterConfig = block.rate_limiter().into(); BlockDeviceConfig { @@ -108,6 +109,7 @@ pub struct BlockBuilder { } impl BlockBuilder { + #[tracing::instrument(level = "trace", skip())] /// Constructor for BlockDevices. It initializes an empty LinkedList. pub fn new() -> Self { Self { @@ -115,6 +117,7 @@ impl BlockBuilder { } } + #[tracing::instrument(level = "trace", skip(self))] /// Specifies whether there is a root block device already present in the list. fn has_root_device(&self) -> bool { // If there is a root device, it would be at the top of the list. @@ -125,6 +128,7 @@ impl BlockBuilder { } } + #[tracing::instrument(level = "trace", skip(self, drive_id))] /// Gets the index of the device with the specified `drive_id` if it exists in the list. fn get_index_of_drive_id(&self, drive_id: &str) -> Option { self.list @@ -132,6 +136,7 @@ impl BlockBuilder { .position(|b| b.lock().expect("Poisoned lock").id().eq(drive_id)) } + #[tracing::instrument(level = "trace", skip(self, block_device))] /// Inserts an existing block device. pub fn add_device(&mut self, block_device: Arc>) { if block_device.lock().expect("Poisoned lock").is_root_device() { @@ -141,6 +146,7 @@ impl BlockBuilder { } } + #[tracing::instrument(level = "trace", skip(self, config))] /// Inserts a `Block` in the block devices list using the specified configuration. /// If a block with the same id already exists, it will overwrite it. /// Inserting a secondary root block device will fail. @@ -180,6 +186,7 @@ impl BlockBuilder { Ok(()) } + #[tracing::instrument(level = "trace", skip(block_device_config))] /// Creates a Block device from a BlockDeviceConfig. fn create_block(block_device_config: BlockDeviceConfig) -> Result { // check if the path exists @@ -210,6 +217,7 @@ impl BlockBuilder { .map_err(DriveError::CreateBlockDevice) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a vec with the structures used to configure the devices. pub fn configs(&self) -> Vec { let mut ret = vec![]; @@ -228,6 +236,7 @@ mod tests { use crate::rate_limiter::RateLimiter; impl PartialEq for DriveError { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &DriveError) -> bool { self.to_string() == other.to_string() } @@ -236,6 +245,7 @@ mod tests { // This implementation is used only in tests. // We cannot directly derive clone because RateLimiter does not implement clone. impl Clone for BlockDeviceConfig { + #[tracing::instrument(level = "trace", skip(self))] fn clone(&self) -> Self { BlockDeviceConfig { path_on_host: self.path_on_host.clone(), diff --git a/src/vmm/src/vmm_config/entropy.rs b/src/vmm/src/vmm_config/entropy.rs index d443f7dcda8..f63b66b9d98 100644 --- a/src/vmm/src/vmm_config/entropy.rs +++ b/src/vmm/src/vmm_config/entropy.rs @@ -19,6 +19,7 @@ pub struct EntropyDeviceConfig { } impl From<&Entropy> for EntropyDeviceConfig { + #[tracing::instrument(level = "trace", skip(dev))] fn from(dev: &Entropy) -> Self { let rate_limiter: RateLimiterConfig = dev.rate_limiter().into(); EntropyDeviceConfig { @@ -44,11 +45,13 @@ pub enum EntropyDeviceError { pub struct EntropyDeviceBuilder(Option>>); impl EntropyDeviceBuilder { + #[tracing::instrument(level = "trace", skip())] /// Create a new instance for the builder pub fn new() -> Self { Self(None) } + #[tracing::instrument(level = "trace", skip(self, config))] /// Build an entropy device and return a (counted) reference to it protected by a mutex pub fn build( &mut self, @@ -64,17 +67,20 @@ impl EntropyDeviceBuilder { Ok(dev) } + #[tracing::instrument(level = "trace", skip(self, config))] /// Insert a new entropy device from a configuration object pub fn insert(&mut self, config: EntropyDeviceConfig) -> Result<(), EntropyDeviceError> { let _ = self.build(config)?; Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Get a reference to the entropy device, if present pub fn get(&self) -> Option<&Arc>> { self.0.as_ref() } + #[tracing::instrument(level = "trace", skip(self))] /// Get the configuration of the entropy device (if any) pub fn config(&self) -> Option { self.0 @@ -82,6 +88,7 @@ impl EntropyDeviceBuilder { .map(|dev| EntropyDeviceConfig::from(dev.lock().unwrap().deref())) } + #[tracing::instrument(level = "trace", skip(self, device))] /// Set the entropy device from an already created object pub fn set_device(&mut self, device: Arc>) { self.0 = Some(device); diff --git a/src/vmm/src/vmm_config/instance_info.rs b/src/vmm/src/vmm_config/instance_info.rs index 67fd335deaa..05b9a392941 100644 --- a/src/vmm/src/vmm_config/instance_info.rs +++ b/src/vmm/src/vmm_config/instance_info.rs @@ -17,6 +17,7 @@ pub enum VmState { } impl Display for VmState { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { VmState::NotStarted => write!(f, "Not started"), @@ -27,6 +28,7 @@ impl Display for VmState { } impl ser::Serialize for VmState { + #[tracing::instrument(level = "trace", skip(self, serializer))] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, diff --git a/src/vmm/src/vmm_config/logger.rs b/src/vmm/src/vmm_config/logger.rs index 4c108c14bf7..d44a36b5731 100644 --- a/src/vmm/src/vmm_config/logger.rs +++ b/src/vmm/src/vmm_config/logger.rs @@ -1,70 +1,107 @@ // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//! Auxiliary module for configuring the logger. +use std::convert::From; +use std::fmt; +use std::fs::OpenOptions; +use std::io::{BufWriter, LineWriter}; +use std::os::unix::fs::OpenOptionsExt; use std::path::PathBuf; +use std::str::FromStr; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::SeqCst; +use std::sync::Mutex; -use logger::{FcLineWriter, LevelFilter, LOGGER}; -use serde::{de, Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; +use tracing::Event; +use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields}; +use tracing_subscriber::fmt::writer::BoxMakeWriter; +use tracing_subscriber::fmt::{FmtContext, Layer as FmtLayer}; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::registry::{LookupSpan, Registry}; +use tracing_subscriber::reload::Layer as ReloadLayer; +use tracing_subscriber::util::SubscriberInitExt; -use super::open_file_nonblock; -use crate::vmm_config::instance_info::InstanceInfo; +type ReloadError = tracing_subscriber::reload::Error; -/// Enum used for setting the log level. -#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] -pub enum LoggerLevel { - /// When the level is set to `Error`, the logger will only contain entries - /// that come from the `error` macro. +// TODO: See below doc comment. +/// Mimic of `log::LevelFilter`. +/// +/// This is used instead of `log::LevelFilter` to support aliasing `Warn` as `Warning` to avoid a +/// breaking change in the API (which previously only accepted `Warning`). +/// +/// This alias should be removed in the next breaking update to simplify +/// the code and API (and `log::LevelFilter` should be used in place). +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum LevelFilter { + /// A level lower than all log levels. + Off, + /// Corresponds to the `Error` log level. + #[serde(alias = "ERROR")] Error, - /// When the level is set to `Warning`, the logger will only contain entries - /// that come from the `error` and `warn` macros. - #[default] - Warning, - /// When the level is set to `Info`, the logger will only contain entries - /// that come from the `error`, `warn` and `info` macros. + /// Corresponds to the `Warn` log level. + #[serde(alias = "WARNING", alias = "Warning")] + Warn, + /// Corresponds to the `Info` log level. + #[serde(alias = "INFO")] Info, - /// The most verbose log level. + /// Corresponds to the `Debug` log level. + #[serde(alias = "DEBUG")] Debug, + /// Corresponds to the `Trace` log level. + #[serde(alias = "TRACE")] + Trace, } -impl LoggerLevel { - /// Converts from a logger level value of type String to the corresponding LoggerLevel variant - /// or returns an error if the parsing failed. - pub fn from_string(level: String) -> Result { - match level.to_ascii_lowercase().as_str() { - "error" => Ok(LoggerLevel::Error), - "warning" => Ok(LoggerLevel::Warning), - "info" => Ok(LoggerLevel::Info), - "debug" => Ok(LoggerLevel::Debug), - _ => Err(LoggerConfigError::InitializationFailure(level)), - } +fn from_log(level: log::LevelFilter) -> tracing_subscriber::filter::LevelFilter { + match level { + log::LevelFilter::Off => tracing_subscriber::filter::LevelFilter::OFF, + log::LevelFilter::Error => tracing_subscriber::filter::LevelFilter::ERROR, + log::LevelFilter::Warn => tracing_subscriber::filter::LevelFilter::WARN, + log::LevelFilter::Info => tracing_subscriber::filter::LevelFilter::INFO, + log::LevelFilter::Debug => tracing_subscriber::filter::LevelFilter::DEBUG, + log::LevelFilter::Trace => tracing_subscriber::filter::LevelFilter::TRACE, } } -impl From for LevelFilter { - fn from(logger_level: LoggerLevel) -> Self { - match logger_level { - LoggerLevel::Error => LevelFilter::Error, - LoggerLevel::Warning => LevelFilter::Warn, - LoggerLevel::Info => LevelFilter::Info, - LoggerLevel::Debug => LevelFilter::Debug, +impl From for log::LevelFilter { + fn from(level: LevelFilter) -> log::LevelFilter { + match level { + LevelFilter::Off => log::LevelFilter::Off, + LevelFilter::Error => log::LevelFilter::Error, + LevelFilter::Warn => log::LevelFilter::Warn, + LevelFilter::Info => log::LevelFilter::Info, + LevelFilter::Debug => log::LevelFilter::Debug, + LevelFilter::Trace => log::LevelFilter::Trace, } } } - -// This allows `level` field, which is an enum, to be case-insensitive. -fn case_insensitive<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let level = String::deserialize(deserializer).map_err(de::Error::custom)?; - LoggerLevel::from_string(level).or_else(|err| { - Err(format!( - "unknown variant `{}`, expected one of `Error`, `Warning`, `Info`, `Debug`", - err - )) - .map_err(de::Error::custom) - }) +impl From for LevelFilter { + fn from(level: log::LevelFilter) -> LevelFilter { + match level { + log::LevelFilter::Off => LevelFilter::Off, + log::LevelFilter::Error => LevelFilter::Error, + log::LevelFilter::Warn => LevelFilter::Warn, + log::LevelFilter::Info => LevelFilter::Info, + log::LevelFilter::Debug => LevelFilter::Debug, + log::LevelFilter::Trace => LevelFilter::Trace, + } + } +} +impl FromStr for LevelFilter { + type Err = ::Err; + fn from_str(s: &str) -> std::result::Result { + // This is required to avoid a breaking change. + match s { + "OFF" => Ok(LevelFilter::Off), + "ERROR" => Ok(LevelFilter::Error), + "WARNING" | "Warning" => Ok(LevelFilter::Warn), + "INFO" => Ok(LevelFilter::Info), + "DEBUG" => Ok(LevelFilter::Debug), + "TRACE" => Ok(LevelFilter::Trace), + _ => log::LevelFilter::from_str(s).map(LevelFilter::from), + } + } } /// Strongly typed structure used to describe the logger. @@ -72,186 +109,288 @@ where #[serde(deny_unknown_fields)] pub struct LoggerConfig { /// Named pipe or file used as output for logs. - pub log_path: PathBuf, + pub log_path: Option, + // TODO Deprecate this API argument. /// The level of the Logger. - #[serde( - default = "LoggerLevel::default", - deserialize_with = "case_insensitive" - )] - pub level: LoggerLevel, + pub level: Option, /// When enabled, the logger will append to the output the severity of the log entry. - #[serde(default)] - pub show_level: bool, + pub show_level: Option, /// When enabled, the logger will append the origin of the log entry. - #[serde(default)] - pub show_log_origin: bool, + pub show_log_origin: Option, + /// Filter components. If this is `Some` it overrides `self.level`. + pub filter: Option, + /// Named pipe or file used as output for profile. + pub profile_path: Option, } -impl LoggerConfig { - /// Creates a new LoggerConfig. - pub fn new( - log_path: PathBuf, - level: LoggerLevel, - show_level: bool, - show_log_origin: bool, - ) -> LoggerConfig { - LoggerConfig { - log_path, - level, - show_level, - show_log_origin, - } - } +/// Error type for [`LoggerConfig::init`]. +#[derive(Debug, thiserror::Error)] +pub enum InitLoggerError { + /// Failed to initialize logger. + #[error("Failed to initialize logger: {0}")] + Init(tracing_subscriber::util::TryInitError), + /// Failed to open target file. + #[error("Failed to open target file: {0}")] + File(std::io::Error), } -/// Errors associated with actions on the `LoggerConfig`. +/// Error type for [`LoggerConfig::update`]. #[derive(Debug, thiserror::Error)] -pub enum LoggerConfigError { - /// Cannot initialize the logger due to bad user input. - #[error("{}", format!("{:?}", .0).replace('\"', ""))] - InitializationFailure(String), +pub enum UpdateLoggerError { + /// Failed to open target file. + #[error("Failed to open target file: {0}")] + File(std::io::Error), + /// Failed to modify format layer writer. + #[error("Failed to modify format layer writer: {0}")] + Fmt(ReloadError), + /// Failed to modify level filter. + #[error("Failed to modify level filter: {0}")] + Level(ReloadError), } -/// Configures the logger as described in `logger_cfg`. -pub fn init_logger( - logger_cfg: LoggerConfig, - instance_info: &InstanceInfo, -) -> Result<(), LoggerConfigError> { - LOGGER - .set_max_level(logger_cfg.level.into()) - .set_include_origin(logger_cfg.show_log_origin, logger_cfg.show_log_origin) - .set_include_level(logger_cfg.show_level); +/// The filter arguments for logs. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct FilterArgs { + /// A filepath to filter by e.g. `src/main.rs`. + file: Option, + /// A module path to filter by e.g. `vmm::vmm_config`. + module: Option, + /// A level to filter by e.g. `tracing::Level::INFO`. + level: Option, +} - let writer = FcLineWriter::new( - open_file_nonblock(&logger_cfg.log_path) - .map_err(|err| LoggerConfigError::InitializationFailure(err.to_string()))?, - ); - LOGGER - .init( - format!( - "Running {} v{}", - instance_info.app_name, instance_info.vmm_version - ), - Box::new(writer), - ) - .map_err(|err| LoggerConfigError::InitializationFailure(err.to_string())) +// Initialize filter to default. +static FILTER: Mutex = Mutex::new(FilterArgs { + file: None, + module: None, + level: Some(log::LevelFilter::Warn), +}); + +// `type_alias_impl_trait` is the nightly feature required to move this to a `type FmtHandle = ..` +// and remove these polluting generics. +/// Handles that allow re-configuring the logger. +#[derive(Debug)] +pub struct LoggerHandles { + fmt: FmtHandle, } -#[cfg(test)] -mod tests { - use std::io::{BufRead, BufReader}; +type FmtHandle = tracing_subscriber::reload::Handle< + tracing_subscriber::fmt::Layer< + tracing_subscriber::layer::Layered< + tracing_subscriber::filter::FilterFn, + tracing_subscriber::registry::Registry, + >, + tracing_subscriber::fmt::format::DefaultFields, + LoggerFormatter, + tracing_subscriber::fmt::writer::BoxMakeWriter, + >, + tracing_subscriber::layer::Layered< + tracing_subscriber::filter::FilterFn, + tracing_subscriber::registry::Registry, + >, +>; - use logger::warn; - use utils::tempfile::TempFile; - use utils::time::TimestampUs; +/// An alias for the specific [`tracing_flame::FlushGuard`] used to flush the +/// [`tracing_flame::FlameLayer`]. +pub type FlameGuard = tracing_flame::FlushGuard>; - use super::*; - use crate::devices::pseudo::BootTimer; +impl LoggerConfig { + /// Initializes the logger. + /// + /// Returns handles that can be used to dynamically re-configure the logger. + pub fn init( + self, + ) -> Result< + ( + LoggerHandles< + impl Fn(&tracing::Metadata<'_>) -> bool, + impl Fn(&tracing::Metadata<'_>) -> bool, + >, + Option, + ), + InitLoggerError, + > { + // Update default filter to match passed arguments. + match (self.level, self.filter) { + (_, Some(filter)) => { + *FILTER.lock().unwrap() = filter; + } + (Some(level), None) => { + *FILTER.lock().unwrap() = FilterArgs { + file: None, + module: None, + level: Some(log::LevelFilter::from(level)), + }; + } + (None, None) => {} + } - #[test] - fn test_init_logger() { - let default_instance_info = InstanceInfo::default(); + // Setup filter layer + let filter = tracing_subscriber::filter::FilterFn::new(|metadata| { + let args = FILTER.lock().unwrap(); + let file_cond = args.file.as_ref().map_or(true, |f| { + metadata + .file() + .map(|file| file.starts_with(f)) + .unwrap_or(false) + }); + let module_cond = args.module.as_ref().map_or(true, |m| { + metadata + .module_path() + .map(|module_path| module_path.starts_with(m)) + .unwrap_or(false) + }); + let level_cond = args + .level + .map_or(true, |l| *metadata.level() <= from_log(l)); + file_cond && module_cond && level_cond + }); - // Error case: initializing logger with invalid pipe returns error. - let desc = LoggerConfig { - log_path: PathBuf::from("not_found_file_log"), - level: LoggerLevel::Debug, - show_level: false, - show_log_origin: false, + // Setup fmt layer + let (fmt, fmt_handle) = { + let fmt_writer = match &self.log_path { + Some(path) => { + // In case we open a FIFO, in order to not block the instance if nobody is + // consuming the message that is flushed to the two pipes, we are opening it + // with `O_NONBLOCK` flag. In this case, writing to a pipe will start failing + // when reaching 64K of unconsumed content. + let file = OpenOptions::new() + .custom_flags(libc::O_NONBLOCK) + .read(true) + .write(true) + .open(path) + .map_err(InitLoggerError::File)?; + // Wrap file to satisfy `tracing_subscriber::fmt::MakeWriter`. + let writer = Mutex::new(LineWriter::new(file)); + BoxMakeWriter::new(writer) + } + None => BoxMakeWriter::new(std::io::stdout), + }; + let fmt_subscriber = FmtLayer::new() + .event_format(LoggerFormatter::new( + self.show_level.unwrap_or_default(), + self.show_log_origin.unwrap_or_default(), + )) + .with_writer(fmt_writer); + ReloadLayer::new(fmt_subscriber) }; - assert!(init_logger(desc, &default_instance_info).is_err()); - // Initializing logger with valid pipe is ok. - let log_file = TempFile::new().unwrap(); - let desc = LoggerConfig { - log_path: log_file.as_path().to_path_buf(), - level: LoggerLevel::Info, - show_level: true, - show_log_origin: true, + // Setup flame layer + let flame_guard = if let Some(profile_path) = self.profile_path { + let writer = OpenOptions::new().write(true).open(profile_path).unwrap(); + let buffer = BufWriter::new(writer); + let flame_layer = tracing_flame::FlameLayer::new(buffer); + let guard = flame_layer.flush_on_drop(); + + Registry::default() + .with(filter) + .with(fmt) + .with(flame_layer) + .try_init() + .map_err(InitLoggerError::Init)?; + + Some(guard) + } else { + Registry::default() + .with(filter) + .with(fmt) + .try_init() + .map_err(InitLoggerError::Init)?; + None }; - assert!(init_logger(desc.clone(), &default_instance_info).is_ok()); - assert!(init_logger(desc, &default_instance_info).is_err()); + tracing::error!("Error level logs enabled."); + tracing::warn!("Warn level logs enabled."); + tracing::info!("Info level logs enabled."); + tracing::debug!("Debug level logs enabled."); + tracing::trace!("Trace level logs enabled."); - // Validate logfile works. - warn!("this is a test"); + Ok((LoggerHandles { fmt: fmt_handle }, flame_guard)) + } + /// Updates the logger using the given handles. + pub fn update( + self, + LoggerHandles { fmt }: &LoggerHandles< + impl Fn(&tracing::Metadata<'_>) -> bool, + impl Fn(&tracing::Metadata<'_>) -> bool, + >, + ) -> Result<(), UpdateLoggerError> { + // Update the log path + if let Some(log_path) = &self.log_path { + // In case we open a FIFO, in order to not block the instance if nobody is consuming the + // message that is flushed to the two pipes, we are opening it with `O_NONBLOCK` flag. + // In this case, writing to a pipe will start failing when reaching 64K of unconsumed + // content. + let file = OpenOptions::new() + .custom_flags(libc::O_NONBLOCK) + .read(true) + .write(true) + .open(log_path) + .map_err(UpdateLoggerError::File)?; - let mut reader = BufReader::new(log_file.into_file()); + fmt.modify(|f| *f.writer_mut() = BoxMakeWriter::new(Mutex::new(LineWriter::new(file)))) + .map_err(UpdateLoggerError::Fmt)?; + } - let mut line = String::new(); - loop { - if line.contains("this is a test") { - break; + // Update the filter + match (self.level, self.filter) { + (_, Some(filter)) => { + *FILTER.lock().unwrap() = filter; } - if reader.read_line(&mut line).unwrap() == 0 { - // If it ever gets here, this assert will fail. - assert!(line.contains("this is a test")); + (Some(level), None) => { + *FILTER.lock().unwrap() = FilterArgs { + file: None, + module: None, + level: Some(log::LevelFilter::from(level)), + }; } + (None, None) => {} } - // Validate logging the boot time works. - let mut boot_timer = BootTimer::new(TimestampUs::default()); - boot_timer.bus_write(0, &[123]); + // Update if the logger shows the level + if let Some(show_level) = self.show_level { + SHOW_LEVEL.store(show_level, SeqCst); + } - let mut line = String::new(); - loop { - if line.contains("Guest-boot-time =") { - break; - } - if reader.read_line(&mut line).unwrap() == 0 { - // If it ever gets here, this assert will fail. - assert!(line.contains("Guest-boot-time =")); - } + // Updates if the logger shows the origin + if let Some(show_log_origin) = self.show_log_origin { + SHOW_LOG_ORIGIN.store(show_log_origin, SeqCst); } + + Ok(()) } +} - #[test] - fn test_new_logger_config() { - let logger_config = - LoggerConfig::new(PathBuf::from("log"), LoggerLevel::Debug, false, true); - assert_eq!(logger_config.log_path, PathBuf::from("log")); - assert_eq!(logger_config.level, LoggerLevel::Debug); - assert!(!logger_config.show_level); - assert!(logger_config.show_log_origin); +#[derive(Debug)] +struct LoggerFormatter; +impl LoggerFormatter { + pub fn new(show_level: bool, show_log_origin: bool) -> Self { + SHOW_LEVEL.store(show_level, SeqCst); + SHOW_LOG_ORIGIN.store(show_log_origin, SeqCst); + Self } +} + +static SHOW_LEVEL: AtomicBool = AtomicBool::new(false); +static SHOW_LOG_ORIGIN: AtomicBool = AtomicBool::new(false); - #[test] - fn test_parse_level() { - // Check `from_string()` behaviour for different scenarios. - assert_eq!( - format!( - "{}", - LoggerLevel::from_string("random_value".to_string()).unwrap_err() - ), - "random_value" - ); - assert_eq!( - LoggerLevel::from_string("Error".to_string()).unwrap(), - LoggerLevel::Error - ); - assert_eq!( - LoggerLevel::from_string("Warning".to_string()).unwrap(), - LoggerLevel::Warning - ); - assert_eq!( - LoggerLevel::from_string("Info".to_string()).unwrap(), - LoggerLevel::Info - ); - assert_eq!( - LoggerLevel::from_string("Debug".to_string()).unwrap(), - LoggerLevel::Debug - ); - assert_eq!( - LoggerLevel::from_string("error".to_string()).unwrap(), - LoggerLevel::Error - ); - assert_eq!( - LoggerLevel::from_string("WaRnIng".to_string()).unwrap(), - LoggerLevel::Warning - ); - assert_eq!( - LoggerLevel::from_string("DEBUG".to_string()).unwrap(), - LoggerLevel::Debug - ); +impl FormatEvent for LoggerFormatter +where + S: tracing::Subscriber + for<'a> LookupSpan<'a>, + N: for<'a> FormatFields<'a> + 'static, +{ + fn format_event( + &self, + ctx: &FmtContext<'_, S, N>, + writer: format::Writer<'_>, + event: &Event<'_>, + ) -> fmt::Result { + tracing_subscriber::fmt::format::Format::default() + .with_thread_names(true) + .with_ansi(false) + .with_level(SHOW_LEVEL.load(SeqCst)) + .with_file(SHOW_LOG_ORIGIN.load(SeqCst)) + .with_line_number(SHOW_LOG_ORIGIN.load(SeqCst)) + .format_event(ctx, writer, event) } } diff --git a/src/vmm/src/vmm_config/machine_config.rs b/src/vmm/src/vmm_config/machine_config.rs index 236c64b9d70..fc2615bf2f6 100644 --- a/src/vmm/src/vmm_config/machine_config.rs +++ b/src/vmm/src/vmm_config/machine_config.rs @@ -60,12 +60,14 @@ pub struct MachineConfig { } impl Default for MachineConfig { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self::from(&VmConfig::default()) } } impl fmt::Display for MachineConfig { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -111,6 +113,7 @@ pub struct MachineConfigUpdate { } impl MachineConfigUpdate { + #[tracing::instrument(level = "trace", skip(self))] /// Checks if the update request contains any data. /// Returns `true` if all fields are set to `None` which means that there is nothing /// to be updated. @@ -129,6 +132,7 @@ impl MachineConfigUpdate { } impl From for MachineConfigUpdate { + #[tracing::instrument(level = "trace", skip(cfg))] fn from(cfg: MachineConfig) -> Self { MachineConfigUpdate { vcpu_count: Some(cfg.vcpu_count), @@ -156,11 +160,13 @@ pub struct VmConfig { } impl VmConfig { + #[tracing::instrument(level = "trace", skip(self, cpu_template))] /// Sets cpu tempalte field to `CpuTemplateType::Custom(cpu_template)`. pub fn set_custom_cpu_template(&mut self, cpu_template: CustomCpuTemplate) { self.cpu_template = Some(CpuTemplateType::Custom(cpu_template)); } + #[tracing::instrument(level = "trace", skip(self, update))] /// Updates `VmConfig` with `MachineConfigUpdate`. /// Mapping for cpu tempalte update: /// StaticCpuTemplate::None -> None @@ -207,6 +213,7 @@ impl VmConfig { } impl Default for VmConfig { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { Self { vcpu_count: 1, @@ -219,6 +226,7 @@ impl Default for VmConfig { } impl From<&VmConfig> for MachineConfig { + #[tracing::instrument(level = "trace", skip(value))] fn from(value: &VmConfig) -> Self { Self { vcpu_count: value.vcpu_count, @@ -230,6 +238,7 @@ impl From<&VmConfig> for MachineConfig { } } +#[tracing::instrument(level = "trace", skip(d))] /// Deserialization function for the `vcpu_num` field in `MachineConfig` and `MachineConfigUpdate`. /// This is called only when `vcpu_num` is present in the JSON configuration. /// `T` can be either `u8` or `Option` which both support ordering if `vcpu_num` is @@ -257,6 +266,7 @@ where Ok(val) } +#[tracing::instrument(level = "trace", skip(d))] /// Deserialization function for the `smt` field in `MachineConfig` and `MachineConfigUpdate`. /// This is called only when `smt` is present in the JSON configuration. fn deserialize_smt<'de, D, T>(d: D) -> Result diff --git a/src/vmm/src/vmm_config/metrics.rs b/src/vmm/src/vmm_config/metrics.rs index 4ba6d21089f..be5407f959c 100644 --- a/src/vmm/src/vmm_config/metrics.rs +++ b/src/vmm/src/vmm_config/metrics.rs @@ -24,6 +24,7 @@ pub enum MetricsConfigError { InitializationFailure(String), } +#[tracing::instrument(level = "trace", skip(metrics_cfg))] /// Configures the metrics as described in `metrics_cfg`. pub fn init_metrics(metrics_cfg: MetricsConfig) -> Result<(), MetricsConfigError> { let writer = FcLineWriter::new( diff --git a/src/vmm/src/vmm_config/mmds.rs b/src/vmm/src/vmm_config/mmds.rs index d2c0a6f4619..76a0cf7b0c6 100644 --- a/src/vmm/src/vmm_config/mmds.rs +++ b/src/vmm/src/vmm_config/mmds.rs @@ -20,16 +20,19 @@ pub struct MmdsConfig { } impl MmdsConfig { + #[tracing::instrument(level = "trace", skip(self))] /// Returns the MMDS version configured. pub fn version(&self) -> MmdsVersion { self.version } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the network interfaces that accept MMDS requests. pub fn network_interfaces(&self) -> Vec { self.network_interfaces.clone() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the MMDS IPv4 address if one was configured. /// Otherwise returns None. pub fn ipv4_addr(&self) -> Option { diff --git a/src/vmm/src/vmm_config/mod.rs b/src/vmm/src/vmm_config/mod.rs index 74e9b78baea..36846d4bf58 100644 --- a/src/vmm/src/vmm_config/mod.rs +++ b/src/vmm/src/vmm_config/mod.rs @@ -59,6 +59,7 @@ pub struct TokenBucketConfig { } impl From<&TokenBucket> for TokenBucketConfig { + #[tracing::instrument(level = "trace", skip(tb))] fn from(tb: &TokenBucket) -> Self { let one_time_burst = match tb.initial_one_time_burst() { 0 => None, @@ -92,6 +93,7 @@ pub struct RateLimiterUpdate { pub ops: BucketUpdate, } +#[tracing::instrument(level = "trace", skip(tb_cfg))] fn get_bucket_update(tb_cfg: &Option) -> BucketUpdate { match tb_cfg { // There is data to update. @@ -112,6 +114,7 @@ fn get_bucket_update(tb_cfg: &Option) -> BucketUpdate { } impl From> for RateLimiterUpdate { + #[tracing::instrument(level = "trace", skip(cfg))] fn from(cfg: Option) -> Self { if let Some(cfg) = cfg { RateLimiterUpdate { @@ -130,7 +133,7 @@ impl From> for RateLimiterUpdate { impl TryInto for RateLimiterConfig { type Error = io::Error; - + #[tracing::instrument(level = "trace", skip(self))] fn try_into(self) -> Result { let bw = self.bandwidth.unwrap_or_default(); let ops = self.ops.unwrap_or_default(); @@ -146,6 +149,7 @@ impl TryInto for RateLimiterConfig { } impl From<&RateLimiter> for RateLimiterConfig { + #[tracing::instrument(level = "trace", skip(rl))] fn from(rl: &RateLimiter) -> Self { RateLimiterConfig { bandwidth: rl.bandwidth().map(TokenBucketConfig::from), @@ -156,6 +160,7 @@ impl From<&RateLimiter> for RateLimiterConfig { impl RateLimiterConfig { // Option already implements From so we have to use a custom one. + #[tracing::instrument(level = "trace", skip(self))] fn into_option(self) -> Option { if self.bandwidth.is_some() || self.ops.is_some() { Some(self) @@ -165,6 +170,7 @@ impl RateLimiterConfig { } } +#[tracing::instrument(level = "trace", skip(path))] /// Create and opens a File for writing to it. /// In case we open a FIFO, in order to not block the instance if nobody is consuming the message /// that is flushed to the two pipes, we are opening it with `O_NONBLOCK` flag. diff --git a/src/vmm/src/vmm_config/net.rs b/src/vmm/src/vmm_config/net.rs index 6f21ac23064..2752956212e 100644 --- a/src/vmm/src/vmm_config/net.rs +++ b/src/vmm/src/vmm_config/net.rs @@ -31,6 +31,7 @@ pub struct NetworkInterfaceConfig { } impl From<&Net> for NetworkInterfaceConfig { + #[tracing::instrument(level = "trace", skip(net))] fn from(net: &Net) -> Self { let rx_rl: RateLimiterConfig = net.rx_rate_limiter().into(); let tx_rl: RateLimiterConfig = net.tx_rate_limiter().into(); @@ -86,6 +87,7 @@ pub struct NetBuilder { } impl NetBuilder { + #[tracing::instrument(level = "trace", skip())] /// Creates an empty list of Network Devices. pub fn new() -> Self { NetBuilder { @@ -94,21 +96,25 @@ impl NetBuilder { } } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a immutable iterator over the network devices. pub fn iter(&self) -> ::std::slice::Iter>> { self.net_devices.iter() } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a mutable iterator over the network devices. pub fn iter_mut(&mut self) -> ::std::slice::IterMut>> { self.net_devices.iter_mut() } + #[tracing::instrument(level = "trace", skip(self, device))] /// Adds an existing network device in the builder. pub fn add_device(&mut self, device: Arc>) { self.net_devices.push(device); } + #[tracing::instrument(level = "trace", skip(self, netif_config))] /// Builds a network device based on a network interface config. Keeps a device reference /// in the builder's internal list. pub fn build( @@ -147,6 +153,7 @@ impl NetBuilder { Ok(net) } + #[tracing::instrument(level = "trace", skip(cfg))] /// Creates a Net device from a NetworkInterfaceConfig. pub fn create_net(cfg: NetworkInterfaceConfig) -> Result { let rx_rate_limiter = cfg @@ -171,6 +178,7 @@ impl NetBuilder { .map_err(NetworkInterfaceError::CreateNetworkDevice) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a vec with the structures used to configure the net devices. pub fn configs(&self) -> Vec { let mut ret = vec![]; @@ -189,15 +197,18 @@ mod tests { use crate::rate_limiter::RateLimiter; impl NetBuilder { + #[tracing::instrument(level = "trace", skip(self))] pub fn len(&self) -> usize { self.net_devices.len() } + #[tracing::instrument(level = "trace", skip(self))] pub fn is_empty(&self) -> bool { self.net_devices.len() == 0 } } + #[tracing::instrument(level = "trace", skip(id, name, mac))] fn create_netif(id: &str, name: &str, mac: &str) -> NetworkInterfaceConfig { NetworkInterfaceConfig { iface_id: String::from(id), @@ -209,6 +220,7 @@ mod tests { } impl Clone for NetworkInterfaceConfig { + #[tracing::instrument(level = "trace", skip(self))] fn clone(&self) -> Self { NetworkInterfaceConfig { iface_id: self.iface_id.clone(), diff --git a/src/vmm/src/vmm_config/vsock.rs b/src/vmm/src/vmm_config/vsock.rs index 0e30b5322e1..8c5f87c406c 100644 --- a/src/vmm/src/vmm_config/vsock.rs +++ b/src/vmm/src/vmm_config/vsock.rs @@ -43,6 +43,7 @@ struct VsockAndUnixPath { } impl From<&VsockAndUnixPath> for VsockDeviceConfig { + #[tracing::instrument(level = "trace", skip(vsock))] fn from(vsock: &VsockAndUnixPath) -> Self { let vsock_lock = vsock.vsock.lock().unwrap(); VsockDeviceConfig { @@ -60,11 +61,13 @@ pub struct VsockBuilder { } impl VsockBuilder { + #[tracing::instrument(level = "trace", skip())] /// Creates an empty Vsock with Unix backend Store. pub fn new() -> Self { Self { inner: None } } + #[tracing::instrument(level = "trace", skip(self, device))] /// Inserts an existing vsock device. pub fn set_device(&mut self, device: Arc>>) { self.inner = Some(VsockAndUnixPath { @@ -78,6 +81,7 @@ impl VsockBuilder { }); } + #[tracing::instrument(level = "trace", skip(self, cfg))] /// Inserts a Unix backend Vsock in the store. /// If an entry already exists, it will overwrite it. pub fn insert(&mut self, cfg: VsockDeviceConfig) -> Result<(), VsockConfigError> { @@ -92,11 +96,13 @@ impl VsockBuilder { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Provides a reference to the Vsock if present. pub fn get(&self) -> Option<&MutexVsockUnix> { self.inner.as_ref().map(|pair| &pair.vsock) } + #[tracing::instrument(level = "trace", skip(cfg))] /// Creates a Vsock device from a VsockDeviceConfig. pub fn create_unixsock_vsock( cfg: VsockDeviceConfig, @@ -106,6 +112,7 @@ impl VsockBuilder { Vsock::new(u64::from(cfg.guest_cid), backend).map_err(VsockConfigError::CreateVsockDevice) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns the structure used to configure the vsock device. pub fn config(&self) -> Option { self.inner.as_ref().map(VsockDeviceConfig::from) @@ -119,6 +126,7 @@ pub(crate) mod tests { use super::*; use crate::devices::virtio::vsock::VSOCK_DEV_ID; + #[tracing::instrument(level = "trace", skip(tmp_sock_file))] pub(crate) fn default_config(tmp_sock_file: &TempFile) -> VsockDeviceConfig { VsockDeviceConfig { vsock_id: None, diff --git a/src/vmm/src/vstate/system.rs b/src/vmm/src/vstate/system.rs index 351c176a76a..aa5b4f9ce74 100644 --- a/src/vmm/src/vstate/system.rs +++ b/src/vmm/src/vstate/system.rs @@ -42,6 +42,7 @@ pub struct KvmContext { } impl KvmContext { + #[tracing::instrument(level = "trace", skip())] pub fn new() -> Result { use kvm_ioctls::Cap::*; let kvm = Kvm::new()?; @@ -90,10 +91,12 @@ impl KvmContext { } } + #[tracing::instrument(level = "trace", skip(self))] pub fn fd(&self) -> &Kvm { &self.kvm } + #[tracing::instrument(level = "trace", skip(self))] /// Get the maximum number of memory slots reported by this KVM context. pub fn max_memslots(&self) -> usize { self.max_memslots diff --git a/src/vmm/src/vstate/vcpu/aarch64.rs b/src/vmm/src/vstate/vcpu/aarch64.rs index c4c3257e2c2..7df68d7a98b 100644 --- a/src/vmm/src/vstate/vcpu/aarch64.rs +++ b/src/vmm/src/vstate/vcpu/aarch64.rs @@ -56,6 +56,7 @@ pub struct KvmVcpu { } impl KvmVcpu { + #[tracing::instrument(level = "trace", skip(index, vm))] /// Constructs a new kvm vcpu with arch specific functionality. /// /// # Arguments @@ -76,11 +77,13 @@ impl KvmVcpu { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Gets the MPIDR register value. pub fn get_mpidr(&self) -> u64 { self.mpidr } + #[tracing::instrument(level = "trace", skip(self, guest_mem, kernel_load_addr, vcpu_config))] /// Configures an aarch64 specific vcpu for booting Linux. /// /// # Arguments @@ -113,6 +116,7 @@ impl KvmVcpu { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, vm_fd))] /// Initializes an aarch64 specific vcpu for booting Linux. /// /// # Arguments @@ -134,6 +138,7 @@ impl KvmVcpu { self.fd.vcpu_init(&kvi).map_err(KvmVcpuError::Init) } + #[tracing::instrument(level = "trace", skip(self))] /// Save the KVM internal state. pub fn save_state(&self) -> Result { let mut state = VcpuState { @@ -145,6 +150,7 @@ impl KvmVcpu { Ok(state) } + #[tracing::instrument(level = "trace", skip(self, state))] /// Use provided state to populate KVM internal state. pub fn restore_state(&self, state: &VcpuState) -> Result<(), KvmVcpuError> { set_registers(&self.fd, &state.regs).map_err(KvmVcpuError::RestoreState)?; @@ -152,6 +158,7 @@ impl KvmVcpu { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Dumps CPU configuration. pub fn dump_cpu_config(&self) -> Result { let mut reg_list = get_all_registers_ids(&self.fd).map_err(KvmVcpuError::DumpCpuConfig)?; @@ -168,6 +175,7 @@ impl KvmVcpu { Ok(CpuConfiguration { regs }) } + #[tracing::instrument(level = "trace", skip(self, exit))] /// Runs the vCPU in KVM context and handles the kvm exit reason. /// /// Returns error or enum specifying whether emulation was handled or interrupted. @@ -195,10 +203,12 @@ pub struct VcpuState { } impl VcpuState { + #[tracing::instrument(level = "trace", skip())] fn default_old_regs(_: u16) -> Vec { Vec::default() } + #[tracing::instrument(level = "trace", skip(self, _source_version))] fn de_regs(&mut self, _source_version: u16) -> VersionizeResult<()> { let mut regs = Aarch64RegisterVec::default(); for reg in self.old_regs.iter() { @@ -211,6 +221,7 @@ impl VcpuState { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, _target_version))] fn ser_regs(&mut self, _target_version: u16) -> VersionizeResult<()> { self.old_regs = self .regs @@ -237,6 +248,7 @@ mod tests { use crate::vstate::vm::tests::setup_vm; use crate::vstate::vm::Vm; + #[tracing::instrument(level = "trace", skip(mem_size))] fn setup_vcpu(mem_size: usize) -> (Vm, KvmVcpu, GuestMemoryMmap) { let (mut vm, vm_mem) = setup_vm(mem_size); let vcpu = KvmVcpu::new(0, &vm).unwrap(); @@ -246,6 +258,7 @@ mod tests { (vm, vcpu, vm_mem) } + #[tracing::instrument(level = "trace", skip(vcpu, vm))] fn init_vcpu(vcpu: &VcpuFd, vm: &VmFd) { let mut kvi = kvm_bindings::kvm_vcpu_init::default(); vm.get_preferred_target(&mut kvi).unwrap(); diff --git a/src/vmm/src/vstate/vcpu/mod.rs b/src/vmm/src/vstate/vcpu/mod.rs index e0b3ae94c81..5b83b5bd4b7 100644 --- a/src/vmm/src/vstate/vcpu/mod.rs +++ b/src/vmm/src/vstate/vcpu/mod.rs @@ -16,8 +16,7 @@ use std::{fmt, io, thread}; use kvm_bindings::{KVM_SYSTEM_EVENT_RESET, KVM_SYSTEM_EVENT_SHUTDOWN}; use kvm_ioctls::VcpuExit; use libc::{c_int, c_void, siginfo_t}; -use log::{error, info}; -use logger::{IncMetric, METRICS}; +use logger::{error, info, IncMetric, METRICS}; use seccompiler::{BpfProgram, BpfProgramRef}; use utils::errno; use utils::eventfd::EventFd; @@ -114,6 +113,7 @@ pub struct Vcpu { impl Vcpu { thread_local!(static TLS_VCPU_PTR: VcpuCell = Cell::new(None)); + #[tracing::instrument(level = "trace", skip(self))] /// Associates `self` with the current thread. /// /// It is a prerequisite to successfully run `init_thread_local_data()` before using @@ -129,6 +129,7 @@ impl Vcpu { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Deassociates `self` from the current thread. /// /// Should be called if the current `self` had called `init_thread_local_data()` and @@ -149,6 +150,7 @@ impl Vcpu { }) } + #[tracing::instrument(level = "trace", skip(func))] /// Runs `func` for the `Vcpu` associated with the current thread. /// /// It requires that `init_thread_local_data()` was run on this thread. @@ -176,9 +178,11 @@ impl Vcpu { }) } + #[tracing::instrument(level = "trace", skip())] /// Registers a signal handler which makes use of TLS and kvm immediate exit to /// kick the vcpu running on the current thread, if there is one. pub fn register_kick_signal_handler() { + #[tracing::instrument(level = "trace", skip())] extern "C" fn handle_signal(_: c_int, _: *mut siginfo_t, _: *mut c_void) { // SAFETY: This is safe because it's temporarily aliasing the `Vcpu` object, but we are // only reading `vcpu.fd` which does not change for the lifetime of the `Vcpu`. @@ -194,6 +198,7 @@ impl Vcpu { .expect("Failed to register vcpu signal handler"); } + #[tracing::instrument(level = "trace", skip(index, vm, exit_evt))] /// Constructs a new VCPU for `vm`. /// /// # Arguments @@ -218,11 +223,13 @@ impl Vcpu { }) } + #[tracing::instrument(level = "trace", skip(self, mmio_bus))] /// Sets a MMIO bus for this vcpu. pub fn set_mmio_bus(&mut self, mmio_bus: crate::devices::Bus) { self.kvm_vcpu.mmio_bus = Some(mmio_bus); } + #[tracing::instrument(level = "trace", skip(self, seccomp_filter, barrier))] /// Moves the vcpu to its own thread and constructs a VcpuHandle. /// The handle can be used to control the remote vcpu. pub fn start_threaded( @@ -250,6 +257,7 @@ impl Vcpu { )) } + #[tracing::instrument(level = "trace", skip(self, seccomp_filter))] /// Main loop of the vCPU thread. /// /// Runs the vCPU in KVM context in a loop. Handles KVM_EXITs then goes back in. @@ -271,6 +279,7 @@ impl Vcpu { } // This is the main loop of the `Running` state. + #[tracing::instrument(level = "trace", skip(self))] fn running(&mut self) -> StateMachine { // This loop is here just for optimizing the emulation path. // No point in ticking the state machine if there are no external events. @@ -343,6 +352,7 @@ impl Vcpu { } // This is the main loop of the `Paused` state. + #[tracing::instrument(level = "trace", skip(self))] fn paused(&mut self) -> StateMachine { match self.event_receiver.recv() { // Paused ---- Resume ----> Running @@ -419,6 +429,7 @@ impl Vcpu { } // Transition to the exited state and finish on command. + #[tracing::instrument(level = "trace", skip(self, exit_code))] fn exit(&mut self, exit_code: FcExitCode) -> StateMachine { // To avoid cycles, all teardown paths take the following route: // +------------------------+----------------------------+------------------------+ @@ -455,6 +466,7 @@ impl Vcpu { StateMachine::finish() } + #[tracing::instrument(level = "trace", skip(self))] #[cfg(not(test))] /// Calls `KVM_RUN` with this [`Vcpu`]'s underlying file descriptor. /// @@ -464,6 +476,7 @@ impl Vcpu { self.kvm_vcpu.fd.run() } + #[tracing::instrument(level = "trace", skip(self))] /// Runs the vCPU in KVM context and handles the kvm exit reason. /// /// Returns error or enum specifying whether emulation was handled or interrupted. @@ -572,6 +585,7 @@ impl Vcpu { } impl Drop for Vcpu { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { let _ = self.reset_thread_local_data(); } @@ -615,6 +629,7 @@ pub enum VcpuResponse { } impl fmt::Debug for VcpuResponse { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::VcpuResponse::*; match self { @@ -646,6 +661,7 @@ pub struct VcpuHandle { pub struct VcpuSendEventError(pub utils::errno::Error); impl VcpuHandle { + #[tracing::instrument(level = "trace", skip(event_sender, response_receiver, vcpu_thread))] /// Creates a new [`VcpuHandle`]. /// /// # Arguments @@ -663,6 +679,7 @@ impl VcpuHandle { vcpu_thread: Some(vcpu_thread), } } + #[tracing::instrument(level = "trace", skip(self, event))] /// Sends event to vCPU. /// /// # Errors @@ -682,6 +699,7 @@ impl VcpuHandle { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a reference to the [`Received`] from which the vcpu's responses can be read. pub fn response_receiver(&self) -> &Receiver { &self.response_receiver @@ -690,6 +708,7 @@ impl VcpuHandle { // Wait for the Vcpu thread to finish execution impl Drop for VcpuHandle { + #[tracing::instrument(level = "trace", skip(self))] fn drop(&mut self) { // We assume that by the time a VcpuHandle is dropped, other code has run to // get the state machine loop to finish so the thread is ready to join. @@ -731,6 +750,7 @@ pub mod tests { use crate::RECV_TIMEOUT_SEC; impl Vcpu { + #[tracing::instrument(level = "trace", skip(self))] pub fn emulate(&self) -> Result { self.test_vcpu_exit_reason .lock() @@ -865,6 +885,7 @@ pub mod tests { } impl PartialEq for VcpuResponse { + #[tracing::instrument(level = "trace", skip(self, other))] fn eq(&self, other: &Self) -> bool { use crate::VcpuResponse::*; // Guard match with no wildcard to make sure we catch new enum variants. @@ -888,6 +909,7 @@ pub mod tests { } // Auxiliary function being used throughout the tests. + #[tracing::instrument(level = "trace", skip(mem_size))] #[allow(unused_mut)] pub(crate) fn setup_vcpu(mem_size: usize) -> (Vm, Vcpu, GuestMemoryMmap) { let (mut vm, gm) = setup_vm(mem_size); @@ -908,6 +930,7 @@ pub mod tests { (vm, vcpu, gm) } + #[tracing::instrument(level = "trace", skip(vm_memory))] fn load_good_kernel(vm_memory: &GuestMemoryMmap) -> GuestAddress { use std::fs::File; use std::path::PathBuf; @@ -936,6 +959,7 @@ pub mod tests { entry_addr.unwrap().kernel_load } + #[tracing::instrument(level = "trace", skip())] fn vcpu_configured_for_boot() -> (VcpuHandle, utils::eventfd::EventFd) { Vcpu::register_kick_signal_handler(); // Need enough mem to boot linux. @@ -1081,6 +1105,7 @@ pub mod tests { } // Sends an event to a vcpu and expects a particular response. + #[tracing::instrument(level = "trace", skip(handle, event, response))] fn queue_event_expect_response(handle: &VcpuHandle, event: VcpuEvent, response: VcpuResponse) { handle .send_event(event) diff --git a/src/vmm/src/vstate/vcpu/x86_64.rs b/src/vmm/src/vstate/vcpu/x86_64.rs index cb9e3ba351c..8596630e178 100644 --- a/src/vmm/src/vstate/vcpu/x86_64.rs +++ b/src/vmm/src/vstate/vcpu/x86_64.rs @@ -12,8 +12,7 @@ use kvm_bindings::{ kvm_xsave, CpuId, Msrs, KVM_MAX_CPUID_ENTRIES, KVM_MAX_MSR_ENTRIES, }; use kvm_ioctls::{VcpuExit, VcpuFd}; -use log::{error, warn}; -use logger::{IncMetric, METRICS}; +use logger::{error, warn, IncMetric, METRICS}; use utils::vm_memory::{Address, GuestAddress, GuestMemoryMmap}; use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult}; use versionize_derive::Versionize; @@ -180,6 +179,7 @@ pub struct KvmVcpu { } impl KvmVcpu { + #[tracing::instrument(level = "trace", skip(index, vm))] /// Constructs a new kvm vcpu with arch specific functionality. /// /// # Arguments @@ -201,6 +201,7 @@ impl KvmVcpu { }) } + #[tracing::instrument(level = "trace", skip(self, guest_mem, kernel_start_addr, vcpu_config))] /// Configures a x86_64 specific vcpu for booting Linux and should be called once per vcpu. /// /// # Arguments @@ -280,11 +281,13 @@ impl KvmVcpu { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, pio_bus))] /// Sets a Port Mapped IO bus for this vcpu. pub fn set_pio_bus(&mut self, pio_bus: crate::devices::Bus) { self.pio_bus = Some(pio_bus); } + #[tracing::instrument(level = "trace", skip(self))] /// Get the current TSC frequency for this vCPU. /// /// # Errors @@ -295,6 +298,7 @@ impl KvmVcpu { Ok(res) } + #[tracing::instrument(level = "trace", skip(self))] /// Get CPUID for this vCPU. /// /// Opposed to KVM_GET_SUPPORTED_CPUID, KVM_GET_CPUID2 does not update "nent" with valid number @@ -319,6 +323,7 @@ impl KvmVcpu { Ok(cpuid) } + #[tracing::instrument(level = "trace", skip(self, msr_index_list))] /// Get MSR chunks for the given MSR index list. /// /// KVM only supports getting `KVM_MAX_MSR_ENTRIES` at a time, so we divide @@ -361,6 +366,7 @@ impl KvmVcpu { Ok(msr_chunks) } + #[tracing::instrument(level = "trace", skip(self, msr_index_list))] /// Get MSRs for the given MSR index list. /// /// # Arguments @@ -382,6 +388,7 @@ impl KvmVcpu { Ok(msrs) } + #[tracing::instrument(level = "trace", skip(self))] /// Save the KVM internal state. pub fn save_state(&self) -> Result { // Ordering requirements: @@ -446,6 +453,7 @@ impl KvmVcpu { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Dumps CPU configuration (CPUID and MSRs). /// /// Opposed to `save_state()`, this dumps all the supported and dumpable MSRs not limited to @@ -458,6 +466,7 @@ impl KvmVcpu { Ok(CpuConfiguration { cpuid, msrs }) } + #[tracing::instrument(level = "trace", skip(self, state_tsc_freq))] /// Checks whether the TSC needs scaling when restoring a snapshot. /// /// # Errors @@ -475,10 +484,12 @@ impl KvmVcpu { } // Scale the TSC frequency of this vCPU to the one provided as a parameter. + #[tracing::instrument(level = "trace", skip(self, tsc_freq))] pub fn set_tsc_khz(&self, tsc_freq: u32) -> Result<(), SetTscError> { self.fd.set_tsc_khz(tsc_freq).map_err(SetTscError) } + #[tracing::instrument(level = "trace", skip(self, state))] /// Use provided state to populate KVM internal state. pub fn restore_state(&self, state: &VcpuState) -> Result<(), KvmVcpuError> { // Ordering requirements: @@ -538,6 +549,7 @@ impl KvmVcpu { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, exit))] /// Runs the vCPU in KVM context and handles the kvm exit reason. /// /// Returns error or enum specifying whether emulation was handled or interrupted. @@ -593,11 +605,13 @@ pub struct VcpuState { } impl VcpuState { + #[tracing::instrument(level = "trace", skip())] fn default_tsc_khz(_: u16) -> Option { warn!("CPU TSC freq not found in snapshot"); None } + #[tracing::instrument(level = "trace", skip(self, _target_version))] fn ser_tsc(&mut self, _target_version: u16) -> VersionizeResult<()> { // v0.24 and older versions do not support TSC scaling. warn!( @@ -610,12 +624,14 @@ impl VcpuState { Ok(()) } + #[tracing::instrument(level = "trace", skip(_source_version))] fn default_msrs(_source_version: u16) -> Msrs { // Safe to unwrap since Msrs::new() only returns an error if the number // of elements exceeds KVM_MAX_MSR_ENTRIES Msrs::new(0).unwrap() } + #[tracing::instrument(level = "trace", skip(self, source_version))] fn de_saved_msrs(&mut self, source_version: u16) -> VersionizeResult<()> { if source_version < 3 { self.saved_msrs.push(self.msrs.clone()); @@ -623,6 +639,7 @@ impl VcpuState { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, target_version))] fn ser_saved_msrs(&mut self, target_version: u16) -> VersionizeResult<()> { match self.saved_msrs.len() { 0 => Err(VersionizeError::Serialize( @@ -667,6 +684,7 @@ mod tests { use crate::vstate::vm::Vm; impl Default for VcpuState { + #[tracing::instrument(level = "trace", skip())] fn default() -> Self { VcpuState { cpuid: CpuId::new(1).unwrap(), @@ -685,6 +703,7 @@ mod tests { } } + #[tracing::instrument(level = "trace", skip(mem_size))] fn setup_vcpu(mem_size: usize) -> (Vm, KvmVcpu, GuestMemoryMmap) { let (vm, vm_mem) = setup_vm(mem_size); vm.setup_irqchip().unwrap(); @@ -692,6 +711,7 @@ mod tests { (vm, vcpu, vm_mem) } + #[tracing::instrument(level = "trace", skip())] fn is_at_least_cascade_lake() -> bool { CpuModel::get_cpu_model() >= (CpuModel { @@ -703,6 +723,7 @@ mod tests { }) } + #[tracing::instrument(level = "trace", skip(vm, vcpu, template))] fn create_vcpu_config( vm: &Vm, vcpu: &KvmVcpu, diff --git a/src/vmm/src/vstate/vm.rs b/src/vmm/src/vstate/vm.rs index c0bb5e23ed2..cf612b22b2f 100644 --- a/src/vmm/src/vstate/vm.rs +++ b/src/vmm/src/vstate/vm.rs @@ -126,6 +126,10 @@ pub struct Vm { /// Contains Vm functions that are usable across CPU architectures impl Vm { + #[tracing::instrument( + level = "trace", + skip(self, guest_mem, kvm_max_memslots, track_dirty_pages) + )] /// Initializes the guest memory. pub fn memory_init( &mut self, @@ -145,6 +149,7 @@ impl Vm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self, guest_mem, track_dirty_pages))] pub(crate) fn set_kvm_memory_regions( &self, guest_mem: &GuestMemoryMmap, @@ -174,6 +179,7 @@ impl Vm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Gets a reference to the kvm file descriptor owned by this VM. pub fn fd(&self) -> &VmFd { &self.fd @@ -182,6 +188,7 @@ impl Vm { #[cfg(target_arch = "aarch64")] impl Vm { + #[tracing::instrument(level = "trace", skip(kvm))] /// Constructs a new `Vm` using the given `Kvm` instance. pub fn new(kvm: &Kvm) -> Result { // Create fd for interacting with kvm-vm specific functions. @@ -193,6 +200,7 @@ impl Vm { }) } + #[tracing::instrument(level = "trace", skip(self, vcpu_count))] /// Creates the GIC (Global Interrupt Controller). pub fn setup_irqchip(&mut self, vcpu_count: u8) -> Result<(), VmError> { self.irqchip_handle = Some( @@ -202,11 +210,13 @@ impl Vm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Gets a reference to the irqchip of the VM. pub fn get_irqchip(&self) -> &GICDevice { self.irqchip_handle.as_ref().expect("IRQ chip not set") } + #[tracing::instrument(level = "trace", skip(self, mpidrs))] /// Saves and returns the Kvm Vm state. pub fn save_state(&self, mpidrs: &[u64]) -> Result { Ok(VmState { @@ -217,6 +227,7 @@ impl Vm { }) } + #[tracing::instrument(level = "trace", skip(self, mpidrs, state))] /// Restore the KVM VM state /// /// # Errors @@ -231,6 +242,7 @@ impl Vm { #[cfg(target_arch = "x86_64")] impl Vm { + #[tracing::instrument(level = "trace", skip(kvm))] /// Constructs a new `Vm` using the given `Kvm` instance. pub fn new(kvm: &Kvm) -> Result { // Create fd for interacting with kvm-vm specific functions. @@ -248,16 +260,19 @@ impl Vm { }) } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a ref to the supported `CpuId` for this Vm. pub fn supported_cpuid(&self) -> &CpuId { &self.supported_cpuid } + #[tracing::instrument(level = "trace", skip(self))] /// Returns a ref to the list of serializable MSR indices. pub fn msrs_to_save(&self) -> &MsrList { &self.msrs_to_save } + #[tracing::instrument(level = "trace", skip(self, state))] /// Restores the KVM VM state. /// /// # Errors @@ -287,6 +302,7 @@ impl Vm { Ok(()) } + #[tracing::instrument(level = "trace", skip(self))] /// Creates the irq chip and an in-kernel device model for the PIT. pub fn setup_irqchip(&self) -> Result<(), VmError> { self.fd.create_irq_chip().map_err(VmError::VmSetup)?; @@ -299,6 +315,7 @@ impl Vm { self.fd.create_pit2(pit_config).map_err(VmError::VmSetup) } + #[tracing::instrument(level = "trace", skip(self))] /// Saves and returns the Kvm Vm state. pub fn save_state(&self) -> Result { let pitstate = self.fd.get_pit2().map_err(VmError::VmGetPit2)?; @@ -357,6 +374,7 @@ pub struct VmState { #[cfg(target_arch = "x86_64")] impl fmt::Debug for VmState { + #[tracing::instrument(level = "trace", skip(self, f))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("VmState") .field("pitstate", &self.pitstate) @@ -386,6 +404,7 @@ pub(crate) mod tests { use crate::vstate::system::KvmContext; // Auxiliary function being used throughout the tests. + #[tracing::instrument(level = "trace", skip(mem_size))] pub(crate) fn setup_vm(mem_size: usize) -> (Vm, GuestMemoryMmap) { let kvm = KvmContext::new().unwrap(); let gm = utils::vm_memory::test_utils::create_anon_guest_memory( diff --git a/src/vmm/tests/devices.rs b/src/vmm/tests/devices.rs index 3160a7cd3b9..ebe4749624f 100644 --- a/src/vmm/tests/devices.rs +++ b/src/vmm/tests/devices.rs @@ -13,6 +13,7 @@ use vm_superio::Serial; use vmm::devices::legacy::serial::SerialOut; use vmm::devices::legacy::{EventFdTrigger, SerialEventsWrapper, SerialWrapper}; +#[tracing::instrument(level = "trace", skip(pipe))] fn create_serial( pipe: c_int, ) -> Arc>>> { @@ -36,6 +37,7 @@ fn create_serial( pub struct MockSerialInput(pub RawFd); impl std::io::Read for MockSerialInput { + #[tracing::instrument(level = "trace", skip(self, buf))] fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let count = unsafe { libc::read(self.0, buf.as_mut_ptr().cast(), buf.len()) }; @@ -44,6 +46,7 @@ impl std::io::Read for MockSerialInput { } impl AsRawFd for MockSerialInput { + #[tracing::instrument(level = "trace", skip(self))] fn as_raw_fd(&self) -> RawFd { self.0 } diff --git a/src/vmm/tests/integration_tests.rs b/src/vmm/tests/integration_tests.rs index 349240a1ee5..78a8bcffd4f 100644 --- a/src/vmm/tests/integration_tests.rs +++ b/src/vmm/tests/integration_tests.rs @@ -168,6 +168,7 @@ fn test_disallow_dump_cpu_config_without_pausing() { vmm.lock().unwrap().stop(FcExitCode::Ok); } +#[tracing::instrument(level = "trace", skip(is_diff))] fn verify_create_snapshot(is_diff: bool) -> (TempFile, TempFile) { let snapshot_file = TempFile::new().unwrap(); let memory_file = TempFile::new().unwrap(); @@ -232,6 +233,7 @@ fn verify_create_snapshot(is_diff: bool) -> (TempFile, TempFile) { (snapshot_file, memory_file) } +#[tracing::instrument(level = "trace", skip(snapshot_file, memory_file))] fn verify_load_snapshot(snapshot_file: TempFile, memory_file: TempFile) { use utils::vm_memory::GuestMemoryMmap; use vmm::memory_snapshot::SnapshotMemory; @@ -339,6 +341,7 @@ fn test_snapshot_load_sanity_checks() { ); } +#[tracing::instrument(level = "trace", skip())] fn get_microvm_state_from_snapshot() -> MicrovmState { // Create a diff snapshot let (snapshot_file, _) = verify_create_snapshot(true); diff --git a/src/vmm/tests/io_uring.rs b/src/vmm/tests/io_uring.rs index 373402b4aa5..6dde838ff87 100644 --- a/src/vmm/tests/io_uring.rs +++ b/src/vmm/tests/io_uring.rs @@ -20,12 +20,14 @@ mod test_utils { use vmm::io_uring::operation::{OpCode, Operation}; use vmm::io_uring::{IoUring, IoUringError, SQueueError}; + #[tracing::instrument(level = "trace", skip(ring))] fn drain_cqueue(ring: &mut IoUring) { while let Some(entry) = unsafe { ring.pop::().unwrap() } { assert!(entry.result().is_ok()); } } + #[tracing::instrument(level = "trace", skip(ring, mem_region, opcode, num_bytes))] pub fn drive_submission_and_completion( ring: &mut IoUring, mem_region: &MmapRegion, diff --git a/tests/framework/microvm.py b/tests/framework/microvm.py index 04b7aff145d..fcfe6780a08 100644 --- a/tests/framework/microvm.py +++ b/tests/framework/microvm.py @@ -628,8 +628,6 @@ def spawn( # and leave 0.2 delay between them. if "no-api" not in self.jailer.extra_args: self._wait_create() - if create_logger: - self.check_log_message("Running Firecracker") @retry(delay=0.2, tries=5) def _wait_create(self): diff --git a/tests/integration_tests/build/test_clippy.py b/tests/integration_tests/build/test_clippy.py index dc4ae415c65..973a2a44c10 100644 --- a/tests/integration_tests/build/test_clippy.py +++ b/tests/integration_tests/build/test_clippy.py @@ -7,6 +7,7 @@ import pytest +from framework import utils from host_tools.cargo_build import cargo SUCCESS_CODE = 0 @@ -23,3 +24,13 @@ def test_rust_clippy(target): Test that clippy does not generate any errors/warnings. """ cargo("clippy", f"--target {target} --all --profile test", "-D warnings") + +def test_clippy_tracing(): + """ + Tests clippy-tracing + """ + + # TODO Temporary for testing before creating a new docker container. + utils.run_cmd("cargo install clippy-tracing") + + utils.run_cmd("clippy-tracing --action check --path ../src --exclude vmm_config/logger.rs,virtio_gen,bindings.rs,net_gen,benches") diff --git a/tests/integration_tests/functional/test_logging.py b/tests/integration_tests/functional/test_logging.py index 520c44361f0..c26f947686a 100644 --- a/tests/integration_tests/functional/test_logging.py +++ b/tests/integration_tests/functional/test_logging.py @@ -5,69 +5,85 @@ It checks the response of the API configuration calls and the logs that show up in the configured logging FIFO. """ + +import datetime import os -import re -from time import strptime import host_tools.logging as log_tools -# Array of supported log levels of the current logging system. -# Do not change order of values inside this array as logic depends on this. -LOG_LEVELS = ["ERROR", "WARN", "INFO", "DEBUG"] - -def to_formal_log_level(log_level): - """Convert a pretty-print log level into the related log level code. +def level_int(level): + """Converts a log level string to an integer representation""" - Turns a pretty formatted log level (i.e Warning) into the one actually - being logged (i.e WARN). - :param log_level: pretty formatted log level - :return: actual level being logged - """ - if log_level == "Error": - return LOG_LEVELS[0] - if log_level == "Warning": - return LOG_LEVELS[1] - if log_level == "Info": - return LOG_LEVELS[2] - if log_level == "Debug": - return LOG_LEVELS[3] - return "" + if level == "ERROR": + return 0 + if level == "WARN": + return 1 + if level == "INFO": + return 2 + if level == "DEBUG": + return 3 + if level == "TRACE": + return 4 + raise Exception("Invalid level") -def check_log_message_format(log_str, instance_id, level, show_level, show_origin): +# pylint: disable=anomalous-backslash-in-string +def check_log_message_format(log_str, log_level, show_level, show_origin): """Ensure correctness of the logged message. Parse the string representing the logs and look for the parts that should be there. - The log line should look lie this: - YYYY-MM-DDTHH:MM:SS.NNNNNNNNN [ID:THREAD:LEVEL:FILE:LINE] MESSAGE - where LEVEL and FILE:LINE are both optional. - e.g. with THREAD NAME as TN - `2018-09-09T12:52:00.123456789 [MYID:TN:WARN:/path/to/file.rs:52] warning` - """ - timestamp, tag_and_msg = log_str.split(" ", maxsplit=1) - timestamp = timestamp[:-10] - strptime(timestamp, "%Y-%m-%dT%H:%M:%S") - - pattern = "\\[(" + instance_id + ")" - pattern += ":(.*)" + The log line should look like: + > {year}-{month}-{day}T{hour}:{minute}:{second}.{microsecond}Z {level} {thread name} + > {process name}: {file}:{line number} {message} + where `level`, `file` and `line number` are optional e.g. + > 2023-07-19T12:10:54.608814Z INFO main test_bin_3: src\main.rs:18: yak shaving completed. + """ + split = iter(log_str.split()) + now = datetime.datetime.now() + + timestamp = next(split) + date, time = timestamp.split("T") + year, month, day = date.split("-") + assert len(month) == 2 + assert len(day) == 2 + + assert time[-1] == "Z" + hour, minute, secs = time[:-1].split(":") + second, microsecond = secs.split(".") + assert len(hour) == 2 + assert len(minute) == 2 + assert len(second) == 2 + assert len(microsecond) == 6 + + # Assert the time in the logs is less than or equal to the current time + log_time = datetime.datetime( + year=int(year), + month=int(month), + day=int(day), + hour=int(hour), + minute=int(minute), + second=int(second), + microsecond=int(microsecond), + ) + assert log_time <= now + if show_level: - pattern += ":(" + "|".join(LOG_LEVELS) + ")" - if show_origin: - pattern += ":([^:]+/[^:]+):([0-9]+)" - pattern += "\\].*" + level = next(split) + assert level in ("ERROR", "WARN", "INFO", "DEBUG", "TRACE") + assert level_int(level) <= level_int(log_level.upper()) - mo = re.match(pattern, tag_and_msg) - assert ( - mo is not None - ), f"Log message ({tag_and_msg}) does not match pattern ({pattern})." + # Thread names are not optional. + _thread_name = next(split) + # Process names are not optional. + _process_name = next(split) - if show_level: - tag_level = mo.group(3) - tag_level_no = LOG_LEVELS.index(tag_level) - configured_level_no = LOG_LEVELS.index(to_formal_log_level(level)) - assert tag_level_no <= configured_level_no + if show_origin: + origin = next(split) + assert origin[-1] == ":" + _path, line = origin[:-1].split(":") + assert line.isnumeric() def test_no_origin_logs(test_microvm_with_api): @@ -102,7 +118,7 @@ def test_warn_logs(test_microvm_with_api): """ Check output of logs when minimum level to be displayed is warning. """ - _test_log_config(microvm=test_microvm_with_api, log_level="Warning") + _test_log_config(microvm=test_microvm_with_api, log_level="Warn") def test_error_logs(test_microvm_with_api): @@ -232,8 +248,5 @@ def _test_log_config(microvm, log_level="Info", show_level=True, show_origin=Tru microvm.start() lines = microvm.log_data.splitlines() - for idx, line in enumerate(lines): - if idx == 0: - assert line.startswith("Running Firecracker") - continue - check_log_message_format(line, microvm.id, log_level, show_level, show_origin) + for line in lines: + check_log_message_format(line, log_level, show_level, show_origin)