use nlink::netlink::{Connection, Route};
#[tokio::main]
async fn main() -> nlink::Result<()> {
let conn = Connection::<Route>::new()?;
println!("=== Bridge FDB Entries ===\n");
let links = conn.get_links().await?;
let bridges: Vec<_> = links
.iter()
.filter(|l| l.link_kind() == Some("bridge"))
.collect();
if bridges.is_empty() {
println!("No bridge interfaces found.\n");
println!("Create a bridge with:");
println!(" sudo ip link add br0 type bridge");
println!(" sudo ip link set br0 up");
println!();
} else {
for bridge in &bridges {
let name = bridge.name_or("?");
println!("Bridge: {}", name);
match conn.get_fdb(name).await {
Ok(entries) => {
if entries.is_empty() {
println!(" No FDB entries\n");
} else {
for entry in &entries {
print!(" {} ", entry.mac_str());
if let Some(vlan) = entry.vlan {
print!("vlan {} ", vlan);
}
if let Some(dst) = &entry.dst {
print!("dst {} ", dst);
}
if entry.is_permanent() {
print!("permanent ");
}
if entry.is_local() {
print!("local ");
}
println!();
}
println!();
}
}
Err(e) => println!(" Error: {}\n", e),
}
}
}
println!("=== FDB Management Examples ===\n");
println!("--- Query FDB entries ---");
println!(
r#"
use nlink::netlink::{{Connection, Route}};
let conn = Connection::<Route>::new()?;
// Get all FDB entries for a bridge
let entries = conn.get_fdb("br0").await?;
for entry in &entries {
println!("{} vlan={:?}", entry.mac_str(), entry.vlan);
}
// Get entries for a specific port
let port_entries = conn.get_fdb_for_port("br0", "veth0").await?;
"#
);
println!("--- Add static FDB entry ---");
println!(
r#"
use nlink::netlink::fdb::FdbEntryBuilder;
// Parse MAC address
let mac = FdbEntryBuilder::parse_mac("aa:bb:cc:dd:ee:ff")?;
// Add permanent static entry
conn.add_fdb(
FdbEntryBuilder::new(mac)
.dev("veth0") // Bridge port
.master("br0") // Bridge interface
.vlan(100) // Optional VLAN
.permanent() // Static entry
).await?;
"#
);
println!("--- Add VXLAN FDB entry (remote VTEP) ---");
println!(
r#"
use std::net::Ipv4Addr;
// Add entry for BUM (broadcast/unknown/multicast) traffic
conn.add_fdb(
FdbEntryBuilder::new([0x00; 6]) // All-zeros for BUM
.dev("vxlan0")
.dst(Ipv4Addr::new(192, 168, 1, 100).into())
).await?;
// Add specific MAC -> VTEP mapping
let mac = FdbEntryBuilder::parse_mac("00:11:22:33:44:55")?;
conn.add_fdb(
FdbEntryBuilder::new(mac)
.dev("vxlan0")
.dst(Ipv4Addr::new(192, 168, 1, 101).into())
).await?;
"#
);
println!("--- Delete FDB entry ---");
println!(
r#"
let mac = FdbEntryBuilder::parse_mac("aa:bb:cc:dd:ee:ff")?;
// Delete without VLAN
conn.del_fdb("veth0", mac, None).await?;
// Delete with specific VLAN
conn.del_fdb("veth0", mac, Some(100)).await?;
"#
);
println!("--- Replace FDB entry ---");
println!(
r#"
// Add or update an entry
conn.replace_fdb(
FdbEntryBuilder::new(mac)
.dev("veth0")
.master("br0")
.permanent()
).await?;
"#
);
println!("--- Flush FDB entries ---");
println!(
r#"
// Flush all dynamic entries (keeps permanent)
conn.flush_fdb("br0").await?;
"#
);
Ok(())
}