Commit 7c33e739 authored by Maor Dickman's avatar Maor Dickman Committed by Saeed Mahameed
Browse files

net/mlx5e: multipath, support routes with more than 2 nexthops



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: default avatarMaor Dickman <maord@nvidia.com>
Reviewed-by: default avatarRoi Dayan <roid@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent 6fda078d
Loading
Loading
Loading
Loading
+48 −31
Original line number Diff line number Diff line
@@ -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)
	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;