1use std::convert::TryFrom;
5use std::sync::{Arc, Mutex};
6
7use serde::{Deserialize, Serialize};
8
9use crate::devices::virtio::vsock::{Vsock, VsockError, VsockUnixBackend, VsockUnixBackendError};
10
11type MutexVsockUnix = Arc<Mutex<Vsock<VsockUnixBackend>>>;
12
13#[derive(Debug, derive_more::From, thiserror::Error, displaydoc::Display)]
15pub enum VsockConfigError {
16 CreateVsockBackend(VsockUnixBackendError),
18 CreateVsockDevice(VsockError),
20}
21
22#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
25#[serde(deny_unknown_fields)]
26pub struct VsockDeviceConfig {
27 #[serde(default)]
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub vsock_id: Option<String>,
31 pub guest_cid: u32,
33 pub uds_path: String,
35}
36
37#[derive(Debug)]
38struct VsockAndUnixPath {
39 vsock: MutexVsockUnix,
40 uds_path: String,
41}
42
43impl From<&VsockAndUnixPath> for VsockDeviceConfig {
44 fn from(vsock: &VsockAndUnixPath) -> Self {
45 let vsock_lock = vsock.vsock.lock().unwrap();
46 VsockDeviceConfig {
47 vsock_id: None,
48 guest_cid: u32::try_from(vsock_lock.cid()).unwrap(),
49 uds_path: vsock.uds_path.clone(),
50 }
51 }
52}
53
54#[derive(Debug, Default)]
56pub struct VsockBuilder {
57 inner: Option<VsockAndUnixPath>,
58}
59
60impl VsockBuilder {
61 pub fn new() -> Self {
63 Self { inner: None }
64 }
65
66 pub fn set_device(&mut self, device: Arc<Mutex<Vsock<VsockUnixBackend>>>) {
68 self.inner = Some(VsockAndUnixPath {
69 uds_path: device
70 .lock()
71 .expect("Poisoned lock")
72 .backend()
73 .host_sock_path()
74 .to_owned(),
75 vsock: device.clone(),
76 });
77 }
78
79 pub fn insert(&mut self, cfg: VsockDeviceConfig) -> Result<(), VsockConfigError> {
82 if let Some(existing) = self.inner.take() {
84 std::fs::remove_file(existing.uds_path).map_err(VsockUnixBackendError::UnixBind)?;
85 }
86 self.inner = Some(VsockAndUnixPath {
87 uds_path: cfg.uds_path.clone(),
88 vsock: Arc::new(Mutex::new(Self::create_unixsock_vsock(cfg)?)),
89 });
90 Ok(())
91 }
92
93 pub fn get(&self) -> Option<&MutexVsockUnix> {
95 self.inner.as_ref().map(|pair| &pair.vsock)
96 }
97
98 pub fn create_unixsock_vsock(
100 cfg: VsockDeviceConfig,
101 ) -> Result<Vsock<VsockUnixBackend>, VsockConfigError> {
102 let backend = VsockUnixBackend::new(u64::from(cfg.guest_cid), cfg.uds_path)?;
103
104 Vsock::new(u64::from(cfg.guest_cid), backend).map_err(VsockConfigError::CreateVsockDevice)
105 }
106
107 pub fn config(&self) -> Option<VsockDeviceConfig> {
109 self.inner.as_ref().map(VsockDeviceConfig::from)
110 }
111}
112
113#[cfg(test)]
114pub(crate) mod tests {
115 use vmm_sys_util::tempfile::TempFile;
116
117 use super::*;
118 use crate::devices::virtio::vsock::VSOCK_DEV_ID;
119
120 pub(crate) fn default_config(tmp_sock_file: &TempFile) -> VsockDeviceConfig {
121 VsockDeviceConfig {
122 vsock_id: None,
123 guest_cid: 3,
124 uds_path: tmp_sock_file.as_path().to_str().unwrap().to_string(),
125 }
126 }
127
128 #[test]
129 fn test_vsock_create() {
130 let mut tmp_sock_file = TempFile::new().unwrap();
131 tmp_sock_file.remove().unwrap();
132 let vsock_config = default_config(&tmp_sock_file);
133 VsockBuilder::create_unixsock_vsock(vsock_config).unwrap();
134 }
135
136 #[test]
137 fn test_vsock_insert() {
138 let mut store = VsockBuilder::new();
139 let mut tmp_sock_file = TempFile::new().unwrap();
140 tmp_sock_file.remove().unwrap();
141 let mut vsock_config = default_config(&tmp_sock_file);
142
143 store.insert(vsock_config.clone()).unwrap();
144 let vsock = store.get().unwrap();
145 assert_eq!(vsock.lock().unwrap().id(), VSOCK_DEV_ID);
146
147 let new_cid = vsock_config.guest_cid + 1;
148 vsock_config.guest_cid = new_cid;
149 store.insert(vsock_config).unwrap();
150 let vsock = store.get().unwrap();
151 assert_eq!(vsock.lock().unwrap().cid(), u64::from(new_cid));
152 }
153
154 #[test]
155 fn test_vsock_config() {
156 let mut vsock_builder = VsockBuilder::new();
157 let mut tmp_sock_file = TempFile::new().unwrap();
158 tmp_sock_file.remove().unwrap();
159 let vsock_config = default_config(&tmp_sock_file);
160 vsock_builder.insert(vsock_config.clone()).unwrap();
161
162 let config = vsock_builder.config();
163 assert!(config.is_some());
164 assert_eq!(config.unwrap(), vsock_config);
165 }
166
167 #[test]
168 fn test_set_device() {
169 let mut vsock_builder = VsockBuilder::new();
170 let mut tmp_sock_file = TempFile::new().unwrap();
171 tmp_sock_file.remove().unwrap();
172 let vsock = Vsock::new(
173 0,
174 VsockUnixBackend::new(1, tmp_sock_file.as_path().to_str().unwrap().to_string())
175 .unwrap(),
176 )
177 .unwrap();
178
179 vsock_builder.set_device(Arc::new(Mutex::new(vsock)));
180 assert!(vsock_builder.inner.is_some());
181 assert_eq!(
182 vsock_builder.inner.unwrap().uds_path,
183 tmp_sock_file.as_path().to_str().unwrap().to_string()
184 )
185 }
186}