Skip to content

Commit 6592627

Browse files
committed
add QueueStateSer
This provides serialization capabilities to QueueState, and is defined in the virtio-queue-ser crate. QueueStateSer mirrors the state structure from virtio-queue, and derives the required (de)serialization/versioning traits (i.e. Serialize, Deserialize, Versionize). Also added some clarifications to why we can't validate data that is part of the queue. Signed-off-by: Laura Loghin <[email protected]>
1 parent d8ef45f commit 6592627

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22
members = [
33
"crates/virtio-queue",
4+
"crates/virtio-queue-ser",
45
"crates/virtio-device",
56
"crates/devices/*",
67
]

crates/virtio-queue-ser/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "virtio-queue-ser"
3+
version = "0.1.0"
4+
authors = ["rust-vmm AWS maintainers <[email protected]>"]
5+
description = "Serialization for virtio queue state"
6+
repository = "https://github.com/rust-vmm/vm-virtio"
7+
keywords = ["queue", "serialization", "versioning"]
8+
readme = "README.md"
9+
license = "Apache-2.0 OR BSD-3-Clause"
10+
edition = "2018"
11+
12+
[dependencies]
13+
serde = { version = ">=1.0.27", features = ["derive"] }
14+
versionize = ">=0.1.6"
15+
versionize_derive = ">=0.1.3"
16+
virtio-queue = { path = "../../crates/virtio-queue" }
17+
vm-memory = "0.7.0"

