xref: /aosp_15_r20/external/crosvm/net_util/src/slirp/sys/windows.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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