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