-
Notifications
You must be signed in to change notification settings - Fork 157
mana: save and restore mana devices when keepalive is enabled #2123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
mana: save and restore mana devices when keepalive is enabled #2123
Conversation
… but might be storage?
…ve unnecessary results
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements MANA keepalive functionality for OpenHCL, allowing MANA device state and DMA memory to be preserved across servicing operations. This builds on the existing keepalive infrastructure by adding MANA-specific save/restore capabilities alongside the previously implemented NVMe keepalive feature.
Key changes:
- Added comprehensive save/restore functionality for MANA devices including driver state and memory preservation
- Extended command-line and flag support for MANA keepalive configuration
- Added test coverage for MANA keepalive functionality
Reviewed Changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| vmm_tests/vmm_tests/tests/tests/x86_64/openhcl_linux_direct.rs | Removed duplicate MANA servicing test to avoid conflicts |
| vmm_tests/vmm_tests/tests/tests/multiarch/openhcl_servicing.rs | Added MANA NIC validation function and new test for keepalive functionality |
| vm/devices/net/net_mana/src/lib.rs | Updated test calls to include new mana_state parameter |
| vm/devices/net/mana_driver/src/save_restore.rs | Added ManaSavedState and ManaDeviceSavedState protobuf structures |
| vm/devices/net/mana_driver/src/mana.rs | Added save method and state restoration logic to ManaDevice |
| vm/devices/net/mana_driver/src/gdma_driver.rs | Removed dead_code attributes from save/restore methods |
| vm/devices/get/guest_emulation_device/src/lib.rs | Added mana_keepalive flag support to GED capabilities |
| vm/devices/get/get_resources/src/lib.rs | Added mana_keepalive field to GuestServicingFlags |
| vm/devices/get/get_protocol/src/lib.rs | Added enable_mana_keepalive bit to SaveGuestVtl2StateFlags |
| petri/src/worker.rs | Added mana_keepalive field mapping for servicing flags |
| petri/src/vm/mod.rs | Added enable_mana_keepalive field to OpenHclServicingFlags |
| openvmm/openvmm_entry/src/lib.rs | Added CLI support for mana-keepalive parameter |
| openhcl/underhill_core/src/worker.rs | Integrated MANA state handling into VM lifecycle management |
| openhcl/underhill_core/src/servicing.rs | Added mana_state field to servicing state structures |
| openhcl/underhill_core/src/options.rs | Added OPENHCL_MANA_KEEP_ALIVE environment variable support |
| openhcl/underhill_core/src/lib.rs | Wired mana_keep_alive option through worker configuration |
| openhcl/underhill_core/src/emuplat/netvsp.rs | Implemented comprehensive MANA device save/restore in VF manager |
| openhcl/underhill_core/src/dispatch/mod.rs | Added network settings save method and MANA state coordination |
Comments suppressed due to low confidence (1)
openhcl/underhill_core/src/emuplat/netvsp.rs:1
- Using expect() can cause panic if the memory with matching PFN is not found. Consider returning a proper error instead of panicking in production code.
// Copyright (c) Microsoft Corporation.
| if let Some(hwc_task) = self.hwc_task { | ||
| hwc_task.cancel().await; | ||
| } | ||
| let inner = Arc::into_inner(self.inner).unwrap(); |
Copilot
AI
Oct 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using unwrap() on Arc::into_inner() can panic if there are multiple references to the Arc. Consider using a safer approach with proper error handling or ensuring single ownership before this call.
| let inner = Arc::into_inner(self.inner).unwrap(); | |
| let inner = match Arc::into_inner(self.inner) { | |
| Some(inner) => inner, | |
| None => { | |
| tracing::error!("Failed to save MANA device state: multiple references to device exist"); | |
| return ( | |
| Err(anyhow::anyhow!("Failed to save MANA device state: multiple references to device exist")), | |
| // We cannot recover the device, so return a default error value. | |
| // This assumes T: Default, otherwise consider another approach. | |
| // For now, use std::mem::zeroed() as a placeholder (unsafe). | |
| unsafe { std::mem::zeroed() }, | |
| ); | |
| } | |
| }; |
Copilot uses AI. Check for mistakes.
|
|
||
| if let Some(device) = self.mana_device.take() { | ||
| let (saved_state, device) = device.save().await; | ||
| std::mem::forget(device); |
Copilot
AI
Oct 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using std::mem::forget() prevents the device destructor from running, which could lead to resource leaks. Consider documenting why this is necessary or finding an alternative approach that properly manages the device lifetime.
| std::mem::forget(device); |
Copilot uses AI. Check for mistakes.
| /// Test an OpenHCL Linux direct VM with a MANA nic assigned to VTL2 (backed by | ||
| /// the MANA emulator), and vmbus relay. Perform servicing and validate that the | ||
| /// nic is still functional. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you given thought to how you will validate that servicing used keepalive, rather than falling back to the non-KA path?
In addition, please consider adding cases for going to/from downlevel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a fair question, and I actually ran into a race condition during manual testing where it looked like we successfully went through the save/restore path but actually hadn't.
For a short answer, I'm not sure how to validate that we went through the codepath we think we did without parsing some logs (do we see a gdma restoration message etc.). How is NVMe validating this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gurasinghMS can give you some pointers. But in short, we inject faults into the nvme emulator, such that a restore would never succeed if keepalive isn't used. In addition, I'm adding checks that look at the driver state in VTL2, so that we can ascertain if it thinks it will go down the right path (this is more akin to look at logs, as you say)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the nvme-keepalive side, we ended up just forking out the nvme-emulator in to a test-only emulator where we added hooks to fault certain functions (This was much easier than adding test hooks alongside the existing implementation).
To test that keepalive was being used I added tests that would check for command activity during restore. In our case, the driver should never be issuing CREATE_IO_QUEUE commands during restore. Happy to discuss more offline too if you would like
| mem: SavedMemoryState { | ||
| base_pfn: self.dma_buffer.pfns()[0], | ||
| len: self.dma_buffer.len(), | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably you need some check here (or at a higher layer?) to gracefully fail the save if this memory is not from a persistent pool. (You don't have that primitive from the DMA APIs yet, ofc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DMA client usage is definitely very optimistic/fail-fast in this PR. I need to take another pass and think more critically about how to handle failures here or if we're going to pass that responsibility onto the DMA APIs somehow. Do you have thoughts here?
I know the DmaClient will error if all marked persisted memory isn't restored, but saving the memory this way I don't think there's any way to to check that we're not saving some non-persisted memory. Maybe DmaClient should have some method that spits out a common MemorySavedState that can be passed into persisted state and it can double check that it's persisted memory? Not sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'd check at allocation time. See my suggested change in #2087 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Few questions to get started.
| persistent_allocations: false, | ||
| persistent_allocations: save_restore_supported, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will need to be more discerning here:
- Use the DMA client with persistent allocations for the memory regions you will save/restore
- Use a new DMA client (without persistent allocations) for the memory regions you will not save/restore
The private pool is a limited resource, and should only be used for memory that needs to come from it. @chris-oo FYI.
This adds the code that utilizes GdmaDevice::restore and VfioDevice::restore in cases where MANA keepalive is enabled. This requires a GuestServicingFlag to be set to enable MANA keepalive, a command line parameter of OPENHCL_MANA_KEEP_ALIVE=1, and for OPENHCL_ENABLE_VTL2_GPA_POOL to be set with enough memory for keepalive to function.
I've also modified the interactive console's service-vtl2 to take arguments for
--mana-keepaliveand--nvme-keepaliveso that keepalive can be manually tested with the console.