From 59e1361f5eaa7be1fecbf95a9c444b3024d68598 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 15 May 2020 09:56:45 +0100 Subject: [PATCH] net_util: tap: Add support for setting tap MAC address Do this by reading the HW address information and then modifying the HW address to match the desired address. Preserving the rest of the state including the address type. Signed-off-by: Rob Bradford Signed-off-by: Sebastien Boeuf --- net_util/src/tap.rs | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/net_util/src/tap.rs b/net_util/src/tap.rs index fe0ada459..8de8e9667 100644 --- a/net_util/src/tap.rs +++ b/net_util/src/tap.rs @@ -5,15 +5,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the THIRD-PARTY file. +use super::{create_sockaddr, create_socket, Error as NetUtilError, MacAddr}; +use libc; +use net_gen; use std::fs::File; use std::io::{Error as IoError, Read, Result as IoResult, Write}; use std::net; use std::os::raw::*; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; - -use super::{create_sockaddr, create_socket, Error as NetUtilError}; -use libc; -use net_gen; use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val}; #[derive(Debug)] @@ -176,6 +175,38 @@ impl Tap { Ok(()) } + /// Set mac addr for tap interface. + pub fn set_mac_addr(&self, addr: MacAddr) -> Result<()> { + let sock = create_socket().map_err(Error::NetUtil)?; + + let mut ifreq = self.get_ifreq(); + + // ioctl is safe. Called with a valid sock fd, and we check the return. + #[allow(clippy::cast_lossless)] + let ret = + unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) }; + if ret < 0 { + return Err(Error::IoctlError(IoError::last_os_error())); + } + // We only access one field of the ifru union, hence this is safe. + unsafe { + let ifru_hwaddr = ifreq.ifr_ifru.ifru_hwaddr.as_mut(); + for (i, v) in addr.get_bytes().iter().enumerate() { + ifru_hwaddr.sa_data[i] = *v as i8; + } + } + + // ioctl is safe. Called with a valid sock fd, and we check the return. + #[allow(clippy::cast_lossless)] + let ret = + unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) }; + if ret < 0 { + return Err(Error::IoctlError(IoError::last_os_error())); + } + + Ok(()) + } + /// Set the netmask for the subnet that the tap interface will exist on. pub fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> { let sock = create_socket().map_err(Error::NetUtil)?;