• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fmt::{self, Display};
6 use std::fs::File;
7 use std::io::{Read, Result as IoResult, Write};
8 use std::mem;
9 use std::net;
10 use std::num::ParseIntError;
11 use std::os::raw::*;
12 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
13 use std::str::FromStr;
14 
15 use libc::EPERM;
16 
17 use sys_util::Error as SysError;
18 use sys_util::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
19 
20 #[derive(Debug)]
21 pub enum Error {
22     /// Failed to create a socket.
23     CreateSocket(SysError),
24     /// Couldn't open /dev/net/tun.
25     OpenTun(SysError),
26     /// Unable to create tap interface.
27     CreateTap(SysError),
28     /// ioctl failed.
29     IoctlError(SysError),
30 }
31 pub type Result<T> = std::result::Result<T, Error>;
32 
33 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result34     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35         use self::Error::*;
36 
37         match self {
38             CreateSocket(e) => write!(f, "failed to create a socket: {}", e),
39             OpenTun(e) => write!(f, "failed to open /dev/net/tun: {}", e),
40             CreateTap(e) => write!(f, "failed to create tap interface: {}", e),
41             IoctlError(e) => write!(f, "ioctl failed: {}", e),
42         }
43     }
44 }
45 
46 impl Error {
sys_error(&self) -> SysError47     pub fn sys_error(&self) -> SysError {
48         match *self {
49             Error::CreateSocket(e) => e,
50             Error::OpenTun(e) => e,
51             Error::CreateTap(e) => e,
52             Error::IoctlError(e) => e,
53         }
54     }
55 }
56 
57 /// Create a sockaddr_in from an IPv4 address, and expose it as
58 /// an opaque sockaddr suitable for usage by socket ioctls.
create_sockaddr(ip_addr: net::Ipv4Addr) -> net_sys::sockaddr59 fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_sys::sockaddr {
60     // IPv4 addresses big-endian (network order), but Ipv4Addr will give us
61     // a view of those bytes directly so we can avoid any endian trickiness.
62     let addr_in = net_sys::sockaddr_in {
63         sin_family: net_sys::AF_INET as u16,
64         sin_port: 0,
65         sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
66         __pad: [0; 8usize],
67     };
68 
69     unsafe { mem::transmute(addr_in) }
70 }
71 
72 /// Extract the IPv4 address from a sockaddr. Assumes the sockaddr is a sockaddr_in.
read_ipv4_addr(addr: &net_sys::sockaddr) -> net::Ipv4Addr73 fn read_ipv4_addr(addr: &net_sys::sockaddr) -> net::Ipv4Addr {
74     debug_assert_eq!(addr.sa_family as u32, net_sys::AF_INET);
75     // This is safe because sockaddr and sockaddr_in are the same size, and we've checked that
76     // this address is AF_INET.
77     let in_addr: net_sys::sockaddr_in = unsafe { mem::transmute(*addr) };
78     net::Ipv4Addr::from(in_addr.sin_addr.s_addr)
79 }
80 
create_socket() -> Result<net::UdpSocket>81 fn create_socket() -> Result<net::UdpSocket> {
82     // This is safe since we check the return value.
83     let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
84     if sock < 0 {
85         return Err(Error::CreateSocket(SysError::last()));
86     }
87 
88     // This is safe; nothing else will use or hold onto the raw sock fd.
89     Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
90 }
91 
92 #[derive(Debug)]
93 pub enum MacAddressError {
94     /// Invalid number of octets.
95     InvalidNumOctets(usize),
96     /// Failed to parse octet.
97     ParseOctet(ParseIntError),
98 }
99 
100 impl Display for MacAddressError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result101     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102         use self::MacAddressError::*;
103 
104         match self {
105             InvalidNumOctets(n) => write!(f, "invalid number of octets: {}", n),
106             ParseOctet(e) => write!(f, "failed to parse octet: {}", e),
107         }
108     }
109 }
110 
111 /// An Ethernet mac address. This struct is compatible with the C `struct sockaddr`.
112 #[repr(C)]
113 #[derive(Clone, Copy)]
114 pub struct MacAddress {
115     family: net_sys::sa_family_t,
116     addr: [u8; 6usize],
117     __pad: [u8; 8usize],
118 }
119 
120 impl MacAddress {
octets(&self) -> [u8; 6usize]121     pub fn octets(&self) -> [u8; 6usize] {
122         self.addr
123     }
124 }
125 
126 impl FromStr for MacAddress {
127     type Err = MacAddressError;
128 
from_str(s: &str) -> std::result::Result<Self, Self::Err>129     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
130         let octets: Vec<&str> = s.split(':').collect();
131         if octets.len() != 6usize {
132             return Err(MacAddressError::InvalidNumOctets(octets.len()));
133         }
134 
135         let mut result = MacAddress {
136             family: net_sys::ARPHRD_ETHER,
137             addr: [0; 6usize],
138             __pad: [0; 8usize],
139         };
140 
141         for (i, octet) in octets.iter().enumerate() {
142             result.addr[i] = u8::from_str_radix(octet, 16).map_err(MacAddressError::ParseOctet)?;
143         }
144 
145         Ok(result)
146     }
147 }
148 
149 impl Display for MacAddress {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result150     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151         write!(
152             f,
153             "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
154             self.addr[0], self.addr[1], self.addr[2], self.addr[3], self.addr[4], self.addr[5]
155         )
156     }
157 }
158 
159 /// Handle for a network tap interface.
160 ///
161 /// For now, this simply wraps the file descriptor for the tap device so methods
162 /// can run ioctls on the interface. The tap interface fd will be closed when
163 /// Tap goes out of scope, and the kernel will clean up the interface
164 /// automatically.
165 #[derive(Debug)]
166 pub struct Tap {
167     tap_file: File,
168     if_name: [c_char; 16usize],
169     if_flags: ::std::os::raw::c_short,
170 }
171 
172 impl Tap {
from_raw_fd(fd: RawFd) -> Result<Tap>173     pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Tap> {
174         let tap_file = File::from_raw_fd(fd);
175 
176         // Get the interface name since we will need it for some ioctls.
177         let mut ifreq: net_sys::ifreq = Default::default();
178         let ret = ioctl_with_mut_ref(&tap_file, net_sys::TUNGETIFF(), &mut ifreq);
179 
180         if ret < 0 {
181             return Err(Error::IoctlError(SysError::last()));
182         }
183 
184         Ok(Tap {
185             tap_file,
186             if_name: ifreq.ifr_ifrn.ifrn_name,
187             if_flags: ifreq.ifr_ifru.ifru_flags,
188         })
189     }
190 }
191 
192 pub trait TapT: Read + Write + AsRawFd + Send + Sized {
193     /// Create a new tap interface. Set the `vnet_hdr` flag to true to allow offloading on this tap,
194     /// which will add an extra 12 byte virtio net header to incoming frames. Offloading cannot
195     /// be used if `vnet_hdr` is false.
new(vnet_hdr: bool) -> Result<Self>196     fn new(vnet_hdr: bool) -> Result<Self>;
197 
198     /// Get the host-side IP address for the tap interface.
ip_addr(&self) -> Result<net::Ipv4Addr>199     fn ip_addr(&self) -> Result<net::Ipv4Addr>;
200 
201     /// Set the host-side IP address for the tap interface.
set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>202     fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>;
203 
204     /// Get the netmask for the tap interface's subnet.
netmask(&self) -> Result<net::Ipv4Addr>205     fn netmask(&self) -> Result<net::Ipv4Addr>;
206 
207     /// Set the netmask for the subnet that the tap interface will exist on.
set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>208     fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>;
209 
210     /// Get the mac address for the tap interface.
mac_address(&self) -> Result<MacAddress>211     fn mac_address(&self) -> Result<MacAddress>;
212 
213     /// Set the mac address for the tap interface.
set_mac_address(&self, mac_addr: MacAddress) -> Result<()>214     fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>;
215 
216     /// Set the offload flags for the tap interface.
set_offload(&self, flags: c_uint) -> Result<()>217     fn set_offload(&self, flags: c_uint) -> Result<()>;
218 
219     /// Enable the tap interface.
enable(&self) -> Result<()>220     fn enable(&self) -> Result<()>;
221 
222     /// Set the size of the vnet hdr.
set_vnet_hdr_size(&self, size: c_int) -> Result<()>223     fn set_vnet_hdr_size(&self, size: c_int) -> Result<()>;
224 
get_ifreq(&self) -> net_sys::ifreq225     fn get_ifreq(&self) -> net_sys::ifreq;
226 
227     /// Get the interface flags
if_flags(&self) -> u32228     fn if_flags(&self) -> u32;
229 }
230 
231 impl TapT for Tap {
new(vnet_hdr: bool) -> Result<Tap>232     fn new(vnet_hdr: bool) -> Result<Tap> {
233         // Open calls are safe because we give a constant nul-terminated
234         // string and verify the result.
235         let fd = unsafe {
236             libc::open(
237                 b"/dev/net/tun\0".as_ptr() as *const c_char,
238                 libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
239             )
240         };
241         if fd < 0 {
242             return Err(Error::OpenTun(SysError::last()));
243         }
244 
245         // We just checked that the fd is valid.
246         let tuntap = unsafe { File::from_raw_fd(fd) };
247 
248         const TUNTAP_DEV_FORMAT: &[u8; 8usize] = b"vmtap%d\0";
249 
250         // This is pretty messy because of the unions used by ifreq. Since we
251         // don't call as_mut on the same union field more than once, this block
252         // is safe.
253         let mut ifreq: net_sys::ifreq = Default::default();
254         unsafe {
255             let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
256             let name_slice = &mut ifrn_name[..TUNTAP_DEV_FORMAT.len()];
257             for (dst, src) in name_slice.iter_mut().zip(TUNTAP_DEV_FORMAT.iter()) {
258                 *dst = *src as c_char;
259             }
260             ifreq.ifr_ifru.ifru_flags = (net_sys::IFF_TAP
261                 | net_sys::IFF_NO_PI
262                 | if vnet_hdr { net_sys::IFF_VNET_HDR } else { 0 })
263                 as c_short;
264         }
265 
266         // ioctl is safe since we call it with a valid tap fd and check the return
267         // value.
268         let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_sys::TUNSETIFF(), &mut ifreq) };
269 
270         if ret < 0 {
271             let error = SysError::last();
272 
273             // In a non-root, test environment, we won't have permission to call this; allow
274             if !(cfg!(test) && error.errno() == EPERM) {
275                 return Err(Error::CreateTap(error));
276             }
277         }
278 
279         // Safe since only the name is accessed, and it's copied out.
280         Ok(Tap {
281             tap_file: tuntap,
282             if_name: unsafe { ifreq.ifr_ifrn.ifrn_name },
283             if_flags: unsafe { ifreq.ifr_ifru.ifru_flags },
284         })
285     }
286 
ip_addr(&self) -> Result<net::Ipv4Addr>287     fn ip_addr(&self) -> Result<net::Ipv4Addr> {
288         let sock = create_socket()?;
289         let mut ifreq = self.get_ifreq();
290 
291         // ioctl is safe. Called with a valid sock fd, and we check the return.
292         let ret = unsafe {
293             ioctl_with_mut_ref(&sock, net_sys::sockios::SIOCGIFADDR as c_ulong, &mut ifreq)
294         };
295         if ret < 0 {
296             return Err(Error::IoctlError(SysError::last()));
297         }
298 
299         // We only access one field of the ifru union, hence this is safe.
300         let addr = unsafe { ifreq.ifr_ifru.ifru_addr };
301 
302         Ok(read_ipv4_addr(&addr))
303     }
304 
set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>305     fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
306         let sock = create_socket()?;
307         let addr = create_sockaddr(ip_addr);
308 
309         let mut ifreq = self.get_ifreq();
310         ifreq.ifr_ifru.ifru_addr = addr;
311 
312         // ioctl is safe. Called with a valid sock fd, and we check the return.
313         let ret =
314             unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
315         if ret < 0 {
316             return Err(Error::IoctlError(SysError::last()));
317         }
318 
319         Ok(())
320     }
321 
netmask(&self) -> Result<net::Ipv4Addr>322     fn netmask(&self) -> Result<net::Ipv4Addr> {
323         let sock = create_socket()?;
324         let mut ifreq = self.get_ifreq();
325 
326         // ioctl is safe. Called with a valid sock fd, and we check the return.
327         let ret = unsafe {
328             ioctl_with_mut_ref(
329                 &sock,
330                 net_sys::sockios::SIOCGIFNETMASK as c_ulong,
331                 &mut ifreq,
332             )
333         };
334         if ret < 0 {
335             return Err(Error::IoctlError(SysError::last()));
336         }
337 
338         // We only access one field of the ifru union, hence this is safe.
339         let addr = unsafe { ifreq.ifr_ifru.ifru_netmask };
340 
341         Ok(read_ipv4_addr(&addr))
342     }
343 
set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>344     fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
345         let sock = create_socket()?;
346         let addr = create_sockaddr(netmask);
347 
348         let mut ifreq = self.get_ifreq();
349         ifreq.ifr_ifru.ifru_netmask = addr;
350 
351         // ioctl is safe. Called with a valid sock fd, and we check the return.
352         let ret =
353             unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
354         if ret < 0 {
355             return Err(Error::IoctlError(SysError::last()));
356         }
357 
358         Ok(())
359     }
360 
mac_address(&self) -> Result<MacAddress>361     fn mac_address(&self) -> Result<MacAddress> {
362         let sock = create_socket()?;
363         let mut ifreq = self.get_ifreq();
364 
365         // ioctl is safe. Called with a valid sock fd, and we check the return.
366         let ret = unsafe {
367             ioctl_with_mut_ref(
368                 &sock,
369                 net_sys::sockios::SIOCGIFHWADDR as c_ulong,
370                 &mut ifreq,
371             )
372         };
373         if ret < 0 {
374             return Err(Error::IoctlError(SysError::last()));
375         }
376 
377         // We only access one field of the ifru union, hence this is safe.
378         // This is safe since the MacAddress struct is already sized to match the C sockaddr
379         // struct. The address family has also been checked.
380         Ok(unsafe { mem::transmute(ifreq.ifr_ifru.ifru_hwaddr) })
381     }
382 
set_mac_address(&self, mac_addr: MacAddress) -> Result<()>383     fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()> {
384         let sock = create_socket()?;
385 
386         let mut ifreq = self.get_ifreq();
387 
388         // We only access one field of the ifru union, hence this is safe.
389         unsafe {
390             // This is safe since the MacAddress struct is already sized to match the C sockaddr
391             // struct.
392             ifreq.ifr_ifru.ifru_hwaddr = std::mem::transmute(mac_addr);
393         }
394 
395         // ioctl is safe. Called with a valid sock fd, and we check the return.
396         let ret =
397             unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
398         if ret < 0 {
399             return Err(Error::IoctlError(SysError::last()));
400         }
401 
402         Ok(())
403     }
404 
set_offload(&self, flags: c_uint) -> Result<()>405     fn set_offload(&self, flags: c_uint) -> Result<()> {
406         // ioctl is safe. Called with a valid tap fd, and we check the return.
407         let ret =
408             unsafe { ioctl_with_val(&self.tap_file, net_sys::TUNSETOFFLOAD(), flags as c_ulong) };
409         if ret < 0 {
410             return Err(Error::IoctlError(SysError::last()));
411         }
412 
413         Ok(())
414     }
415 
enable(&self) -> Result<()>416     fn enable(&self) -> Result<()> {
417         let sock = create_socket()?;
418 
419         let mut ifreq = self.get_ifreq();
420         ifreq.ifr_ifru.ifru_flags =
421             (net_sys::net_device_flags_IFF_UP | net_sys::net_device_flags_IFF_RUNNING) as i16;
422 
423         // ioctl is safe. Called with a valid sock fd, and we check the return.
424         let ret =
425             unsafe { ioctl_with_ref(&sock, net_sys::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
426         if ret < 0 {
427             return Err(Error::IoctlError(SysError::last()));
428         }
429 
430         Ok(())
431     }
432 
set_vnet_hdr_size(&self, size: c_int) -> Result<()>433     fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
434         // ioctl is safe. Called with a valid tap fd, and we check the return.
435         let ret = unsafe { ioctl_with_ref(&self.tap_file, net_sys::TUNSETVNETHDRSZ(), &size) };
436         if ret < 0 {
437             return Err(Error::IoctlError(SysError::last()));
438         }
439 
440         Ok(())
441     }
442 
get_ifreq(&self) -> net_sys::ifreq443     fn get_ifreq(&self) -> net_sys::ifreq {
444         let mut ifreq: net_sys::ifreq = Default::default();
445 
446         // This sets the name of the interface, which is the only entry
447         // in a single-field union.
448         unsafe {
449             let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
450             ifrn_name.clone_from_slice(&self.if_name);
451         }
452 
453         // This sets the flags with which the interface was created, which is the only entry we set
454         // on the second union.
455         ifreq.ifr_ifru.ifru_flags = self.if_flags;
456 
457         ifreq
458     }
459 
if_flags(&self) -> u32460     fn if_flags(&self) -> u32 {
461         self.if_flags as u32
462     }
463 }
464 
465 impl Read for Tap {
read(&mut self, buf: &mut [u8]) -> IoResult<usize>466     fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
467         self.tap_file.read(buf)
468     }
469 }
470 
471 impl Write for Tap {
write(&mut self, buf: &[u8]) -> IoResult<usize>472     fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
473         self.tap_file.write(&buf)
474     }
475 
flush(&mut self) -> IoResult<()>476     fn flush(&mut self) -> IoResult<()> {
477         Ok(())
478     }
479 }
480 
481 impl AsRawFd for Tap {
as_raw_fd(&self) -> RawFd482     fn as_raw_fd(&self) -> RawFd {
483         self.tap_file.as_raw_fd()
484     }
485 }
486 
487 pub mod fakes {
488     use super::*;
489     use std::fs::remove_file;
490     use std::fs::OpenOptions;
491 
492     const TMP_FILE: &str = "/tmp/crosvm_tap_test_file";
493 
494     pub struct FakeTap {
495         tap_file: File,
496     }
497 
498     impl TapT for FakeTap {
new(_: bool) -> Result<FakeTap>499         fn new(_: bool) -> Result<FakeTap> {
500             Ok(FakeTap {
501                 tap_file: OpenOptions::new()
502                     .read(true)
503                     .append(true)
504                     .create(true)
505                     .open(TMP_FILE)
506                     .unwrap(),
507             })
508         }
509 
ip_addr(&self) -> Result<net::Ipv4Addr>510         fn ip_addr(&self) -> Result<net::Ipv4Addr> {
511             Ok(net::Ipv4Addr::new(1, 2, 3, 4))
512         }
513 
set_ip_addr(&self, _: net::Ipv4Addr) -> Result<()>514         fn set_ip_addr(&self, _: net::Ipv4Addr) -> Result<()> {
515             Ok(())
516         }
517 
netmask(&self) -> Result<net::Ipv4Addr>518         fn netmask(&self) -> Result<net::Ipv4Addr> {
519             Ok(net::Ipv4Addr::new(255, 255, 255, 252))
520         }
521 
set_netmask(&self, _: net::Ipv4Addr) -> Result<()>522         fn set_netmask(&self, _: net::Ipv4Addr) -> Result<()> {
523             Ok(())
524         }
525 
mac_address(&self) -> Result<MacAddress>526         fn mac_address(&self) -> Result<MacAddress> {
527             Ok("01:02:03:04:05:06".parse().unwrap())
528         }
529 
set_mac_address(&self, _: MacAddress) -> Result<()>530         fn set_mac_address(&self, _: MacAddress) -> Result<()> {
531             Ok(())
532         }
533 
set_offload(&self, _: c_uint) -> Result<()>534         fn set_offload(&self, _: c_uint) -> Result<()> {
535             Ok(())
536         }
537 
enable(&self) -> Result<()>538         fn enable(&self) -> Result<()> {
539             Ok(())
540         }
541 
set_vnet_hdr_size(&self, _: c_int) -> Result<()>542         fn set_vnet_hdr_size(&self, _: c_int) -> Result<()> {
543             Ok(())
544         }
545 
get_ifreq(&self) -> net_sys::ifreq546         fn get_ifreq(&self) -> net_sys::ifreq {
547             let ifreq: net_sys::ifreq = Default::default();
548             ifreq
549         }
550 
if_flags(&self) -> u32551         fn if_flags(&self) -> u32 {
552             net_sys::IFF_TAP
553         }
554     }
555 
556     impl Drop for FakeTap {
drop(&mut self)557         fn drop(&mut self) {
558             let _ = remove_file(TMP_FILE);
559         }
560     }
561 
562     impl Read for FakeTap {
read(&mut self, _: &mut [u8]) -> IoResult<usize>563         fn read(&mut self, _: &mut [u8]) -> IoResult<usize> {
564             Ok(0)
565         }
566     }
567 
568     impl Write for FakeTap {
write(&mut self, _: &[u8]) -> IoResult<usize>569         fn write(&mut self, _: &[u8]) -> IoResult<usize> {
570             Ok(0)
571         }
572 
flush(&mut self) -> IoResult<()>573         fn flush(&mut self) -> IoResult<()> {
574             Ok(())
575         }
576     }
577 
578     impl AsRawFd for FakeTap {
as_raw_fd(&self) -> RawFd579         fn as_raw_fd(&self) -> RawFd {
580             self.tap_file.as_raw_fd()
581         }
582     }
583 }
584 
585 #[cfg(test)]
586 mod tests {
587     use super::*;
588 
589     #[test]
parse_mac_address()590     fn parse_mac_address() {
591         assert!("01:02:03:04:05:06".parse::<MacAddress>().is_ok());
592         assert!("01:06".parse::<MacAddress>().is_err());
593         assert!("01:02:03:04:05:06:07:08:09".parse::<MacAddress>().is_err());
594         assert!("not a mac address".parse::<MacAddress>().is_err());
595     }
596 
597     #[test]
tap_create()598     fn tap_create() {
599         Tap::new(true).unwrap();
600     }
601 
602     #[test]
tap_configure()603     fn tap_configure() {
604         let tap = Tap::new(true).unwrap();
605         let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap();
606         let netmask: net::Ipv4Addr = "255.255.255.252".parse().unwrap();
607         let mac_addr: MacAddress = "a2:06:b9:3d:68:4d".parse().unwrap();
608 
609         let ret = tap.set_ip_addr(ip_addr);
610         assert_ok_or_perm_denied(ret);
611         let ret = tap.set_netmask(netmask);
612         assert_ok_or_perm_denied(ret);
613         let ret = tap.set_mac_address(mac_addr);
614         assert_ok_or_perm_denied(ret);
615     }
616 
617     /// This test will only work if the test is run with root permissions and, unlike other tests
618     /// in this file, do not return PermissionDenied. They fail because the TAP FD is not
619     /// initialized (as opposed to permission denial). Run this with "cargo test -- --ignored".
620     #[test]
621     #[ignore]
root_only_tests()622     fn root_only_tests() {
623         // This line will fail to provide an initialized FD if the test is not run as root.
624         let tap = Tap::new(true).unwrap();
625         tap.set_vnet_hdr_size(16).unwrap();
626         tap.set_offload(0).unwrap();
627     }
628 
629     #[test]
tap_enable()630     fn tap_enable() {
631         let tap = Tap::new(true).unwrap();
632 
633         let ret = tap.enable();
634         assert_ok_or_perm_denied(ret);
635     }
636 
assert_ok_or_perm_denied<T>(res: Result<T>)637     fn assert_ok_or_perm_denied<T>(res: Result<T>) {
638         match res {
639             // We won't have permission in test environments; allow that
640             Ok(_t) => {}
641             Err(Error::IoctlError(e)) if e.errno() == EPERM => {}
642             Err(e) => panic!("Unexpected Error:\n{}", e),
643         }
644     }
645 }
646