18个版本 (破坏性)
0.15.0 | 2024年4月15日 |
---|---|
0.14.0 | 2024年3月15日 |
0.13.1 | 2024年1月16日 |
0.11.0 | 2023年11月7日 |
0.1.0 | 2021年12月22日 |
205 在 HTTP服务器
每月15,242 次下载
用于 12 crate
455KB
9K SLoC
vhost-user-backend
设计
vhost-user-backend
crate提供了一个框架来实现vhost-user
后端服务,包括以下外部公共API
- 守护进程控制对象(
VhostUserDaemon
),用于启动和停止服务守护进程。 - 处理vhost-user控制消息和virtio消息的vhost-user后端trait(
VhostUserBackendMut
)。 - 访问virtio队列的vring访问trait(
VringT
),以及该trait的三个实现:VringState,
VringMutex和
VringRwLock
。
用法
vhost-user-backend
crate提供了一个框架来实现vhost-user后端服务。由vhost-user-backend
库提供的主要接口是struct VhostUserDaemon
pub struct VhostUserDaemon<S, V, B = ()>
where
S: VhostUserBackend<V, B>,
V: VringT<GM<B>> + Clone + Send + Sync + 'static,
B: Bitmap + 'static,
{
pub fn new(name: String, backend: S, atomic_mem: GuestMemoryAtomic<GuestMemoryMmap<B>>) -> Result<Self>;
pub fn start(&mut self, listener: Listener) -> Result<()>;
pub fn wait(&mut self) -> Result<()>;
pub fn get_epoll_handlers(&self) -> Vec<Arc<VringEpollHandler<S, V, B>>>;
}
创建一个VhostUserDaemon
实例
VhostUserDaemon::new()
函数创建了一个VhostUserDaemon
对象的实例。客户端需要传递一个VhostUserBackend
对象,该对象将被用于配置VhostUserDaemon
实例、处理来自vhost-user前端的控制消息和处理来自virtio队列的virtio请求。将创建一组工作线程来处理来自已配置virtio队列的virtio请求。
启动VhostUserDaemon
VhostUserDaemon::start()
方法等待在listener
上来自vhost-user前端的新连接。一旦连接就绪,将创建一个主线程来处理来自vhost-user前端的消息。
停止VhostUserDaemon
VhostUserDaemon::stop()
方法等待主线程退出。在等待它退出之前,必须向主线程发送一个退出事件,通过向exit_event
EventFd写入。
线程模型
主线程和virtio队列工作线程将并发访问底层virtio队列,因此在多线程模型中,所有virtio队列。但是主线程只访问virtio队列进行配置,因此客户端可以采用锁定策略来优化virtio队列工作线程。
示例
处理来自virtio队列的virtio消息的示例代码
impl VhostUserBackendMut for VhostUserService {
fn process_queue(&mut self, vring: &VringMutex) -> Result<bool> {
let mut used_any = false;
let mem = match &self.mem {
Some(m) => m.memory(),
None => return Err(Error::NoMemoryConfigured),
};
let mut vring_state = vring.get_mut();
while let Some(avail_desc) = vring_state
.get_queue_mut()
.iter()
.map_err(|_| Error::IterateQueue)?
.next()
{
// Process the request...
if self.event_idx {
if vring_state.add_used(head_index, 0).is_err() {
warn!("Couldn't return used descriptors to the ring");
}
match vring_state.needs_notification() {
Err(_) => {
warn!("Couldn't check if queue needs to be notified");
vring_state.signal_used_queue().unwrap();
}
Ok(needs_notification) => {
if needs_notification {
vring_state.signal_used_queue().unwrap();
}
}
}
} else {
if vring_state.add_used(head_index, 0).is_err() {
warn!("Couldn't return used descriptors to the ring");
}
vring_state.signal_used_queue().unwrap();
}
}
Ok(used_any)
}
}
Postcopy支持
要启用POSTCOPY_*消息支持,有一个postcopy
功能。由于Xen处理内存映射的方式,postcopy
功能与xen
功能不兼容。同时启用两者将导致编译错误。
postcopy
功能启用可选的userfaultfd
依赖项,以便创建和与userfaultfd
对象交互。这需要从后端访问/dev/userfaultfd
文件的权限。
Xen支持
支持Xen在映射虚拟机内存时需要特殊处理。vm-memory
库通过一个单独的功能xen
实现了xen内存映射支持,并且该库使用相同的功能名称来启用Xen支持。
此外,对于xen映射,前端传递的内存区域包含一些额外字段,如vhost-user协议文档所述。
由rust-vmm
维护者决定保持接口简单,并为标准Unix内存映射或Xen构建库,而不是两者都构建。
许可证
本项目采用
- Apache License,版本2.0
依赖关系
~1.6–3.5MB
~54K SLoC