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