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 libc::{self, EFD_NONBLOCK}; 10 use log::*; 11 use net_util::{ 12 open_tap, MacAddr, NetCounters, NetQueuePair, OpenTapError, RxVirtio, Tap, TxVirtio, 13 }; 14 use option_parser::Toggle; 15 use option_parser::{OptionParser, OptionParserError}; 16 use std::fmt; 17 use std::io; 18 use std::net::Ipv4Addr; 19 use std::ops::Deref; 20 use std::os::unix::io::{AsRawFd, RawFd}; 21 use std::process; 22 use std::sync::{Arc, Mutex, RwLock}; 23 use std::vec::Vec; 24 use vhost::vhost_user::message::*; 25 use vhost::vhost_user::Listener; 26 use vhost_user_backend::{VhostUserBackendMut, VhostUserDaemon, VringRwLock, VringT}; 27 use virtio_bindings::bindings::virtio_net::*; 28 use vm_memory::GuestAddressSpace; 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 mem: GuestMemoryAtomic<GuestMemoryMmap>, 117 } 118 119 impl VhostUserNetBackend { 120 #[allow(clippy::too_many_arguments)] 121 fn new( 122 ip_addr: Ipv4Addr, 123 host_mac: MacAddr, 124 netmask: Ipv4Addr, 125 mtu: Option<u16>, 126 num_queues: usize, 127 queue_size: u16, 128 ifname: Option<&str>, 129 mem: GuestMemoryAtomic<GuestMemoryMmap>, 130 ) -> Result<Self> { 131 let mut taps = open_tap( 132 ifname, 133 Some(ip_addr), 134 Some(netmask), 135 &mut Some(host_mac), 136 mtu, 137 num_queues / 2, 138 None, 139 ) 140 .map_err(Error::OpenTap)?; 141 142 let mut queues_per_thread = Vec::new(); 143 let mut threads = Vec::new(); 144 for (i, tap) in taps.drain(..).enumerate() { 145 let thread = Mutex::new(VhostUserNetThread::new(tap)?); 146 threads.push(thread); 147 queues_per_thread.push(0b11 << (i * 2)); 148 } 149 150 Ok(VhostUserNetBackend { 151 threads, 152 num_queues, 153 queue_size, 154 queues_per_thread, 155 mem, 156 }) 157 } 158 } 159 160 impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, AtomicBitmap> 161 for VhostUserNetBackend 162 { 163 fn num_queues(&self) -> usize { 164 self.num_queues 165 } 166 167 fn max_queue_size(&self) -> usize { 168 self.queue_size as usize 169 } 170 171 fn features(&self) -> u64 { 172 1 << VIRTIO_NET_F_GUEST_CSUM 173 | 1 << VIRTIO_NET_F_CSUM 174 | 1 << VIRTIO_NET_F_GUEST_TSO4 175 | 1 << VIRTIO_NET_F_GUEST_TSO6 176 | 1 << VIRTIO_NET_F_GUEST_ECN 177 | 1 << VIRTIO_NET_F_GUEST_UFO 178 | 1 << VIRTIO_NET_F_HOST_TSO4 179 | 1 << VIRTIO_NET_F_HOST_TSO6 180 | 1 << VIRTIO_NET_F_HOST_ECN 181 | 1 << VIRTIO_NET_F_HOST_UFO 182 | 1 << VIRTIO_NET_F_CTRL_VQ 183 | 1 << VIRTIO_NET_F_MQ 184 | 1 << VIRTIO_NET_F_MAC 185 | 1 << VIRTIO_NET_F_MTU 186 | 1 << VIRTIO_F_NOTIFY_ON_EMPTY 187 | 1 << VIRTIO_F_VERSION_1 188 | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() 189 } 190 191 fn protocol_features(&self) -> VhostUserProtocolFeatures { 192 VhostUserProtocolFeatures::MQ 193 | VhostUserProtocolFeatures::REPLY_ACK 194 | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS 195 } 196 197 fn set_event_idx(&mut self, _enabled: bool) {} 198 199 fn handle_event( 200 &mut self, 201 device_event: u16, 202 _evset: EventSet, 203 vrings: &[VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>], 204 thread_id: usize, 205 ) -> VhostUserBackendResult<bool> { 206 let mut thread = self.threads[thread_id].lock().unwrap(); 207 match device_event { 208 0 => { 209 if !thread.net.rx_tap_listening { 210 net_util::register_listener( 211 thread.net.epoll_fd.unwrap(), 212 thread.net.tap.as_raw_fd(), 213 epoll::Events::EPOLLIN, 214 u64::from(thread.net.tap_rx_event_id), 215 ) 216 .map_err(Error::RegisterTapListener)?; 217 thread.net.rx_tap_listening = true; 218 } 219 } 220 1 | 4 => { 221 let mut vring = vrings[1].get_mut(); 222 if thread 223 .net 224 .process_tx(self.mem.memory().deref(), vring.get_queue_mut()) 225 .map_err(Error::NetQueuePair)? 226 { 227 vring 228 .signal_used_queue() 229 .map_err(Error::FailedSignalingUsedQueue)? 230 } 231 } 232 3 => { 233 let mut vring = vrings[0].get_mut(); 234 if thread 235 .net 236 .process_rx(self.mem.memory().deref(), vring.get_queue_mut()) 237 .map_err(Error::NetQueuePair)? 238 { 239 vring 240 .signal_used_queue() 241 .map_err(Error::FailedSignalingUsedQueue)? 242 } 243 } 244 _ => return Err(Error::HandleEventUnknownEvent.into()), 245 } 246 247 Ok(false) 248 } 249 250 fn exit_event(&self, thread_index: usize) -> Option<EventFd> { 251 Some( 252 self.threads[thread_index] 253 .lock() 254 .unwrap() 255 .kill_evt 256 .try_clone() 257 .unwrap(), 258 ) 259 } 260 261 fn queues_per_thread(&self) -> Vec<u64> { 262 self.queues_per_thread.clone() 263 } 264 265 fn update_memory( 266 &mut self, 267 _mem: GuestMemoryAtomic<GuestMemoryMmap>, 268 ) -> VhostUserBackendResult<()> { 269 Ok(()) 270 } 271 } 272 273 pub struct VhostUserNetBackendConfig { 274 pub ip: Ipv4Addr, 275 pub host_mac: MacAddr, 276 pub mask: Ipv4Addr, 277 pub mtu: Option<u16>, 278 pub socket: String, 279 pub num_queues: usize, 280 pub queue_size: u16, 281 pub tap: Option<String>, 282 pub client: bool, 283 } 284 285 impl VhostUserNetBackendConfig { 286 pub fn parse(backend: &str) -> Result<Self> { 287 let mut parser = OptionParser::new(); 288 289 parser 290 .add("tap") 291 .add("ip") 292 .add("host_mac") 293 .add("mask") 294 .add("mtu") 295 .add("queue_size") 296 .add("num_queues") 297 .add("socket") 298 .add("client"); 299 300 parser.parse(backend).map_err(Error::FailedConfigParse)?; 301 302 let tap = parser.get("tap"); 303 let ip = parser 304 .convert("ip") 305 .map_err(Error::FailedConfigParse)? 306 .unwrap_or_else(|| Ipv4Addr::new(192, 168, 100, 1)); 307 let host_mac = parser 308 .convert("host_mac") 309 .map_err(Error::FailedConfigParse)? 310 .unwrap_or_else(MacAddr::local_random); 311 let mask = parser 312 .convert("mask") 313 .map_err(Error::FailedConfigParse)? 314 .unwrap_or_else(|| Ipv4Addr::new(255, 255, 255, 0)); 315 let mtu = parser.convert("mtu").map_err(Error::FailedConfigParse)?; 316 let queue_size = parser 317 .convert("queue_size") 318 .map_err(Error::FailedConfigParse)? 319 .unwrap_or(256); 320 let num_queues = parser 321 .convert("num_queues") 322 .map_err(Error::FailedConfigParse)? 323 .unwrap_or(2); 324 let socket = parser.get("socket").ok_or(Error::SocketParameterMissing)?; 325 let client = parser 326 .convert::<Toggle>("client") 327 .map_err(Error::FailedConfigParse)? 328 .unwrap_or(Toggle(false)) 329 .0; 330 331 Ok(VhostUserNetBackendConfig { 332 ip, 333 host_mac, 334 mask, 335 mtu, 336 socket, 337 num_queues, 338 queue_size, 339 tap, 340 client, 341 }) 342 } 343 } 344 345 pub fn start_net_backend(backend_command: &str) { 346 let backend_config = match VhostUserNetBackendConfig::parse(backend_command) { 347 Ok(config) => config, 348 Err(e) => { 349 eprintln!("Failed parsing parameters {e:?}"); 350 process::exit(1); 351 } 352 }; 353 354 let tap = backend_config.tap.as_deref(); 355 356 let mem = GuestMemoryAtomic::new(GuestMemoryMmap::new()); 357 358 let net_backend = Arc::new(RwLock::new( 359 VhostUserNetBackend::new( 360 backend_config.ip, 361 backend_config.host_mac, 362 backend_config.mask, 363 backend_config.mtu, 364 backend_config.num_queues, 365 backend_config.queue_size, 366 tap, 367 mem.clone(), 368 ) 369 .unwrap(), 370 )); 371 372 let mut net_daemon = VhostUserDaemon::new( 373 "vhost-user-net-backend".to_string(), 374 net_backend.clone(), 375 mem, 376 ) 377 .unwrap(); 378 379 let epoll_handlers = net_daemon.get_epoll_handlers(); 380 if epoll_handlers.len() != net_backend.read().unwrap().threads.len() { 381 error!("Number of vring workers must be identical to the number of backend threads"); 382 process::exit(1); 383 } 384 385 for (index, thread) in net_backend.read().unwrap().threads.iter().enumerate() { 386 thread 387 .lock() 388 .unwrap() 389 .set_epoll_fd(epoll_handlers[index].as_raw_fd()); 390 } 391 392 if let Err(e) = if backend_config.client { 393 net_daemon.start_client(&backend_config.socket) 394 } else { 395 net_daemon.start(Listener::new(&backend_config.socket, true).unwrap()) 396 } { 397 error!( 398 "failed to start daemon for vhost-user-net with error: {:?}", 399 e 400 ); 401 process::exit(1); 402 } 403 404 if let Err(e) = net_daemon.wait() { 405 error!("Error from the main thread: {:?}", e); 406 } 407 408 for thread in net_backend.read().unwrap().threads.iter() { 409 if let Err(e) = thread.lock().unwrap().kill_evt.write(1) { 410 error!("Error shutting down worker thread: {:?}", e) 411 } 412 } 413 } 414