• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / alioth / 17385795674

01 Sep 2025 07:28PM UTC coverage: 18.009% (-0.1%) from 18.149%
17385795674

Pull #281

github

web-flow
Merge 2fe071710 into 6ec9a6d6b
Pull Request #281: Port to Apple Hypervisor framework

0 of 154 new or added lines in 11 files covered. (0.0%)

1166 existing lines in 29 files now uncovered.

1362 of 7563 relevant lines covered (18.01%)

18.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/alioth/src/virtio/dev/vsock/vhost_vsock.rs
1
// Copyright 2024 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

15
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
16
use std::path::PathBuf;
17
use std::sync::Arc;
18
use std::sync::atomic::Ordering;
19
use std::sync::mpsc::Receiver;
20
use std::thread::JoinHandle;
21

22
use libc::{EFD_CLOEXEC, EFD_NONBLOCK, eventfd};
23
use mio::event::Event;
24
use mio::unix::SourceFd;
25
use mio::{Interest, Registry, Token};
26
use serde::Deserialize;
27
use serde_aco::Help;
28

29
use crate::ffi;
30
use crate::hv::IoeventFd;
31
use crate::mem::LayoutUpdated;
32
use crate::mem::mapped::RamBus;
33
use crate::virtio::dev::vsock::{VsockConfig, VsockFeature};
34
use crate::virtio::dev::{DevParam, DeviceId, Virtio, WakeEvent};
35
use crate::virtio::queue::{QueueReg, VirtQueue};
36
use crate::virtio::vhost::bindings::{VHOST_FILE_UNBIND, VirtqAddr, VirtqFile, VirtqState};
37
use crate::virtio::vhost::{UpdateVsockMem, VhostDev, error};
38
use crate::virtio::worker::Waker;
39
use crate::virtio::worker::mio::{ActiveMio, Mio, VirtioMio};
40
use crate::virtio::{IrqSender, Result, VirtioFeature};
41

42
#[derive(Debug, Clone, Deserialize, Help)]
43
pub struct VhostVsockParam {
44
    /// Vsock context id.
45
    pub cid: u32,
46
    /// Path to the host device file. [default: /dev/vhost-vsock]
47
    pub dev: Option<PathBuf>,
48
}
49

50
impl DevParam for VhostVsockParam {
51
    type Device = VhostVsock;
52

53
    fn build(self, name: impl Into<Arc<str>>) -> Result<Self::Device> {
×
54
        VhostVsock::new(self, name)
×
55
    }
56
}
57

58
#[derive(Debug)]
59
pub struct VhostVsock {
60
    name: Arc<str>,
61
    vhost_dev: Arc<VhostDev>,
62
    config: VsockConfig,
63
    features: u64,
64
    error_fds: [Option<OwnedFd>; 2],
65
}
66

67
impl VhostVsock {
68
    pub fn new(param: VhostVsockParam, name: impl Into<Arc<str>>) -> Result<VhostVsock> {
×
69
        let name = name.into();
×
70
        let vhost_dev = match param.dev {
×
71
            Some(dev) => VhostDev::new(dev),
×
72
            None => VhostDev::new("/dev/vhost-vsock"),
×
73
        }?;
74
        vhost_dev.set_owner()?;
×
75
        vhost_dev.vsock_set_guest_cid(param.cid as _)?;
×
76
        if let Ok(backend_feature) = vhost_dev.get_backend_features() {
×
77
            log::debug!("{name}: vhost-vsock backend feature: {backend_feature:x?}");
×
78
            vhost_dev.set_backend_features(&backend_feature)?;
×
79
        }
80
        let dev_feat = vhost_dev.get_features()? as u128;
×
81
        let known_feat = VirtioFeature::from_bits_truncate(dev_feat).bits()
×
82
            | VsockFeature::from_bits_truncate(dev_feat).bits();
×
83
        if !VirtioFeature::from_bits_retain(known_feat).contains(VirtioFeature::VERSION_1) {
×
84
            return error::VhostMissingDeviceFeature {
×
85
                feature: VirtioFeature::VERSION_1.bits(),
×
86
            }
87
            .fail()?;
×
88
        }
89
        Ok(VhostVsock {
×
90
            name,
×
91
            vhost_dev: Arc::new(vhost_dev),
×
92
            config: VsockConfig {
×
93
                guest_cid: param.cid,
×
94
                ..Default::default()
×
95
            },
96
            features: known_feat as u64,
×
97
            error_fds: [None, None],
×
98
        })
99
    }
100
}
101

