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