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