Skip to content

Commit 390e2a1

Browse files
committed
[trace-host] handle a TraceBatch from the guest
- Parse the spans and events coming from the guest and create corresponding spans and events from the host that mimics a single call from host - Create a `TraceContext` that handles a call into a guest Signed-off-by: Doru Blânzeanu <[email protected]>
1 parent 2aee07e commit 390e2a1

File tree

9 files changed

+525
-26
lines changed

9 files changed

+525
-26
lines changed

Cargo.lock

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hyperlight_guest_tracing/src/lib.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ mod trace {
170170

171171
/// Sets the guset starting timestamp reported to the host on a VMExit
172172
pub fn set_start_tsc(guest_start_tsc: u64) {
173-
if let Some(w) = GUEST_STATE.get() {
174-
if let Some(state) = w.upgrade() {
175-
state.lock().set_start_tsc(guest_start_tsc);
176-
}
173+
if let Some(w) = GUEST_STATE.get()
174+
&& let Some(state) = w.upgrade()
175+
{
176+
state.lock().set_start_tsc(guest_start_tsc);
177177
}
178178
}
179179

@@ -184,31 +184,31 @@ mod trace {
184184
/// After calling this function, the internal state is marked
185185
/// for cleaning on the next access.
186186
pub fn end_trace() {
187-
if let Some(w) = GUEST_STATE.get() {
188-
if let Some(state) = w.upgrade() {
189-
state.lock().end_trace();
190-
}
187+
if let Some(w) = GUEST_STATE.get()
188+
&& let Some(state) = w.upgrade()
189+
{
190+
state.lock().end_trace();
191191
}
192192
}
193193

194194
/// Cleans the internal trace state by removing closed spans and events.
195195
/// This ensures that after a VM exit, we keep the spans that
196196
/// are still active (in the stack) and remove all other spans and events.
197197
pub fn clean_trace_state() {
198-
if let Some(w) = GUEST_STATE.get() {
199-
if let Some(state) = w.upgrade() {
200-
state.lock().clean();
201-
}
198+
if let Some(w) = GUEST_STATE.get()
199+
&& let Some(state) = w.upgrade()
200+
{
201+
state.lock().clean();
202202
}
203203
}
204204

205205
/// Returns information about the current trace state needed by the host to read the spans.
206206
pub fn guest_trace_info() -> Option<TraceBatchInfo> {
207207
let mut res = None;
208-
if let Some(w) = GUEST_STATE.get() {
209-
if let Some(state) = w.upgrade() {
210-
res = Some(state.lock().guest_trace_info());
211-
}
208+
if let Some(w) = GUEST_STATE.get()
209+
&& let Some(state) = w.upgrade()
210+
{
211+
res = Some(state.lock().guest_trace_info());
212212
}
213213
res
214214
}

src/hyperlight_host/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ page_size = "0.6.0"
3535
termcolor = "1.2.0"
3636
bitflags = "2.9.4"
3737
log = "0.4.28"
38+
opentelemetry = { version = "0.30.0", optional = true }
3839
tracing = { version = "0.1.41", features = ["log"] }
3940
tracing-log = "0.2.0"
4041
tracing-core = "0.1.34"
42+
tracing-opentelemetry = { version = "0.31.0", optional = true }
4143
hyperlight-common = { workspace = true, default-features = true, features = [ "std" ] }
4244
hyperlight-guest-tracing = { workspace = true, default-features = true, optional = true }
4345
vmm-sys-util = "0.15.0"
@@ -97,7 +99,7 @@ tracing = "0.1.41"
9799
tracing-subscriber = {version = "0.3.20", features = ["std", "env-filter"]}
98100
tracing-opentelemetry = "0.31.0"
99101
opentelemetry = "0.30.0"
100-
opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] }
102+
opentelemetry-otlp = { version = "0.30.0", default-features = false, features = ["http-proto", "reqwest-blocking-client", "grpc-tonic"] }
101103
opentelemetry-semantic-conventions = "0.30"
102104
opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] }
103105
tokio = { version = "1.47.1", features = ["full"] }
@@ -131,7 +133,7 @@ executable_heap = []
131133
print_debug = []
132134
# Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged.
133135
crashdump = ["dep:chrono"]
134-
trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest-tracing/trace"]
136+
trace_guest = ["dep:opentelemetry", "dep:tracing-opentelemetry", "dep:hyperlight-guest-tracing", "hyperlight-common/trace_guest"]
135137
mem_profile = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/mem_profile" ]
136138
kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"]
137139
# This feature is deprecated in favor of mshv3

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ use mshv_bindings::{
5050
};
5151
use mshv_ioctls::{Mshv, VcpuFd, VmFd};
5252
use tracing::{Span, instrument};
53+
#[cfg(feature = "trace_guest")]
54+
use tracing_opentelemetry::OpenTelemetrySpanExt;
5355
#[cfg(crashdump)]
5456
use {super::crashdump, std::path::Path};
5557

@@ -319,7 +321,6 @@ pub(crate) struct HypervLinuxDriver {
319321
gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
320322
#[cfg(crashdump)]
321323
rt_cfg: SandboxRuntimeConfig,
322-
#[allow(dead_code)]
323324
#[cfg(feature = "mem_profile")]
324325
trace_info: MemTraceInfo,
325326
}
@@ -732,7 +733,10 @@ impl Hypervisor for HypervLinuxDriver {
732733
}
733734

734735
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
735-
fn run(&mut self) -> Result<super::HyperlightExit> {
736+
fn run(
737+
&mut self,
738+
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
739+
) -> Result<super::HyperlightExit> {
736740
const HALT_MESSAGE: hv_message_type = hv_message_type_HVMSG_X64_HALT;
737741
const IO_PORT_INTERCEPT_MESSAGE: hv_message_type =
738742
hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT;
@@ -774,6 +778,9 @@ impl Hypervisor for HypervLinuxDriver {
774778
{
775779
Err(mshv_ioctls::MshvError::from(libc::EINTR))
776780
} else {
781+
#[cfg(feature = "trace_guest")]
782+
tc.setup_guest_trace(Span::current().context());
783+
777784
// Note: if a `InterruptHandle::kill()` called while this thread is **here**
778785
// Then the vcpu will run, but we will keep sending signals to this thread
779786
// to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will
@@ -1139,6 +1146,17 @@ impl Hypervisor for HypervLinuxDriver {
11391146
Ok(X86_64Regs::from(self.vcpu_fd.get_regs()?))
11401147
}
11411148

1149+
#[cfg(feature = "trace_guest")]
1150+
fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> {
1151+
let regs = self.read_regs()?;
1152+
tc.handle_trace(
1153+
&regs,
1154+
self.mem_mgr.as_ref().ok_or_else(|| {
1155+
new_error!("Memory manager is not initialized before handling trace")
1156+
})?,
1157+
)
1158+
}
1159+
11421160
#[cfg(feature = "mem_profile")]
11431161
fn trace_info_mut(&mut self) -> &mut MemTraceInfo {
11441162
&mut self.trace_info

src/hyperlight_host/src/hypervisor/hyperv_windows.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex};
2222

2323
use log::LevelFilter;
2424
use tracing::{Span, instrument};
25+
#[cfg(feature = "trace_guest")]
26+
use tracing_opentelemetry::OpenTelemetrySpanExt;
2527
use windows::Win32::System::Hypervisor::{
2628
WHV_MEMORY_ACCESS_TYPE, WHV_PARTITION_HANDLE, WHV_REGISTER_VALUE, WHV_RUN_VP_EXIT_CONTEXT,
2729
WHV_RUN_VP_EXIT_REASON, WHV_X64_SEGMENT_REGISTER, WHV_X64_SEGMENT_REGISTER_0,
@@ -292,7 +294,6 @@ pub(crate) struct HypervWindowsDriver {
292294
#[cfg(crashdump)]
293295
rt_cfg: SandboxRuntimeConfig,
294296
#[cfg(feature = "mem_profile")]
295-
#[allow(dead_code)]
296297
trace_info: MemTraceInfo,
297298
}
298299
/* This does not automatically impl Send because the host
@@ -735,7 +736,10 @@ impl Hypervisor for HypervWindowsDriver {
735736
}
736737

737738
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
738-
fn run(&mut self) -> Result<super::HyperlightExit> {
739+
fn run(
740+
&mut self,
741+
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
742+
) -> Result<super::HyperlightExit> {
739743
self.interrupt_handle.running.store(true, Ordering::Relaxed);
740744

741745
#[cfg(not(gdb))]
@@ -760,6 +764,9 @@ impl Hypervisor for HypervWindowsDriver {
760764
Reserved: Default::default(),
761765
}
762766
} else {
767+
#[cfg(feature = "trace_guest")]
768+
tc.setup_guest_trace(Span::current().context());
769+
763770
self.processor.run()?
764771
};
765772
self.interrupt_handle
@@ -1091,6 +1098,17 @@ impl Hypervisor for HypervWindowsDriver {
10911098
Ok(X86_64Regs::from(regs))
10921099
}
10931100

1101+
#[cfg(feature = "trace_guest")]
1102+
fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> {
1103+
let regs = self.read_regs()?;
1104+
tc.handle_trace(
1105+
&regs,
1106+
self.mem_mgr.as_ref().ok_or_else(|| {
1107+
new_error!("Memory manager is not initialized before handling trace")
1108+
})?,
1109+
)
1110+
}
1111+
10941112
#[cfg(feature = "mem_profile")]
10951113
fn trace_info_mut(&mut self) -> &mut MemTraceInfo {
10961114
&mut self.trace_info

src/hyperlight_host/src/hypervisor/kvm.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use kvm_ioctls::Cap::UserMemory;
2424
use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd};
2525
use log::LevelFilter;
2626
use tracing::{Span, instrument};
27+
#[cfg(feature = "trace_guest")]
28+
use tracing_opentelemetry::OpenTelemetrySpanExt;
2729
#[cfg(crashdump)]
2830
use {super::crashdump, std::path::Path};
2931

@@ -305,7 +307,6 @@ pub(crate) struct KVMDriver {
305307
#[cfg(crashdump)]
306308
rt_cfg: SandboxRuntimeConfig,
307309
#[cfg(feature = "mem_profile")]
308-
#[allow(dead_code)]
309310
trace_info: MemTraceInfo,
310311
}
311312

@@ -659,7 +660,10 @@ impl Hypervisor for KVMDriver {
659660
}
660661

661662
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
662-
fn run(&mut self) -> Result<HyperlightExit> {
663+
fn run(
664+
&mut self,
665+
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
666+
) -> Result<HyperlightExit> {
663667
self.interrupt_handle
664668
.tid
665669
.store(unsafe { libc::pthread_self() as u64 }, Ordering::Relaxed);
@@ -692,6 +696,9 @@ impl Hypervisor for KVMDriver {
692696
{
693697
Err(kvm_ioctls::Error::new(libc::EINTR))
694698
} else {
699+
#[cfg(feature = "trace_guest")]
700+
tc.setup_guest_trace(Span::current().context());
701+
695702
// Note: if a `InterruptHandle::kill()` called while this thread is **here**
696703
// Then the vcpu will run, but we will keep sending signals to this thread
697704
// to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will
@@ -1031,6 +1038,17 @@ impl Hypervisor for KVMDriver {
10311038
Ok(X86_64Regs::from(self.vcpu_fd.get_regs()?))
10321039
}
10331040

1041+
#[cfg(feature = "trace_guest")]
1042+
fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> {
1043+
let regs = self.read_regs()?;
1044+
tc.handle_trace(
1045+
&regs,
1046+
self.mem_mgr.as_ref().ok_or_else(|| {
1047+
new_error!("Memory manager is not initialized before handling trace")
1048+
})?,
1049+
)
1050+
}
1051+
10341052
#[cfg(feature = "mem_profile")]
10351053
fn trace_info_mut(&mut self) -> &mut MemTraceInfo {
10361054
&mut self.trace_info

0 commit comments

Comments
 (0)