crates/virtio-queue-ser/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4+
5+
//! Adds serialization capabilities to the state objects from `virtio-queue`.
6+
//!
7+
//! Provides wrappers over the state objects from `virtio-queue` crate that
8+
//! implement the `Serialize`, `Deserialize` and `Versionize` traits.
9+
10+
#![deny(missing_docs)]
11+
12+
mod state;
13+
14+
pub use state::QueueStateSer;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4+
5+
use std::num::Wrapping;
6+
7+
use serde::{Deserialize, Serialize};
8+
use versionize::{VersionMap, Versionize, VersionizeResult};
9+
use versionize_derive::Versionize;
10+
use virtio_queue::QueueState;
11+
use vm_memory::GuestAddress;
12+
13+
/// Wrapper over a `QueueState` that has serialization capabilities.
14+
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Versionize)]
15+
pub struct QueueStateSer {
16+
/// The maximum size in elements offered by the device.
17+
pub max_size: u16,
18+
/// Tail position of the available ring.
19+
pub next_avail: u16,
20+
/// Head position of the used ring.
21+
pub next_used: u16,
22+
/// VIRTIO_F_RING_EVENT_IDX negotiated.
23+
pub event_idx_enabled: bool,
24+
/// The last used value when using VIRTIO_F_EVENT_IDX.
25+
pub signalled_used: Option<u16>,
26+
/// The queue size in elements the driver selected.
27+
pub size: u16,
28+
/// Indicates if the queue finished with the configuration.
29+
pub ready: bool,
30+
/// Guest physical address of the descriptor table.
31+
pub desc_table: u64,
32+
/// Guest physical address of the available ring.
33+
pub avail_ring: u64,
34+
/// Guest physical address of the used ring.
35+
pub used_ring: u64,
36+
}
37+
38+
// The following `From` implementations can be used to convert from a `QueueStateSer` to the
39+
// `QueueState` from the base crate and vice versa.
40+
// WARNING: They don't check for any invalid data, that would otherwise be checked when initializing
41+
// a queue object from scratch (for example setting a queue size greater than its max possible
42+
// size). The problem with the current `QueueState` implementation is that it can be used as the
43+
// queue object itself. `QueueState`'s fields are public, which allows the user to set up and use an
44+
// invalid queue. Once we fix https://github.com/rust-vmm/vm-virtio/issues/143, `QueueState` will be
45+
// renamed to `Queue`, its fields will no longer be public, and `QueueState` will consist of the
46+
// actual state. This way we can also check against any invalid data when trying to get a `Queue`
47+
// from the state object.
48+
// Nevertheless, we don't make any assumptions in the virtio-queue code about the queue's state that
49+
// would otherwise result in a panic, when initialized with random data, so from this point of view
50+
// these conversions are safe to use.
51+
impl From<&QueueStateSer> for QueueState {
52+
fn from(state: &QueueStateSer) -> Self {
53+
QueueState {
54+
max_size: state.max_size,
55+
next_avail: Wrapping(state.next_avail),
56+
next_used: Wrapping(state.next_used),
57+
event_idx_enabled: state.event_idx_enabled,
58+
signalled_used: state.signalled_used.map(Wrapping),
59+
size: state.size,
60+
ready: state.ready,
61+
desc_table: GuestAddress(state.desc_table),
62+
avail_ring: GuestAddress(state.avail_ring),
63+
used_ring: GuestAddress(state.used_ring),
64+
}
65+
}
66+
}
67+
68+
impl From<&QueueState> for QueueStateSer {
69+
fn from(state: &QueueState) -> Self {
70+
QueueStateSer {
71+
max_size: state.max_size,
72+
next_avail: state.next_avail.0,
73+
next_used: state.next_used.0,
74+
event_idx_enabled: state.event_idx_enabled,
75+
signalled_used: state.signalled_used.map(|value| value.0),
76+
size: state.size,
77+
ready: state.ready,
78+
desc_table: state.desc_table.0,
79+
avail_ring: state.avail_ring.0,
80+
used_ring: state.used_ring.0,
81+
}
82+
}
83+
}
84+
85+
impl Default for QueueStateSer {
86+
fn default() -> Self {
87+
QueueStateSer::from(&QueueState::default())
88+
}
89+
}
90+
91+
#[cfg(test)]
92+
mod tests {
93+
use super::*;
94+
95+
#[test]
96+
fn test_state_ser() {
97+
const SOME_VALUE: u16 = 16;
98+
99+
let state = QueueState {
100+
max_size: SOME_VALUE * 2,
101+
next_avail: Wrapping(SOME_VALUE - 1),
102+
next_used: Wrapping(SOME_VALUE + 1),
103+
event_idx_enabled: false,
104+
signalled_used: None,
105+
size: SOME_VALUE,
106+
ready: true,
107+
desc_table: GuestAddress(SOME_VALUE as u64),
108+
avail_ring: GuestAddress(SOME_VALUE as u64 * 2),
109+
used_ring: GuestAddress(SOME_VALUE as u64 * 4),
110+
};
111+
112+
let ser_state = QueueStateSer::from(&state);
113+
let state_from_ser = QueueState::from(&ser_state);
114+
115+
// Check that the old and the new state are identical when using the intermediate
116+
// `QueueStateSer` object.
117+
assert_eq!(state, state_from_ser);
118+
119+
// Test the `Default` implementation of `QueueStateSer`.
120+
let default_queue_state_ser = QueueStateSer::default();
121+
assert_eq!(
122+
QueueState::from(&default_queue_state_ser),
123+
QueueState::default()
124+
);
125+
}
126+
}

crates/virtio-queue/src/state.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,15 @@ use crate::defs::{
2222
use crate::{error, AvailIter, Descriptor, Error, QueueStateGuard, QueueStateT, VirtqUsedElem};
2323

2424
/// Struct to maintain information and manipulate state of a virtio queue.
25-
#[derive(Debug)]
25+
///
26+
/// WARNING: The way the `QueueState` is defined now, it can be used as the queue object, therefore
27+
/// it is allowed to set up and use an invalid queue (initialized with random data since the
28+
/// `QueueState`'s fields are public). When fixing https://github.com/rust-vmm/vm-virtio/issues/143,
29+
/// we plan to rename `QueueState` to `Queue`, and define a new `QueueState` that would be the
30+
/// actual state of the queue (no `Wrapping`s in it, for example). This way, we will also be able to
31+
/// do the checks that we normally do in the queue's field setters when starting from scratch, when
32+
/// trying to create a `Queue` from a `QueueState`.
33+
#[derive(Debug, Default, PartialEq)]
2634
pub struct QueueState {
2735
/// The maximum size in elements offered by the device.
2836
pub max_size: u16,

0 commit comments

Comments
 (0)