Skip to content

Commit f36fc3d

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 0a6c80b commit f36fc3d

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.10.0"
3737
log = "0.4.28"
38+
opentelemetry = { version = "0.31.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.32.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"
@@ -98,7 +100,7 @@ tracing = "0.1.41"
98100
tracing-subscriber = {version = "0.3.20", features = ["std", "env-filter"]}
99101
tracing-opentelemetry = "0.32.0"
100102
opentelemetry = "0.31.0"
101-
opentelemetry-otlp = { version = "0.31.0", default-features = false, features = ["http-proto", "reqwest-blocking-client"] }
103+
opentelemetry-otlp = { version = "0.31.0", default-features = false, features = ["http-proto", "reqwest-blocking-client", "grpc-tonic"] }
102104
opentelemetry-semantic-conventions = "0.31"
103105
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] }
104106
tokio = { version = "1.48.0", features = ["full"] }
@@ -132,7 +134,7 @@ executable_heap = []
132134
print_debug = []
133135
# Dumps the VM state to a file on unexpected errors or crashes. The path of the file will be printed on stdout and logged.
134136
crashdump = ["dep:chrono"]
135-
trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest-tracing/trace"]
137+
trace_guest = ["dep:opentelemetry", "dep:tracing-opentelemetry", "dep:hyperlight-guest-tracing", "hyperlight-common/trace_guest"]
136138
mem_profile = [ "trace_guest", "dep:framehop", "dep:fallible-iterator", "hyperlight-common/mem_profile" ]
137139
kvm = ["dep:kvm-bindings", "dep:kvm-ioctls"]
138140
# 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

@@ -296,7 +298,6 @@ pub(crate) struct HypervLinuxDriver {
296298
gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
297299
#[cfg(crashdump)]
298300
rt_cfg: SandboxRuntimeConfig,
299-
#[allow(dead_code)]
300301
#[cfg(feature = "mem_profile")]
301302
trace_info: MemTraceInfo,
302303
}
@@ -643,7 +644,10 @@ impl Hypervisor for HypervLinuxDriver {
643644
}
644645

