net/mlx5: Lag, record inactive state of bond device
authorMark Bloch <mbloch@nvidia.com>
Wed, 12 Jan 2022 14:31:36 +0000 (14:31 +0000)
committerSaeed Mahameed <saeedm@nvidia.com>
Wed, 23 Feb 2022 23:21:58 +0000 (15:21 -0800)
A bond device will drop duplicate packets (received on inactive ports)
by default. A flag (all_slaves_active) can be set to override such
behaviour. This flag is a global flag per bond device (ALB mode isn't
supported by mlx5 driver so it can be ignored)

When NETDEV_CHANGEUPPER / NETDEV_CHANGEINFODATA event is received check if
there is an interface that is inactive.

Downstream patch will use this information in order to decide if a drop
rule is needed.

Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Reviewed-by: Maor Gottlieb <maorg@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c

index 05e8cbe..125ac4b 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <linux/netdevice.h>
+#include <net/bonding.h>
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/eswitch.h>
 #include <linux/mlx5/vport.h>
@@ -619,6 +620,8 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
        struct net_device *upper = info->upper_dev, *ndev_tmp;
        struct netdev_lag_upper_info *lag_upper_info = NULL;
        bool is_bonded, is_in_lag, mode_supported;
+       bool has_inactive = 0;
+       struct slave *slave;
        int bond_status = 0;
        int num_slaves = 0;
        int changed = 0;
@@ -638,8 +641,12 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
        rcu_read_lock();
        for_each_netdev_in_bond_rcu(upper, ndev_tmp) {
                idx = mlx5_lag_dev_get_netdev_idx(ldev, ndev_tmp);
-               if (idx >= 0)
+               if (idx >= 0) {
+                       slave = bond_slave_get_rcu(ndev_tmp);
+                       if (slave)
+                               has_inactive |= bond_is_slave_inactive(slave);
                        bond_status |= (1 << idx);
+               }
 
                num_slaves++;
        }
@@ -654,6 +661,7 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev,
                tracker->hash_type = lag_upper_info->hash_type;
        }
 
+       tracker->has_inactive = has_inactive;
        /* Determine bonding status:
         * A device is considered bonded if both its physical ports are slaves
         * of the same lag master, and only them.
@@ -710,6 +718,38 @@ static int mlx5_handle_changelowerstate_event(struct mlx5_lag *ldev,
        return 1;
 }
 
+static int mlx5_handle_changeinfodata_event(struct mlx5_lag *ldev,
+                                           struct lag_tracker *tracker,
+                                           struct net_device *ndev)
+{
+       struct net_device *ndev_tmp;
+       struct slave *slave;
+       bool has_inactive = 0;
+       int idx;
+
+       if (!netif_is_lag_master(ndev))
+               return 0;
+
+       rcu_read_lock();
+       for_each_netdev_in_bond_rcu(ndev, ndev_tmp) {
+               idx = mlx5_lag_dev_get_netdev_idx(ldev, ndev_tmp);
+               if (idx < 0)
+                       continue;
+
+               slave = bond_slave_get_rcu(ndev_tmp);
+               if (slave)
+                       has_inactive |= bond_is_slave_inactive(slave);
+       }
+       rcu_read_unlock();
+
+       if (tracker->has_inactive == has_inactive)
+               return 0;
+
+       tracker->has_inactive = has_inactive;
+
+       return 1;
+}
+
 static int mlx5_lag_netdev_event(struct notifier_block *this,
                                 unsigned long event, void *ptr)
 {
@@ -718,7 +758,9 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
        struct mlx5_lag *ldev;
        int changed = 0;
 
-       if ((event != NETDEV_CHANGEUPPER) && (event != NETDEV_CHANGELOWERSTATE))
+       if (event != NETDEV_CHANGEUPPER &&
+           event != NETDEV_CHANGELOWERSTATE &&
+           event != NETDEV_CHANGEINFODATA)
                return NOTIFY_DONE;
 
        ldev    = container_of(this, struct mlx5_lag, nb);
@@ -734,6 +776,9 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
                changed = mlx5_handle_changelowerstate_event(ldev, &tracker,
                                                             ndev, ptr);
                break;
+       case NETDEV_CHANGEINFODATA:
+               changed = mlx5_handle_changeinfodata_event(ldev, &tracker, ndev);
+               break;
        }
 
        ldev->tracker = tracker;
index e5d231c..305d9ad 100644 (file)
@@ -35,6 +35,7 @@ struct lag_tracker {
        enum   netdev_lag_tx_type           tx_type;
        struct netdev_lag_lower_state_info  netdev_state[MLX5_MAX_PORTS];
        unsigned int is_bonded:1;
+       unsigned int has_inactive:1;
        enum netdev_lag_hash hash_type;
 };
 
index 1ca01a5..4213208 100644 (file)
@@ -50,7 +50,7 @@ bool mlx5_lag_is_multipath(struct mlx5_core_dev *dev)
 static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev,
                                       enum mlx5_lag_port_affinity port)
 {
-       struct lag_tracker tracker;
+       struct lag_tracker tracker = {};
 
        if (!__mlx5_lag_is_multipath(ldev))
                return;