From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm2-f13.google.com (mail-wm2-f13.google.com [74.125.225.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFD9145090A for ; Wed, 30 Sep 2026 07:15:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.141 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790752518; cv=none; b=HfxEMlpMeNHjL12d2g/tOtlaDNcKp3NpIgfkg0xWr4IwVCEJ3qdCmQeWRqE5SjjMZ0psR0ZgZd4aND5IOrZtNkTkXNV1D0RJ8JskjnxwcaFaYlRJCOYThhPByyM7eX8a925AcSlo+btLS9gduuYHlnL08Z6oWWwm551WDeUzZOs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790752518; c=relaxed/simple; bh=ldlfciuIYbv5X4j0OpaOB1JAWwUlNJAVu78g/rnmcXc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZmgJGq8sUUxUFfBqli2ji5YViD9wgJHP1cXT9uxWsxnWveqEL6Moi1KPvBgJd2K/rgVONEOIZNqrHEGvwOrM0EzFI/1ESSVGHWvsm/lZ6aTKYR9bYLAk82Lgy0mjESgYXp19bkLyqpgT8+bX4SRSF4g3xQbkdZf/gIvPIDSokis= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=blackwall.org; spf=none smtp.mailfrom=blackwall.org; dkim=pass (2048-bit key) header.d=blackwall.org header.i=@blackwall.org header.b=KmHwAyXL; arc=none smtp.client-ip=74.125.225.141 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=blackwall.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=blackwall.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=blackwall.org header.i=@blackwall.org header.b="KmHwAyXL" Received: by mail-wm2-f13.google.com with SMTP id 5b1f17b1804b1-49e6b885ef8so28946765e9.1 for ; Wed, 30 Sep 2026 00:15:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=blackwall.org; s=google; t=1790752511; x=1791357311; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=WfaeNk+TbvRqojZcx8T2YQ1WiNBIMIQG8iQ0MxbUCt8=; b=KmHwAyXLaY8LeEKhIG03fTCcWRUX1AHloq7dWwpMfPSs7eGwY5iw14Erpbv8mz2JSq wkyI3Svi6WCIdbzbMEki2cc7hJ/piqL842txcL+FCfC5lga+3zk27oIIvbud07AEJSRs jNGeuHQHg/AEH50/O+51F2LpfLAXfKNBA5scHVPQ2/smLRhXg5VgA4Mx7fZuGx2O+IHM SjrI4EwqVQ104kC+HZOIQ5fMEHU+NhVby2P/J3QP/BAZ45dUxdeqHbgYpwbAvjjdrVRM chY5kBDeweJXHA1UBP/xmTfEA/wMoElULAYRN50L3RPaJWhS+5hvvp4q45pURlXcqC4/ Gemw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790752511; x=1791357311; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=WfaeNk+TbvRqojZcx8T2YQ1WiNBIMIQG8iQ0MxbUCt8=; b=1lxnOiPdR3v18wgrWxwTmSrqRoGKTYR9loKpx+iQH4qrCsdOavJNDUi6SLyvu60uhN MdbdwmJvgoRk5PmCiJUkTV3L7hNXT+isAuib6UoaW+QfdCeZUWdlS1R61z2ByZKoIYi2 n+/LwoKHABQYStiCc26Lik5LotaCQX37X2AdrQz81HWJd7GeoT8JKzim+nYtK53HSx0d VnDR9WFc71Lx52Lz9V/iEe3GGQws5uzOsl6c4VT7fQeYkeitVOEVxTSsQ/4lakvnkfFJ iF9BVjUBwA5OACAQPInIpT3/v4AAlvErzVRK9zUvQKwigVdlmPJ4WymsqMyaBqS/kKax FDaQ== X-Gm-Message-State: AFuF++m88VcjNEFwqnsC8Th5mPxBERTsmIeWM+0qOz92H61ePIuDZ8Av UOQ3BSjOFv5pMb0SMqi4xbrapcf/tFPKyQ3NsplhzOSpVHEfCbT6q8xYaXu0eJhM5C42s6GK3XR 9mjdP X-Gm-Gg: AYBFou19GYyOYbbouP7nq2pkDx5iM6S1/OArA0e7DnOG36cjkdlOCdw+EcWviZaLiGM gXL4mSkfWrhQ3OZIrpkY++k8snDYHsWPH+sSLJv7B8OPogRYNXkwFMFRR4X3NWOXxQVyU7ZBW7R aCLNLzAVOAYac8TnbxCvrnnp+7+aHNDvYpcRpakOJnlAGKTvF0uS7CFUt7gQoBf4bhoEdPGVw4z y7zxoUY0xZDHW4xoD9U4yBjqLA1UDIhXfJ2tHIruqAyzSBcxjGvv6v4BoU3AuHVlT2xjYMQMlOa D/GQhdSNsYzosWDidhG8t9fVu1r5AjDFoYLoUrho2xGsT4XVOtB2sEcRapEHPdjOd5CF1Grf8QA +MEyBVkoWybBEIrWIxVZuHqtf22+yWY5Ml6IXmx7WYVYqkqdANdhHzQClxWGnpKO7UAyjyWG9e8 eOtBmkjfaouXNID1HQ280HxZXrVBWWYKYfDXzZ3GPKacgTeygni/ka6RZWNZpJJ+paveXWnb3G/ Yc10eGdPXoG9ZQ+cPQ2 X-Received: by 2002:a05:600c:c162:b0:49e:6778:c2bd with SMTP id 5b1f17b1804b1-4a01afe1e88mr6149585e9.6.1790752510711; Wed, 30 Sep 2026 00:15:10 -0700 (PDT) Received: from localhost (78-154-14-127.ip.btc-net.bg. [78.154.14.127]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-4a017b67813sm18251115e9.2.2026.09.30.00.15.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Sep 2026 00:15:09 -0700 (PDT) From: Nikolay Aleksandrov To: netdev@vger.kernel.org Cc: idosch@nvidia.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, bridge@lists.linux.dev, Nikolay Aleksandrov Subject: [PATCH net-next 08/12] net: bridge: vlan: quiesce readers before freeing port VLANs Date: Wed, 30 Sep 2026 10:14:07 +0300 Message-ID: <20260930071411.2786201-9-razor@blackwall.org> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260930071411.2786201-1-razor@blackwall.org> References: <20260930071411.2786201-1-razor@blackwall.org> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Later fdb entries will cache port-VLAN pointers so unpublish a VLAN, wait for a grace period (existing readers) and then purge or rewrite fdb references before releasing it. Cached destinations can continue forwarding until they are cleaned, that is acceptable so add a comment to document it. During port teardown unpublish the complete VLAN group first, clean the port fdbs and then release the VLANs. This lets all VLANs share one grace period. Reviewed-by: Ido Schimmel Signed-off-by: Nikolay Aleksandrov --- net/bridge/br_fdb.c | 20 ++++++++++++++++---- net/bridge/br_if.c | 7 +++++-- net/bridge/br_private.h | 12 ++++++++++-- net/bridge/br_vlan.c | 21 +++++++++++++++------ 4 files changed, 46 insertions(+), 14 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 7c68b540b358..307f9c12914e 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -883,7 +883,9 @@ void br_fdb_cleanup_by_dst(struct net_bridge *br, spin_lock_bh(&br->hash_lock); hlist_for_each_entry_safe(f, tmp, &br->fdb_list, fdb_node) { - if (br_fdb_dst_port(f) != p) + struct net_bridge_dst dst = br_fdb_dst_read(f); + + if (br_dst_port(dst) != p) continue; if (vlan && f->key.vlan_id == vlan->vid && @@ -894,12 +896,22 @@ void br_fdb_cleanup_by_dst(struct net_bridge *br, continue; } - if (!do_all) + if (!do_all) { + if (vid && f->key.vlan_id != vid) + continue; + if (test_bit(BR_FDB_STATIC, &f->flags) || (test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags) && - !test_bit(BR_FDB_OFFLOADED, &f->flags)) || - (vid && f->key.vlan_id != vid)) + !test_bit(BR_FDB_OFFLOADED, &f->flags))) { + /* The entry outlives the VLAN, so it must fall + * back to the raw port destination + */ + if (vlan && br_dst_vlan(dst) == vlan) + br_fdb_dst_write(f, + br_port_to_dst(p)); continue; + } + } if (test_bit(BR_FDB_LOCAL, &f->flags)) fdb_delete_local(br, p, f); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index d94558a5e3e9..2c05ebc1299d 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -333,8 +333,9 @@ static void update_headroom(struct net_bridge *br, int new_hr) */ static void del_nbp(struct net_bridge_port *p) { - struct net_bridge *br = p->br; + struct net_bridge_vlan_group *vg; struct net_device *dev = p->dev; + struct net_bridge *br = p->br; sysfs_remove_link(br->ifobj, p->dev->name); @@ -354,8 +355,10 @@ static void del_nbp(struct net_bridge_port *p) update_headroom(br, get_max_headroom(br)); netdev_reset_rx_headroom(dev); - nbp_vlan_flush(p); + vg = nbp_vlan_group(p); + nbp_vlan_group_unpublish(p); br_fdb_cleanup_by_dst(br, br_port_to_dst(p), 0, 1); + nbp_vlan_flush(p, vg); switchdev_deferred_process(); nbp_backup_clear(p); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index a790368b69e9..951b6ac5f484 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1735,7 +1735,9 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid, int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags, bool *changed, struct netlink_ext_ack *extack); int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); -void nbp_vlan_flush(struct net_bridge_port *port); +void nbp_vlan_group_unpublish(struct net_bridge_port *port); +void nbp_vlan_flush(struct net_bridge_port *port, + struct net_bridge_vlan_group *vg); int nbp_vlan_init(struct net_bridge_port *port, struct netlink_ext_ack *extack); int nbp_get_num_vlan_infos(struct net_bridge_port *p, u32 filter_mask); void br_vlan_get_stats(const struct net_bridge_vlan *v, @@ -1894,7 +1896,13 @@ static inline int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) return -EOPNOTSUPP; } -static inline void nbp_vlan_flush(struct net_bridge_port *port) +static inline void nbp_vlan_group_unpublish(struct net_bridge_port *port) +{ +} + +static inline void +nbp_vlan_flush(struct net_bridge_port *port, + struct net_bridge_vlan_group *vg) { } diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 8a914e249767..0675f74cf1b9 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -1406,23 +1406,32 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) v = br_vlan_find(vg, vid); if (!v) return -ENOENT; - br_fdb_cleanup_by_dst(port->br, br_vlan_to_dst(v), vid, 0); __vlan_unpublish(vg, v); + synchronize_net(); + /* Traffic may still use v through cached fdb dsts until they are + * cleaned below. This is acceptable during vlan deletion. Above we + * drain the readers that could republish the dst before cleaning it + */ + br_fdb_cleanup_by_dst(port->br, br_vlan_to_dst(v), vid, 0); __vlan_del(vg, v); return 0; } -void nbp_vlan_flush(struct net_bridge_port *port) +void nbp_vlan_group_unpublish(struct net_bridge_port *port) { - struct net_bridge_vlan_group *vg; - ASSERT_RTNL(); - vg = nbp_vlan_group(port); - __vlan_flush(port->br, port, vg); RCU_INIT_POINTER(port->vlgrp, NULL); synchronize_net(); +} + +void nbp_vlan_flush(struct net_bridge_port *port, + struct net_bridge_vlan_group *vg) +{ + ASSERT_RTNL(); + + __vlan_flush(port->br, port, vg); __vlan_group_free(vg); } -- 2.47.3