bridge: 5 unit tests for FDB learn/age/lookup

Bridge MAC learning tests:
- learn_stores_unicast_mapping: stored MAC resolves on correct port
- learn_ignores_multicast: broadcast/multicast never enters FDB
- learn_replaces_existing_entry_on_new_port: MAC moves update port
- age_entries_removes_expired_macs: 300s timeout respected
- lookup_returns_none_for_unknown_mac: unknown MAC returns None

Total tests across netstack: 20 (5 table + 4 conntrack + 6 nat + 5 bridge)
All passing.
This commit is contained in:
Red Bear OS
2026-07-08 21:20:32 +03:00
parent d2e6ea1ba9
commit 596e73a92e
+59 -1
View File
@@ -259,4 +259,62 @@ impl LinkDevice for BridgeDevice {
}
out
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use smoltcp::wire::EthernetAddress;
fn mac(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> EthernetAddress {
EthernetAddress([a, b, c, d, e, f])
}
#[test]
fn learn_stores_unicast_mapping() {
let b = BridgeDevice::new("br0");
let m = mac(0x00, 0x11, 0x22, 0x33, 0x44, 0x55);
b.learn(m, 2, Instant::from_secs(0));
assert_eq!(b.lookup(m), Some(2),
"Learned MAC must be found on port 2");
}
#[test]
fn learn_ignores_multicast() {
let b = BridgeDevice::new("br0");
let multicast = EthernetAddress::BROADCAST;
b.learn(multicast, 1, Instant::from_secs(0));
assert_eq!(b.lookup(multicast), None,
"Multicast MACs must not be learned");
}
#[test]
fn learn_replaces_existing_entry_on_new_port() {
let b = BridgeDevice::new("br0");
let m = mac(0x00, 0x11, 0x22, 0x33, 0x44, 0x55);
b.learn(m, 1, Instant::from_secs(0));
assert_eq!(b.lookup(m), Some(1));
b.learn(m, 2, Instant::from_secs(10));
assert_eq!(b.lookup(m), Some(2),
"MAC move from port 1 to port 2 must update FDB");
}
#[test]
fn age_entries_removes_expired_macs() {
let b = BridgeDevice::new("br0");
let m1 = mac(0x00, 0x11, 0x22, 0x33, 0x44, 0x55);
let m2 = mac(0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE);
b.learn(m1, 1, Instant::from_secs(0));
b.learn(m2, 2, Instant::from_secs(MAC_AGE_TIMEOUT.secs() as i64)); // Age boundary
// Age just past the 300s timeout
b.age_entries(Instant::from_secs(MAC_AGE_TIMEOUT.secs() as i64 + 1));
assert_eq!(b.lookup(m1), None, "m1 (learned at 0) must be aged out");
assert_eq!(b.lookup(m2), Some(2),
"m2 (learned at 300s) must still be valid");
}
#[test]
fn lookup_returns_none_for_unknown_mac() {
let b = BridgeDevice::new("br0");
assert_eq!(b.lookup(mac(0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01)), None);
}
}