devices/virtio/vsock/sys/
linux.rs1use std::path::Path;
6use std::path::PathBuf;
7
8use serde::Deserialize;
9use serde::Serialize;
10use serde_keyvalue::FromKeyValues;
11
12static VHOST_VSOCK_DEFAULT_PATH: &str = "/dev/vhost-vsock";
13
14fn default_vsock_path() -> PathBuf {
15 PathBuf::from(VHOST_VSOCK_DEFAULT_PATH)
16}
17
18#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, FromKeyValues)]
19#[serde(deny_unknown_fields, rename_all = "kebab-case")]
20pub struct VsockConfig {
22 pub cid: u64,
24 #[serde(default = "default_vsock_path", rename = "device")]
26 pub vhost_device: PathBuf,
27 #[serde(default)]
28 pub max_queue_sizes: Option<[u16; 3]>,
29}
30
31impl VsockConfig {
32 pub fn new<P: AsRef<Path>>(cid: u64, vhost_device: Option<P>) -> Self {
35 Self {
36 cid,
37 #[cfg(any(target_os = "android", target_os = "linux"))]
38 vhost_device: vhost_device
39 .map(|p| PathBuf::from(p.as_ref()))
40 .unwrap_or_else(|| PathBuf::from(VHOST_VSOCK_DEFAULT_PATH)),
41 max_queue_sizes: None,
42 }
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use serde_keyvalue::from_key_values;
49 use serde_keyvalue::ErrorKind;
50 use serde_keyvalue::ParseError;
51
52 use super::*;
53
54 fn from_vsock_arg(options: &str) -> Result<VsockConfig, ParseError> {
55 from_key_values(options)
56 }
57
58 #[test]
59 fn params_from_key_values() {
60 assert_eq!(
62 from_vsock_arg("cid=56").unwrap(),
63 VsockConfig {
64 vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
65 cid: 56,
66 max_queue_sizes: None,
67 }
68 );
69
70 assert_eq!(
72 from_vsock_arg("").unwrap_err(),
73 ParseError {
74 kind: ErrorKind::SerdeError("missing field `cid`".into()),
75 pos: 0
76 }
77 );
78
79 assert_eq!(
81 from_vsock_arg("78").unwrap(),
82 VsockConfig {
83 #[cfg(any(target_os = "android", target_os = "linux"))]
84 vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
85 cid: 78,
86 max_queue_sizes: None,
87 }
88 );
89
90 assert_eq!(
92 from_vsock_arg("cid=42,cid=56").unwrap_err(),
93 ParseError {
94 kind: ErrorKind::SerdeError("duplicate field `cid`".into()),
95 pos: 0,
96 }
97 );
98
99 assert_eq!(
101 from_vsock_arg("invalid=foo").unwrap_err(),
102 ParseError {
103 kind: ErrorKind::SerdeError(
104 "unknown field `invalid`, expected one of `cid`, `device`, `max-queue-sizes`"
105 .into()
106 ),
107 pos: 0,
108 }
109 );
110
111 assert_eq!(
113 from_vsock_arg("device=/some/path,cid=56").unwrap(),
114 VsockConfig {
115 vhost_device: "/some/path".into(),
116 cid: 56,
117 max_queue_sizes: None,
118 }
119 );
120
121 assert_eq!(
123 from_vsock_arg("56,device=/some/path").unwrap(),
124 VsockConfig {
125 vhost_device: "/some/path".into(),
126 cid: 56,
127 max_queue_sizes: None,
128 }
129 );
130
131 assert_eq!(
133 from_vsock_arg("device=42").unwrap_err(),
134 ParseError {
135 kind: ErrorKind::SerdeError("missing field `cid`".into()),
136 pos: 0,
137 }
138 );
139
140 assert_eq!(
142 from_vsock_arg("cid=56,device=42,device=/some/path").unwrap_err(),
143 ParseError {
144 kind: ErrorKind::SerdeError("duplicate field `device`".into()),
145 pos: 0,
146 }
147 );
148
149 assert_eq!(
151 from_vsock_arg("cid=56,max-queue-sizes=[1,2,4]").unwrap(),
152 VsockConfig {
153 vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
154 cid: 56,
155 max_queue_sizes: Some([1, 2, 4]),
156 }
157 );
158 }
159}