]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
team: use common function to compute the features
authorHangbin Liu <liuhangbin@gmail.com>
Fri, 17 Oct 2025 03:41:54 +0000 (03:41 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 22 Oct 2025 01:08:23 +0000 (18:08 -0700)
Use the new helper netdev_compute_master_upper_features() to compute the
team device features. This helper performs both the feature computation
and the netdev_change_features() call.

Note that such change replace the lower layer traversing currently done
using team->port_list with netdev_for_each_lower_dev(). Such change is
safe as `port_list` contains exactly the same elements as
`team->dev->adj_list.lower` and the helper is always invoked under the
RTNL lock.

With this change, the explicit netdev_change_features() in team_add_slave()
can be safely removed, as team_port_add() already takes care of the
notification via netdev_compute_master_upper_features(), and same thing for
team_del_slave()

This also fixes missing computations for MPLS, XFRM, and TSO/GSO partial
features.

Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Link: https://patch.msgid.link/20251017034155.61990-4-liuhangbin@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/team/team_core.c

index 17f07eb0ee52a625c77c485c0543a737f4f39d25..29dc04c299a3b9be8498f9ebf15452ca4fa0f9cf 100644 (file)
@@ -982,63 +982,6 @@ static void team_port_disable(struct team *team,
        team_lower_state_changed(port);
 }
 
-#define TEAM_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
-                           NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \
-                           NETIF_F_HIGHDMA | NETIF_F_LRO | \
-                           NETIF_F_GSO_ENCAP_ALL)
-
-#define TEAM_ENC_FEATURES      (NETIF_F_HW_CSUM | NETIF_F_SG | \
-                                NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE)
-
-static void __team_compute_features(struct team *team)
-{
-       struct team_port *port;
-       netdev_features_t vlan_features = TEAM_VLAN_FEATURES;
-       netdev_features_t enc_features  = TEAM_ENC_FEATURES;
-       unsigned short max_hard_header_len = ETH_HLEN;
-       unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
-                                       IFF_XMIT_DST_RELEASE_PERM;
-
-       rcu_read_lock();
-       if (list_empty(&team->port_list))
-               goto done;
-
-       vlan_features = netdev_base_features(vlan_features);
-       enc_features = netdev_base_features(enc_features);
-
-       list_for_each_entry_rcu(port, &team->port_list, list) {
-               vlan_features = netdev_increment_features(vlan_features,
-                                       port->dev->vlan_features,
-                                       TEAM_VLAN_FEATURES);
-               enc_features =
-                       netdev_increment_features(enc_features,
-                                                 port->dev->hw_enc_features,
-                                                 TEAM_ENC_FEATURES);
-
-               dst_release_flag &= port->dev->priv_flags;
-               if (port->dev->hard_header_len > max_hard_header_len)
-                       max_hard_header_len = port->dev->hard_header_len;
-       }
-done:
-       rcu_read_unlock();
-
-       team->dev->vlan_features = vlan_features;
-       team->dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
-                                    NETIF_F_HW_VLAN_CTAG_TX |
-                                    NETIF_F_HW_VLAN_STAG_TX;
-       team->dev->hard_header_len = max_hard_header_len;
-
-       team->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
-       if (dst_release_flag == (IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM))
-               team->dev->priv_flags |= IFF_XMIT_DST_RELEASE;
-}
-
-static void team_compute_features(struct team *team)
-{
-       __team_compute_features(team);
-       netdev_change_features(team->dev);
-}
-
 static int team_port_enter(struct team *team, struct team_port *port)
 {
        int err = 0;
@@ -1300,7 +1243,7 @@ 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);
-       __team_compute_features(team);
+       netdev_compute_master_upper_features(team->dev, true);
        __team_port_change_port_added(port, !!netif_oper_up(port_dev));
        __team_options_change_check(team);
 
@@ -1382,7 +1325,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
        dev_set_mtu(port_dev, port->orig.mtu);
        kfree_rcu(port, rcu);
        netdev_info(dev, "Port device %s removed\n", portname);
-       __team_compute_features(team);
+       netdev_compute_master_upper_features(team->dev, true);
 
        return 0;
 }
@@ -1970,33 +1913,19 @@ static int team_add_slave(struct net_device *dev, struct net_device *port_dev,
                          struct netlink_ext_ack *extack)
 {
        struct team *team = netdev_priv(dev);
-       int err;
 
        ASSERT_RTNL();
 
-       err = team_port_add(team, port_dev, extack);
-
-       if (!err)
-               netdev_change_features(dev);
-
-       return err;
+       return team_port_add(team, port_dev, extack);
 }
 
 static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
 {
        struct team *team = netdev_priv(dev);
-       int err;
 
        ASSERT_RTNL();
 
-       err = team_port_del(team, port_dev);
-
-       if (err)
-               return err;
-
-       netdev_change_features(dev);
-
-       return err;
+       return team_port_del(team, port_dev);
 }
 
 static netdev_features_t team_fix_features(struct net_device *dev,
@@ -2190,7 +2119,7 @@ static void team_setup(struct net_device *dev)
 
        dev->features |= NETIF_F_GRO;
 
-       dev->hw_features = TEAM_VLAN_FEATURES |
+       dev->hw_features = MASTER_UPPER_DEV_VLAN_FEATURES |
                           NETIF_F_HW_VLAN_CTAG_RX |
                           NETIF_F_HW_VLAN_CTAG_FILTER |
                           NETIF_F_HW_VLAN_STAG_RX |
@@ -2994,7 +2923,7 @@ static int team_device_event(struct notifier_block *unused,
        case NETDEV_FEAT_CHANGE:
                if (!port->team->notifier_ctx) {
                        port->team->notifier_ctx = true;
-                       team_compute_features(port->team);
+                       netdev_compute_master_upper_features(port->team->dev, true);
                        port->team->notifier_ctx = false;
                }
                break;