Skip to content

Commit

Permalink
net/mlx5: Handle IPsec steering upon master unbind/bind
Browse files Browse the repository at this point in the history
When the master device is unbinded, make sure to clean up all of the
steering rules or flow tables that were created over the master, in
order to allow proper unbinding of master, and for ethernet traffic
to continue to work independently.

Upon bringing master device back up and attaching the slave to it,
checks if the slave already has IPsec configured and if so reconfigure
the rules needed to support RoCE traffic.

Note that while master device is unbound, the user is unable to
configure IPsec again, since they are in a kind of illegal state in
which they are in MPV mode but the slave has no master.

However if IPsec was configured before hand, it will continue to work
for ethernet traffic while master is unbound, and would continue to
work for all traffic when the master is bound back again.

Signed-off-by: Patrisious Haddad <phaddad@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Link: https://lore.kernel.org/r/8434e88912c588affe51b34669900382a132e873.1695296682.git.leon@kernel.org
Signed-off-by: Leon Romanovsky <leon@kernel.org>
  • Loading branch information
Patrisious Haddad authored and Leon Romanovsky committed Oct 2, 2023
1 parent f2f0231 commit 82f9378
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 32 deletions.
7 changes: 7 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ struct page_pool;
#define mlx5e_state_dereference(priv, p) \
rcu_dereference_protected((p), lockdep_is_held(&(priv)->state_lock))

enum mlx5e_devcom_events {
MPV_DEVCOM_MASTER_UP,
MPV_DEVCOM_MASTER_DOWN,
MPV_DEVCOM_IPSEC_MASTER_UP,
MPV_DEVCOM_IPSEC_MASTER_DOWN,
};

