From: Hangbin Liu <liuhangbin@gmail.com>
To: Jay Vosburgh <jv@jvosburgh.net>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>, Jiri Pirko <jiri@resnulli.us>,
Nikolay Aleksandrov <razor@blackwall.org>,
Ido Schimmel <idosch@nvidia.com>,
Simon Horman <horms@kernel.org>,
Sabrina Dubroca <sd@queasysnail.net>,
Sridhar Samudrala <sridhar.samudrala@intel.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
bridge@lists.linux.dev, Hangbin Liu <liuhangbin@gmail.com>
Subject: [PATCH net-next v3 2/5] net: use ndo_update_offloads to set offload features for bonding/bridge/team
Date: Mon, 16 Mar 2026 12:26:10 +0800 [thread overview]
Message-ID: <20260316-offload_compute-v3-2-a5d4a07d86d3@gmail.com> (raw)
In-Reply-To: <20260316-offload_compute-v3-0-a5d4a07d86d3@gmail.com>
Convert bonding, bridge, and team drivers to use the new
ndo_update_offloads callback instead of manually calling
netdev_compute_master_upper_features() during port add/remove operations.
This change centralizes the feature computation flow:
Before:
- netdev_master_upper_dev_link()
- netdev_compute_master_upper_features() <- called manually
- compute offload features
- netdev_change_features()
- __netdev_update_features()
- update other features
After:
- netdev_master_upper_dev_link()
- __netdev_upper_dev_link()
- netdev_change_features()
- __netdev_update_features()
- ndo_update_offloads()
- netdev_compute_master_upper_features()
- update other features
This ensures offload features are computed automatically when
upper/lower device links change, removing the need for manual
feature computation calls in the driver code.
The netdev_change_features() call in team_uninit() is also removed
since it calls team_port_del() for each port, which now triggers
feature updates automatically.
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
---
drivers/net/bonding/bond_main.c | 10 +++++++---
drivers/net/team/team_core.c | 11 +++++++----
net/bridge/br_device.c | 6 ++++++
net/bridge/br_if.c | 4 ----
net/core/dev.c | 8 ++++++--
5 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 90b71bd53040..ea6bb20f9348 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1509,6 +1509,11 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
return features;
}
+static void bond_update_offloads(struct net_device *dev)
+{
+ netdev_compute_master_upper_features(dev, true);
+}
+
static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
unsigned short type, const void *daddr,
const void *saddr, unsigned int len)
@@ -2273,7 +2278,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
}
bond->slave_cnt++;
- netdev_compute_master_upper_features(bond->dev, true);
bond_set_carrier(bond);
/* Needs to be called before bond_select_active_slave(), which will
@@ -2528,7 +2532,6 @@ static int __bond_release_one(struct net_device *bond_dev,
call_netdevice_notifiers(NETDEV_RELEASE, bond->dev);
}
- netdev_compute_master_upper_features(bond->dev, true);
if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
(old_features & NETIF_F_VLAN_CHALLENGED))
slave_info(bond_dev, slave_dev, "last VLAN challenged slave left bond - VLAN blocking is removed\n");
@@ -4026,7 +4029,7 @@ static int bond_slave_netdev_event(unsigned long event,
case NETDEV_FEAT_CHANGE:
if (!bond->notifier_ctx) {
bond->notifier_ctx = true;
- netdev_compute_master_upper_features(bond->dev, true);
+ netdev_change_features(bond->dev);
bond->notifier_ctx = false;
}
break;
@@ -5953,6 +5956,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
.ndo_fix_features = bond_fix_features,
+ .ndo_update_offloads = bond_update_offloads,
.ndo_features_check = passthru_features_check,
.ndo_get_xmit_slave = bond_xmit_get_slave,
.ndo_sk_get_lower_dev = bond_sk_get_lower_dev,
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index b7282f5c9632..affbcc6fc130 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -1247,7 +1247,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
port->index = -1;
list_add_tail_rcu(&port->list, &team->port_list);
team_port_enable(team, port);
- netdev_compute_master_upper_features(team->dev, true);
__team_port_change_port_added(port, !!netif_oper_up(port_dev));
__team_options_change_check(team);
@@ -1337,7 +1336,6 @@ static int team_port_del(struct team *team, struct net_device *port_dev, bool un
}
kfree_rcu(port, rcu);
netdev_info(dev, "Port device %s removed\n", portname);
- netdev_compute_master_upper_features(team->dev, true);
return 0;
}
@@ -1645,7 +1643,6 @@ static void team_uninit(struct net_device *dev)
team_mcast_rejoin_fini(team);
team_notify_peers_fini(team);
team_queue_override_fini(team);
- netdev_change_features(dev);
}
static void team_destructor(struct net_device *dev)
@@ -1972,6 +1969,11 @@ static netdev_features_t team_fix_features(struct net_device *dev,
return features;
}
+static void team_update_offloads(struct net_device *dev)
+{
+ netdev_compute_master_upper_features(dev, true);
+}
+
static int team_change_carrier(struct net_device *dev, bool new_carrier)
{
struct team *team = netdev_priv(dev);
@@ -2007,6 +2009,7 @@ static const struct net_device_ops team_netdev_ops = {
.ndo_add_slave = team_add_slave,
.ndo_del_slave = team_del_slave,
.ndo_fix_features = team_fix_features,
+ .ndo_update_offloads = team_update_offloads,
.ndo_change_carrier = team_change_carrier,
.ndo_features_check = passthru_features_check,
};
@@ -2944,7 +2947,7 @@ static int team_device_event(struct notifier_block *unused,
case NETDEV_FEAT_CHANGE:
if (!port->team->notifier_ctx) {
port->team->notifier_ctx = true;
- netdev_compute_master_upper_features(port->team->dev, true);
+ netdev_change_features(port->team->dev);
port->team->notifier_ctx = false;
}
break;
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index f7502e62dd35..137cad13379b 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -289,6 +289,11 @@ static netdev_features_t br_fix_features(struct net_device *dev,
return br_features_recompute(br, features);
}
+static void br_update_offloads(struct net_device *dev)
+{
+ netdev_compute_master_upper_features(dev, false);
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void br_poll_controller(struct net_device *br_dev)
{
@@ -456,6 +461,7 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_add_slave = br_add_slave,
.ndo_del_slave = br_del_slave,
.ndo_fix_features = br_fix_features,
+ .ndo_update_offloads = br_update_offloads,
.ndo_fdb_add = br_fdb_add,
.ndo_fdb_del = br_fdb_delete,
.ndo_fdb_del_bulk = br_fdb_delete_bulk,
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index d39571e13744..030248bc94c5 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -680,8 +680,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
br_mtu_auto_adjust(br);
- netdev_compute_master_upper_features(br->dev, false);
-
kobject_uevent(&p->kobj, KOBJ_ADD);
return 0;
@@ -734,8 +732,6 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
if (changed_addr)
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
- netdev_compute_master_upper_features(br->dev, false);
-
return 0;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index bbd532aa6a1b..8bcbf7c22830 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8923,6 +8923,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
priv);
+ /* re-compute all features after adding link */
+ netdev_change_features(upper_dev);
+
return 0;
rollback:
@@ -9015,6 +9018,9 @@ static void __netdev_upper_dev_unlink(struct net_device *dev,
__netdev_update_lower_level(upper_dev, priv);
__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
priv);
+
+ /* re-compute all features after removing link */
+ netdev_change_features(upper_dev);
}
/**
@@ -12880,8 +12886,6 @@ void netdev_compute_master_upper_features(struct net_device *dev, bool update_he
netif_set_tso_max_segs(dev, tso_max_segs);
netif_set_tso_max_size(dev, tso_max_size);
-
- netdev_change_features(dev);
}
EXPORT_SYMBOL(netdev_compute_master_upper_features);
--
Git-155)
next prev parent reply other threads:[~2026-03-16 4:27 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-16 4:26 [PATCH net-next v3 0/5] net: centralize master device offload feature computation Hangbin Liu
2026-03-16 4:26 ` [PATCH net-next v3 1/5] net: add ndo_update_offloads for offload computation Hangbin Liu
2026-03-17 15:14 ` Sabrina Dubroca
2026-03-18 1:15 ` Hangbin Liu
2026-03-18 23:29 ` Sabrina Dubroca
2026-03-19 2:02 ` Hangbin Liu
2026-03-16 4:26 ` Hangbin Liu [this message]
2026-03-19 9:16 ` [net-next,v3,2/5] net: use ndo_update_offloads to set offload features for bonding/bridge/team Paolo Abeni
2026-03-16 4:26 ` [PATCH net-next v3 3/5] macsec: move netdev_upper_dev_link() after macsec_changelink_common() Hangbin Liu
2026-03-17 11:58 ` Sabrina Dubroca
2026-03-16 4:26 ` [PATCH net-next v3 4/5] failover: use ndo_update_offloads for failover offload compute Hangbin Liu
2026-03-16 4:26 ` [PATCH net-next v3 5/5] net: no need to disable LRO specifically Hangbin Liu
2026-03-19 9:52 ` [PATCH net-next v3 0/5] net: centralize master device offload feature computation Paolo Abeni
2026-03-19 13:37 ` Hangbin Liu
2026-03-19 16:01 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260316-offload_compute-v3-2-a5d4a07d86d3@gmail.com \
--to=liuhangbin@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=bridge@lists.linux.dev \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=jiri@resnulli.us \
--cc=jv@jvosburgh.net \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=razor@blackwall.org \
--cc=sd@queasysnail.net \
--cc=sridhar.samudrala@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.