Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d8fcf21 authored by Alaa Hleihel's avatar Alaa Hleihel Committed by Saeed Mahameed
Browse files

net/mlx5e: Avoid unbounded peer devices when unpairing TC hairpin rules



If the peer device was already unbound, then do not attempt to modify
it's resources, otherwise we will crash on dereferencing non-existing
device.

Fixes: 5c65c564 ("net/mlx5e: Support offloading TC NIC hairpin flows")
Signed-off-by: default avatarAlaa Hleihel <alaa@mellanox.com>
Reviewed-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 43955a45
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@
#include "en_stats.h"
#include "en/fs.h"

extern const struct net_device_ops mlx5e_netdev_ops;
struct page_pool;

#define MLX5E_METADATA_ETHER_TYPE (0x8CE4)
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@ struct mlx5e_tc_table {

	DECLARE_HASHTABLE(mod_hdr_tbl, 8);
	DECLARE_HASHTABLE(hairpin_tbl, 8);

	struct notifier_block     netdevice_nb;
};

struct mlx5e_flow_table {
+1 −1
Original line number Diff line number Diff line
@@ -4315,7 +4315,7 @@ static int mlx5e_xdp(struct net_device *dev, struct netdev_bpf *xdp)
	}
}

static const struct net_device_ops mlx5e_netdev_ops = {
const struct net_device_ops mlx5e_netdev_ops = {
	.ndo_open                = mlx5e_open,
	.ndo_stop                = mlx5e_close,
	.ndo_start_xmit          = mlx5e_xmit,
+61 −1
Original line number Diff line number Diff line
@@ -2946,14 +2946,71 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
	return 0;
}

static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
					      struct mlx5e_priv *peer_priv)
{
	struct mlx5_core_dev *peer_mdev = peer_priv->mdev;
	struct mlx5e_hairpin_entry *hpe;
	u16 peer_vhca_id;
	int bkt;

	if (!same_hw_devs(priv, peer_priv))
		return;

	peer_vhca_id = MLX5_CAP_GEN(peer_mdev, vhca_id);

	hash_for_each(priv->fs.tc.hairpin_tbl, bkt, hpe, hairpin_hlist) {
		if (hpe->peer_vhca_id == peer_vhca_id)
			hpe->hp->pair->peer_gone = true;
	}
}

static int mlx5e_tc_netdev_event(struct notifier_block *this,
				 unsigned long event, void *ptr)
{
	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
	struct mlx5e_flow_steering *fs;
	struct mlx5e_priv *peer_priv;
	struct mlx5e_tc_table *tc;
	struct mlx5e_priv *priv;

	if (ndev->netdev_ops != &mlx5e_netdev_ops ||
	    event != NETDEV_UNREGISTER ||
	    ndev->reg_state == NETREG_REGISTERED)
		return NOTIFY_DONE;

	tc = container_of(this, struct mlx5e_tc_table, netdevice_nb);
	fs = container_of(tc, struct mlx5e_flow_steering, tc);
	priv = container_of(fs, struct mlx5e_priv, fs);
	peer_priv = netdev_priv(ndev);
	if (priv == peer_priv ||
	    !(priv->netdev->features & NETIF_F_HW_TC))
		return NOTIFY_DONE;

	mlx5e_tc_hairpin_update_dead_peer(priv, peer_priv);

	return NOTIFY_DONE;
}

int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
{
	struct mlx5e_tc_table *tc = &priv->fs.tc;
	int err;

	hash_init(tc->mod_hdr_tbl);
	hash_init(tc->hairpin_tbl);

	return rhashtable_init(&tc->ht, &tc_ht_params);
	err = rhashtable_init(&tc->ht, &tc_ht_params);
	if (err)
		return err;

	tc->netdevice_nb.notifier_call = mlx5e_tc_netdev_event;
	if (register_netdevice_notifier(&tc->netdevice_nb)) {
		tc->netdevice_nb.notifier_call = NULL;
		mlx5_core_warn(priv->mdev, "Failed to register netdev notifier\n");
	}

	return err;
}

static void _mlx5e_tc_del_flow(void *ptr, void *arg)
@@ -2969,6 +3026,9 @@ void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv)
{
	struct mlx5e_tc_table *tc = &priv->fs.tc;

	if (tc->netdevice_nb.notifier_call)
		unregister_netdevice_notifier(&tc->netdevice_nb);

	rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, NULL);

	if (!IS_ERR_OR_NULL(tc->t)) {
+4 −1
Original line number Diff line number Diff line
@@ -475,6 +475,7 @@ static void mlx5_hairpin_destroy_queues(struct mlx5_hairpin *hp)

	for (i = 0; i < hp->num_channels; i++) {
		mlx5_core_destroy_rq(hp->func_mdev, hp->rqn[i]);
		if (!hp->peer_gone)
			mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
	}
}
@@ -567,6 +568,8 @@ static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
				       MLX5_RQC_STATE_RST, 0, 0);

	/* unset peer SQs */
	if (hp->peer_gone)
		return;
	for (i = 0; i < hp->num_channels; i++)
		mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
				       MLX5_SQC_STATE_RST, 0, 0);
Loading