xref: /cloud-hypervisor/net_util/src/tap.rs (revision 7d7bfb2034001d4cb15df2ddc56d2d350c8da30f)
1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style license that can be
6 // found in the THIRD-PARTY file.
7 
8 use super::{
9     create_inet_socket, create_sockaddr, create_unix_socket, vnet_hdr_len, Error as NetUtilError,
10     MacAddr,
11 };
12 use crate::mac::MAC_ADDR_LEN;
13 use std::fs::File;
14 use std::io::{Error as IoError, Read, Result as IoResult, Write};
15 use std::net;
16 use std::os::raw::*;
17 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
18 use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
19 
20 #[derive(Debug)]
21 pub enum Error {
22     /// Couldn't open /dev/net/tun.
23     OpenTun(IoError),
24     /// Unable to configure tap interface.
25     ConfigureTap(IoError),
26     /// Unable to retrieve features.
27     GetFeatures(IoError),
28     /// Missing multiqueue support in the kernel.
29     MultiQueueKernelSupport,
30     /// ioctl failed.
31     IoctlError(IoError),
32     /// Failed to create a socket.
33     NetUtil(NetUtilError),
34     InvalidIfname,
35     /// Error parsing MAC data
36     MacParsing(IoError),
37 }
38 
39 pub type Result<T> = ::std::result::Result<T, Error>;
40 
41 /// Handle for a network tap interface.
42 ///
43 /// For now, this simply wraps the file descriptor for the tap device so methods
44 /// can run ioctls on the interface. The tap interface fd will be closed when
45 /// Tap goes out of scope, and the kernel will clean up the interface
46 /// automatically.
47 #[derive(Debug)]
48 pub struct Tap {
49     tap_file: File,
50     if_name: Vec<u8>,
51 }
52 
53 impl PartialEq for Tap {
54     fn eq(&self, other: &Tap) -> bool {
55         self.if_name == other.if_name
56     }
57 }
58 
59 impl std::clone::Clone for Tap {
60     fn clone(&self) -> Self {
61         Tap {
62             tap_file: self.tap_file.try_clone().unwrap(),
63             if_name: self.if_name.clone(),
64         }
65     }
66 }
67 
68 // Returns a byte vector representing the contents of a null terminated C string which
69 // contains if_name.
70 fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
71     // Convert the string slice to bytes, and shadow the variable,
72     // since we no longer need the &str version.
73     let if_name = if_name.as_bytes();
74 
75     // TODO: the 16usize limit of the if_name member from struct Tap is pretty arbitrary.
76     // We leave it as is for now, but this should be refactored at some point.
77     if if_name.len() > 15 {
78         return Err(Error::InvalidIfname);
79     }
80 
81     let mut terminated_if_name = vec![b'\0'; if_name.len() + 1];
82     terminated_if_name[..if_name.len()].copy_from_slice(if_name);
83 
84     Ok(terminated_if_name)
85 }
86 
87 impl Tap {
88     pub fn open_named(if_name: &str, num_queue_pairs: usize, flags: Option<i32>) -> Result<Tap> {
89         let terminated_if_name = build_terminated_if_name(if_name)?;
90 
91         let fd = unsafe {
92             // Open calls are safe because we give a constant null-terminated
93             // string and verify the result.
94             libc::open(
95                 b"/dev/net/tun\0".as_ptr() as *const c_char,
96                 flags.unwrap_or(libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC),
97             )
98         };
99         if fd < 0 {
100             return Err(Error::OpenTun(IoError::last_os_error()));
101         }
102 
103         // We just checked that the fd is valid.
104         let tuntap = unsafe { File::from_raw_fd(fd) };
105 
106         // Let's validate some features before going any further.
107         // ioctl is safe since we call it with a valid tap fd and check the return
108         // value.
109         let mut features = 0;
110         let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNGETFEATURES(), &mut features) };
111         if ret < 0 {
112             return Err(Error::GetFeatures(IoError::last_os_error()));
113         }
114 
115         // Check if the user parameters match the kernel support for MQ
116         if (features & net_gen::IFF_MULTI_QUEUE == 0) && num_queue_pairs > 1 {
117             return Err(Error::MultiQueueKernelSupport);
118         }
119 
120         // This is pretty messy because of the unions used by ifreq. Since we
121         // don't call as_mut on the same union field more than once, this block
122         // is safe.
123         let mut ifreq: net_gen::ifreq = Default::default();
124         unsafe {
125             let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
126             let name_slice = &mut ifrn_name[..terminated_if_name.len()];
127             name_slice.copy_from_slice(terminated_if_name.as_slice());
128             ifreq.ifr_ifru.ifru_flags =
129                 (net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
130             if num_queue_pairs > 1 {
131                 ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short;
132             }
133         }
134 
135         // ioctl is safe since we call it with a valid tap fd and check the return
136         // value.
137         let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNSETIFF(), &mut ifreq) };
138         if ret < 0 {
139             return Err(Error::ConfigureTap(IoError::last_os_error()));
140         }
141 
142         let mut if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec();
143         if_name.truncate(terminated_if_name.len() - 1);
144         // Safe since only the name is accessed, and it's cloned out.
145         Ok(Tap {
146             tap_file: tuntap,
147             if_name,
148         })
149     }
150 
151     /// Create a new tap interface.
152     pub fn new(num_queue_pairs: usize) -> Result<Tap> {
153         Self::open_named("vmtap%d", num_queue_pairs, None)
154     }
155 
156     pub fn from_tap_fd(fd: RawFd, num_queue_pairs: usize) -> Result<Tap> {
157         // Ensure that the file is opened non-blocking, this is particularly
158         // needed when opened via the shell for macvtap.
159         let ret = unsafe {
160             let mut flags = libc::fcntl(fd, libc::F_GETFL);
161             flags |= libc::O_NONBLOCK;
162             libc::fcntl(fd, libc::F_SETFL, flags)
163         };
164         if ret < 0 {
165             return Err(Error::ConfigureTap(IoError::last_os_error()));
166         }
167 
168         let tap_file = unsafe { File::from_raw_fd(fd) };
169         let mut ifreq: net_gen::ifreq = Default::default();
170 
171         // Get current config including name
172         let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNGETIFF(), &mut ifreq) };
173         if ret < 0 {
174             return Err(Error::IoctlError(IoError::last_os_error()));
175         }
176         // We only access one field of the ifru union, hence this is safe.
177         let if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec();
178 
179         // Try and update flags. Depending on how the tap was created (macvtap
180         // or via open_named()) this might return -EEXIST so we just ignore that.
181         unsafe {
182             ifreq.ifr_ifru.ifru_flags =
183                 (net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
184             if num_queue_pairs > 1 {
185                 ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short;
186             }
187         }
188         let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) };
189         if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST {
190             return Err(Error::ConfigureTap(IoError::last_os_error()));
191         }
192 
193         let tap = Tap { tap_file, if_name };
194         let vnet_hdr_size = vnet_hdr_len() as i32;
195         tap.set_vnet_hdr_size(vnet_hdr_size)?;
196 
197         Ok(tap)
198     }
199 
200     /// Set the host-side IP address for the tap interface.
201     pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
202         let sock = create_inet_socket().map_err(Error::NetUtil)?;
203         let addr = create_sockaddr(ip_addr);
204 
205         let mut ifreq = self.get_ifreq();
206 
207         ifreq.ifr_ifru.ifru_addr = addr;
208 
209         // ioctl is safe. Called with a valid sock fd, and we check the return.
210         let ret =
211             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
212         if ret < 0 {
213             return Err(Error::IoctlError(IoError::last_os_error()));
214         }
215 
216         Ok(())
217     }
218 
219     /// Set mac addr for tap interface.
220     pub fn set_mac_addr(&self, addr: MacAddr) -> Result<()> {
221         // Checking if the mac address already matches the desired one
222         // is useful to avoid making the "set ioctl" in the case where
223         // the VMM is running without the privilege to do that.
224         // In practice this comes from a reboot after the configuration
225         // has been update with the kernel generated address.
226         if self.get_mac_addr()? == addr {
227             return Ok(());
228         }
229 
230         let sock = create_unix_socket().map_err(Error::NetUtil)?;
231 
232         let mut ifreq = self.get_ifreq();
233 
234         // ioctl is safe. Called with a valid sock fd, and we check the return.
235         let ret =
236             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
237         if ret < 0 {
238             return Err(Error::IoctlError(IoError::last_os_error()));
239         }
240         // We only access one field of the ifru union, hence this is safe.
241         unsafe {
242             let ifru_hwaddr = &mut ifreq.ifr_ifru.ifru_hwaddr;
243             for (i, v) in addr.get_bytes().iter().enumerate() {
244                 ifru_hwaddr.sa_data[i] = *v as c_uchar;
245             }
246         }
247 
248         // ioctl is safe. Called with a valid sock fd, and we check the return.
249         let ret =
250             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
251         if ret < 0 {
252             return Err(Error::IoctlError(IoError::last_os_error()));
253         }
254 
255         Ok(())
256     }
257 
258     /// Get mac addr for tap interface.
259     pub fn get_mac_addr(&self) -> Result<MacAddr> {
260         let sock = create_unix_socket().map_err(Error::NetUtil)?;
261 
262         let ifreq = self.get_ifreq();
263 
264         // ioctl is safe. Called with a valid sock fd, and we check the return.
265         let ret =
266             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
267         if ret < 0 {
268             return Err(Error::IoctlError(IoError::last_os_error()));
269         }
270 
271         // We only access one field of the ifru union, hence this is safe.
272         let addr = unsafe {
273             MacAddr::from_bytes(&ifreq.ifr_ifru.ifru_hwaddr.sa_data[0..MAC_ADDR_LEN])
274                 .map_err(Error::MacParsing)?
275         };
276         Ok(addr)
277     }
278 
279     /// Set the netmask for the subnet that the tap interface will exist on.
280     pub fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
281         let sock = create_inet_socket().map_err(Error::NetUtil)?;
282         let addr = create_sockaddr(netmask);
283 
284         let mut ifreq = self.get_ifreq();
285 
286         ifreq.ifr_ifru.ifru_addr = addr;
287 
288         // ioctl is safe. Called with a valid sock fd, and we check the return.
289         let ret =
290             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
291         if ret < 0 {
292             return Err(Error::IoctlError(IoError::last_os_error()));
293         }
294 
295         Ok(())
296     }
297 
298     /// Set the offload flags for the tap interface.
299     pub fn set_offload(&self, flags: c_uint) -> Result<()> {
300         // ioctl is safe. Called with a valid tap fd, and we check the return.
301         let ret =
302             unsafe { ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) };
303         if ret < 0 {
304             return Err(Error::IoctlError(IoError::last_os_error()));
305         }
306 
307         Ok(())
308     }
309 
310     /// Enable the tap interface.
311     pub fn enable(&self) -> Result<()> {
312         let sock = create_unix_socket().map_err(Error::NetUtil)?;
313 
314         let mut ifreq = self.get_ifreq();
315 
316         let ret =
317             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq) };
318         if ret < 0 {
319             return Err(Error::IoctlError(IoError::last_os_error()));
320         }
321 
322         // If TAP device is already up don't try and enable it
323         let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
324         if ifru_flags
325             & (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16
326             == (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16
327         {
328             return Ok(());
329         }
330 
331         ifreq.ifr_ifru.ifru_flags =
332             (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16;
333 
334         // ioctl is safe. Called with a valid sock fd, and we check the return.
335         let ret =
336             unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
337         if ret < 0 {
338             return Err(Error::IoctlError(IoError::last_os_error()));
339         }
340 
341         Ok(())
342     }
343 
344     /// Set the size of the vnet hdr.
345     pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
346         // ioctl is safe. Called with a valid tap fd, and we check the return.
347         let ret = unsafe { ioctl_with_ref(&self.tap_file, net_gen::TUNSETVNETHDRSZ(), &size) };
348         if ret < 0 {
349             return Err(Error::IoctlError(IoError::last_os_error()));
350         }
351 
352         Ok(())
353     }
354 
355     fn get_ifreq(&self) -> net_gen::ifreq {
356         let mut ifreq: net_gen::ifreq = Default::default();
357 
358         // This sets the name of the interface, which is the only entry
359         // in a single-field union.
360         unsafe {
361             let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
362             let name_slice = &mut ifrn_name[..self.if_name.len()];
363             name_slice.copy_from_slice(&self.if_name);
364         }
365 
366         ifreq
367     }
368 
369     pub fn get_if_name(&self) -> Vec<u8> {
370         self.if_name.clone()
371     }
372 }
373 
374 impl Read for Tap {
375     fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
376         self.tap_file.read(buf)
377     }
378 }
379 
380 impl Write for Tap {
381     fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
382         self.tap_file.write(buf)
383     }
384 
385     fn flush(&mut self) -> IoResult<()> {
386         Ok(())
387     }
388 }
389 
390 impl AsRawFd for Tap {
391     fn as_raw_fd(&self) -> RawFd {
392         self.tap_file.as_raw_fd()
393     }
394 }
395 
396 #[cfg(test)]
397 mod tests {
398     extern crate pnet;
399 
400     use std::net::Ipv4Addr;
401     use std::str;
402     use std::sync::{mpsc, Mutex};
403     use std::thread;
404     use std::time::Duration;
405 
406     use self::pnet::datalink::Channel::Ethernet;
407     use self::pnet::datalink::{self, DataLinkReceiver, DataLinkSender, NetworkInterface};
408     use self::pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
409     use self::pnet::packet::ip::IpNextHeaderProtocols;
410     use self::pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
411     use self::pnet::packet::udp::{MutableUdpPacket, UdpPacket};
412     use self::pnet::packet::{MutablePacket, Packet};
413     use self::pnet::util::MacAddr;
414 
415     use super::*;
416 
417     static DATA_STRING: &str = "test for tap";
418     static SUBNET_MASK: &str = "255.255.255.0";
419 
420     // We needed to have a mutex as a global variable, so we used the crate that provides the
421     // lazy_static! macro for testing. The main potential problem, caused by tests being run in
422     // parallel by cargo, is creating different TAPs and trying to associate the same address,
423     // so we hide the IP address &str behind this mutex, more as a convention to remember to lock
424     // it at the very beginning of each function susceptible to this issue. Another variant is
425     // to use a different IP address per function, but we must remember to pick an unique one
426     // each time.
427     lazy_static! {
428         static ref TAP_IP_LOCK: Mutex<&'static str> = Mutex::new("192.168.241.1");
429     }
430 
431     // Describes the outcomes we are currently interested in when parsing a packet (we use
432     // an UDP packet for testing).
433     struct ParsedPkt<'a> {
434         eth: EthernetPacket<'a>,
435         ipv4: Option<Ipv4Packet<'a>>,
436         udp: Option<UdpPacket<'a>>,
437     }
438 
439     impl<'a> ParsedPkt<'a> {
440         fn new(buf: &'a [u8]) -> Self {
441             let eth = EthernetPacket::new(buf).unwrap();
442             let mut ipv4 = None;
443             let mut udp = None;
444 
445             if eth.get_ethertype() == EtherTypes::Ipv4 {
446                 let ipv4_start = 14;
447                 ipv4 = Some(Ipv4Packet::new(&buf[ipv4_start..]).unwrap());
448 
449                 // Hiding the old ipv4 variable for the rest of this block.
450                 let ipv4 = Ipv4Packet::new(eth.payload()).unwrap();
451 
452                 if ipv4.get_next_level_protocol() == IpNextHeaderProtocols::Udp {
453                     // The value in header_length indicates the number of 32 bit words
454                     // that make up the header, not the actual length in bytes.
455                     let udp_start = ipv4_start + ipv4.get_header_length() as usize * 4;
456                     udp = Some(UdpPacket::new(&buf[udp_start..]).unwrap());
457                 }
458             }
459 
460             ParsedPkt { eth, ipv4, udp }
461         }
462 
463         fn print(&self) {
464             print!(
465                 "{} {} {} ",
466                 self.eth.get_source(),
467                 self.eth.get_destination(),
468                 self.eth.get_ethertype()
469             );
470             if let Some(ref ipv4) = self.ipv4 {
471                 print!(
472                     "{} {} {} ",
473                     ipv4.get_source(),
474                     ipv4.get_destination(),
475                     ipv4.get_next_level_protocol()
476                 );
477             }
478             if let Some(ref udp) = self.udp {
479                 print!(
480                     "{} {} {}",
481                     udp.get_source(),
482                     udp.get_destination(),
483                     str::from_utf8(udp.payload()).unwrap()
484                 );
485             }
486             println!();
487         }
488     }
489 
490     fn tap_name_to_string(tap: &Tap) -> String {
491         let null_pos = tap.if_name.iter().position(|x| *x == 0).unwrap();
492         str::from_utf8(&tap.if_name[..null_pos])
493             .unwrap()
494             .to_string()
495     }
496 
497     // Given a buffer of appropriate size, this fills in the relevant fields based on the
498     // provided information. Payload refers to the UDP payload.
499     fn pnet_build_packet(buf: &mut [u8], dst_mac: MacAddr, payload: &[u8]) {
500         let mut eth = MutableEthernetPacket::new(buf).unwrap();
501         eth.set_source(MacAddr::new(0x06, 0, 0, 0, 0, 0));
502         eth.set_destination(dst_mac);
503         eth.set_ethertype(EtherTypes::Ipv4);
504 
505         let mut ipv4 = MutableIpv4Packet::new(eth.payload_mut()).unwrap();
506         ipv4.set_version(4);
507         ipv4.set_header_length(5);
508         ipv4.set_total_length(20 + 8 + payload.len() as u16);
509         ipv4.set_ttl(200);
510         ipv4.set_next_level_protocol(IpNextHeaderProtocols::Udp);
511         ipv4.set_source(Ipv4Addr::new(192, 168, 241, 1));
512         ipv4.set_destination(Ipv4Addr::new(192, 168, 241, 2));
513 
514         let mut udp = MutableUdpPacket::new(ipv4.payload_mut()).unwrap();
515         udp.set_source(1000);
516         udp.set_destination(1001);
517         udp.set_length(8 + payload.len() as u16);
518         udp.set_payload(payload);
519     }
520 
521     // Sends a test packet on the interface named "ifname".
522     fn pnet_send_packet(ifname: String) {
523         let payload = DATA_STRING.as_bytes();
524 
525         // eth hdr + ip hdr + udp hdr + payload len
526         let buf_size = 14 + 20 + 8 + payload.len();
527 
528         let (mac, mut tx, _) = pnet_get_mac_tx_rx(ifname);
529 
530         let res = tx.build_and_send(1, buf_size, &mut |buf| {
531             pnet_build_packet(buf, mac, payload);
532         });
533         // Make sure build_and_send() -> Option<io::Result<()>> succeeds.
534         res.unwrap().unwrap();
535     }
536 
537     // For a given interface name, this returns a tuple that contains the MAC address of the
538     // interface, an object that can be used to send Ethernet frames, and a receiver of
539     // Ethernet frames arriving at the specified interface.
540     fn pnet_get_mac_tx_rx(
541         ifname: String,
542     ) -> (MacAddr, Box<dyn DataLinkSender>, Box<dyn DataLinkReceiver>) {
543         let interface_name_matches = |iface: &NetworkInterface| iface.name == ifname;
544 
545         // Find the network interface with the provided name.
546         let interfaces = datalink::interfaces();
547         let interface = interfaces.into_iter().find(interface_name_matches).unwrap();
548 
549         if let Ok(Ethernet(tx, rx)) = datalink::channel(&interface, Default::default()) {
550             (interface.mac.unwrap(), tx, rx)
551         } else {
552             panic!("datalink channel error or unhandled channel type");
553         }
554     }
555 
556     #[test]
557     fn test_tap_create() {
558         let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
559 
560         let t = Tap::new(1).unwrap();
561         println!("created tap: {:?}", t);
562     }
563 
564     #[test]
565     fn test_tap_from_fd() {
566         let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
567 
568         let orig_tap = Tap::new(1).unwrap();
569         let fd = orig_tap.as_raw_fd();
570         let _new_tap = Tap::from_tap_fd(fd, 1).unwrap();
571     }
572 
573     #[test]
574     fn test_tap_configure() {
575         // This should be the first thing to be called inside the function, so everything else
576         // is torn down by the time the mutex is automatically released. Also, we should
577         // explicitly bind the MutexGuard to a variable via let, the make sure it lives until
578         // the end of the function.
579         let tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
580 
581         let tap = Tap::new(1).unwrap();
582         let ip_addr: net::Ipv4Addr = (*tap_ip_guard).parse().unwrap();
583         let netmask: net::Ipv4Addr = SUBNET_MASK.parse().unwrap();
584 
585         let ret = tap.set_ip_addr(ip_addr);
586         assert!(ret.is_ok());
587         let ret = tap.set_netmask(netmask);
588         assert!(ret.is_ok());
589     }
590 
591     #[test]
592     fn test_set_options() {
593         let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
594 
595         // This line will fail to provide an initialized FD if the test is not run as root.
596         let tap = Tap::new(1).unwrap();
597         tap.set_vnet_hdr_size(16).unwrap();
598         tap.set_offload(0).unwrap();
599     }
600 
601     #[test]
602     fn test_tap_enable() {
603         let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
604 
605         let tap = Tap::new(1).unwrap();
606         let ret = tap.enable();
607         assert!(ret.is_ok());
608     }
609 
610     #[test]
611     fn test_raw_fd() {
612         let _tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
613 
614         let tap = Tap::new(1).unwrap();
615         assert_eq!(tap.as_raw_fd(), tap.tap_file.as_raw_fd());
616     }
617 
618     #[test]
619     fn test_read() {
620         let tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
621 
622         let mut tap = Tap::new(1).unwrap();
623         tap.set_ip_addr((*tap_ip_guard).parse().unwrap()).unwrap();
624         tap.set_netmask(SUBNET_MASK.parse().unwrap()).unwrap();
625         tap.enable().unwrap();
626 
627         // Send a packet to the interface. We expect to be able to receive it on the associated fd.
628         pnet_send_packet(tap_name_to_string(&tap));
629 
630         let mut buf = [0u8; 4096];
631 
632         let mut found_packet_sz = None;
633 
634         // In theory, this could actually loop forever if something keeps sending data through the
635         // tap interface, but it's highly unlikely.
636         while found_packet_sz.is_none() {
637             let result = tap.read(&mut buf);
638             assert!(result.is_ok());
639 
640             let size = result.unwrap();
641 
642             // We skip the first 10 bytes because the IFF_VNET_HDR flag is set when the interface
643             // is created, and the legacy header is 10 bytes long without a certain flag which
644             // is not set in Tap::new().
645             let eth_bytes = &buf[10..size];
646 
647             let packet = EthernetPacket::new(eth_bytes).unwrap();
648             if packet.get_ethertype() != EtherTypes::Ipv4 {
649                 // not an IPv4 packet
650                 continue;
651             }
652 
653             let ipv4_bytes = &eth_bytes[14..];
654             let packet = Ipv4Packet::new(ipv4_bytes).unwrap();
655 
656             // Our packet should carry an UDP payload, and not contain IP options.
657             if packet.get_next_level_protocol() != IpNextHeaderProtocols::Udp
658                 && packet.get_header_length() != 5
659             {
660                 continue;
661             }
662 
663             let udp_bytes = &ipv4_bytes[20..];
664 
665             let udp_len = UdpPacket::new(udp_bytes).unwrap().get_length() as usize;
666 
667             // Skip the header bytes.
668             let inner_string = str::from_utf8(&udp_bytes[8..udp_len]).unwrap();
669 
670             if inner_string.eq(DATA_STRING) {
671                 found_packet_sz = Some(size);
672                 break;
673             }
674         }
675 
676         assert!(found_packet_sz.is_some());
677     }
678 
679     #[test]
680     fn test_write() {
681         let tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
682 
683         let mut tap = Tap::new(1).unwrap();
684         tap.set_ip_addr((*tap_ip_guard).parse().unwrap()).unwrap();
685         tap.set_netmask(SUBNET_MASK.parse().unwrap()).unwrap();
686         tap.enable().unwrap();
687 
688         let (mac, _, mut rx) = pnet_get_mac_tx_rx(tap_name_to_string(&tap));
689 
690         let payload = DATA_STRING.as_bytes();
691 
692         // vnet hdr + eth hdr + ip hdr + udp hdr + payload len
693         let buf_size = 10 + 14 + 20 + 8 + payload.len();
694 
695         let mut buf = vec![0u8; buf_size];
696         // leave the vnet hdr as is
697         pnet_build_packet(&mut buf[10..], mac, payload);
698 
699         assert!(tap.write(&buf[..]).is_ok());
700         assert!(tap.flush().is_ok());
701 
702         let (channel_tx, channel_rx) = mpsc::channel();
703 
704         // We use a separate thread to wait for the test packet because the API exposed by pnet is
705         // blocking. This thread will be killed when the main thread exits.
706         let _handle = thread::spawn(move || loop {
707             let buf = rx.next().unwrap();
708             let p = ParsedPkt::new(buf);
709             p.print();
710 
711             if let Some(ref udp) = p.udp {
712                 if payload == udp.payload() {
713                     channel_tx.send(true).unwrap();
714                     break;
715                 }
716             }
717         });
718 
719         // We wait for at most SLEEP_MILLIS * SLEEP_ITERS milliseconds for the reception of the
720         // test packet to be detected.
721         static SLEEP_MILLIS: u64 = 500;
722         static SLEEP_ITERS: u32 = 6;
723 
724         let mut found_test_packet = false;
725 
726         for _ in 0..SLEEP_ITERS {
727             thread::sleep(Duration::from_millis(SLEEP_MILLIS));
728             if let Ok(true) = channel_rx.try_recv() {
729                 found_test_packet = true;
730                 break;
731             }
732         }
733 
734         assert!(found_test_packet);
735     }
736 }
737