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 = ð_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