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