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