stp: enforce blocking on unicast send + enhanced stats display

BridgeDevice STP hardening:
- send(): check STP blocking before unicast forwarding (host-originated)
- recv(): check STP blocking before unicast forwarding (switched frames)
- Previously only flood() checked STP; unicast forwarding bypassed it.
  A blocked port must never forward any traffic — STP semantics now correct.

netcfg stats enhancement:
- Per-interface stats now include mtu= and link= fields alongside counters
- Applies to both eth0 and loopback
- Enables bandwidth monitoring tools to self-discover MTU/link state
This commit is contained in:
Red Bear OS
2026-07-08 14:53:08 +03:00
parent 0baceb0ef6
commit 107e3b6851
2 changed files with 12 additions and 5 deletions
+6 -1
View File
@@ -117,6 +117,9 @@ impl LinkDevice for BridgeDevice {
if repr.dst_addr.is_broadcast() || repr.dst_addr.is_multicast() {
self.flood(packet, now, None);
} else if let Some(port_idx) = self.lookup(dst_mac) {
if self.stp.borrow().as_ref().is_some_and(|s| s.is_blocked(port_idx)) {
return;
}
if let Some(port) = self.ports.borrow_mut().get_mut(port_idx) {
port.send(IpAddress::Ipv4(smoltcp::wire::Ipv4Address::UNSPECIFIED), packet, now);
}
@@ -179,7 +182,9 @@ impl LinkDevice for BridgeDevice {
self.flood(&self.recv_buffer, now, Some(port_idx));
return Some(&self.recv_buffer);
} else if let Some(dst_port_idx) = self.lookup(dst_mac) {
if dst_port_idx != port_idx {
if dst_port_idx != port_idx
&& !self.stp.borrow().as_ref().is_some_and(|s| s.is_blocked(dst_port_idx))
{
let mut ports = self.ports.borrow_mut();
if let Some(target) = ports.get_mut(dst_port_idx) {
target.send(IpAddress::Ipv4(smoltcp::wire::Ipv4Address::UNSPECIFIED), &packet, now);
+6 -4
View File
@@ -351,8 +351,9 @@ fn mk_root_node(
match devices.borrow().get("eth0") {
Some(dev) => {
let s = dev.statistics();
format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={}\n",
s.rx_bytes, s.rx_packets, s.tx_bytes, s.tx_packets)
format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={} mtu={} link={}\n",
s.rx_bytes, s.rx_packets, s.tx_bytes, s.tx_packets,
dev.mtu(), dev.link_state())
}
None => "Device not found\n".into(),
}
@@ -394,8 +395,9 @@ fn mk_root_node(
match devices.borrow().get("loopback") {
Some(dev) => {
let s = dev.statistics();
format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={}\n",
s.rx_bytes, s.rx_packets, s.tx_bytes, s.tx_packets)
format!("rx_bytes={} rx_packets={} tx_bytes={} tx_packets={} mtu={} link={}\n",
s.rx_bytes, s.rx_packets, s.tx_bytes, s.tx_packets,
dev.mtu(), dev.link_state())
}
None => "Device not found\n".into(),
}