From 2d3614fb132b1cb8efd1e0accdd0c98ce6893efa Mon Sep 17 00:00:00 2001 From: Zhenlei Huang Date: Fri, 7 Apr 2023 22:25:41 +0800 Subject: [PATCH] bridge: Log MAC address port flapping MAC flapping occurs when a bridge receives packets with the same source MAC address on different member interfaces. The common reasons are: - user roams from one bridge port to another - user has wrong network setup, bridge loops e.g. - someone set duplicated ethernet address on his/her nic - some bad guy / virus / trojan send spoofed packets if_bridge currently updates the bridge routing entry silently hence it is hard to diagnose. Emit logs when MAC address port flapping occurs to make it easier to diagnose. Reviewed by: kp MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D39375 --- sys/net/if_bridge.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 2855236e4013..78be987d681b 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -460,6 +460,21 @@ SYSCTL_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap, "Allow overlap of link-local scope " "zones of a bridge interface and the member interfaces"); +/* log MAC address port flapping */ +VNET_DEFINE_STATIC(bool, log_mac_flap) = true; +#define V_log_mac_flap VNET(log_mac_flap) +SYSCTL_BOOL(_net_link_bridge, OID_AUTO, log_mac_flap, + CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(log_mac_flap), true, + "Log MAC address port flapping"); + +VNET_DEFINE_STATIC(int, log_interval) = 5; +VNET_DEFINE_STATIC(int, log_count) = 0; +VNET_DEFINE_STATIC(struct timeval, log_last) = { 0 }; + +#define V_log_interval VNET(log_interval) +#define V_log_count VNET(log_count) +#define V_log_last VNET(log_last) + struct bridge_control { int (*bc_func)(struct bridge_softc *, void *); int bc_argsize; @@ -2768,6 +2783,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, struct bridge_iflist *bif, int setflags, uint8_t flags) { struct bridge_rtnode *brt; + struct bridge_iflist *obif; int error; BRIDGE_LOCK_OR_NET_EPOCH_ASSERT(sc); @@ -2791,7 +2807,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, /* Check again, now that we have the lock. There could have * been a race and we only want to insert this once. */ - if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) != NULL) { + if (bridge_rtnode_lookup(sc, dst, vlan) != NULL) { BRIDGE_RT_UNLOCK(sc); return (0); } @@ -2840,12 +2856,24 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, } if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && - brt->brt_dst != bif) { + (obif = brt->brt_dst) != bif) { BRIDGE_RT_LOCK(sc); brt->brt_dst->bif_addrcnt--; brt->brt_dst = bif; brt->brt_dst->bif_addrcnt++; BRIDGE_RT_UNLOCK(sc); + + if (V_log_mac_flap && + ppsratecheck(&V_log_last, &V_log_count, V_log_interval)) { + uint8_t *addr = &brt->brt_addr[0]; + log(LOG_NOTICE, + "%s: mac address %02x:%02x:%02x:%02x:%02x:%02x vlan %d moved from %s to %s\n", + sc->sc_ifp->if_xname, + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], + brt->brt_vlan, + obif->bif_ifp->if_xname, + bif->bif_ifp->if_xname); + } } if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)