From a3919f117041524042e16c7698a8a08a16d42a4c Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Thu, 9 May 2024 22:42:30 -0700 Subject: [PATCH] feat(net): use a tun/tap interface as a backend The current virtio-net implementation assumes the tap device path is referring to a macvtap or ipvtap. This commit allows using a tun/tap interface pre-created by `ip tuntap add mode tap $IF_NAME` as a backend. Usage: ``` --net if=$IF_NAME,mac=$IF_MAC,mtu=$IF_MTU ``` Signed-off-by: Changyuan Lyu --- alioth-cli/src/main.rs | 7 +++++-- alioth/src/virtio/dev/net/net.rs | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/alioth-cli/src/main.rs b/alioth-cli/src/main.rs index 80ad91a..2fd1752 100644 --- a/alioth-cli/src/main.rs +++ b/alioth-cli/src/main.rs @@ -101,8 +101,10 @@ fn parse_mem(s: &str) -> Result { fn parse_net<'a>(s: &'a str) -> Result { let mut parts = s.trim().splitn(3, ','); let splitter = |s: &'a str| s.split_once::<'a, _>('='); - let Some(("tap", tap_path)) = parts.next().and_then(splitter) else { - bail!("invalid net opt: {s}"); + let (tap_path, if_name) = match parts.next().and_then(splitter) { + Some(("tap", p)) => (p, None), + Some(("if", name)) => ("/dev/net/tun", Some(name.to_owned())), + _ => bail!("invalid net opt: {s}"), }; let Some(("mac", mac_str)) = parts.next().and_then(splitter) else { bail!("invalid net opt: {s}"); @@ -133,6 +135,7 @@ fn parse_net<'a>(s: &'a str) -> Result { mtu: mtu_str.parse()?, queue_pairs: 1, tap: tap_path.into(), + if_name, }) } diff --git a/alioth/src/virtio/dev/net/net.rs b/alioth/src/virtio/dev/net/net.rs index b88201a..051262a 100644 --- a/alioth/src/virtio/dev/net/net.rs +++ b/alioth/src/virtio/dev/net/net.rs @@ -15,6 +15,8 @@ use std::fmt::Debug; use std::fs::{self, File}; use std::io; +use std::iter::zip; +use std::mem::MaybeUninit; use std::os::fd::AsRawFd; use std::os::unix::prelude::OpenOptionsExt; use std::path::PathBuf; @@ -107,6 +109,7 @@ pub struct NetParam { pub mtu: u16, pub queue_pairs: u16, pub tap: PathBuf, + pub if_name: Option, } impl DevParam for NetParam { @@ -125,7 +128,7 @@ impl Net { .write(true) .open(param.tap)?; - setup_tap(&mut file)?; + setup_tap(&mut file, param.if_name.as_deref())?; let net = Net { name, config: Arc::new(NetConfig { @@ -244,8 +247,18 @@ pub const TOKEN_TAP: Token = Token(0); const VNET_HEADER_SIZE: i32 = 12; -fn setup_tap(file: &mut File) -> Result<()> { - let mut tap_ifconfig = unsafe { tun_get_iff(file) }?; +fn setup_tap(file: &mut File, if_name: Option<&str>) -> Result<()> { + let mut tap_ifconfig = match if_name { + None => unsafe { tun_get_iff(file) }?, + Some(name) => { + let mut tap_ifconfig = unsafe { MaybeUninit::::zeroed().assume_init() }; + for (s, d) in zip(name.as_bytes(), tap_ifconfig.ifr_name.as_mut()) { + *d = *s as i8; + } + tap_ifconfig + } + }; + tap_ifconfig.ifr_ifru.ifru_flags = (IFF_TAP | IFF_NO_PI | IFF_VNET_HDR) as i16; unsafe { tun_set_iff(file, &tap_ifconfig) }?; unsafe { tun_set_vnet_hdr_sz(file, &VNET_HEADER_SIZE) }?;