102
impl Virtio for VhostVsock {
103
    type Config = VsockConfig;
104
    type Feature = VsockFeature;
105

UNCOV
106
    fn id(&self) -> DeviceId {
UNCOV
107
        DeviceId::Socket
108
    }
109

UNCOV
110
    fn name(&self) -> &str {
UNCOV
111
        &self.name
112
    }
113

UNCOV
114
    fn num_queues(&self) -> u16 {
UNCOV
115
        3
116
    }
117

UNCOV
118
    fn config(&self) -> Arc<VsockConfig> {
UNCOV
119
        Arc::new(self.config)
120
    }
121

UNCOV
122
    fn feature(&self) -> u128 {
UNCOV
123
        self.features as u128
124
    }
125

UNCOV
126
    fn ioeventfd_offloaded(&self, q_index: u16) -> Result<bool> {
UNCOV
127
        match q_index {
UNCOV
128
            0 | 1 => Ok(true),
UNCOV
129
            _ => Ok(false),
130
        }
131
    }
132

UNCOV
133
    fn mem_update_callback(&self) -> Option<Box<dyn LayoutUpdated>> {
UNCOV
134
        Some(Box::new(UpdateVsockMem {
UNCOV
135
            dev: self.vhost_dev.clone(),
136
        }))
137
    }
138

UNCOV
139
    fn spawn_worker<S, E>(
140
        self,
141
        event_rx: Receiver<WakeEvent<S, E>>,
142
        memory: Arc<RamBus>,
143
        queue_regs: Arc<[QueueReg]>,
144
    ) -> Result<(JoinHandle<()>, Arc<Waker>)>
145
    where
146
        S: IrqSender,
147
        E: IoeventFd,
148
    {
149
        Mio::spawn_worker(self, event_rx, memory, queue_regs)
×
150
    }
151
}
152

153
impl VirtioMio for VhostVsock {
UNCOV
154
    fn activate<'m, Q, S, E>(
155
        &mut self,
156
        feature: u128,
157
        active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,
158
    ) -> Result<()>
159
    where
160
        Q: VirtQueue<'m>,
161
        S: IrqSender,
162
        E: IoeventFd,
