• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::path::Path;
6 use std::path::PathBuf;
7 
8 use serde::Deserialize;
9 use serde::Serialize;
10 use serde_keyvalue::FromKeyValues;
11 
12 static VHOST_VSOCK_DEFAULT_PATH: &str = "/dev/vhost-vsock";
13 
default_vsock_path() -> PathBuf14 fn 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)]
20 
21 /// Configuration for a Vsock device.
22 pub struct VsockConfig {
23     /// CID to be used for this vsock device.
24     pub cid: u64,
25     /// Path to the vhost-vsock device.
26     #[serde(default = "default_vsock_path", rename = "device")]
27     pub vhost_device: PathBuf,
28 }
29 
30 impl VsockConfig {
31     /// Create a new vsock configuration. If `vhost_device` is `None`, the default vhost-vsock
32     /// device path will be used.
new<P: AsRef<Path>>(cid: u64, vhost_device: Option<P>) -> Self33     pub fn new<P: AsRef<Path>>(cid: u64, vhost_device: Option<P>) -> Self {
34         Self {
35             cid,
36             #[cfg(unix)]
37             vhost_device: vhost_device
38                 .map(|p| PathBuf::from(p.as_ref()))
39                 .unwrap_or_else(|| PathBuf::from(VHOST_VSOCK_DEFAULT_PATH)),
40         }
41     }
42 }
43 
44 #[cfg(test)]
45 mod tests {
46     use serde_keyvalue::from_key_values;
47     use serde_keyvalue::ErrorKind;
48     use serde_keyvalue::ParseError;
49 
50     use super::*;
51 
from_vsock_arg(options: &str) -> Result<VsockConfig, ParseError>52     fn from_vsock_arg(options: &str) -> Result<VsockConfig, ParseError> {
53         from_key_values(options)
54     }
55 
56     #[test]
params_from_key_values()57     fn params_from_key_values() {
58         // Default device
59         assert_eq!(
60             from_vsock_arg("cid=56").unwrap(),
61             VsockConfig {
62                 vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
63                 cid: 56,
64             }
65         );
66 
67         // No argument
68         assert_eq!(
69             from_vsock_arg("").unwrap_err(),
70             ParseError {
71                 kind: ErrorKind::SerdeError("missing field `cid`".into()),
72                 pos: 0
73             }
74         );
75 
76         // CID passed without key
77         assert_eq!(
78             from_vsock_arg("78").unwrap(),
79             VsockConfig {
80                 #[cfg(unix)]
81                 vhost_device: VHOST_VSOCK_DEFAULT_PATH.into(),
82                 cid: 78,
83             }
84         );
85 
86         // CID passed twice
87         assert_eq!(
88             from_vsock_arg("cid=42,cid=56").unwrap_err(),
89             ParseError {
90                 kind: ErrorKind::SerdeError("duplicate field `cid`".into()),
91                 pos: 0,
92             }
93         );
94 
95         // Invalid argument
96         assert_eq!(
97             from_vsock_arg("invalid=foo").unwrap_err(),
98             ParseError {
99                 kind: ErrorKind::SerdeError(
100                     "unknown field `invalid`, expected `cid` or `device`".into()
101                 ),
102                 pos: 0,
103             }
104         );
105 
106         // Path device
107         assert_eq!(
108             from_vsock_arg("device=/some/path,cid=56").unwrap(),
109             VsockConfig {
110                 vhost_device: "/some/path".into(),
111                 cid: 56,
112             }
113         );
114 
115         // CID passed without key
116         assert_eq!(
117             from_vsock_arg("56,device=/some/path").unwrap(),
118             VsockConfig {
119                 vhost_device: "/some/path".into(),
120                 cid: 56,
121             }
122         );
123 
124         // Missing cid
125         assert_eq!(
126             from_vsock_arg("device=42").unwrap_err(),
127             ParseError {
128                 kind: ErrorKind::SerdeError("missing field `cid`".into()),
129                 pos: 0,
130             }
131         );
132 
133         // Device passed twice
134         assert_eq!(
135             from_vsock_arg("cid=56,device=42,device=/some/path").unwrap_err(),
136             ParseError {
137                 kind: ErrorKind::SerdeError("duplicate field `device`".into()),
138                 pos: 0,
139             }
140         );
141     }
142 }
143