git: de53ebb0f20e - stable/13 - bridge: Log MAC address port flapping

From: Zhenlei Huang <zlei_at_FreeBSD.org>
Date: Fri, 21 Apr 2023 10:11:34 UTC
The branch stable/13 has been updated by zlei:

URL: https://cgit.FreeBSD.org/src/commit/?id=de53ebb0f20e9735a6167230eb38fd4695aa9c51

commit de53ebb0f20e9735a6167230eb38fd4695aa9c51
Author:     Zhenlei Huang <zlei@FreeBSD.org>
AuthorDate: 2023-04-07 14:25:41 +0000
Commit:     Zhenlei Huang <zlei@FreeBSD.org>
CommitDate: 2023-04-21 10:10:12 +0000

    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
    Differential Revision:  https://reviews.freebsd.org/D39542
    
    (cherry picked from commit 2d3614fb132b1cb8efd1e0accdd0c98ce6893efa)
    (cherry picked from commit 9af6f4268ac3cc8203f34c746d955b4405279099)
---
 sys/net/if_bridge.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index ef01be9c5b49..cd2fbff3a85c 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -466,6 +466,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;
@@ -2745,6 +2760,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);
@@ -2768,7 +2784,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);
 		}
@@ -2817,12 +2833,23 @@ 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)) {
+			log(LOG_NOTICE,
+			    "%s: mac address %6D vlan %d moved from %s to %s\n",
+			    sc->sc_ifp->if_xname,
+			    &brt->brt_addr[0], ":",
+			    brt->brt_vlan,
+			    obif->bif_ifp->if_xname,
+			    bif->bif_ifp->if_xname);
+		}
 	}
 
 	if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)