163
    {
164
        self.vhost_dev.set_features(&(feature as u64))?;
×
165
        for (index, fd) in active_mio.ioeventfds.iter().take(2).enumerate() {
×
166
            let kick = VirtqFile {
167
                index: index as u32,
×
168
                fd: fd.as_fd().as_raw_fd(),
×
169
            };
170
            self.vhost_dev.set_virtq_kick(&kick)?;
×
171
        }
172
        for (index, queue) in active_mio.queues.iter().take(2).enumerate() {
×
173
            let Some(queue) = queue else {
×
174
                continue;
×
175
            };
176
            let reg = queue.reg();
×
177
            let index = index as u32;
×
178
            active_mio.irq_sender.queue_irqfd(index as _, |fd| {
×
179
                self.vhost_dev.set_virtq_call(&VirtqFile {
×
180
                    index,
×
181
                    fd: fd.as_raw_fd(),
×
182
                })?;
183
                Ok(())
×
184
            })?;
185

186
            self.vhost_dev.set_virtq_num(&VirtqState {
×
187
                index,
×
188
                val: reg.size.load(Ordering::Acquire) as _,
×
189
            })?;
190
            self.vhost_dev
×
191
                .set_virtq_base(&VirtqState { index, val: 0 })?;
×
192
            let mem = active_mio.mem;
×
193
            let virtq_addr = VirtqAddr {
194
                index,
195
                flags: 0,
196
                desc_hva: mem.translate(reg.desc.load(Ordering::Acquire))? as _,
×
197
                used_hva: mem.translate(reg.device.load(Ordering::Acquire))? as _,
×
198
                avail_hva: mem.translate(reg.driver.load(Ordering::Acquire))? as _,
×
199
                log_guest_addr: 0,
200
            };
201
            self.vhost_dev.set_virtq_addr(&virtq_addr)?;
×
202
        }
203
        for (index, fd) in self.error_fds.iter_mut().enumerate() {
×
204
            let err_fd =
×
205
                unsafe { OwnedFd::from_raw_fd(ffi!(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))?) };
×
206
            self.vhost_dev.set_virtq_err(&VirtqFile {
×
207
                index: index as u32,
×
208
                fd: err_fd.as_raw_fd(),
×
209
            })?;
210
            active_mio.poll.registry().register(
×
211
                &mut SourceFd(&err_fd.as_raw_fd()),
×
212
                Token(index as _),
×
213
                Interest::READABLE,
×
214
            )?;
215
            *fd = Some(err_fd);
×
216
        }
217
        self.vhost_dev.vsock_set_running(true)?;
×
218
        Ok(())
×
219
    }
220

UNCOV
221
    fn reset(&mut self, registry: &Registry) {
UNCOV
222
        self.vhost_dev.vsock_set_running(false).unwrap();
UNCOV
223
        for (index, error_fd) in self.error_fds.iter_mut().enumerate() {
UNCOV
224
            let Some(err_fd) = error_fd else {
UNCOV
225
                continue;
226
            };
UNCOV
227
            self.vhost_dev
UNCOV
228
                .set_virtq_err(&VirtqFile {
UNCOV
229
                    index: index as _,
UNCOV
230
                    fd: VHOST_FILE_UNBIND,
231
                })
232
                .unwrap();
UNCOV
233
            registry
UNCOV
234
                .deregister(&mut SourceFd(&err_fd.as_raw_fd()))
235
                .unwrap();
UNCOV
236
            *error_fd = None;
237
        }
238
    }
239

UNCOV
240
    fn handle_event<'a, 'm, Q, S, E>(
241
        &mut self,
242
        event: &Event,
243
        _active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,
244
    ) -> Result<()>
245
    where
246
        Q: VirtQueue<'m>,
247
        S: IrqSender,
248
        E: IoeventFd,
249
    {
250
        let q_index = event.token();
×
251
        error::VhostQueueErr {
252
            dev: "vsock",
253
            index: q_index.0 as u16,
×
254
        }
255
        .fail()?;
256
        Ok(())
×
257
    }
258

UNCOV
259
    fn handle_queue<'m, Q, S, E>(
260
        &mut self,
261
        index: u16,
262
        _active_mio: &mut ActiveMio<'_, '_, 'm, Q, S, E>,
263
    ) -> Result<()>
264
    where
265
        Q: VirtQueue<'m>,
266
        S: IrqSender,
267
        E: IoeventFd,
268
    {
269
        match index {
×
270
            0 | 1 => unreachable!("{}: queue 0 and 1 are offloaded to kernel", self.name),
271
            2 => log::info!("{}: event queue buffer available", self.name),
×
272
            _ => unreachable!(),
273
        }
274
        Ok(())
×
275
    }
276
}
277

278
impl Drop for VhostVsock {
UNCOV
279
    fn drop(&mut self) {
UNCOV
280
        let ret = self.vhost_dev.vsock_set_running(false);
UNCOV
281
        if let Err(e) = ret {
UNCOV
282
            log::error!("{}: {e}", self.name)
283
        }
284
    }
285
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc