1 // Copyright 2022 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 pub mod handler; 6 7 use std::io::Read; 8 use std::io::Result as IoResult; 9 use std::io::Write; 10 use std::net; 11 use std::os::raw::*; 12 use std::os::windows::io::AsRawHandle; 13 use std::thread; 14 15 use base::info; 16 use base::named_pipes; 17 use base::named_pipes::BlockingMode; 18 use base::named_pipes::FramingMode; 19 use base::named_pipes::OverlappedWrapper; 20 use base::named_pipes::PipeConnection; 21 use base::named_pipes::ReadOverlapped; 22 use base::named_pipes::WriteOverlapped; 23 use base::warn; 24 use base::AsRawDescriptor; 25 use base::Error as SysError; 26 use base::Event; 27 use base::RawDescriptor; 28 use base::ReadNotifier; 29 use cros_async::IntoAsync; 30 use serde::Deserialize; 31 use serde::Serialize; 32 33 use crate::slirp::SlirpError; 34 use crate::slirp::ETHERNET_FRAME_SIZE; 35 use crate::Error; 36 use crate::MacAddress; 37 use crate::Result; 38 use crate::TapT; 39 use crate::TapTCommon; 40 41 // Size of the buffer for packets in transit between the the virtio-net backend & Slirp. 42 pub const SLIRP_BUFFER_SIZE: usize = 1000 * ETHERNET_FRAME_SIZE; 43 44 /// Handle for a pseudo-tap interface backed by libslirp. 45 pub struct Slirp { 46 guest_pipe: PipeConnection, 47 overlapped_wrapper: OverlappedWrapper, 48 slirp_thread: Option<thread::JoinHandle<()>>, 49 } 50 51 impl Slirp { 52 // TODO(nkgold): delete this code path as single process mode is no longer supported. new( shutdown_event: Event, #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] slirp_capture_file: &Option<String>, ) -> Result<Slirp>53 pub fn new( 54 shutdown_event: Event, 55 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] 56 slirp_capture_file: &Option<String>, 57 ) -> Result<Slirp> { 58 let (host_pipe, guest_pipe) = named_pipes::pair_with_buffer_size( 59 &FramingMode::Message, 60 &BlockingMode::Wait, 61 /* timeout= */ 0, 62 SLIRP_BUFFER_SIZE, 63 /* overlapped= */ true, 64 ) 65 .map_err(SysError::from) 66 .map_err(Error::CreateSocket)?; 67 // TODO: (b/188947559): put this in a separate process 68 let slirp_thread; 69 { 70 let slirp_pipe = host_pipe; 71 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] 72 let slirp_capture_file_clone = slirp_capture_file.clone(); 73 slirp_thread = thread::spawn(move || { 74 let disable_access_to_host = !cfg!(feature = "guest-to-host-net-loopback"); 75 76 handler::start_slirp( 77 slirp_pipe, 78 shutdown_event, 79 disable_access_to_host, 80 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] 81 slirp_capture_file_clone, 82 ) 83 .expect("Failed to start slirp"); 84 }); 85 } 86 87 Ok(Slirp { 88 guest_pipe, 89 overlapped_wrapper: OverlappedWrapper::new(true).unwrap(), 90 slirp_thread: Some(slirp_thread), 91 }) 92 } 93 94 /// Instantiate Slirp when running crosvm in multi process mode. new_for_multi_process(guest_pipe: PipeConnection) -> Result<Slirp>95 pub fn new_for_multi_process(guest_pipe: PipeConnection) -> Result<Slirp> { 96 Ok(Slirp { 97 guest_pipe, 98 overlapped_wrapper: OverlappedWrapper::new(true).unwrap(), 99 slirp_thread: None, 100 }) 101 } 102 try_clone(&self) -> Result<Self>103 fn try_clone(&self) -> Result<Self> { 104 Ok(Slirp { 105 guest_pipe: self 106 .guest_pipe 107 .try_clone() 108 .map_err(|e| Error::Slirp(SlirpError::CloneFailed(e)))?, 109 overlapped_wrapper: OverlappedWrapper::new(true).unwrap(), 110 slirp_thread: None, 111 }) 112 } 113 114 /// Start the Slirp listening loop. This is meant to be called when running crosvm in multi 115 /// process mode. run_slirp_process( slirp_pipe: PipeConnection, shutdown_event: Event, #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] mut slirp_capture_file: Option<String>, )116 pub fn run_slirp_process( 117 slirp_pipe: PipeConnection, 118 shutdown_event: Event, 119 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] 120 mut slirp_capture_file: Option<String>, 121 ) { 122 // SLIRP_DEBUG is basically a CSV of debug options as defined in libslirp/src/slirp.c. See 123 // g_parse_debug_string for more info on the format. 124 std::env::set_var("SLIRP_DEBUG", "dhcp,error"); 125 126 // libslirp uses glib's g_debug facility. Yes, that means it has glib's log level system, 127 // and its own internal system. Anyway, we have to tell glib to actually print things out, 128 // because libslirp logs *everything* as a debug entry. 129 std::env::set_var("G_MESSAGES_DEBUG", "all"); 130 131 let disable_access_to_host = !cfg!(feature = "guest-to-host-net-loopback"); 132 133 info!("starting slirp loop..."); 134 match handler::start_slirp( 135 slirp_pipe, 136 shutdown_event, 137 disable_access_to_host, 138 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] 139 slirp_capture_file.take(), 140 ) { 141 Err(Error::Slirp(SlirpError::BrokenPipe(e))) => { 142 warn!("exited slirp listening loop: {}", e) 143 } 144 Err(e) => panic!("error while running slirp listening loop: {}", e), 145 _ => {} 146 } 147 } 148 } 149 150 impl Drop for Slirp { drop(&mut self)151 fn drop(&mut self) { 152 if let Some(slirp_thread) = self.slirp_thread.take() { 153 slirp_thread.join().expect("Failed to join slirp thread"); 154 } 155 } 156 } 157 158 impl TapT for Slirp {} 159 160 impl TapTCommon for Slirp { new_with_name(_name: &[u8], _vnet_hdr: bool, _multi_vq: bool) -> Result<Self>161 fn new_with_name(_name: &[u8], _vnet_hdr: bool, _multi_vq: bool) -> Result<Self> { 162 unimplemented!("not implemented for Slirp"); 163 } 164 new(_vnet_hdr: bool, _multi_vq: bool) -> Result<Slirp>165 fn new(_vnet_hdr: bool, _multi_vq: bool) -> Result<Slirp> { 166 unimplemented!("not implemented for Slirp"); 167 } 168 into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>169 fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>> { 170 if vq_pairs != 1 { 171 unimplemented!("libslirp is single threaded; only one vq pair is supported."); 172 } 173 174 Ok(vec![self]) 175 } 176 ip_addr(&self) -> Result<net::Ipv4Addr>177 fn ip_addr(&self) -> Result<net::Ipv4Addr> { 178 // Only used by the plugin system. 179 unimplemented!("need to fetch the client's IP address from Slirp"); 180 } 181 set_ip_addr(&self, _ip_addr: net::Ipv4Addr) -> Result<()>182 fn set_ip_addr(&self, _ip_addr: net::Ipv4Addr) -> Result<()> { 183 // Only used by the plugin system. 184 unimplemented!("need to fetch the client's IP address from Slirp"); 185 } 186 netmask(&self) -> Result<net::Ipv4Addr>187 fn netmask(&self) -> Result<net::Ipv4Addr> { 188 // Only used by the plugin system. 189 unimplemented!("need to fetch the client's IP address from Slirp"); 190 } 191 set_netmask(&self, _netmask: net::Ipv4Addr) -> Result<()>192 fn set_netmask(&self, _netmask: net::Ipv4Addr) -> Result<()> { 193 // Only used by the plugin system. 194 unimplemented!("need to fetch the client's IP address from Slirp"); 195 } 196 mtu(&self) -> Result<u16>197 fn mtu(&self) -> Result<u16> { 198 unimplemented!("Get MTU unsupported by Slirp"); 199 } 200 set_mtu(&self, _mtu: u16) -> Result<()>201 fn set_mtu(&self, _mtu: u16) -> Result<()> { 202 unimplemented!("Set MTU unsupported by Slirp"); 203 } 204 mac_address(&self) -> Result<MacAddress>205 fn mac_address(&self) -> Result<MacAddress> { 206 // Only used by the plugin system. 207 unimplemented!("need to fetch the client's IP address from Slirp"); 208 } 209 set_mac_address(&self, _mac_addr: MacAddress) -> Result<()>210 fn set_mac_address(&self, _mac_addr: MacAddress) -> Result<()> { 211 // Only used by the plugin system. 212 unimplemented!("need to fetch the client's IP address from Slirp"); 213 } 214 set_offload(&self, flags: c_uint) -> Result<()>215 fn set_offload(&self, flags: c_uint) -> Result<()> { 216 // Slirp does not support offload. 217 if flags != 0 { 218 unimplemented!("offloading is unsupported by Slirp."); 219 } 220 Ok(()) 221 } 222 enable(&self) -> Result<()>223 fn enable(&self) -> Result<()> { 224 Ok(()) 225 } 226 227 /// WARNING: This is used so that we can pass Slirp into a listening loop. StreamChannels can't 228 /// have >1 reader on one end of a channel, but in Slirp, there is only one guest packet stream 229 /// so we have one reader and one writer. try_clone(&self) -> Result<Self>230 fn try_clone(&self) -> Result<Self> { 231 self.try_clone() 232 } 233 from_raw_descriptor(_descriptor: RawDescriptor) -> Result<Self>234 unsafe fn from_raw_descriptor(_descriptor: RawDescriptor) -> Result<Self> { 235 unimplemented!("not used by Slirp"); 236 } 237 } 238 239 impl Read for Slirp { read(&mut self, buf: &mut [u8]) -> IoResult<usize>240 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { 241 // SAFETY: 242 // Safe because we are reading simple bytes. 243 unsafe { 244 self.guest_pipe 245 .read_overlapped(buf, &mut self.overlapped_wrapper)?; 246 }; 247 self.guest_pipe 248 .get_overlapped_result(&mut self.overlapped_wrapper) 249 .map(|x| x as usize) 250 } 251 } 252 253 impl ReadOverlapped for Slirp { 254 /// # Safety 255 /// See requirements on [ReadOverlapped]. read_overlapped( &mut self, buf: &mut [u8], overlapped_wrapper: &mut OverlappedWrapper, ) -> IoResult<()>256 unsafe fn read_overlapped( 257 &mut self, 258 buf: &mut [u8], 259 overlapped_wrapper: &mut OverlappedWrapper, 260 ) -> IoResult<()> { 261 self.guest_pipe.read_overlapped(buf, overlapped_wrapper) 262 } 263 read_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize>264 fn read_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize> { 265 self.guest_pipe 266 .get_overlapped_result(overlapped_wrapper) 267 .map(|x| x as usize) 268 } 269 try_read_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize>270 fn try_read_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize> { 271 self.guest_pipe 272 .try_get_overlapped_result(overlapped_wrapper) 273 .map(|x| x as usize) 274 } 275 } 276 277 impl Write for Slirp { write(&mut self, buf: &[u8]) -> IoResult<usize>278 fn write(&mut self, buf: &[u8]) -> IoResult<usize> { 279 // SAFETY: safe because the operation ends with buf & overlapped_wrapper 280 // still in scope. 281 unsafe { 282 self.guest_pipe 283 .write_overlapped(buf, &mut self.overlapped_wrapper)? 284 }; 285 self.guest_pipe 286 .get_overlapped_result(&mut self.overlapped_wrapper) 287 .map(|x| x as usize) 288 } 289 flush(&mut self) -> IoResult<()>290 fn flush(&mut self) -> IoResult<()> { 291 Ok(()) 292 } 293 } 294 295 impl WriteOverlapped for Slirp { 296 /// # Safety 297 /// See requirements on [WriteOverlapped]. write_overlapped( &mut self, buf: &mut [u8], overlapped_wrapper: &mut OverlappedWrapper, ) -> IoResult<()>298 unsafe fn write_overlapped( 299 &mut self, 300 buf: &mut [u8], 301 overlapped_wrapper: &mut OverlappedWrapper, 302 ) -> IoResult<()> { 303 self.guest_pipe.write_overlapped(buf, overlapped_wrapper) 304 } 305 write_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize>306 fn write_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize> { 307 self.guest_pipe 308 .get_overlapped_result(overlapped_wrapper) 309 .map(|x| x as usize) 310 } 311 try_write_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize>312 fn try_write_result(&mut self, overlapped_wrapper: &mut OverlappedWrapper) -> IoResult<usize> { 313 self.guest_pipe 314 .try_get_overlapped_result(overlapped_wrapper) 315 .map(|x| x as usize) 316 } 317 } 318 319 impl AsRawDescriptor for Slirp { as_raw_descriptor(&self) -> RawDescriptor320 fn as_raw_descriptor(&self) -> RawDescriptor { 321 self.guest_pipe.as_raw_descriptor() 322 } 323 } 324 325 impl ReadNotifier for Slirp { get_read_notifier(&self) -> &dyn AsRawDescriptor326 fn get_read_notifier(&self) -> &dyn AsRawDescriptor { 327 self.overlapped_wrapper.get_h_event_ref().unwrap() 328 } 329 } 330 331 impl AsRawHandle for Slirp { as_raw_handle(&self) -> RawDescriptor332 fn as_raw_handle(&self) -> RawDescriptor { 333 self.guest_pipe.as_raw_descriptor() 334 } 335 } 336 337 impl IntoAsync for Slirp {} 338 339 /// Config arguments passed through the bootstrap Tube from the broker to the Slirp listening 340 /// process. 341 #[derive(Serialize, Deserialize, Debug)] 342 pub struct SlirpStartupConfig { 343 pub slirp_pipe: PipeConnection, 344 pub shutdown_event: Event, 345 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))] 346 pub slirp_capture_file: Option<String>, 347 } 348