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; 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::{GuestMemoryMmap, VhostUserBackend, VhostUserDaemon, Vring, VringWorker}; 26 use virtio_bindings::bindings::virtio_net::*; 27 use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; 28 use vm_memory::GuestMemoryAtomic; 29 use vmm_sys_util::eventfd::EventFd; 30 31 pub type Result<T> = std::result::Result<T, Error>; 32 type VhostUserBackendResult<T> = std::result::Result<T, std::io::Error>; 33 34 #[derive(Debug)] 35 pub enum Error { 36 /// Failed to create kill eventfd 37 CreateKillEventFd(io::Error), 38 /// Failed to parse configuration string 39 FailedConfigParse(OptionParserError), 40 /// Failed to signal used queue. 41 FailedSignalingUsedQueue(io::Error), 42 /// Failed to handle event other than input event. 43 HandleEventNotEpollIn, 44 /// Failed to handle unknown event. 45 HandleEventUnknownEvent, 46 /// Open tap device failed. 47 OpenTap(OpenTapError), 48 /// No socket provided 49 SocketParameterMissing, 50 /// Underlying QueuePair error 51 NetQueuePair(net_util::NetQueuePairError), 52 /// Failed registering the TAP listener 53 RegisterTapListener(io::Error), 54 } 55 56 pub const SYNTAX: &str = "vhost-user-net backend parameters \ 57 \"ip=<ip_addr>,mask=<net_mask>,socket=<socket_path>,client=on|off,\ 58 num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,tap=<if_name>\""; 59 60 impl fmt::Display for Error { 61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 62 write!(f, "vhost_user_net_error: {:?}", self) 63 } 64 } 65 66 impl std::error::Error for Error {} 67 68 impl std::convert::From<Error> for std::io::Error { 69 fn from(e: Error) -> Self { 70 std::io::Error::new(io::ErrorKind::Other, e) 71 } 72 } 73 74 struct VhostUserNetThread { 75 net: NetQueuePair, 76 kill_evt: EventFd, 77 } 78 79 impl VhostUserNetThread { 80 /// Create a new virtio network device with the given TAP interface. 81 fn new(tap: Tap) -> Result<Self> { 82 Ok(VhostUserNetThread { 83 kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?, 84 net: NetQueuePair { 85 mem: None, 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: 2, 95 tap_tx_event_id: 3, 96 rx_desc_avail: false, 97 rx_rate_limiter: None, 98 tx_rate_limiter: None, 99 }, 100 }) 101 } 102 103 pub fn set_vring_worker(&mut self, vring_worker: Option<Arc<VringWorker>>) { 104 self.net.epoll_fd = Some(vring_worker.as_ref().unwrap().as_raw_fd()); 105 } 106 } 107 108 pub struct VhostUserNetBackend { 109 threads: Vec<Mutex<VhostUserNetThread>>, 110 num_queues: usize, 111 queue_size: u16, 112 queues_per_thread: Vec<u64>, 113 } 114 115 impl VhostUserNetBackend { 116 fn new( 117 ip_addr: Ipv4Addr, 118 host_mac: MacAddr, 119 netmask: Ipv4Addr, 120 num_queues: usize, 121 queue_size: u16, 122 ifname: Option<&str>, 123 ) -> Result<Self> { 124 let mut taps = open_tap( 125 ifname, 126 Some(ip_addr), 127 Some(netmask), 128 &mut Some(host_mac), 129 num_queues / 2, 130 None, 131 ) 132 .map_err(Error::OpenTap)?; 133 134 let mut queues_per_thread = Vec::new(); 135 let mut threads = Vec::new(); 136 for (i, tap) in taps.drain(..).enumerate() { 137 let thread = Mutex::new(VhostUserNetThread::new(tap)?); 138 threads.push(thread); 139 queues_per_thread.push(0b11 << (i * 2)); 140 } 141 142 Ok(VhostUserNetBackend { 143 threads, 144 num_queues, 145 queue_size, 146 queues_per_thread, 147 }) 148 } 149 } 150 151 impl VhostUserBackend for VhostUserNetBackend { 152 fn num_queues(&self) -> usize { 153 self.num_queues 154 } 155 156 fn max_queue_size(&self) -> usize { 157 self.queue_size as usize 158 } 159 160 fn features(&self) -> u64 { 161 1 << VIRTIO_NET_F_GUEST_CSUM 162 | 1 << VIRTIO_NET_F_CSUM 163 | 1 << VIRTIO_NET_F_GUEST_TSO4 164 | 1 << VIRTIO_NET_F_GUEST_TSO6 165 | 1 << VIRTIO_NET_F_GUEST_ECN 166 | 1 << VIRTIO_NET_F_GUEST_UFO 167 | 1 << VIRTIO_NET_F_HOST_TSO4 168 | 1 << VIRTIO_NET_F_HOST_TSO6 169 | 1 << VIRTIO_NET_F_HOST_ECN 170 | 1 << VIRTIO_NET_F_HOST_UFO 171 | 1 << VIRTIO_NET_F_MRG_RXBUF 172 | 1 << VIRTIO_NET_F_CTRL_VQ 173 | 1 << VIRTIO_NET_F_MQ 174 | 1 << VIRTIO_NET_F_MAC 175 | 1 << VIRTIO_F_NOTIFY_ON_EMPTY 176 | 1 << VIRTIO_F_VERSION_1 177 | 1 << VIRTIO_RING_F_EVENT_IDX 178 | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() 179 } 180 181 fn protocol_features(&self) -> VhostUserProtocolFeatures { 182 VhostUserProtocolFeatures::MQ 183 | VhostUserProtocolFeatures::REPLY_ACK 184 | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS 185 } 186 187 fn set_event_idx(&mut self, _enabled: bool) {} 188 189 fn update_memory(&mut self, mem: GuestMemoryMmap) -> VhostUserBackendResult<()> { 190 for thread in self.threads.iter() { 191 thread.lock().unwrap().net.mem = Some(GuestMemoryAtomic::new(mem.clone())); 192 } 193 Ok(()) 194 } 195 196 fn handle_event( 197 &self, 198 device_event: u16, 199 _evset: epoll::Events, 200 vrings: &[Arc<RwLock<Vring>>], 201 thread_id: usize, 202 ) -> VhostUserBackendResult<bool> { 203 let mut thread = self.threads[thread_id].lock().unwrap(); 204 match device_event { 205 0 => { 206 if !thread.net.rx_tap_listening { 207 net_util::register_listener( 208 thread.net.epoll_fd.unwrap(), 209 thread.net.tap.as_raw_fd(), 210 epoll::Events::EPOLLIN, 211 u64::from(thread.net.tap_rx_event_id), 212 ) 213 .map_err(Error::RegisterTapListener)?; 214 thread.net.rx_tap_listening = true; 215 } 216 } 217 1 | 3 => { 218 let mut vring = vrings[1].write().unwrap(); 219 if thread 220 .net 221 .process_tx(&mut vring.mut_queue()) 222 .map_err(Error::NetQueuePair)? 223 { 224 vring 225 .signal_used_queue() 226 .map_err(Error::FailedSignalingUsedQueue)? 227 } 228 } 229 2 => { 230 let mut vring = vrings[0].write().unwrap(); 231 if thread 232 .net 233 .process_rx(&mut vring.mut_queue()) 234 .map_err(Error::NetQueuePair)? 235 { 236 vring 237 .signal_used_queue() 238 .map_err(Error::FailedSignalingUsedQueue)? 239 } 240 } 241 _ => return Err(Error::HandleEventUnknownEvent.into()), 242 } 243 244 Ok(false) 245 } 246 247 fn exit_event(&self, thread_index: usize) -> Option<(EventFd, Option<u16>)> { 248 // The exit event is placed after the queues and the tap event, which 249 // is event index 3. 250 Some(( 251 self.threads[thread_index] 252 .lock() 253 .unwrap() 254 .kill_evt 255 .try_clone() 256 .unwrap(), 257 Some(3), 258 )) 259 } 260 261 fn queues_per_thread(&self) -> Vec<u64> { 262 self.queues_per_thread.clone() 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 = 358 VhostUserDaemon::new("vhost-user-net-backend".to_string(), net_backend.clone()).unwrap(); 359 360 let mut vring_workers = net_daemon.get_vring_workers(); 361 362 if vring_workers.len() != net_backend.read().unwrap().threads.len() { 363 error!("Number of vring workers must be identical to the number of backend threads"); 364 process::exit(1); 365 } 366 367 for thread in net_backend.read().unwrap().threads.iter() { 368 thread 369 .lock() 370 .unwrap() 371 .set_vring_worker(Some(vring_workers.remove(0))); 372 } 373 374 if let Err(e) = if backend_config.client { 375 net_daemon.start_client(&backend_config.socket) 376 } else { 377 net_daemon.start_server(Listener::new(&backend_config.socket, true).unwrap()) 378 } { 379 error!( 380 "failed to start daemon for vhost-user-net with error: {:?}", 381 e 382 ); 383 process::exit(1); 384 } 385 386 if let Err(e) = net_daemon.wait() { 387 error!("Error from the main thread: {:?}", e); 388 } 389 390 for thread in net_backend.read().unwrap().threads.iter() { 391 if let Err(e) = thread.lock().unwrap().kill_evt.write(1) { 392 error!("Error shutting down worker thread: {:?}", e) 393 } 394 } 395 } 396