use std::ffi::CString;
#[derive(Debug, Clone)]
pub struct BridgeTarget {
pub name: String,
pub ifindex: u32,
}
pub fn resolve_bridge_by_mac(mac_str: &str) -> Option<BridgeTarget> {
let mac: ifbridge::MacAddr = mac_str.parse().ok()?;
let bridge_name = ifbridge::find_bridge_by_mac(mac)
.inspect_err(|e| tracing::debug!(error = %e, "bridge enumeration failed"))
.ok()
.flatten()?;
let ifindex = if_nametoindex(&bridge_name)?;
Some(BridgeTarget {
name: bridge_name,
ifindex,
})
}
pub fn find_bridge_with_vmenet() -> Option<(String, String)> {
let bridges = ifbridge::list_bridges().ok()?;
for bridge in bridges {
if let Ok(members) = ifbridge::list_members(&bridge) {
for member in &members {
if member.name.starts_with("vmenet") {
return Some((bridge, member.name.clone()));
}
}
}
}
None
}
fn if_nametoindex(name: &str) -> Option<u32> {
let cname = CString::new(name).ok()?;
let idx = unsafe { libc::if_nametoindex(cname.as_ptr()) };
if idx == 0 { None } else { Some(idx) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resolve_nonexistent_mac() {
assert!(resolve_bridge_by_mac("ff:ff:ff:ff:ff:ff").is_none());
}
#[test]
fn test_resolve_invalid_mac() {
assert!(resolve_bridge_by_mac("not-a-mac").is_none());
}
#[test]
fn test_find_bridge_with_vmenet_no_panic() {
let _ = find_bridge_with_vmenet();
}
}