• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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