xref: /cloud-hypervisor/vhost_user_net/src/lib.rs (revision 88a9f799449c04180c6b9a21d3b9c0c4b57e2bd6)
1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 //
3 // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 //
5 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
6 //
7 // SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause)
8 
9 use std::fmt;
10 use std::io;
11 use std::net::Ipv4Addr;
12 use std::ops::Deref;
13 use std::os::unix::io::{AsRawFd, RawFd};
14 use std::process;
15 use std::sync::{Arc, Mutex, RwLock};
16 
17 use libc::EFD_NONBLOCK;
18 use log::*;
19 use net_util::{
20     open_tap, MacAddr, NetCounters, NetQueuePair, OpenTapError, RxVirtio, Tap, TxVirtio,
21 };
22 use option_parser::Toggle;
23 use option_parser::{OptionParser, OptionParserError};
24 use vhost::vhost_user::message::*;
25 use vhost::vhost_user::Listener;
26 use vhost_user_backend::bitmap::BitmapMmapRegion;
27 use vhost_user_backend::{VhostUserBackendMut, VhostUserDaemon, VringRwLock, VringT};
28 use virtio_bindings::virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1};
29 use virtio_bindings::virtio_net::*;
30 use vm_memory::GuestAddressSpace;
31 use vm_memory::GuestMemoryAtomic;
32 use vmm_sys_util::{epoll::EventSet, eventfd::EventFd};
33 
34 type GuestMemoryMmap = vm_memory::GuestMemoryMmap<BitmapMmapRegion>;
35 
36 pub type Result<T> = std::result::Result<T, Error>;
37 type VhostUserBackendResult<T> = std::result::Result<T, std::io::Error>;
38 
39 #[derive(Debug)]
40 pub enum Error {
41     /// Failed to create kill eventfd.
42     CreateKillEventFd(io::Error),
43     /// Failed to parse configuration string.
44     FailedConfigParse(OptionParserError),
45     /// Failed to signal used queue.
46     FailedSignalingUsedQueue(io::Error),
47     /// Failed to handle event other than input event.
48     HandleEventNotEpollIn,
49     /// Failed to handle unknown event.
50     HandleEventUnknownEvent,
51     /// Failed to open tap device.
52     OpenTap(OpenTapError),
53     /// No socket provided.
54     SocketParameterMissing,
55     /// Underlying QueuePair error.
56     NetQueuePair(net_util::NetQueuePairError),
57     /// Failed to register the TAP listener.
58     RegisterTapListener(io::Error),
59 }
60 
61 pub const SYNTAX: &str = "vhost-user-net backend parameters \
62 \"ip=<ip_addr>,mask=<net_mask>,socket=<socket_path>,client=on|off,\
63 num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,tap=<if_name>\"";
64 
65 impl fmt::Display for Error {
66     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67         write!(f, "vhost_user_net_error: {self:?}")
68     }
69 }
70 
71 impl std::error::Error for Error {}
72 
73 impl std::convert::From<Error> for std::io::Error {
74     fn from(e: Error) -> Self {
75         std::io::Error::new(io::ErrorKind::Other, e)
76     }
77 }
78 
79 struct VhostUserNetThread {
80     net: NetQueuePair,
81     kill_evt: EventFd,
82 }
83 
84 impl VhostUserNetThread {
85     /// Create a new virtio network device with the given TAP interface.
86     fn new(tap: Tap) -> Result<Self> {
87         Ok(VhostUserNetThread {
88             kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?,
89             net: NetQueuePair {
90                 tap_for_write_epoll: tap.clone(),
91                 tap,
92                 rx: RxVirtio::new(),
93                 tx: TxVirtio::new(),
94                 rx_tap_listening: false,
95                 tx_tap_listening: false,
96                 epoll_fd: None,
97                 counters: NetCounters::default(),
98                 tap_rx_event_id: 3,
99                 tap_tx_event_id: 4,
100                 rx_desc_avail: false,
101                 rx_rate_limiter: None,
102                 tx_rate_limiter: None,
103                 access_platform: None,
104             },
105         })
106     }
107 
108     pub fn set_epoll_fd(&mut self, fd: RawFd) {
109         self.net.epoll_fd = Some(fd);
110     }
111 }
112 
113 pub struct VhostUserNetBackend {
114     threads: Vec<Mutex<VhostUserNetThread>>,
115     num_queues: usize,
116     queue_size: u16,
117     queues_per_thread: Vec<u64>,
118     mem: GuestMemoryAtomic<GuestMemoryMmap>,
119 }
120 
121 impl VhostUserNetBackend {
122     #[allow(clippy::too_many_arguments)]
123     fn new(
124         ip_addr: Ipv4Addr,
125         host_mac: MacAddr,
126         netmask: Ipv4Addr,
127         mtu: Option<u16>,
128         num_queues: usize,
129         queue_size: u16,
130         ifname: Option<&str>,
131         mem: GuestMemoryAtomic<GuestMemoryMmap>,
132     ) -> Result<Self> {
133         let mut taps = open_tap(
134             ifname,
135             Some(ip_addr),
136             Some(netmask),
137             &mut Some(host_mac),
138             mtu,
139             num_queues / 2,
140             None,
141         )
142         .map_err(Error::OpenTap)?;
143 
144         let mut queues_per_thread = Vec::new();
145         let mut threads = Vec::new();
146         for (i, tap) in taps.drain(..).enumerate() {
147             let thread = Mutex::new(VhostUserNetThread::new(tap)?);
148             threads.push(thread);
149             queues_per_thread.push(0b11 << (i * 2));
150         }
151 
152         Ok(VhostUserNetBackend {
153             threads,
154             num_queues,
155             queue_size,
156             queues_per_thread,
157             mem,
158         })
159     }
160 }
161 
162 impl VhostUserBackendMut for VhostUserNetBackend {
163     type Bitmap = BitmapMmapRegion;
164     type Vring = VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>;
165 
166     fn num_queues(&self) -> usize {
167         self.num_queues
168     }
169 
170     fn max_queue_size(&self) -> usize {
171         self.queue_size as usize
172     }
173 
174     fn features(&self) -> u64 {
175         1 << VIRTIO_NET_F_GUEST_CSUM
176             | 1 << VIRTIO_NET_F_CSUM
177             | 1 << VIRTIO_NET_F_GUEST_TSO4
178             | 1 << VIRTIO_NET_F_GUEST_TSO6
179             | 1 << VIRTIO_NET_F_GUEST_ECN
180             | 1 << VIRTIO_NET_F_GUEST_UFO
181             | 1 << VIRTIO_NET_F_HOST_TSO4
182             | 1 << VIRTIO_NET_F_HOST_TSO6
183             | 1 << VIRTIO_NET_F_HOST_ECN
184             | 1 << VIRTIO_NET_F_HOST_UFO
185             | 1 << VIRTIO_NET_F_CTRL_VQ
186             | 1 << VIRTIO_NET_F_MQ
187             | 1 << VIRTIO_NET_F_MAC
188             | 1 << VIRTIO_NET_F_MTU
189             | 1 << VIRTIO_F_NOTIFY_ON_EMPTY
190             | 1 << VIRTIO_F_VERSION_1
191             | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
192     }
193 
194     fn protocol_features(&self) -> VhostUserProtocolFeatures {
195         VhostUserProtocolFeatures::MQ
196             | VhostUserProtocolFeatures::REPLY_ACK
197             | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS
198     }
199 
200     fn set_event_idx(&mut self, _enabled: bool) {}
201 
202     fn handle_event(
203         &mut self,
204         device_event: u16,
205         _evset: EventSet,
206         vrings: &[VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>],
207         thread_id: usize,
208     ) -> VhostUserBackendResult<()> {
209         let mut thread = self.threads[thread_id].lock().unwrap();
210         match device_event {
211             0 => {
212                 if !thread.net.rx_tap_listening {
213                     net_util::register_listener(
214                         thread.net.epoll_fd.unwrap(),
215                         thread.net.tap.as_raw_fd(),
216                         epoll::Events::EPOLLIN,
217                         u64::from(thread.net.tap_rx_event_id),
218                     )
219                     .map_err(Error::RegisterTapListener)?;
220                     thread.net.rx_tap_listening = true;
221                 }
222             }
223             1 | 4 => {
224                 let mut vring = vrings[1].get_mut();
225                 if thread
226                     .net
227                     .process_tx(self.mem.memory().deref(), vring.get_queue_mut())
228                     .map_err(Error::NetQueuePair)?
229                 {
230                     vring
231                         .signal_used_queue()
232                         .map_err(Error::FailedSignalingUsedQueue)?
233                 }
234             }
235             3 => {
236                 let mut vring = vrings[0].get_mut();
237                 if thread
238                     .net
239                     .process_rx(self.mem.memory().deref(), vring.get_queue_mut())
240                     .map_err(Error::NetQueuePair)?
241                 {
242                     vring
243                         .signal_used_queue()
244                         .map_err(Error::FailedSignalingUsedQueue)?
245                 }
246             }
247             _ => return Err(Error::HandleEventUnknownEvent.into()),
248         }
249 
250         Ok(())
251     }
252 
253     fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
254         Some(
255             self.threads[thread_index]
256                 .lock()
257                 .unwrap()
258                 .kill_evt
259                 .try_clone()
260                 .unwrap(),
261         )
262     }
263 
264     fn queues_per_thread(&self) -> Vec<u64> {
265         self.queues_per_thread.clone()
266     }
267 
268     fn update_memory(
269         &mut self,
270         _mem: GuestMemoryAtomic<GuestMemoryMmap>,
271     ) -> VhostUserBackendResult<()> {
272         Ok(())
273     }
274 }
275 
276 pub struct VhostUserNetBackendConfig {
277     pub ip: Ipv4Addr,
278     pub host_mac: MacAddr,
279     pub mask: Ipv4Addr,
280     pub mtu: Option<u16>,
281     pub socket: String,
282     pub num_queues: usize,
283     pub queue_size: u16,
284     pub tap: Option<String>,
285     pub client: bool,
286 }
287 
288 impl VhostUserNetBackendConfig {
289     pub fn parse(backend: &str) -> Result<Self> {
290         let mut parser = OptionParser::new();
291 
292         parser
293             .add("tap")
294             .add("ip")
295             .add("host_mac")
296             .add("mask")
297             .add("mtu")
298             .add("queue_size")
299             .add("num_queues")
300             .add("socket")
301             .add("client");
302 
303         parser.parse(backend).map_err(Error::FailedConfigParse)?;
304 
305         let tap = parser.get("tap");
306         let ip = parser
307             .convert("ip")
308             .map_err(Error::FailedConfigParse)?
309             .unwrap_or_else(|| Ipv4Addr::new(192, 168, 100, 1));
310         let host_mac = parser
311             .convert("host_mac")
312             .map_err(Error::FailedConfigParse)?
313             .unwrap_or_else(MacAddr::local_random);
314         let mask = parser
315             .convert("mask")
316             .map_err(Error::FailedConfigParse)?
317             .unwrap_or_else(|| Ipv4Addr::new(255, 255, 255, 0));
318         let mtu = parser.convert("mtu").map_err(Error::FailedConfigParse)?;
319         let queue_size = parser
320             .convert("queue_size")
321             .map_err(Error::FailedConfigParse)?
322             .unwrap_or(256);
323         let num_queues = parser
324             .convert("num_queues")
325             .map_err(Error::FailedConfigParse)?
326             .unwrap_or(2);
327         let socket = parser.get("socket").ok_or(Error::SocketParameterMissing)?;
328         let client = parser
329             .convert::<Toggle>("client")
330             .map_err(Error::FailedConfigParse)?
331             .unwrap_or(Toggle(false))
332             .0;
333 
334         Ok(VhostUserNetBackendConfig {
335             ip,
336             host_mac,
337             mask,
338             mtu,
339             socket,
340             num_queues,
341             queue_size,
342             tap,
343             client,
344         })
345     }
346 }
347 
348 pub fn start_net_backend(backend_command: &str) {
349     let backend_config = match VhostUserNetBackendConfig::parse(backend_command) {
350         Ok(config) => config,
351         Err(e) => {
352             eprintln!("Failed parsing parameters {e:?}");
353             process::exit(1);
354         }
355     };
356 
357     let tap = backend_config.tap.as_deref();
358 
359     let mem = GuestMemoryAtomic::new(GuestMemoryMmap::new());
360 
361     let net_backend = Arc::new(RwLock::new(
362         VhostUserNetBackend::new(
363             backend_config.ip,
364             backend_config.host_mac,
365             backend_config.mask,
366             backend_config.mtu,
367             backend_config.num_queues,
368             backend_config.queue_size,
369             tap,
370             mem.clone(),
371         )
372         .unwrap(),
373     ));
374 
375     let mut net_daemon = VhostUserDaemon::new(
376         "vhost-user-net-backend".to_string(),
377         net_backend.clone(),
378         mem,
379     )
380     .unwrap();
381 
382     let epoll_handlers = net_daemon.get_epoll_handlers();
383     if epoll_handlers.len() != net_backend.read().unwrap().threads.len() {
384         error!("Number of vring workers must be identical to the number of backend threads");
385         process::exit(1);
386     }
387 
388     for (index, thread) in net_backend.read().unwrap().threads.iter().enumerate() {
389         thread
390             .lock()
391             .unwrap()
392             .set_epoll_fd(epoll_handlers[index].as_raw_fd());
393     }
394 
395     if let Err(e) = if backend_config.client {
396         net_daemon.start_client(&backend_config.socket)
397     } else {
398         net_daemon.start(Listener::new(&backend_config.socket, true).unwrap())
399     } {
400         error!(
401             "failed to start daemon for vhost-user-net with error: {:?}",
402             e
403         );
404         process::exit(1);
405     }
406 
407     if let Err(e) = net_daemon.wait() {
408         error!("Error from the main thread: {:?}", e);
409     }
410 
411     for thread in net_backend.read().unwrap().threads.iter() {
412         if let Err(e) = thread.lock().unwrap().kill_evt.write(1) {
413             error!("Error shutting down worker thread: {:?}", e)
414         }
415     }
416 }
417