diff --git a/net_util/src/open_tap.rs b/net_util/src/open_tap.rs index 10d71b29f..e711529ca 100644 --- a/net_util/src/open_tap.rs +++ b/net_util/src/open_tap.rs @@ -58,6 +58,54 @@ fn check_mq_support(if_name: &Option<&str>, queue_pairs: usize) -> Result<()> { Ok(()) } +/// Opens a Tap device and configures it. +/// +/// Afterward, further RX queues can be opened with a common config. +fn open_tap_rx_q_0( + if_name: Option<&str>, + ip_addr: Option, + netmask: Option, + host_mac: &mut Option, + mtu: Option, + num_rx_q: usize, + flags: Option, +) -> Result { + // Check if the given interface exists before we create it. + let tap_exists = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists()); + + let tap = match if_name { + Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?, + // Create a new Tap device in Linux, if none was specified. + None => Tap::new(num_rx_q).map_err(Error::TapOpen)?, + }; + // Don't overwrite ip configuration of existing interfaces: + if !tap_exists { + if let Some(ip) = ip_addr { + tap.set_ip_addr(ip, netmask) + .map_err(Error::TapSetIpNetmask)?; + } + } else { + warn!( + "Tap {} already exists. IP configuration will not be overwritten.", + if_name.unwrap_or_default() + ); + } + if let Some(mac) = host_mac { + tap.set_mac_addr(*mac).map_err(Error::TapSetMac)? + } else { + *host_mac = Some(tap.get_mac_addr().map_err(Error::TapGetMac)?) + } + if let Some(mtu) = mtu { + tap.set_mtu(mtu as i32).map_err(Error::TapSetMtu)?; + } + tap.enable().map_err(Error::TapEnable)?; + + tap.set_vnet_hdr_size(vnet_hdr_len() as i32) + .map_err(Error::TapSetVnetHdrSize)?; + + Ok(tap) +} + /// Create a new virtio network device with the given IP address and /// netmask. pub fn open_tap( @@ -71,9 +119,6 @@ pub fn open_tap( ) -> Result> { let mut taps: Vec = Vec::new(); let mut ifname: String = String::new(); - let vnet_hdr_size = vnet_hdr_len() as i32; - // Check if the given interface exists before we create it. - let tap_existed = if_name.is_some_and(|n| Path::new(&format!("/sys/class/net/{n}")).exists()); // In case the tap interface already exists, check if the number of // queues is appropriate. The tap might not support multiqueue while @@ -85,40 +130,16 @@ pub fn open_tap( for i in 0..num_rx_q { let tap: Tap; if i == 0 { - tap = match if_name { - Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?, - None => Tap::new(num_rx_q).map_err(Error::TapOpen)?, - }; - // Don't overwrite ip configuration of existing interfaces: - if !tap_existed { - if let Some(ip) = ip_addr { - tap.set_ip_addr(ip, netmask) - .map_err(Error::TapSetIpNetmask)?; - } - } else { - warn!( - "Tap {} already exists. IP configuration will not be overwritten.", - if_name.unwrap_or_default() - ); - } - if let Some(mac) = host_mac { - tap.set_mac_addr(*mac).map_err(Error::TapSetMac)? - } else { - *host_mac = Some(tap.get_mac_addr().map_err(Error::TapGetMac)?) - } - if let Some(mtu) = mtu { - tap.set_mtu(mtu as i32).map_err(Error::TapSetMtu)?; - } - tap.enable().map_err(Error::TapEnable)?; - - tap.set_vnet_hdr_size(vnet_hdr_size) - .map_err(Error::TapSetVnetHdrSize)?; - + // Special handling is required for the first RX queue, such as + // configuring the device. Subsequent iterations will then use the + // same device. + tap = open_tap_rx_q_0(if_name, ip_addr, netmask, host_mac, mtu, num_rx_q, flags)?; + // Set the name of the tap device we open in subsequent iterations. ifname = String::from_utf8(tap.get_if_name()).unwrap(); } else { tap = Tap::open_named(ifname.as_str(), num_rx_q, flags).map_err(Error::TapOpen)?; - tap.set_vnet_hdr_size(vnet_hdr_size) + tap.set_vnet_hdr_size(vnet_hdr_len() as i32) .map_err(Error::TapSetVnetHdrSize)?; } taps.push(tap);