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