-
Notifications
You must be signed in to change notification settings - Fork 2.3k
feat(virtio): add generic vhost-user frontend device #5773
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
Open
meAmitPatil
wants to merge
9
commits into
firecracker-microvm:main
Choose a base branch
from
superserve-ai:feat/generic-vhost-user
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,433
−8
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
ebbc801
feat(virtio): add VhostUserGeneric device type sentinel
meAmitPatil d6f530b
feat(virtio): add generic vhost-user frontend device
meAmitPatil ef84896
feat(api): wire generic vhost-user device end-to-end
meAmitPatil dafe574
fix(tests): fix vhost-user generic test mocks
meAmitPatil ce025ec
refactor(vhost-user): address code review findings
meAmitPatil 91ae093
style: apply nightly rustfmt and mdformat
meAmitPatil 0695d0e
docs: add generic vhost-user device documentation
meAmitPatil 5e292b9
docs: address review comments on vhost-user docs
meAmitPatil 388b31d
test(vhost-user): add integration tests for generic vhost-user device
meAmitPatil File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # Using generic vhost-user devices | ||
|
|
||
| ## What is a vhost-user device | ||
|
|
||
| The [vhost-user protocol](https://qemu-project.gitlab.io/qemu/interop/vhost-user.html) | ||
| allows virtio device emulation to be offloaded to a separate backend | ||
| process communicating over a Unix domain socket. The backend handles the | ||
| actual device logic while Firecracker acts as the frontend, managing | ||
| virtqueues and guest memory. | ||
|
|
||
| A generic vhost-user frontend knows nothing about the specific virtio | ||
| device type being implemented. The backend is fully responsible for the | ||
| device configuration space. This allows using device types that | ||
| Firecracker would never support natively (e.g. virtio-fs, virtio-scsi) | ||
| without requiring a dedicated frontend for each. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - The vhost-user backend process must be running and listening on the | ||
| configured Unix domain socket **before** configuring the device in | ||
| Firecracker. | ||
| - The backend must support the `VHOST_USER_PROTOCOL_F_CONFIG` protocol | ||
| feature, as Firecracker relies on the backend to provide the device | ||
| configuration space. | ||
| - The guest kernel must include the driver for the virtio device type | ||
| being emulated (e.g. `CONFIG_VIRTIO_FS=y` for virtio-fs). | ||
|
|
||
| ## Configuration | ||
|
|
||
| The following options are available: | ||
|
|
||
| - `id` - unique identifier of the device. | ||
| - `device_type` - the virtio device type ID as defined in the | ||
| [virtio specification](https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.html#x1-1930005). | ||
| For example: `26` for virtio-fs, `8` for virtio-scsi. | ||
| - `socket` - path to the vhost-user backend Unix domain socket. | ||
| - `num_queues` - number of virtqueues to configure for this device. | ||
| - `queue_size` (optional) - size of each virtqueue. Defaults to 256. | ||
|
|
||
| ### Config file | ||
|
|
||
| ```json | ||
| "vhost-user-devices": [ | ||
| { | ||
| "id": "fs0", | ||
| "device_type": 26, | ||
| "socket": "/tmp/virtiofsd.sock", | ||
| "num_queues": 1, | ||
| "queue_size": 256 | ||
| } | ||
| ] | ||
| ``` | ||
|
|
||
| ### API | ||
|
|
||
| ```console | ||
| curl --unix-socket $socket_location -i \ | ||
| -X PUT 'http://localhost/vhost-user-devices/fs0' \ | ||
| -H 'Accept: application/json' \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d "{ | ||
| \"id\": \"fs0\", | ||
| \"device_type\": 26, | ||
| \"socket\": \"/tmp/virtiofsd.sock\", | ||
| \"num_queues\": 1, | ||
| \"queue_size\": 256 | ||
| }" | ||
| ``` | ||
|
|
||
| ## Example: virtio-fs with virtiofsd | ||
|
|
||
| Start the [virtiofsd](https://gitlab.com/virtio-fs/virtiofsd) backend: | ||
|
|
||
| ```console | ||
| virtiofsd \ | ||
| --socket-path=/tmp/virtiofsd.sock \ | ||
| --shared-dir=/path/to/shared \ | ||
| --tag=myfs | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > | ||
| > The `--tag` flag is required to enable the `VHOST_USER_PROTOCOL_F_CONFIG` | ||
| > protocol feature in virtiofsd. | ||
|
|
||
| Then configure the device in Firecracker as shown above. Inside the | ||
| guest, mount the shared directory: | ||
|
|
||
| ```console | ||
| mount -t virtiofs myfs /mnt | ||
| ``` | ||
|
|
||
| ## Limitations | ||
|
|
||
| - **Snapshotting is not supported.** Creating or restoring snapshots of | ||
| a VM with generic vhost-user devices will fail. | ||
| - **Configuration space writes are not yet forwarded** to the backend | ||
| via `VHOST_USER_SET_CONFIG`. | ||
| - **The backend must be started before the device is attached.** | ||
| Firecracker connects to the socket when processing the | ||
| `PUT /vhost-user-devices/{id}` request and will return an error if the | ||
| backend is not available. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/firecracker/src/api_server/request/vhost_user_device.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| use vmm::logger::{IncMetric, METRICS}; | ||
| use vmm::rpc_interface::VmmAction; | ||
| use vmm::vmm_config::vhost_user_device::VhostUserDeviceConfig; | ||
|
|
||
| use super::super::parsed_request::{ParsedRequest, RequestError, checked_id}; | ||
| use super::{Body, StatusCode}; | ||
|
|
||
| pub(crate) fn parse_put_vhost_user_device( | ||
| body: &Body, | ||
| id_from_path: Option<&str>, | ||
| ) -> Result<ParsedRequest, RequestError> { | ||
| METRICS.put_api_requests.vhost_user_count.inc(); | ||
| let id = if let Some(id) = id_from_path { | ||
| checked_id(id)? | ||
| } else { | ||
| METRICS.put_api_requests.vhost_user_fails.inc(); | ||
| return Err(RequestError::EmptyID); | ||
| }; | ||
|
|
||
| let device_cfg = | ||
| serde_json::from_slice::<VhostUserDeviceConfig>(body.raw()).inspect_err(|_| { | ||
| METRICS.put_api_requests.vhost_user_fails.inc(); | ||
| })?; | ||
|
|
||
| if id != device_cfg.id { | ||
| METRICS.put_api_requests.vhost_user_fails.inc(); | ||
| Err(RequestError::Generic( | ||
| StatusCode::BadRequest, | ||
| "The id from the path does not match the id from the body!".to_string(), | ||
| )) | ||
| } else { | ||
| Ok(ParsedRequest::new_sync(VmmAction::InsertVhostUserDevice( | ||
| device_cfg, | ||
| ))) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
| use crate::api_server::parsed_request::tests::vmm_action_from_request; | ||
|
|
||
| #[test] | ||
| fn test_parse_put_vhost_user_device_request() { | ||
| parse_put_vhost_user_device(&Body::new("invalid_payload"), None).unwrap_err(); | ||
| parse_put_vhost_user_device(&Body::new("invalid_payload"), Some("id")).unwrap_err(); | ||
|
|
||
| let body = r#"{ | ||
| "id": "bar", | ||
| "device_type": 26, | ||
| "socket": "/tmp/test.sock", | ||
| "num_queues": 2 | ||
| }"#; | ||
| parse_put_vhost_user_device(&Body::new(body), Some("1")).unwrap_err(); | ||
|
|
||
| let body = r#"{ | ||
| "foo": "1" | ||
| }"#; | ||
| parse_put_vhost_user_device(&Body::new(body), Some("1")).unwrap_err(); | ||
|
|
||
| let body = r#"{ | ||
| "id": "fs0", | ||
| "device_type": 26, | ||
| "socket": "/tmp/virtiofsd.sock", | ||
| "num_queues": 2 | ||
| }"#; | ||
| let r = vmm_action_from_request( | ||
| parse_put_vhost_user_device(&Body::new(body), Some("fs0")).unwrap(), | ||
| ); | ||
|
|
||
| let expected_config = VhostUserDeviceConfig { | ||
| id: "fs0".to_string(), | ||
| device_type: 26, | ||
| socket: "/tmp/virtiofsd.sock".to_string(), | ||
| num_queues: 2, | ||
| queue_size: None, | ||
| }; | ||
| assert_eq!(r, VmmAction::InsertVhostUserDevice(expected_config)); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Testing this PR, I found that a value of
"num_queues": 1did not work, but instead would fail with --And a value of
"num_queues": 3did not work either, but would allowmount -t virtiofs myfs /mntbutls /mntwould hang.Only
"num_queues": 2worked correctly for me, where I was able to successfully use the shared directory to read/write files.