[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20250912223937.1363559-1-Joseph.Huang@garmin.com>
Date: Fri, 12 Sep 2025 18:39:30 -0400
From: Joseph Huang <Joseph.Huang@...min.com>
To: <netdev@...r.kernel.org>
CC: Joseph Huang <Joseph.Huang@...min.com>,
Joseph Huang
<joseph.huang.2024@...il.com>,
"David S. Miller" <davem@...emloft.net>,
"Eric
Dumazet" <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>, Paolo Abeni
<pabeni@...hat.com>,
Simon Horman <horms@...nel.org>, Andrew Lunn
<andrew+netdev@...n.ch>,
Nikolay Aleksandrov <razor@...ckwall.org>,
"Ido
Schimmel" <idosch@...dia.com>, David Ahern <dsahern@...nel.org>,
"Stanislav
Fomichev" <sdf@...ichev.me>,
Kuniyuki Iwashima <kuniyu@...gle.com>,
"Ahmed
Zaki" <ahmed.zaki@...el.com>,
Alexander Lobakin
<aleksander.lobakin@...el.com>,
<linux-kernel@...r.kernel.org>, <bridge@...ts.linux.dev>
Subject: [PATCH net] net: bridge: Trigger host query on v6 addr valid
Trigger the bridge to (re)start sending out Queries to the Host once
IPv6 address becomes valid.
In current implementation, once the bridge (interface) is brought up,
the bridge will start trying to send v4 and v6 Queries to the Host
immediately. However, at that time most likely the IPv6 address of
the bridge interface is not valid yet, and thus the send (actually
the alloc) operation will fail. So the first v6 Startup Query is
always missed.
This caused a ripple effect on the timing of Querier Election. In
current implementation, :: always wins the election. In order for
the "real" election to take place, the bridge would have to first
select itself (this happens when a v6 Query is successfully sent
to the Host), and then do the real address comparison when the next
Query is received. In worst cast scenario, the bridge would have to
wait for [Startup Query Interval] seconds (for the second Query to
be sent to the Host) plus [Query Interval] seconds (for the real
Querier to send the next Query) before it can recognize the real
Querier.
This patch adds a new notification NETDEV_NEWADDR when IPv6 address
becomes valid. When the bridge receives the notification, it will
restart the Startup Queries (much like how the bridge handles port
NETDEV_CHANGE events today).
Signed-off-by: Joseph Huang <Joseph.Huang@...min.com>
---
include/linux/netdevice.h | 1 +
net/bridge/br.c | 5 +++++
net/bridge/br_multicast.c | 16 ++++++++++++++++
net/bridge/br_private.h | 1 +
net/core/dev.c | 10 +++++-----
net/ipv6/addrconf.c | 3 +++
6 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f3a3b761abfb..27297e46e064 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3129,6 +3129,7 @@ enum netdev_cmd {
NETDEV_REGISTER,
NETDEV_UNREGISTER,
NETDEV_CHANGEMTU, /* notify after mtu change happened */
+ NETDEV_NEWADDR,
NETDEV_CHANGEADDR, /* notify after the address change */
NETDEV_PRE_CHANGEADDR, /* notify before the address change */
NETDEV_GOING_DOWN,
diff --git a/net/bridge/br.c b/net/bridge/br.c
index c683baa3847f..6f66965e8075 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -49,6 +49,11 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
return NOTIFY_DONE;
}
+
+ if (event == NETDEV_NEWADDR) {
+ br_multicast_enable_host(netdev_priv(dev));
+ return NOTIFY_DONE;
+ }
}
if (is_vlan_dev(dev)) {
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 8ce145938b02..5a138c5731f5 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -2076,6 +2076,22 @@ static void br_multicast_enable(struct bridge_mcast_own_query *query)
mod_timer(&query->timer, jiffies);
}
+void br_multicast_enable_host(struct net_bridge *br)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ spin_lock_bh(&br->multicast_lock);
+
+ if (!br_opt_get(br, BROPT_MULTICAST_ENABLED) ||
+ !netif_running(br->dev))
+ goto out;
+
+ br_multicast_enable(&br->multicast_ctx.ip6_own_query);
+
+out:
+ spin_unlock_bh(&br->multicast_lock);
+#endif
+}
+
static void __br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
{
struct net_bridge *br = pmctx->port->br;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8de0904b9627..16864286dc0d 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -967,6 +967,7 @@ br_mdb_entry_skb_get(struct net_bridge_mcast *brmctx, struct sk_buff *skb,
u16 vid);
int br_multicast_add_port(struct net_bridge_port *port);
void br_multicast_del_port(struct net_bridge_port *port);
+void br_multicast_enable_host(struct net_bridge *br);
void br_multicast_enable_port(struct net_bridge_port *port);
void br_multicast_disable_port(struct net_bridge_port *port);
void br_multicast_init(struct net_bridge *br);
diff --git a/net/core/dev.c b/net/core/dev.c
index 93a25d87b86b..70a9f379f003 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1843,11 +1843,11 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd)
return "NETDEV_" __stringify(val);
switch (cmd) {
N(UP) N(DOWN) N(REBOOT) N(CHANGE) N(REGISTER) N(UNREGISTER)
- N(CHANGEMTU) N(CHANGEADDR) N(GOING_DOWN) N(CHANGENAME) N(FEAT_CHANGE)
- N(BONDING_FAILOVER) N(PRE_UP) N(PRE_TYPE_CHANGE) N(POST_TYPE_CHANGE)
- N(POST_INIT) N(PRE_UNINIT) N(RELEASE) N(NOTIFY_PEERS) N(JOIN)
- N(CHANGEUPPER) N(RESEND_IGMP) N(PRECHANGEMTU) N(CHANGEINFODATA)
- N(BONDING_INFO) N(PRECHANGEUPPER) N(CHANGELOWERSTATE)
+ N(CHANGEMTU) N(NEWADDR) N(CHANGEADDR) N(GOING_DOWN) N(CHANGENAME)
+ N(FEAT_CHANGE) N(BONDING_FAILOVER) N(PRE_UP) N(PRE_TYPE_CHANGE)
+ N(POST_TYPE_CHANGE) N(POST_INIT) N(PRE_UNINIT) N(RELEASE)
+ N(NOTIFY_PEERS) N(JOIN) N(CHANGEUPPER) N(RESEND_IGMP) N(PRECHANGEMTU)
+ N(CHANGEINFODATA) N(BONDING_INFO) N(PRECHANGEUPPER) N(CHANGELOWERSTATE)
N(UDP_TUNNEL_PUSH_INFO) N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN)
N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO)
N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f17a5dd4789f..785952377d69 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6292,6 +6292,9 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
addrconf_prefix_route(&ifp->peer_addr, 128,
ifp->rt_priority, ifp->idev->dev,
0, 0, GFP_ATOMIC);
+
+ call_netdevice_notifiers(NETDEV_NEWADDR, ifp->idev->dev);
+
break;
case RTM_DELADDR:
if (ifp->idev->cnf.forwarding)
--
2.50.1
________________________________
CONFIDENTIALITY NOTICE: This email and any attachments are for the sole use of the intended recipient(s) and contain information that may be Garmin confidential and/or Garmin legally privileged. If you have received this email in error, please notify the sender by reply email and delete the message. Any disclosure, copying, distribution or use of this communication (including attachments) by someone other than the intended recipient is prohibited. Thank you.
Powered by blists - more mailing lists