Alioth Code Coverage

backend.rs0.00%

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::min;
16use std::fs::File;
17use std::io::{ErrorKind, Write};
18use std::iter::zip;
19use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
20use std::os::unix::net::UnixStream;
21use std::sync::Arc;
22use std::sync::atomic::Ordering;
23
24use alioth_macros::trace_error;
25use snafu::Snafu;
26use zerocopy::IntoBytes;
27
28use crate::errors::DebugTrace;
29use crate::hv::IoeventFd;
30use crate::mem::mapped::{ArcMemPages, RamBus};
31use crate::virtio::dev::{StartParam, VirtioDevice, WakeEvent};
32use crate::virtio::vu::Error as VuError;
33use crate::virtio::vu::bindings::{
34 MAX_CONFIG_SIZE, MemoryRegion, MemorySingleRegion, Message, VirtqAddr, VirtqState, VuFeature,
35 VuFrontMsg,
36};
37use crate::virtio::vu::conn::{VuChannel, VuSession};
38use crate::virtio::{self, DevStatus, IrqSender, VirtioFeature};
39
40#[trace_error]
41#[derive(Snafu, DebugTrace)]
42#[snafu(module, context(suffix(false)))]
43pub enum Error {
44 #[snafu(display("Error from OS"), context(false))]
45 System { error: std::io::Error },
46 #[snafu(display("Failed to access guest memory"), context(false))]
47 Memory { source: Box<crate::mem::Error> },
48 #[snafu(display("vhost-user protocol error"), context(false))]
49 Vu {
50 source: Box<crate::virtio::vu::Error>,
51 },
52 #[snafu(display("failed to parse the payload of {req:?}"))]
53 Parse { req: VuFrontMsg },
54 #[snafu(display("frontend requested invalid queue index: {index}"))]
55 InvalidQueue { index: u16 },
56 #[snafu(display("{req:?} did not contain an FD"))]
57 MissingFd { req: VuFrontMsg },
58 #[snafu(display("frontend did not set size for queue {index}"))]
59 MissingSize { index: u16 },
60 #[snafu(display("frontend did not set addresses for queue {index}"))]
61 MissingAddr { index: u16 },
62 #[snafu(display("frontend did not set ioeventfd for queue {index}"))]
63 MissingIoeventfd { index: u16 },
64 #[snafu(display("cannot convert frontend HVA {hva:#x} to GPA"))]
65 Convert { hva: u64 },
66 #[snafu(display("invalid message {req:?} with payload size {size}"))]
67 InvalidMsg { req: VuFrontMsg, size: u32 },
68 #[snafu(display("Cannot change memory layout at runtime"))]
69 ChangeMemoryLayout,
70 #[snafu(display("Failed to send backend request channel to device"))]
71 SendChannel,
72}
73
74type Result<T, E = Error> = std::result::Result<T, E>;
75
76#[derive(Debug)]
77pub struct VuIrqSender {
78 queues: Box<[Option<File>]>,
79}
80
81impl VuIrqSender {
82 fn signal_irqfd(&self, mut fd: &File) {
83 if let Err(e) = fd.write(1u64.as_bytes()) {
84 log::error!("failed to signal irqfd: {e:?}");
85 }
86 }
87}
88
89impl IrqSender for VuIrqSender {
90 fn config_irq(&self) {
91 // TODO: investigate VHOST_USER_BACKEND_CONFIG_CHANGE_MSG
92 log::error!("config irqfd is not available");
93 }
94
95 fn queue_irq(&self, idx: u16) {
96 let Some(queue) = self.queues.get(idx as usize) else {
97 log::error!("invalid queue index: {idx}");
98 return;
99 };
100 let Some(fd) = queue.as_ref() else {
101 log::error!("queue-{idx} irqfd is not available");
102 return;
103 };
104 self.signal_irqfd(fd);
105 }
106
107 fn config_irqfd<F, T>(&self, _: F) -> virtio::Result<T>
108 where
109 F: FnOnce(BorrowedFd) -> virtio::Result<T>,
110 {
111 unreachable!()
112 }
113
114 fn queue_irqfd<F, T>(&self, _: u16, _: F) -> virtio::Result<T>
115 where
116 F: FnOnce(BorrowedFd) -> virtio::Result<T>,
117 {
118 unreachable!()
119 }
120}
121
122#[derive(Debug)]
123pub struct VuEventfd {
124 fd: File,
125}
126
127impl AsFd for VuEventfd {
128 fn as_fd(&self) -> BorrowedFd<'_> {
129 self.fd.as_fd()
130 }
131}
132
133impl IoeventFd for VuEventfd {}
134
135#[derive(Debug, Default)]
136struct VuQueueInit {
137 enable: bool,
138 size: Option<u16>,
139 addr: Option<VirtqAddr>,
140 ioeventfd: Option<File>,
141 irqfd: Option<File>,
142 errfd: Option<File>,
143}
144
145#[derive(Debug)]
146struct VuInit {
147 drv_feat: u64,
148 queues: Box<[VuQueueInit]>,
149 regions: Vec<MemoryRegion>,
150}
151
152pub struct VuBackend {
153 session: VuSession,
154 channel: Option<Arc<VuChannel>>,
155 status: DevStatus,
156 memory: Arc<RamBus>,
157 dev: VirtioDevice<VuIrqSender, VuEventfd>,
158 init: VuInit,
159}
160
161impl VuBackend {
162 pub fn new(
163 conn: UnixStream,
164 dev: VirtioDevice<VuIrqSender, VuEventfd>,
165 memory: Arc<RamBus>,
166 ) -> Result<Self> {
167 conn.set_nonblocking(false)?;
168 let queue_num = dev.queue_regs.len();
169 Ok(VuBackend {
170 session: VuSession { conn },
171 channel: None,
172 dev,
173 memory,
174 status: DevStatus::empty(),
175 init: VuInit {
176 drv_feat: 0,
177 queues: (0..queue_num).map(|_| VuQueueInit::default()).collect(),
178 regions: vec![],
179 },
180 })
181 }
182
183 pub fn name(&self) -> &str {
184 self.dev.name.as_ref()
185 }
186
187 fn wake_up_dev(&self, event: WakeEvent<VuIrqSender, VuEventfd>) {
188 let is_start = matches!(event, WakeEvent::Start { .. });
189 if let Err(e) = self.dev.event_tx.send(event) {
190 log::error!("{}: failed to send event: {e}", self.dev.name);
191 return;
192 }
193 if is_start {
194 return;
195 }
196 if let Err(e) = self.dev.notifier.notify() {
197 log::error!("{}: failed to wake up device: {e}", self.dev.name);
198 }
199 }
200
201 fn convert_frontend_hva(&self, hva: u64) -> Result<u64> {
202 for r in &self.init.regions {
203 if hva >= r.hva && hva < r.hva + r.size {
204 return Ok(r.gpa + (hva - r.hva));
205 }
206 }
207 error::Convert { hva }.fail()
208 }
209
210 fn parse_init(&mut self) -> Result<StartParam<VuIrqSender, VuEventfd>> {
211 for (index, (param, queue)) in zip(&self.init.queues, &*self.dev.queue_regs).enumerate() {
212 let index = index as u16;
213 queue.enabled.store(param.enable, Ordering::Release);
214 if !param.enable {
215 continue;
216 }
217
218 let Some(size) = param.size else {
219 return error::MissingSize { index }.fail();
220 };
221 queue.size.store(size, Ordering::Release);
222
223 let Some(addr) = &param.addr else {
224 return error::MissingAddr { index }.fail();
225 };
226
227 let desc_gpa = self.convert_frontend_hva(addr.desc_hva)?;
228 queue.desc.store(desc_gpa, Ordering::Release);
229
230 let dev_gpa = self.convert_frontend_hva(addr.used_hva)?;
231 queue.device.store(dev_gpa, Ordering::Release);
232
233 let drv_gpa = self.convert_frontend_hva(addr.avail_hva)?;
234 queue.driver.store(drv_gpa, Ordering::Release);
235 }
236
237 let queues = &mut self.init.queues;
238
239 let queue_irqfds = queues.iter_mut().map(|q| q.irqfd.take()).collect();
240 let irq_sender = VuIrqSender {
241 queues: queue_irqfds,
242 };
243
244 let mut ioeventfds = vec![];
245 for (index, q) in queues.iter_mut().enumerate() {
246 match q.ioeventfd.take() {
247 Some(fd) => ioeventfds.push(VuEventfd { fd }),
248 None => {
249 let index = index as u16;
250 return error::MissingIoeventfd { index }.fail();
251 }
252 }
253 }
254
255 Ok(StartParam {
256 feature: self.init.drv_feat as u128,
257 irq_sender: Arc::new(irq_sender),
258 ioeventfds: Some(ioeventfds.into()),
259 })
260 }
261
262 fn handle_msg(&mut self, msg: &mut Message, fds: &mut [Option<OwnedFd>; 8]) -> Result<()> {
263 let name = &*self.dev.name;
264 let (req, size) = (VuFrontMsg::from(msg.request), msg.size);
265
266 match (req, size) {
267 (VuFrontMsg::GET_PROTOCOL_FEATURES, 0) => {
268 let feature = VuFeature::MQ
269 | VuFeature::REPLY_ACK
270 | VuFeature::CONFIGURE_MEM_SLOTS
271 | VuFeature::BACKEND_REQ
272 | VuFeature::BACKEND_SEND_FD
273 | VuFeature::CONFIG
274 | VuFeature::STATUS;
275 self.session.reply(req, &feature.bits(), &[])?;
276 msg.flag.set_need_reply(false);
277 log::debug!("{name}: get protocol feature: {feature:x?}");
278 }
279 (VuFrontMsg::SET_PROTOCOL_FEATURES, 8) => {
280 let feature: u64 = self.session.recv_payload()?;
281 let feature = VuFeature::from_bits_retain(feature);
282 log::debug!("{name}: set protocol feature: {feature:x?}");
283 }
284 (VuFrontMsg::GET_FEATURES, 0) => {
285 let feature = self.dev.device_feature | VirtioFeature::VHOST_PROTOCOL.bits();
286 self.session.reply(req, &(feature as u64), &[])?;
287 msg.flag.set_need_reply(false);
288 log::debug!("{name}: get device feature: {feature:#x}");
289 }
290 (VuFrontMsg::SET_FEATURES, 8) => {
291 self.init.drv_feat = self.session.recv_payload()?;
292 log::debug!("{name}: set driver feature: {:#x}", self.init.drv_feat);
293 }
294 (VuFrontMsg::SET_OWNER, 0) => {
295 log::trace!("{name}: set owner");
296 }
297 (VuFrontMsg::GET_QUEUE_NUM, 0) => {
298 let count = self.init.queues.len() as u64;
299 self.session.reply(req, &count, &[])?;
300 log::debug!("{name}: get queue number: {count}");
301 msg.flag.set_need_reply(false);
302 }
303 (VuFrontMsg::SET_BACKEND_REQ_FD, 0) => {
304 let Some(fd) = fds[0].take() else {
305 return error::MissingFd { req }.fail()?;
306 };
307 log::trace!("{name}: set backend request fd: {}", fd.as_raw_fd());
308 let channel = Arc::new(VuChannel {
309 conn: UnixStream::from(fd),
310 });
311 let r = self.dev.event_tx.send(WakeEvent::VuChannel {
312 channel: channel.clone(),
313 });
314 if r.is_err() {
315 return error::SendChannel.fail();
316 }
317 self.channel = Some(channel);
318 }
319 (VuFrontMsg::SET_VIRTQ_ERR, 8) => {
320 let index = self.session.recv_payload::<u64>()? as u16;
321 let Some(fd) = fds[0].take() else {
322 return error::MissingFd { req: msg.request }.fail();
323 };
324 let Some(q) = self.init.queues.get_mut(index as usize) else {
325 return error::InvalidQueue { index }.fail();
326 };
327 log::debug!("{name}: queue-{index}: set error fd: {}", fd.as_raw_fd());
328 q.errfd = Some(File::from(fd));
329 }
330 (VuFrontMsg::SET_VIRTQ_CALL, 8) => {
331 let index = self.session.recv_payload::<u64>()? as u16;
332 let Some(fd) = fds[0].take() else {
333 return error::MissingFd { req: msg.request }.fail();
334 };
335 let Some(q) = self.init.queues.get_mut(index as usize) else {
336 return error::InvalidQueue { index }.fail();
337 };
338 log::debug!("{name}: queue-{index}: set call fd: {}", fd.as_raw_fd());
339 q.irqfd = Some(File::from(fd));
340 }
341 (VuFrontMsg::SET_VIRTQ_KICK, 8) => {
342 let index = self.session.recv_payload::<u64>()? as u16;
343 let Some(fd) = fds[0].take() else {
344 return error::MissingFd { req: msg.request }.fail();
345 };
346 let Some(q) = self.init.queues.get_mut(index as usize) else {
347 return error::InvalidQueue { index }.fail();
348 };
349 log::debug!("{name}: queue-{index}: set kick fd: {}", fd.as_raw_fd());
350 q.ioeventfd = Some(File::from(fd));
351 }
352 (VuFrontMsg::SET_VIRTQ_NUM, 8) => {
353 let virtq_num: VirtqState = self.session.recv_payload()?;
354 let (index, size) = (virtq_num.index as u16, virtq_num.val as u16);
355 let Some(q) = self.init.queues.get_mut(index as usize) else {
356 return error::InvalidQueue { index }.fail();
357 };
358 q.size = Some(size);
359 log::debug!("{name}: queue-{index}: set size: {size}");
360 }
361 (VuFrontMsg::SET_VIRTQ_BASE, 8) => {
362 let virtq_base: VirtqState = self.session.recv_payload()?;
363 let (index, base) = (virtq_base.index as u16, virtq_base.val);
364 let Some(_q) = self.init.queues.get_mut(index as usize) else {
365 return error::InvalidQueue { index }.fail();
366 };
367 log::warn!("{name}: queue-{index}: set base: {base}");
368 }
369 (VuFrontMsg::GET_VIRTQ_BASE, 8) => {
370 let mut virtq_base: VirtqState = self.session.recv_payload()?;
371 let (index, base) = (virtq_base.index as u16, virtq_base.val);
372 let Some(_q) = self.init.queues.get_mut(index as usize) else {
373 return error::InvalidQueue { index }.fail();
374 };
375 virtq_base.val = 0;
376 self.session.reply(req, &virtq_base, &[])?;
377 msg.flag.set_need_reply(false);
378 log::warn!("{name}: queue-{index}: get base: {base}");
379 }
380 (VuFrontMsg::SET_VIRTQ_ADDR, 40) => {
381 let virtq_addr: VirtqAddr = self.session.recv_payload()?;
382 let index = virtq_addr.index as u16;
383 let Some(q) = self.init.queues.get_mut(index as usize) else {
384 return error::InvalidQueue { index }.fail();
385 };
386 log::debug!("{name}: queue-{index}: set addr: {virtq_addr:x?}");
387 q.addr = Some(virtq_addr);
388 }
389 (VuFrontMsg::SET_VIRTQ_ENABLE, 8) => {
390 let virtq_num: VirtqState = self.session.recv_payload()?;
391 let (index, enabled) = (virtq_num.index as u16, virtq_num.val != 0);
392 let Some(q) = self.init.queues.get_mut(index as usize) else {
393 return error::InvalidQueue { index }.fail();
394 };
395 q.enable = enabled;
396 log::debug!("{name}: queue-{index}: set enabled: {enabled}");
397 }
398 (VuFrontMsg::GET_MAX_MEM_SLOTS, 0) => {
399 self.session.reply(req, &128u64, &[])?;
400 msg.flag.set_need_reply(false);
401 log::debug!("{name}: get max mem slots: 128");
402 }
403 (VuFrontMsg::ADD_MEM_REG, 40) => {
404 let single: MemorySingleRegion = self.session.recv_payload()?;
405 let Some(fd) = fds[0].take() else {
406 return error::MissingFd { req: msg.request }.fail();
407 };
408 let region = &single.region;
409 if self.status.contains(DevStatus::DRIVER_OK) {
410 return error::ChangeMemoryLayout.fail();
411 }
412 log::debug!("{name}: add mem: {region:x?}, fd: {}", fd.as_raw_fd());
413 let user_mem = ArcMemPages::from_file(
414 File::from(fd),
415 region.mmap_offset as i64,
416 region.size as usize,
417 libc::PROT_READ | libc::PROT_WRITE,
418 )?;
419 self.memory.add(region.gpa, user_mem)?;
420 self.init.regions.push(single.region);
421 }
422 (VuFrontMsg::REM_MEM_REG, 40) => {
423 let single: MemorySingleRegion = self.session.recv_payload()?;
424 let region = &single.region;
425 if self.status.contains(DevStatus::DRIVER_OK) {
426 return error::ChangeMemoryLayout.fail();
427 }
428 for (index, r) in self.init.regions.iter().enumerate() {
429 if r.gpa == region.gpa && r.hva == region.hva && r.size == region.size {
430 log::info!("{name}: remove mem: {r:x?}");
431 self.init.regions.remove(index);
432 let _ = self.memory.remove(region.gpa);
433 break;
434 }
435 }
436 }
437 (VuFrontMsg::GET_STATUS, 0) => {
438 let status = self.status.bits() as u64;
439 self.session.reply(req, &status, &[])?;
440 msg.flag.set_need_reply(false);
441 log::debug!("{name}: get status: {status:x?}");
442 }
443 (VuFrontMsg::SET_STATUS, 8) => {
444 let status: u64 = self.session.recv_payload()?;
445 let new = DevStatus::from_bits_retain(status as u8);
446 let old = self.status;
447 self.status = new;
448 log::debug!("{name}: set status: {old:x?} -> {new:x?}");
449 if (old ^ new).contains(DevStatus::DRIVER_OK) {
450 let event = if new.contains(DevStatus::DRIVER_OK) {
451 let param = self.parse_init()?;
452 WakeEvent::Start { param }
453 } else {
454 WakeEvent::Reset
455 };
456 self.wake_up_dev(event);
457 }
458 }
459 (VuFrontMsg::GET_CONFIG, 12..) => {
460 let mut region = [0u8; MAX_CONFIG_SIZE];
461 let dev_config = self.session.recv_config(&mut region)?;
462 let mut done = 0;
463 while let Some(n) = (dev_config.size as usize - done).checked_ilog2() {
464 let size = min(1 << n, 8) as u8;
465 let offset = dev_config.offset as u64 + done as u64;
466 let v = self.dev.device_config.read(offset, size)?;
467 region[done..(done + size as usize)]
468 .copy_from_slice(&v.as_bytes()[..size as usize]);
469 done += size as usize;
470 }
471 self.session.reply_config(&dev_config, &region[..done])?;
472 log::debug!("{name}: get config: {dev_config:?}");
473 msg.flag.set_need_reply(false);
474 }
475 (VuFrontMsg::SET_CONFIG, 12..) => {
476 let mut region = [0u8; MAX_CONFIG_SIZE];
477 let dev_config = self.session.recv_config(&mut region)?;
478 let mut done = 0;
479 while let Some(n) = (dev_config.size as usize - done).checked_ilog2() {
480 let size = min(1 << n, 8) as u8;
481 let mut v = 0;
482 v.as_mut_bytes()[..size as usize]
483 .copy_from_slice(&region[done..(done + size as usize)]);
484 let offset = dev_config.offset as u64 + done as u64;
485 self.dev.device_config.write(offset, size, v)?;
486 done += size as usize;
487 }
488 log::debug!("{name}: set config: {dev_config:?}");
489 }
490 _ => return error::InvalidMsg { req, size }.fail(),
491 }
492 Ok(())
493 }
494
495 pub fn run(&mut self) -> Result<()> {
496 let mut fds = [const { None }; 8];
497 loop {
498 let msg = self.session.recv_msg(&mut fds);
499 match msg {
500 Ok(mut msg) => {
501 let ret = self.handle_msg(&mut msg, &mut fds);
502 if let Err(e) = &ret {
503 let name = &*self.dev.name;
504 log::error!("{name}: cannot handle message {:#x}: {e:?}", msg.request);
505 }
506 let req = VuFrontMsg::from(msg.request);
507 if msg.flag.need_reply() {
508 let code = if ret.is_ok() { 0 } else { u64::MAX };
509 self.session.reply(req, &code, &[])?;
510 }
511 }
512 Err(VuError::System { error, .. })
513 if error.kind() == ErrorKind::ConnectionAborted =>
514 {
515 break;
516 }
517 Err(e) => return Err(e)?,
518 }
519 }
520 Ok(())
521 }
522}
523