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: 5c65c564c9
("net/mlx5e: Support offloading TC NIC hairpin flows")
Signed-off-by: Alaa Hleihel <alaa@mellanox.com>
Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:
Родитель
43955a45dc
Коммит
4d8fcf216c
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -475,7 +475,8 @@ 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]);
|
||||
mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[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);
|
||||
|
|
|
@ -90,6 +90,8 @@ struct mlx5_hairpin {
|
|||
|
||||
u32 *rqn;
|
||||
u32 *sqn;
|
||||
|
||||
bool peer_gone;
|
||||
};
|
||||
|
||||
struct mlx5_hairpin *
|
||||
|
|
Загрузка…
Ссылка в новой задаче