net/mlx5e: Make TC and IPsec offloads mutually exclusive on a netdev

For IPsec packet offload mode, the order of TC offload and IPsec
offload on the same netdevice is not aligned with the order in the
non-offload software. For example, for RX, the software performs TC
first and then IPsec transformation, but the implementation for
offload does that in the opposite way.

To resolve the difference for now, either IPsec offload or TC offload,
not both, is allowed for a specific interface.

Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Link: https://lore.kernel.org/r/8e2e5e3b0984d785066e8663aaf97b3ba1bb873f.1690802064.git.leon@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jianbo Liu 2023-07-31 14:28:24 +03:00 committed by Jakub Kicinski
parent 6e56ab1c90
commit c8e350e62f
3 changed files with 131 additions and 6 deletions

View file

@ -1717,12 +1717,68 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)
}
}
#ifdef CONFIG_MLX5_ESWITCH
static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
int err = 0;
if (esw)
down_write(&esw->mode_lock);
if (mdev->num_block_ipsec) {
err = -EBUSY;
goto unlock;
}
mdev->num_block_tc++;
unlock:
if (esw)
up_write(&esw->mode_lock);
return err;
}
#else
static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
{
if (mdev->num_block_ipsec)
return -EBUSY;
mdev->num_block_tc++;
return 0;
}
#endif
static void mlx5e_ipsec_unblock_tc_offload(struct mlx5_core_dev *mdev)
{
mdev->num_block_tc++;
}
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
{
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
return tx_add_rule(sa_entry);
int err;
return rx_add_rule(sa_entry);
if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET) {
err = mlx5e_ipsec_block_tc_offload(sa_entry->ipsec->mdev);
if (err)
return err;
}
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
err = tx_add_rule(sa_entry);
else
err = rx_add_rule(sa_entry);
if (err)
goto err_out;
return 0;
err_out:
if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
mlx5e_ipsec_unblock_tc_offload(sa_entry->ipsec->mdev);
return err;
}
void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
@ -1735,6 +1791,9 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
if (ipsec_rule->pkt_reformat)
mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat);
if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
mlx5e_ipsec_unblock_tc_offload(mdev);
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) {
tx_ft_put(sa_entry->ipsec, sa_entry->attrs.type);
return;
@ -1747,10 +1806,25 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
{
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
return tx_add_policy(pol_entry);
int err;
return rx_add_policy(pol_entry);
err = mlx5e_ipsec_block_tc_offload(pol_entry->ipsec->mdev);
if (err)
return err;
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
err = tx_add_policy(pol_entry);
else
err = rx_add_policy(pol_entry);
if (err)
goto err_out;
return 0;
err_out:
mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
return err;
}
void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
@ -1760,6 +1834,8 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
mlx5_del_flow_rules(ipsec_rule->rule);
mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) {
rx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.family,
pol_entry->attrs.prio, pol_entry->attrs.type);

View file

@ -4606,6 +4606,46 @@ static bool is_flow_rule_duplicate_allowed(struct net_device *dev,
return netif_is_lag_port(dev) && rpriv && rpriv->rep->vport != MLX5_VPORT_UPLINK;
}
/* As IPsec and TC order is not aligned between software and hardware-offload,
* either IPsec offload or TC offload, not both, is allowed for a specific interface.
*/
static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx5e_priv *priv)
{
if (!IS_ENABLED(CONFIG_MLX5_EN_IPSEC))
return false;
if (filter != priv->netdev)
return false;
if (mlx5e_eswitch_vf_rep(priv->netdev))
return false;
return true;
}
static int mlx5e_tc_block_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
if (!is_tc_ipsec_order_check_needed(filter, priv))
return 0;
if (mdev->num_block_tc)
return -EBUSY;
mdev->num_block_ipsec++;
return 0;
}
static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
{
if (!is_tc_ipsec_order_check_needed(filter, priv))
return;
priv->mdev->num_block_ipsec--;
}
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
struct flow_cls_offload *f, unsigned long flags)
{
@ -4618,6 +4658,10 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (!mlx5_esw_hold(priv->mdev))
return -EBUSY;
err = mlx5e_tc_block_ipsec_offload(dev, priv);
if (err)
goto esw_release;
mlx5_esw_get(priv->mdev);
rcu_read_lock();
@ -4663,7 +4707,9 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
err_free:
mlx5e_flow_put(priv, flow);
out:
mlx5e_tc_unblock_ipsec_offload(dev, priv);
mlx5_esw_put(priv->mdev);
esw_release:
mlx5_esw_release(priv->mdev);
return err;
}
@ -4704,6 +4750,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
trace_mlx5e_delete_flower(f);
mlx5e_flow_put(priv, flow);
mlx5e_tc_unblock_ipsec_offload(dev, priv);
mlx5_esw_put(priv->mdev);
return 0;

View file

@ -806,6 +806,8 @@ struct mlx5_core_dev {
u32 vsc_addr;
struct mlx5_hv_vhca *hv_vhca;
struct mlx5_thermal *thermal;
u64 num_block_tc;
u64 num_block_ipsec;
};
struct mlx5_db {