static inline u8 mlx5e_get_num_lag_ports(struct mlx5_core_dev *mdev)
{
if (mlx5_lag_is_lacp_owner(mdev))
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ void mlx5e_ipsec_init(struct mlx5e_priv *priv)

xa_init_flags(&ipsec->sadb, XA_FLAGS_ALLOC);
ipsec->mdev = priv->mdev;
init_completion(&ipsec->comp);
ipsec->wq = alloc_workqueue("mlx5e_ipsec: %s", WQ_UNBOUND, 0,
priv->netdev->name);
if (!ipsec->wq)
Expand Down
24 changes: 22 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@
#define MLX5E_IPSEC_SADB_RX_BITS 10
#define MLX5E_IPSEC_ESN_SCOPE_MID 0x80000000L

#define MPV_DEVCOM_MASTER_UP 1

struct aes_gcm_keymat {
u64 seq_iv;

Expand Down Expand Up @@ -224,12 +222,20 @@ struct mlx5e_ipsec_tx_create_attr {
enum mlx5_flow_namespace_type chains_ns;
};

struct mlx5e_ipsec_mpv_work {
int event;
struct work_struct work;
struct mlx5e_priv *slave_priv;
struct mlx5e_priv *master_priv;
};

struct mlx5e_ipsec {
struct mlx5_core_dev *mdev;
struct xarray sadb;
struct mlx5e_ipsec_sw_stats sw_stats;
struct mlx5e_ipsec_hw_stats hw_stats;
struct workqueue_struct *wq;
struct completion comp;
struct mlx5e_flow_steering *fs;
struct mlx5e_ipsec_rx *rx_ipv4;
struct mlx5e_ipsec_rx *rx_ipv6;
Expand All @@ -241,6 +247,7 @@ struct mlx5e_ipsec {
struct notifier_block netevent_nb;
struct mlx5_ipsec_fs *roce;
u8 is_uplink_rep: 1;
struct mlx5e_ipsec_mpv_work mpv_work;
};

struct mlx5e_ipsec_esn_state {
Expand Down Expand Up @@ -331,6 +338,10 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv,

void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_accel_esp_xfrm_attrs *attrs);
void mlx5e_ipsec_handle_mpv_event(int event, struct mlx5e_priv *slave_priv,
struct mlx5e_priv *master_priv);
void mlx5e_ipsec_send_event(struct mlx5e_priv *priv, int event);

static inline struct mlx5_core_dev *
mlx5e_ipsec_sa2dev(struct mlx5e_ipsec_sa_entry *sa_entry)
{
Expand Down Expand Up @@ -366,6 +377,15 @@ static inline u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
{
return 0;
}

static inline void mlx5e_ipsec_handle_mpv_event(int event, struct mlx5e_priv *slave_priv,
struct mlx5e_priv *master_priv)
{
}

static inline void mlx5e_ipsec_send_event(struct mlx5e_priv *priv, int event)
{
}
#endif

#endif /* __MLX5E_IPSEC_H__ */
111 changes: 110 additions & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,83 @@ static int ipsec_miss_create(struct mlx5_core_dev *mdev,
return err;
}

static void handle_ipsec_rx_bringup(struct mlx5e_ipsec *ipsec, u32 family)
{
struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, XFRM_DEV_OFFLOAD_PACKET);
struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(ipsec->fs, false);
struct mlx5_flow_destination old_dest, new_dest;

old_dest = mlx5_ttc_get_default_dest(mlx5e_fs_get_ttc(ipsec->fs, false),
family2tt(family));

mlx5_ipsec_fs_roce_rx_create(ipsec->mdev, ipsec->roce, ns, &old_dest, family,
MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL, MLX5E_NIC_PRIO);

new_dest.ft = mlx5_ipsec_fs_roce_ft_get(ipsec->roce, family);
new_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
mlx5_modify_rule_destination(rx->status.rule, &new_dest, &old_dest);
mlx5_modify_rule_destination(rx->sa.rule, &new_dest, &old_dest);
}

static void handle_ipsec_rx_cleanup(struct mlx5e_ipsec *ipsec, u32 family)
{
struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, XFRM_DEV_OFFLOAD_PACKET);
struct mlx5_flow_destination old_dest, new_dest;

old_dest.ft = mlx5_ipsec_fs_roce_ft_get(ipsec->roce, family);
old_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
new_dest = mlx5_ttc_get_default_dest(mlx5e_fs_get_ttc(ipsec->fs, false),
family2tt(family));
mlx5_modify_rule_destination(rx->sa.rule, &new_dest, &old_dest);
mlx5_modify_rule_destination(rx->status.rule, &new_dest, &old_dest);

mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family, ipsec->mdev);
}

static void ipsec_mpv_work_handler(struct work_struct *_work)
{
struct mlx5e_ipsec_mpv_work *work = container_of(_work, struct mlx5e_ipsec_mpv_work, work);
struct mlx5e_ipsec *ipsec = work->slave_priv->ipsec;

switch (work->event) {
case MPV_DEVCOM_IPSEC_MASTER_UP:
mutex_lock(&ipsec->tx->ft.mutex);
if (ipsec->tx->ft.refcnt)
mlx5_ipsec_fs_roce_tx_create(ipsec->mdev, ipsec->roce, ipsec->tx->ft.pol,
true);
mutex_unlock(&ipsec->tx->ft.mutex);

mutex_lock(&ipsec->rx_ipv4->ft.mutex);
if (ipsec->rx_ipv4->ft.refcnt)
handle_ipsec_rx_bringup(ipsec, AF_INET);
mutex_unlock(&ipsec->rx_ipv4->ft.mutex);

mutex_lock(&ipsec->rx_ipv6->ft.mutex);
if (ipsec->rx_ipv6->ft.refcnt)
handle_ipsec_rx_bringup(ipsec, AF_INET6);
mutex_unlock(&ipsec->rx_ipv6->ft.mutex);
break;
case MPV_DEVCOM_IPSEC_MASTER_DOWN:
mutex_lock(&ipsec->tx->ft.mutex);
if (ipsec->tx->ft.refcnt)
mlx5_ipsec_fs_roce_tx_destroy(ipsec->roce, ipsec->mdev);
mutex_unlock(&ipsec->tx->ft.mutex);

mutex_lock(&ipsec->rx_ipv4->ft.mutex);
if (ipsec->rx_ipv4->ft.refcnt)
handle_ipsec_rx_cleanup(ipsec, AF_INET);
mutex_unlock(&ipsec->rx_ipv4->ft.mutex);

mutex_lock(&ipsec->rx_ipv6->ft.mutex);
if (ipsec->rx_ipv6->ft.refcnt)
handle_ipsec_rx_cleanup(ipsec, AF_INET6);
mutex_unlock(&ipsec->rx_ipv6->ft.mutex);
break;
}

complete(&work->master_priv->ipsec->comp);
}

static void ipsec_rx_ft_disconnect(struct mlx5e_ipsec *ipsec, u32 family)
{
struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
Expand Down Expand Up @@ -665,7 +742,7 @@ static int tx_create(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
}

connect_roce:
err = mlx5_ipsec_fs_roce_tx_create(mdev, roce, tx->ft.pol);
err = mlx5_ipsec_fs_roce_tx_create(mdev, roce, tx->ft.pol, false);
if (err)
goto err_roce;
return 0;
Expand Down Expand Up @@ -1942,6 +2019,8 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec,
xa_init_flags(&ipsec->rx_esw->ipsec_obj_id_map, XA_FLAGS_ALLOC1);
} else if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ROCE) {
ipsec->roce = mlx5_ipsec_fs_roce_init(mdev, devcom);
} else {
mlx5_core_warn(mdev, "IPsec was initialized without RoCE support\n");
}

