net/mlx5e: multipath, support routes with more than 2 nexthops
authorMaor Dickman <maord@nvidia.com>
Sun, 9 Oct 2022 06:53:22 +0000 (09:53 +0300)
committerSaeed Mahameed <saeedm@nvidia.com>
Fri, 9 Dec 2022 00:10:55 +0000 (16:10 -0800)
Today multipath offload is only supported when the number of
nexthops is 2 which block the use of it in case of system with
2 NICs.

This patch solve it by enabling multipath offload per NIC if
2 nexthops of the route are its uplinks.

Signed-off-by: Maor Dickman <maord@nvidia.com>
Reviewed-by: Roi Dayan <roid@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c

index 0259a14..d9fcb9e 100644 (file)
@@ -118,13 +118,41 @@ struct mlx5_fib_event_work {
        };
 };
 
+static struct net_device*
+mlx5_lag_get_next_fib_dev(struct mlx5_lag *ldev,
+                         struct fib_info *fi,
+                         struct net_device *current_dev)
+{
+       struct net_device *fib_dev;
+       int i, ldev_idx, nhs;
+
+       nhs = fib_info_num_path(fi);
+       i = 0;
+       if (current_dev) {
+               for (; i < nhs; i++) {
+                       fib_dev = fib_info_nh(fi, i)->fib_nh_dev;
+                       if (fib_dev == current_dev) {
+                               i++;
+                               break;
+                       }
+               }
+       }
+       for (; i < nhs; i++) {
+               fib_dev = fib_info_nh(fi, i)->fib_nh_dev;
+               ldev_idx = mlx5_lag_dev_get_netdev_idx(ldev, fib_dev);
+               if (ldev_idx >= 0)
+                       return ldev->pf[ldev_idx].netdev;
+       }
+
+       return NULL;
+}
+
 static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
                                     struct fib_entry_notifier_info *fen_info)
 {
+       struct net_device *nh_dev0, *nh_dev1;
        struct fib_info *fi = fen_info->fi;
        struct lag_mp *mp = &ldev->lag_mp;
-       struct fib_nh *fib_nh0, *fib_nh1;
-       unsigned int nhs;
 
        /* Handle delete event */
        if (event == FIB_EVENT_ENTRY_DEL) {
@@ -140,16 +168,25 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
            fi->fib_priority >= mp->fib.priority)
                return;
 
+       nh_dev0 = mlx5_lag_get_next_fib_dev(ldev, fi, NULL);
+       nh_dev1 = mlx5_lag_get_next_fib_dev(ldev, fi, nh_dev0);
+
        /* Handle add/replace event */
-       nhs = fib_info_num_path(fi);
-       if (nhs == 1) {
-               if (__mlx5_lag_is_active(ldev)) {
-                       struct fib_nh *nh = fib_info_nh(fi, 0);
-                       struct net_device *nh_dev = nh->fib_nh_dev;
-                       int i = mlx5_lag_dev_get_netdev_idx(ldev, nh_dev);
+       if (!nh_dev0) {
+               if (mp->fib.dst == fen_info->dst && mp->fib.dst_len == fen_info->dst_len)
+                       mp->fib.mfi = NULL;
+               return;
+       }
 
-                       if (i < 0)
-                               return;
+       if (nh_dev0 == nh_dev1) {
+               mlx5_core_warn(ldev->pf[MLX5_LAG_P1].dev,
+                              "Multipath offload doesn't support routes with multiple nexthops of the same device");
+               return;
+       }
+
+       if (!nh_dev1) {
+               if (__mlx5_lag_is_active(ldev)) {
+                       int i = mlx5_lag_dev_get_netdev_idx(ldev, nh_dev0);
 
                        i++;
                        mlx5_lag_set_port_affinity(ldev, i);
@@ -159,21 +196,6 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, unsigned long event,
                return;
        }
 
-       if (nhs != 2)
-               return;
-
-       /* Verify next hops are ports of the same hca */
-       fib_nh0 = fib_info_nh(fi, 0);
-       fib_nh1 = fib_info_nh(fi, 1);
-       if (!(fib_nh0->fib_nh_dev == ldev->pf[MLX5_LAG_P1].netdev &&
-             fib_nh1->fib_nh_dev == ldev->pf[MLX5_LAG_P2].netdev) &&
-           !(fib_nh0->fib_nh_dev == ldev->pf[MLX5_LAG_P2].netdev &&
-             fib_nh1->fib_nh_dev == ldev->pf[MLX5_LAG_P1].netdev)) {
-               mlx5_core_warn(ldev->pf[MLX5_LAG_P1].dev,
-                              "Multipath offload require two ports of the same HCA\n");
-               return;
-       }
-
        /* First time we see multipath route */
        if (!mp->fib.mfi && !__mlx5_lag_is_active(ldev)) {
                struct lag_tracker tracker;
@@ -268,7 +290,6 @@ static int mlx5_lag_fib_event(struct notifier_block *nb,
        struct mlx5_fib_event_work *fib_work;
        struct fib_entry_notifier_info *fen_info;
        struct fib_nh_notifier_info *fnh_info;
-       struct net_device *fib_dev;
        struct fib_info *fi;
 
        if (info->family != AF_INET)
@@ -285,11 +306,7 @@ static int mlx5_lag_fib_event(struct notifier_block *nb,
                fi = fen_info->fi;
                if (fi->nh)
                        return NOTIFY_DONE;
-               fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
-               if (fib_dev != ldev->pf[MLX5_LAG_P1].netdev &&
-                   fib_dev != ldev->pf[MLX5_LAG_P2].netdev) {
-                       return NOTIFY_DONE;
-               }
+
                fib_work = mlx5_lag_init_fib_work(ldev, event);
                if (!fib_work)
                        return NOTIFY_DONE;