645646
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
646-
fn run(&mut self) -> Result<super::HyperlightExit> {
647+
fn run(
648+
&mut self,
649+
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
650+
) -> Result<super::HyperlightExit> {
647651
const HALT_MESSAGE: hv_message_type = hv_message_type_HVMSG_X64_HALT;
648652
const IO_PORT_INTERCEPT_MESSAGE: hv_message_type =
649653
hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT;
@@ -685,6 +689,9 @@ impl Hypervisor for HypervLinuxDriver {
685689
{
686690
Err(mshv_ioctls::MshvError::from(libc::EINTR))
687691
} else {
692+
#[cfg(feature = "trace_guest")]
693+
tc.setup_guest_trace(Span::current().context());
694+
688695
// Note: if a `InterruptHandle::kill()` called while this thread is **here**
689696
// Then the vcpu will run, but we will keep sending signals to this thread
690697
// to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will
@@ -1086,6 +1093,17 @@ impl Hypervisor for HypervLinuxDriver {
10861093
}
10871094
}
10881095

1096+
#[cfg(feature = "trace_guest")]
1097+
fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> {
1098+
let regs = self.regs()?;
1099+
tc.handle_trace(
1100+
&regs,
1101+
self.mem_mgr.as_ref().ok_or_else(|| {
1102+
new_error!("Memory manager is not initialized before handling trace")
1103+
})?,
1104+
)
1105+
}
1106+
10891107
#[cfg(feature = "mem_profile")]
10901108
fn trace_info_mut(&mut self) -> &mut MemTraceInfo {
10911109
&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_RUN_VP_EXIT_CONTEXT, WHV_RUN_VP_EXIT_REASON,
2729
WHvCancelRunVirtualProcessor,
@@ -275,7 +277,6 @@ pub(crate) struct HypervWindowsDriver {
275277
#[cfg(crashdump)]
276278
rt_cfg: SandboxRuntimeConfig,
277279
#[cfg(feature = "mem_profile")]
278-
#[allow(dead_code)]
279280
trace_info: MemTraceInfo,
280281
}
281282
/* This does not automatically impl Send because the host
@@ -544,7 +545,10 @@ impl Hypervisor for HypervWindowsDriver {
544545
}
545546

546547
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
547-
fn run(&mut self) -> Result<super::HyperlightExit> {
548+
fn run(
549+
&mut self,
550+
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
551+
) -> Result<super::HyperlightExit> {
548552
self.interrupt_handle.running.store(true, Ordering::Relaxed);
549553

550554
#[cfg(not(gdb))]
@@ -569,6 +573,9 @@ impl Hypervisor for HypervWindowsDriver {
569573
Reserved: Default::default(),
570574
}
571575
} else {
576+
#[cfg(feature = "trace_guest")]
577+
tc.setup_guest_trace(Span::current().context());
578+
572579
self.processor.run()?
573580
};
574581
self.interrupt_handle
@@ -932,6 +939,17 @@ impl Hypervisor for HypervWindowsDriver {
932939
}
933940
}
934941

942+
#[cfg(feature = "trace_guest")]
943+
fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> {
944+
let regs = self.regs()?;
945+
tc.handle_trace(
946+
&regs,
947+
self.mem_mgr.as_ref().ok_or_else(|| {
948+
new_error!("Memory manager is not initialized before handling trace")
949+
})?,
950+
)
951+
}
952+
935953
#[cfg(feature = "mem_profile")]
936954
fn trace_info_mut(&mut self) -> &mut MemTraceInfo {
937955
&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
@@ -23,6 +23,8 @@ use kvm_ioctls::Cap::UserMemory;
2323
use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd};
2424
use log::LevelFilter;
2525
use tracing::{Span, instrument};
26+
#[cfg(feature = "trace_guest")]
27+
use tracing_opentelemetry::OpenTelemetrySpanExt;
2628
#[cfg(crashdump)]
2729
use {super::crashdump, std::path::Path};
2830

@@ -285,7 +287,6 @@ pub(crate) struct KVMDriver {
285287
#[cfg(crashdump)]
286288
rt_cfg: SandboxRuntimeConfig,
287289
#[cfg(feature = "mem_profile")]
288-
#[allow(dead_code)]
289290
trace_info: MemTraceInfo,
290291
}
291292

@@ -613,7 +614,10 @@ impl Hypervisor for KVMDriver {
613614
}
614615

615616
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
616-
fn run(&mut self) -> Result<HyperlightExit> {
617+
fn run(
618+
&mut self,
619+
#[cfg(feature = "trace_guest")] tc: &mut crate::sandbox::trace::TraceContext,
620+
) -> Result<HyperlightExit> {
617621
self.interrupt_handle
618622
.tid
619623
.store(unsafe { libc::pthread_self() as u64 }, Ordering::Relaxed);
@@ -646,6 +650,9 @@ impl Hypervisor for KVMDriver {
646650
{
647651
Err(kvm_ioctls::Error::new(libc::EINTR))
648652
} else {
653+
#[cfg(feature = "trace_guest")]
654+
tc.setup_guest_trace(Span::current().context());
655+
649656
// Note: if a `InterruptHandle::kill()` called while this thread is **here**
650657
// Then the vcpu will run, but we will keep sending signals to this thread
651658
// to interrupt it until `running` is set to false. The `vcpu_fd::run()` call will
@@ -1021,6 +1028,17 @@ impl Hypervisor for KVMDriver {
10211028
}
10221029
}
10231030

1031+
#[cfg(feature = "trace_guest")]
1032+
fn handle_trace(&mut self, tc: &mut crate::sandbox::trace::TraceContext) -> Result<()> {
1033+
let regs = self.regs()?;
1034+
tc.handle_trace(
1035+
&regs,
1036+
self.mem_mgr.as_ref().ok_or_else(|| {
1037+
new_error!("Memory manager is not initialized before handling trace")
1038+
})?,
1039+
)
1040+
}
1041+
10241042
#[cfg(feature = "mem_profile")]
10251043
fn trace_info_mut(&mut self) -> &mut MemTraceInfo {
10261044
&mut self.trace_info

0 commit comments

Comments
 (0)