net/mlx5e: Make IPsec offload work together with eswitch and TC
The eswitch mode is not allowed to change if there are any IPsec rules. Besides, by using mlx5_esw_try_lock() to get eswitch mode lock, IPsec rules are not allowed to be offloaded if there are any TC rules. Signed-off-by: Jianbo Liu <jianbol@nvidia.com> Signed-off-by: Leon Romanovsky <leonro@nvidia.com> Link: https://lore.kernel.org/r/e442b512b21a931fbdfb87d57ae428c37badd58a.1690802064.git.leon@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
1632649d2d
commit
366e46242b
3 changed files with 129 additions and 16 deletions
|
@ -254,8 +254,6 @@ static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
|
||||||
mlx5_del_flow_rules(rx->sa.rule);
|
mlx5_del_flow_rules(rx->sa.rule);
|
||||||
mlx5_destroy_flow_group(rx->sa.group);
|
mlx5_destroy_flow_group(rx->sa.group);
|
||||||
mlx5_destroy_flow_table(rx->ft.sa);
|
mlx5_destroy_flow_table(rx->ft.sa);
|
||||||
if (rx->allow_tunnel_mode)
|
|
||||||
mlx5_eswitch_unblock_encap(mdev);
|
|
||||||
if (rx == ipsec->rx_esw) {
|
if (rx == ipsec->rx_esw) {
|
||||||
mlx5_esw_ipsec_rx_status_destroy(ipsec, rx);
|
mlx5_esw_ipsec_rx_status_destroy(ipsec, rx);
|
||||||
} else {
|
} else {
|
||||||
|
@ -359,8 +357,6 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
|
||||||
goto err_add;
|
goto err_add;
|
||||||
|
|
||||||
/* Create FT */
|
/* Create FT */
|
||||||
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
|
|
||||||
rx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
|
|
||||||
if (rx->allow_tunnel_mode)
|
if (rx->allow_tunnel_mode)
|
||||||
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
|
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
|
||||||
ft = ipsec_ft_create(attr.ns, attr.sa_level, attr.prio, 2, flags);
|
ft = ipsec_ft_create(attr.ns, attr.sa_level, attr.prio, 2, flags);
|
||||||
|
@ -415,8 +411,6 @@ err_pol_ft:
|
||||||
err_fs:
|
err_fs:
|
||||||
mlx5_destroy_flow_table(rx->ft.sa);
|
mlx5_destroy_flow_table(rx->ft.sa);
|
||||||
err_fs_ft:
|
err_fs_ft:
|
||||||
if (rx->allow_tunnel_mode)
|
|
||||||
mlx5_eswitch_unblock_encap(mdev);
|
|
||||||
mlx5_del_flow_rules(rx->status.rule);
|
mlx5_del_flow_rules(rx->status.rule);
|
||||||
mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
|
mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
|
||||||
err_add:
|
err_add:
|
||||||
|
@ -434,13 +428,26 @@ static int rx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
|
||||||
if (rx->ft.refcnt)
|
if (rx->ft.refcnt)
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
err = rx_create(mdev, ipsec, rx, family);
|
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
|
||||||
|
rx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
|
||||||
|
|
||||||
|
err = mlx5_eswitch_block_mode_trylock(mdev);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto err_out;
|
||||||
|
|
||||||
|
err = rx_create(mdev, ipsec, rx, family);
|
||||||
|
mlx5_eswitch_block_mode_unlock(mdev, err);
|
||||||
|
if (err)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
rx->ft.refcnt++;
|
rx->ft.refcnt++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
if (rx->allow_tunnel_mode)
|
||||||
|
mlx5_eswitch_unblock_encap(mdev);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx,
|
static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx,
|
||||||
|
@ -449,7 +456,12 @@ static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx,
|
||||||
if (--rx->ft.refcnt)
|
if (--rx->ft.refcnt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mlx5_eswitch_unblock_mode_lock(ipsec->mdev);
|
||||||
rx_destroy(ipsec->mdev, ipsec, rx, family);
|
rx_destroy(ipsec->mdev, ipsec, rx, family);
|
||||||
|
mlx5_eswitch_unblock_mode_unlock(ipsec->mdev);
|
||||||
|
|
||||||
|
if (rx->allow_tunnel_mode)
|
||||||
|
mlx5_eswitch_unblock_encap(ipsec->mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
|
static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
|
||||||
|
@ -569,8 +581,6 @@ static void tx_destroy(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
|
||||||
mlx5_destroy_flow_group(tx->sa.group);
|
mlx5_destroy_flow_group(tx->sa.group);
|
||||||
}
|
}
|
||||||
mlx5_destroy_flow_table(tx->ft.sa);
|
mlx5_destroy_flow_table(tx->ft.sa);
|
||||||
if (tx->allow_tunnel_mode)
|
|
||||||
mlx5_eswitch_unblock_encap(ipsec->mdev);
|
|
||||||
mlx5_del_flow_rules(tx->status.rule);
|
mlx5_del_flow_rules(tx->status.rule);
|
||||||
mlx5_destroy_flow_table(tx->ft.status);
|
mlx5_destroy_flow_table(tx->ft.status);
|
||||||
}
|
}
|
||||||
|
@ -611,8 +621,6 @@ static int tx_create(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
|
||||||
if (err)
|
if (err)
|
||||||
goto err_status_rule;
|
goto err_status_rule;
|
||||||
|
|
||||||
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
|
|
||||||
tx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
|
|
||||||
if (tx->allow_tunnel_mode)
|
if (tx->allow_tunnel_mode)
|
||||||
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
|
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
|
||||||
ft = ipsec_ft_create(tx->ns, attr.sa_level, attr.prio, 4, flags);
|
ft = ipsec_ft_create(tx->ns, attr.sa_level, attr.prio, 4, flags);
|
||||||
|
@ -679,8 +687,6 @@ err_pol_ft:
|
||||||
err_sa_miss:
|
err_sa_miss:
|
||||||
mlx5_destroy_flow_table(tx->ft.sa);
|
mlx5_destroy_flow_table(tx->ft.sa);
|
||||||
err_sa_ft:
|
err_sa_ft:
|
||||||
if (tx->allow_tunnel_mode)
|
|
||||||
mlx5_eswitch_unblock_encap(mdev);
|
|
||||||
mlx5_del_flow_rules(tx->status.rule);
|
mlx5_del_flow_rules(tx->status.rule);
|
||||||
err_status_rule:
|
err_status_rule:
|
||||||
mlx5_destroy_flow_table(tx->ft.status);
|
mlx5_destroy_flow_table(tx->ft.status);
|
||||||
|
@ -714,16 +720,32 @@ static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
|
||||||
if (tx->ft.refcnt)
|
if (tx->ft.refcnt)
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
err = tx_create(ipsec, tx, ipsec->roce);
|
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
|
||||||
|
tx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
|
||||||
|
|
||||||
|
err = mlx5_eswitch_block_mode_trylock(mdev);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto err_out;
|
||||||
|
|
||||||
|
err = tx_create(ipsec, tx, ipsec->roce);
|
||||||
|
if (err) {
|
||||||
|
mlx5_eswitch_block_mode_unlock(mdev, err);
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
if (tx == ipsec->tx_esw)
|
if (tx == ipsec->tx_esw)
|
||||||
ipsec_esw_tx_ft_policy_set(mdev, tx->ft.pol);
|
ipsec_esw_tx_ft_policy_set(mdev, tx->ft.pol);
|
||||||
|
|
||||||
|
mlx5_eswitch_block_mode_unlock(mdev, err);
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
tx->ft.refcnt++;
|
tx->ft.refcnt++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
if (tx->allow_tunnel_mode)
|
||||||
|
mlx5_eswitch_unblock_encap(mdev);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
|
static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
|
||||||
|
@ -731,10 +753,17 @@ static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
|
||||||
if (--tx->ft.refcnt)
|
if (--tx->ft.refcnt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mlx5_eswitch_unblock_mode_lock(ipsec->mdev);
|
||||||
|
|
||||||
if (tx == ipsec->tx_esw)
|
if (tx == ipsec->tx_esw)
|
||||||
ipsec_esw_tx_ft_policy_set(ipsec->mdev, NULL);
|
ipsec_esw_tx_ft_policy_set(ipsec->mdev, NULL);
|
||||||
|
|
||||||
tx_destroy(ipsec, tx, ipsec->roce);
|
tx_destroy(ipsec, tx, ipsec->roce);
|
||||||
|
|
||||||
|
mlx5_eswitch_unblock_mode_unlock(ipsec->mdev);
|
||||||
|
|
||||||
|
if (tx->allow_tunnel_mode)
|
||||||
|
mlx5_eswitch_unblock_encap(ipsec->mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev,
|
static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev,
|
||||||
|
|
|
@ -270,6 +270,7 @@ struct mlx5_esw_offload {
|
||||||
u8 inline_mode;
|
u8 inline_mode;
|
||||||
atomic64_t num_flows;
|
atomic64_t num_flows;
|
||||||
u64 num_block_encap;
|
u64 num_block_encap;
|
||||||
|
u64 num_block_mode;
|
||||||
enum devlink_eswitch_encap_mode encap;
|
enum devlink_eswitch_encap_mode encap;
|
||||||
struct ida vport_metadata_ida;
|
struct ida vport_metadata_ida;
|
||||||
unsigned int host_number; /* ECPF supports one external host */
|
unsigned int host_number; /* ECPF supports one external host */
|
||||||
|
@ -784,6 +785,11 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
|
||||||
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev);
|
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev);
|
||||||
void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev);
|
void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev);
|
||||||
|
|
||||||
|
int mlx5_eswitch_block_mode_trylock(struct mlx5_core_dev *dev);
|
||||||
|
void mlx5_eswitch_block_mode_unlock(struct mlx5_core_dev *dev, int err);
|
||||||
|
void mlx5_eswitch_unblock_mode_lock(struct mlx5_core_dev *dev);
|
||||||
|
void mlx5_eswitch_unblock_mode_unlock(struct mlx5_core_dev *dev);
|
||||||
|
|
||||||
static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
|
static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
|
||||||
{
|
{
|
||||||
if (mlx5_esw_allowed(esw))
|
if (mlx5_esw_allowed(esw))
|
||||||
|
@ -863,6 +869,14 @@ static inline bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
|
||||||
static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
|
static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int mlx5_eswitch_block_mode_trylock(struct mlx5_core_dev *dev) { return 0; }
|
||||||
|
|
||||||
|
static inline void mlx5_eswitch_block_mode_unlock(struct mlx5_core_dev *dev, int err) {}
|
||||||
|
|
||||||
|
static inline void mlx5_eswitch_unblock_mode_lock(struct mlx5_core_dev *dev) {}
|
||||||
|
|
||||||
|
static inline void mlx5_eswitch_unblock_mode_unlock(struct mlx5_core_dev *dev) {}
|
||||||
#endif /* CONFIG_MLX5_ESWITCH */
|
#endif /* CONFIG_MLX5_ESWITCH */
|
||||||
|
|
||||||
#endif /* __MLX5_ESWITCH_H__ */
|
#endif /* __MLX5_ESWITCH_H__ */
|
||||||
|
|
|
@ -3518,6 +3518,69 @@ static bool esw_offloads_devlink_ns_eq_netdev_ns(struct devlink *devlink)
|
||||||
return net_eq(devl_net, netdev_net);
|
return net_eq(devl_net, netdev_net);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mlx5_eswitch_block_mode_trylock(struct mlx5_core_dev *dev)
|
||||||
|
{
|
||||||
|
struct devlink *devlink = priv_to_devlink(dev);
|
||||||
|
struct mlx5_eswitch *esw;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
devl_lock(devlink);
|
||||||
|
esw = mlx5_devlink_eswitch_get(devlink);
|
||||||
|
if (IS_ERR(esw)) {
|
||||||
|
/* Failure means no eswitch => not possible to change eswitch mode */
|
||||||
|
devl_unlock(devlink);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mlx5_esw_try_lock(esw);
|
||||||
|
if (err < 0) {
|
||||||
|
devl_unlock(devlink);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx5_eswitch_block_mode_unlock(struct mlx5_core_dev *dev, int err)
|
||||||
|
{
|
||||||
|
struct devlink *devlink = priv_to_devlink(dev);
|
||||||
|
struct mlx5_eswitch *esw;
|
||||||
|
|
||||||
|
esw = mlx5_devlink_eswitch_get(devlink);
|
||||||
|
if (IS_ERR(esw))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
esw->offloads.num_block_mode++;
|
||||||
|
mlx5_esw_unlock(esw);
|
||||||
|
devl_unlock(devlink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx5_eswitch_unblock_mode_lock(struct mlx5_core_dev *dev)
|
||||||
|
{
|
||||||
|
struct devlink *devlink = priv_to_devlink(dev);
|
||||||
|
struct mlx5_eswitch *esw;
|
||||||
|
|
||||||
|
esw = mlx5_devlink_eswitch_get(devlink);
|
||||||
|
if (IS_ERR(esw))
|
||||||
|
return;
|
||||||
|
|
||||||
|
down_write(&esw->mode_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mlx5_eswitch_unblock_mode_unlock(struct mlx5_core_dev *dev)
|
||||||
|
{
|
||||||
|
struct devlink *devlink = priv_to_devlink(dev);
|
||||||
|
struct mlx5_eswitch *esw;
|
||||||
|
|
||||||
|
esw = mlx5_devlink_eswitch_get(devlink);
|
||||||
|
if (IS_ERR(esw))
|
||||||
|
return;
|
||||||
|
|
||||||
|
esw->offloads.num_block_mode--;
|
||||||
|
up_write(&esw->mode_lock);
|
||||||
|
}
|
||||||
|
|
||||||
int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
|
@ -3551,6 +3614,13 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
|
||||||
if (cur_mlx5_mode == mlx5_mode)
|
if (cur_mlx5_mode == mlx5_mode)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
|
if (esw->offloads.num_block_mode) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack,
|
||||||
|
"Can't change eswitch mode when IPsec SA and/or policies are configured");
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
mlx5_eswitch_disable_locked(esw);
|
mlx5_eswitch_disable_locked(esw);
|
||||||
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
|
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
|
||||||
if (mlx5_devlink_trap_get_num_active(esw->dev)) {
|
if (mlx5_devlink_trap_get_num_active(esw->dev)) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue