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