return 0;
Expand Down Expand Up @@ -1988,3 +2067,33 @@ bool mlx5e_ipsec_fs_tunnel_enabled(struct mlx5e_ipsec_sa_entry *sa_entry)

return rx->allow_tunnel_mode;
}

void mlx5e_ipsec_handle_mpv_event(int event, struct mlx5e_priv *slave_priv,
struct mlx5e_priv *master_priv)
{
struct mlx5e_ipsec_mpv_work *work;

reinit_completion(&master_priv->ipsec->comp);

if (!slave_priv->ipsec) {
complete(&master_priv->ipsec->comp);
return;
}

work = &slave_priv->ipsec->mpv_work;

INIT_WORK(&work->work, ipsec_mpv_work_handler);
work->event = event;
work->slave_priv = slave_priv;
work->master_priv = master_priv;
queue_work(slave_priv->ipsec->wq, &work->work);
}

void mlx5e_ipsec_send_event(struct mlx5e_priv *priv, int event)
{
if (!priv->ipsec)
return; /* IPsec not supported */

mlx5_devcom_send_event(priv->devcom, event, event, priv);
wait_for_completion(&priv->ipsec->comp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "en.h"
#include "ipsec.h"
#include "lib/crypto.h"
#include "lib/ipsec_fs_roce.h"

enum {
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET,
Expand Down Expand Up @@ -63,7 +64,7 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
caps |= MLX5_IPSEC_CAP_ESPINUDP;
}

if (mlx5_get_roce_state(mdev) &&
if (mlx5_get_roce_state(mdev) && mlx5_ipsec_fs_is_mpv_roce_supported(mdev) &&
MLX5_CAP_GEN_2(mdev, flow_table_type_2_type) & MLX5_FT_NIC_RX_2_NIC_RX_RDMA &&
MLX5_CAP_GEN_2(mdev, flow_table_type_2_type) & MLX5_FT_NIC_TX_RDMA_2_NIC_TX)
caps |= MLX5_IPSEC_CAP_ROCE;
Expand Down
28 changes: 26 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/en_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,20 @@ static int mlx5e_devcom_event_mpv(int event, void *my_data, void *event_data)
{
struct mlx5e_priv *slave_priv = my_data;

mlx5_devcom_comp_set_ready(slave_priv->devcom, true);
switch (event) {
case MPV_DEVCOM_MASTER_UP:
mlx5_devcom_comp_set_ready(slave_priv->devcom, true);
break;
case MPV_DEVCOM_MASTER_DOWN:
/* no need for comp set ready false since we unregister after
* and it hurts cleanup flow.
*/
break;
case MPV_DEVCOM_IPSEC_MASTER_UP:
case MPV_DEVCOM_IPSEC_MASTER_DOWN:
mlx5e_ipsec_handle_mpv_event(event, my_data, event_data);
break;
}

return 0;
}
Expand All @@ -198,15 +211,26 @@ static int mlx5e_devcom_init_mpv(struct mlx5e_priv *priv, u64 *data)
if (IS_ERR_OR_NULL(priv->devcom))
return -EOPNOTSUPP;

if (mlx5_core_is_mp_master(priv->mdev))
if (mlx5_core_is_mp_master(priv->mdev)) {
mlx5_devcom_send_event(priv->devcom, MPV_DEVCOM_MASTER_UP,
MPV_DEVCOM_MASTER_UP, priv);
mlx5e_ipsec_send_event(priv, MPV_DEVCOM_IPSEC_MASTER_UP);
}

return 0;
}

static void mlx5e_devcom_cleanup_mpv(struct mlx5e_priv *priv)
{
if (IS_ERR_OR_NULL(priv->devcom))
return;

if (mlx5_core_is_mp_master(priv->mdev)) {
mlx5_devcom_send_event(priv->devcom, MPV_DEVCOM_MASTER_DOWN,
MPV_DEVCOM_MASTER_DOWN, priv);
mlx5e_ipsec_send_event(priv, MPV_DEVCOM_IPSEC_MASTER_DOWN);
}

mlx5_devcom_unregister_component(priv->devcom);
}

Expand Down
Loading

0 comments on commit 82f9378

Please sign in to comment.