1 // Copyright 2017 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::fs::File; 6 use std::fs::OpenOptions; 7 use std::marker::PhantomData; 8 use std::os::unix::fs::OpenOptionsExt; 9 use std::path::Path; 10 11 use base::ioctl_with_ref; 12 use base::AsRawDescriptor; 13 use base::RawDescriptor; 14 use net_util::TapT; 15 16 use super::ioctl_result; 17 use super::Error; 18 use super::Result; 19 use super::Vhost; 20 21 /// Handle to run VHOST_NET ioctls. 22 /// 23 /// This provides a simple wrapper around a VHOST_NET file descriptor and 24 /// methods that safely run ioctls on that file descriptor. 25 pub struct Net<T> { 26 // descriptor must be dropped first, which will stop and tear down the 27 // vhost-net worker before GuestMemory can potentially be unmapped. 28 descriptor: File, 29 phantom: PhantomData<T>, 30 } 31 32 pub trait NetT<T: TapT>: Vhost + AsRawDescriptor + Send + Sized { 33 /// Create a new NetT instance new(vhost_net_device_path: &Path) -> Result<Self>34 fn new(vhost_net_device_path: &Path) -> Result<Self>; 35 36 /// Set the tap file descriptor that will serve as the VHOST_NET backend. 37 /// This will start the vhost worker for the given queue. 38 /// 39 /// # Arguments 40 /// * `queue_index` - Index of the queue to modify. 41 /// * `descriptor` - Tap interface that will be used as the backend. set_backend(&self, queue_index: usize, descriptor: Option<&T>) -> Result<()>42 fn set_backend(&self, queue_index: usize, descriptor: Option<&T>) -> Result<()>; 43 } 44 45 impl<T> NetT<T> for Net<T> 46 where 47 T: TapT, 48 { 49 /// Opens /dev/vhost-net and holds a file descriptor open for it. 50 /// 51 /// # Arguments 52 /// * `mem` - Guest memory mapping. new(vhost_net_device_path: &Path) -> Result<Net<T>>53 fn new(vhost_net_device_path: &Path) -> Result<Net<T>> { 54 Ok(Net::<T> { 55 descriptor: OpenOptions::new() 56 .read(true) 57 .write(true) 58 .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK) 59 .open(vhost_net_device_path) 60 .map_err(Error::VhostOpen)?, 61 phantom: PhantomData, 62 }) 63 } 64 set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()>65 fn set_backend(&self, queue_index: usize, event: Option<&T>) -> Result<()> { 66 let vring_file = virtio_sys::vhost::vhost_vring_file { 67 index: queue_index as u32, 68 fd: event.map_or(-1, |event| event.as_raw_descriptor()), 69 }; 70 71 // SAFETY: 72 // This ioctl is called on a valid vhost_net descriptor and has its 73 // return value checked. 74 let ret = unsafe { 75 ioctl_with_ref( 76 &self.descriptor, 77 virtio_sys::VHOST_NET_SET_BACKEND, 78 &vring_file, 79 ) 80 }; 81 if ret < 0 { 82 return ioctl_result(); 83 } 84 Ok(()) 85 } 86 } 87 88 impl<T> Vhost for Net<T> {} 89 90 impl<T> AsRawDescriptor for Net<T> { as_raw_descriptor(&self) -> RawDescriptor91 fn as_raw_descriptor(&self) -> RawDescriptor { 92 self.descriptor.as_raw_descriptor() 93 } 94 } 95 96 pub mod fakes { 97 use std::fs::remove_file; 98 use std::fs::OpenOptions; 99 100 use super::*; 101 102 const TMP_FILE: &str = "/tmp/crosvm_vhost_test_file"; 103 104 pub struct FakeNet<T> { 105 descriptor: File, 106 phantom: PhantomData<T>, 107 } 108 109 impl<T> Drop for FakeNet<T> { drop(&mut self)110 fn drop(&mut self) { 111 let _ = remove_file(TMP_FILE); 112 } 113 } 114 115 impl<T> NetT<T> for FakeNet<T> 116 where 117 T: TapT, 118 { new(_vhost_net_device_path: &Path) -> Result<FakeNet<T>>119 fn new(_vhost_net_device_path: &Path) -> Result<FakeNet<T>> { 120 Ok(FakeNet::<T> { 121 descriptor: OpenOptions::new() 122 .read(true) 123 .append(true) 124 .create(true) 125 .open(TMP_FILE) 126 .unwrap(), 127 phantom: PhantomData, 128 }) 129 } 130 set_backend(&self, _queue_index: usize, _fd: Option<&T>) -> Result<()>131 fn set_backend(&self, _queue_index: usize, _fd: Option<&T>) -> Result<()> { 132 Ok(()) 133 } 134 } 135 136 impl<T> Vhost for FakeNet<T> {} 137 138 impl<T> AsRawDescriptor for FakeNet<T> { as_raw_descriptor(&self) -> RawDescriptor139 fn as_raw_descriptor(&self) -> RawDescriptor { 140 self.descriptor.as_raw_descriptor() 141 } 142 } 143 } 144