File: README.md

package info (click to toggle)
rust-vhost-user-backend 0.17.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 272 kB
  • sloc: makefile: 2
file content (127 lines) | stat: -rw-r--r-- 5,182 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# vhost-user-backend

## Design

The `vhost-user-backend` crate provides a framework to implement `vhost-user` backend services,
which includes following external public APIs:
- A daemon control object (`VhostUserDaemon`) to start and stop the service daemon.
- A vhost-user backend trait (`VhostUserBackendMut`) to handle vhost-user control messages and virtio
  messages.
- A vring access trait (`VringT`) to access virtio queues, and three implementations of the trait:
  `VringState`, `VringMutex` and `VringRwLock`.

## Usage
The `vhost-user-backend` crate provides a framework to implement vhost-user backend services. The main interface provided by `vhost-user-backend` library is the `struct VhostUserDaemon`:
```rust
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>>>;
}
```

### Create a `VhostUserDaemon` Instance
The `VhostUserDaemon::new()` creates an instance of `VhostUserDaemon` object. The client needs to
pass in an `VhostUserBackend` object, which will be used to configure the `VhostUserDaemon`
instance, handle control messages from the vhost-user frontend and handle virtio requests from
virtio queues. A group of working threads will be created to handle virtio requests from configured
virtio queues.

### Start the `VhostUserDaemon`
The `VhostUserDaemon::start()` method waits for an incoming connection from the vhost-user frontends
on the `listener`. Once a connection is ready, a main thread will be created to handle vhost-user
messages from the vhost-user frontend.

### Stop the `VhostUserDaemon`
The `VhostUserDaemon::stop()` method waits for the main thread to exit. An exit event must be sent
to the main thread by writing to the `exit_event` EventFd before waiting for it to exit.

### Threading Model
The main thread and virtio queue working threads will concurrently access the underlying virtio
queues, so all virtio queue in multi-threading model. But the main thread only accesses virtio
queues for configuration, so client could adopt locking policies to optimize for the virtio queue
working threads.

## Example
Example code to handle virtio messages from a virtio queue:
```rust
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 support

To enabled POSTCOPY_* messages support there is a `postcopy` feature.
Due to how Xen handles memory mappings the `postcopy` feature is not compatible
with `xen` feature. Enabling both at the same time will result in a compilation error.

`postcopy` feature enables optional `userfaultfd` dependency in order to create and
interact with `userfaultfd` object. This requires access permission to `/dev/userfaultfd`
file from the backend.

## Xen support

Supporting Xen requires special handling while mapping the guest memory. The
`vm-memory` crate implements xen memory mapping support via a separate feature
`xen`, and this crate uses the same feature name to enable Xen support.

Also, for xen mappings, the memory regions passed by the frontend contains few
extra fields as described in the vhost-user protocol documentation.

It was decided by the `rust-vmm` maintainers to keep the interface simple and
build the crate for either standard Unix memory mapping or Xen, and not both.

## License

This project is licensed under

- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0