Leon Romanovsky says:

====================
This PR is collected from
https://lore.kernel.org/all/cover.1695296682.git.leon@kernel.org

This series from Patrisious extends mlx5 to support IPsec packet offload
in multiport devices (MPV, see [1] for more details).

These devices have single flow steering logic and two netdev interfaces,
which require extra logic to manage IPsec configurations as they performed
on netdevs.

[1] https://lore.kernel.org/linux-rdma/20180104152544.28919-1-leon@kernel.org/

* 'mlx5-next' of https://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux:
  net/mlx5: Handle IPsec steering upon master unbind/bind
  net/mlx5: Configure IPsec steering for ingress RoCEv2 MPV traffic
  net/mlx5: Configure IPsec steering for egress RoCEv2 MPV traffic
  net/mlx5: Add create alias flow table function to ipsec roce
  net/mlx5: Implement alias object allow and create functions
  net/mlx5: Add alias flow table bits
  net/mlx5: Store devcom pointer inside IPsec RoCE
  net/mlx5: Register mlx5e priv to devcom in MPV mode
  RDMA/mlx5: Send events from IB driver about device affiliation state
  net/mlx5: Introduce ifc bits for migration in a chunk mode

====================

Link: https://lore.kernel.org/r/20231002083832.19746-1-leon@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2023-10-13 09:35:34 -07:00
commit 1bc60524ca
17 changed files with 936 additions and 45 deletions

View File

@ -24,6 +24,7 @@
#include <linux/mlx5/vport.h>
#include <linux/mlx5/fs.h>
#include <linux/mlx5/eswitch.h>
#include <linux/mlx5/driver.h>
#include <linux/list.h>
#include <rdma/ib_smi.h>
#include <rdma/ib_umem_odp.h>
@ -3175,6 +3176,13 @@ static void mlx5_ib_unbind_slave_port(struct mlx5_ib_dev *ibdev,
lockdep_assert_held(&mlx5_ib_multiport_mutex);
mlx5_core_mp_event_replay(ibdev->mdev,
MLX5_DRIVER_EVENT_AFFILIATION_REMOVED,
NULL);
mlx5_core_mp_event_replay(mpi->mdev,
MLX5_DRIVER_EVENT_AFFILIATION_REMOVED,
NULL);
mlx5_ib_cleanup_cong_debugfs(ibdev, port_num);
spin_lock(&port->mp.mpi_lock);
@ -3226,6 +3234,7 @@ static bool mlx5_ib_bind_slave_port(struct mlx5_ib_dev *ibdev,
struct mlx5_ib_multiport_info *mpi)
{
u32 port_num = mlx5_core_native_port_num(mpi->mdev) - 1;
u64 key;
int err;
lockdep_assert_held(&mlx5_ib_multiport_mutex);
@ -3254,6 +3263,14 @@ static bool mlx5_ib_bind_slave_port(struct mlx5_ib_dev *ibdev,
mlx5_ib_init_cong_debugfs(ibdev, port_num);
key = ibdev->ib_dev.index;
mlx5_core_mp_event_replay(mpi->mdev,
MLX5_DRIVER_EVENT_AFFILIATION_DONE,
&key);
mlx5_core_mp_event_replay(ibdev->mdev,
MLX5_DRIVER_EVENT_AFFILIATION_DONE,
&key);
return true;
unbind:

View File

@ -525,6 +525,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
case MLX5_CMD_OP_SAVE_VHCA_STATE:
case MLX5_CMD_OP_LOAD_VHCA_STATE:
case MLX5_CMD_OP_SYNC_CRYPTO:
case MLX5_CMD_OP_ALLOW_OTHER_VHCA_ACCESS:
*status = MLX5_DRIVER_STATUS_ABORTED;
*synd = MLX5_DRIVER_SYND;
return -ENOLINK;
@ -728,6 +729,7 @@ const char *mlx5_command_str(int command)
MLX5_COMMAND_STR_CASE(SAVE_VHCA_STATE);
MLX5_COMMAND_STR_CASE(LOAD_VHCA_STATE);
MLX5_COMMAND_STR_CASE(SYNC_CRYPTO);
MLX5_COMMAND_STR_CASE(ALLOW_OTHER_VHCA_ACCESS);
default: return "unknown command opcode";
}
}
@ -2090,6 +2092,74 @@ int mlx5_cmd_exec_cb(struct mlx5_async_ctx *ctx, void *in, int in_size,
}
EXPORT_SYMBOL(mlx5_cmd_exec_cb);
int mlx5_cmd_allow_other_vhca_access(struct mlx5_core_dev *dev,
struct mlx5_cmd_allow_other_vhca_access_attr *attr)
{
u32 out[MLX5_ST_SZ_DW(allow_other_vhca_access_out)] = {};
u32 in[MLX5_ST_SZ_DW(allow_other_vhca_access_in)] = {};
void *key;
MLX5_SET(allow_other_vhca_access_in,
in, opcode, MLX5_CMD_OP_ALLOW_OTHER_VHCA_ACCESS);
MLX5_SET(allow_other_vhca_access_in,
in, object_type_to_be_accessed, attr->obj_type);
MLX5_SET(allow_other_vhca_access_in,
in, object_id_to_be_accessed, attr->obj_id);
key = MLX5_ADDR_OF(allow_other_vhca_access_in, in, access_key);
memcpy(key, attr->access_key, sizeof(attr->access_key));
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
int mlx5_cmd_alias_obj_create(struct mlx5_core_dev *dev,
struct mlx5_cmd_alias_obj_create_attr *alias_attr,
u32 *obj_id)
{
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
u32 in[MLX5_ST_SZ_DW(create_alias_obj_in)] = {};
void *param;
void *attr;
void *key;
int ret;
attr = MLX5_ADDR_OF(create_alias_obj_in, in, hdr);
MLX5_SET(general_obj_in_cmd_hdr,
attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr,
attr, obj_type, alias_attr->obj_type);
param = MLX5_ADDR_OF(general_obj_in_cmd_hdr, in, op_param);
MLX5_SET(general_obj_create_param, param, alias_object, 1);
attr = MLX5_ADDR_OF(create_alias_obj_in, in, alias_ctx);
MLX5_SET(alias_context, attr, vhca_id_to_be_accessed, alias_attr->vhca_id);
MLX5_SET(alias_context, attr, object_id_to_be_accessed, alias_attr->obj_id);
key = MLX5_ADDR_OF(alias_context, attr, access_key);
memcpy(key, alias_attr->access_key, sizeof(alias_attr->access_key));
ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
if (ret)
return ret;
*obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
return 0;
}
int mlx5_cmd_alias_obj_destroy(struct mlx5_core_dev *dev, u32 obj_id,
u16 obj_type)
{
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, obj_type);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
static void destroy_msg_cache(struct mlx5_core_dev *dev)
{
struct cmd_msg_cache *ch;

View File

@ -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))
@ -936,6 +943,7 @@ struct mlx5e_priv {
struct mlx5e_htb *htb;
struct mlx5e_mqprio_rl *mqprio_rl;
struct dentry *dfs_root;
struct mlx5_devcom_comp_dev *devcom;
};
struct mlx5e_dev {

View File

@ -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)
@ -870,7 +871,7 @@ void mlx5e_ipsec_init(struct mlx5e_priv *priv)
}
ipsec->is_uplink_rep = mlx5e_is_uplink_rep(priv);
ret = mlx5e_accel_ipsec_fs_init(ipsec);
ret = mlx5e_accel_ipsec_fs_init(ipsec, &priv->devcom);
if (ret)
goto err_fs_init;

View File

@ -38,6 +38,7 @@
#include <net/xfrm.h>
#include <linux/idr.h>
#include "lib/aso.h"
#include "lib/devcom.h"
#define MLX5E_IPSEC_SADB_RX_BITS 10
#define MLX5E_IPSEC_ESN_SCOPE_MID 0x80000000L
@ -221,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;
@ -238,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 {
@ -302,7 +312,7 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv);
void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv);
void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec);
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec);
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec, struct mlx5_devcom_comp_dev **devcom);
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry);
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);
@ -328,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)
{
@ -363,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__ */

View File

@ -229,6 +229,83 @@ out:
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);
@ -264,7 +341,7 @@ static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
}
mlx5_destroy_flow_table(rx->ft.status);
mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family);
mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family, mdev);
}
static void ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
@ -422,7 +499,7 @@ err_fs_ft:
err_add:
mlx5_destroy_flow_table(rx->ft.status);
err_fs_ft_status:
mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family);
mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family, mdev);
return err;
}
@ -562,7 +639,7 @@ err_rule:
static void tx_destroy(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
struct mlx5_ipsec_fs *roce)
{
mlx5_ipsec_fs_roce_tx_destroy(roce);
mlx5_ipsec_fs_roce_tx_destroy(roce, ipsec->mdev);
if (tx->chains) {
ipsec_chains_destroy(tx->chains);
} else {
@ -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;
@ -1888,7 +1965,8 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
}
}
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec,
struct mlx5_devcom_comp_dev **devcom)
{
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_flow_namespace *ns, *ns_esw;
@ -1940,7 +2018,9 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
ipsec->tx_esw->ns = ns_esw;
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);
ipsec->roce = mlx5_ipsec_fs_roce_init(mdev, devcom);
} else {
mlx5_core_warn(mdev, "IPsec was initialized without RoCE support\n");
}
return 0;
@ -1987,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);
}

View File

@ -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,
@ -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;

View File

@ -69,6 +69,7 @@
#include "en/htb.h"
#include "qos.h"
#include "en/trap.h"
#include "lib/devcom.h"
bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev, u8 page_shift,
enum mlx5e_mpwrq_umr_mode umr_mode)
@ -178,6 +179,61 @@ static void mlx5e_disable_async_events(struct mlx5e_priv *priv)
mlx5_notifier_unregister(priv->mdev, &priv->events_nb);
}
static int mlx5e_devcom_event_mpv(int event, void *my_data, void *event_data)
{
struct mlx5e_priv *slave_priv = my_data;
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;
}
static int mlx5e_devcom_init_mpv(struct mlx5e_priv *priv, u64 *data)
{
priv->devcom = mlx5_devcom_register_component(priv->mdev->priv.devc,
MLX5_DEVCOM_MPV,
*data,
mlx5e_devcom_event_mpv,
priv);
if (IS_ERR_OR_NULL(priv->devcom))
return -EOPNOTSUPP;
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);
}
static int blocking_event(struct notifier_block *nb, unsigned long event, void *data)
{
struct mlx5e_priv *priv = container_of(nb, struct mlx5e_priv, blocking_events_nb);
@ -192,6 +248,13 @@ static int blocking_event(struct notifier_block *nb, unsigned long event, void *
return NOTIFY_BAD;
}
break;
case MLX5_DRIVER_EVENT_AFFILIATION_DONE:
if (mlx5e_devcom_init_mpv(priv, data))
return NOTIFY_BAD;
break;
case MLX5_DRIVER_EVENT_AFFILIATION_REMOVED:
mlx5e_devcom_cleanup_mpv(priv);
break;
default:
return NOTIFY_DONE;
}

View File

@ -114,9 +114,9 @@
#define ETHTOOL_NUM_PRIOS 11
#define ETHTOOL_MIN_LEVEL (KERNEL_MIN_LEVEL + ETHTOOL_NUM_PRIOS)
/* Promiscuous, Vlan, mac, ttc, inner ttc, {UDP/ANY/aRFS/accel/{esp, esp_err}}, IPsec policy,
* IPsec RoCE policy
* {IPsec RoCE MPV,Alias table},IPsec RoCE policy
*/
#define KERNEL_NIC_PRIO_NUM_LEVELS 9
#define KERNEL_NIC_PRIO_NUM_LEVELS 11
#define KERNEL_NIC_NUM_PRIOS 1
/* One more level for tc */
#define KERNEL_MIN_LEVEL (KERNEL_NIC_PRIO_NUM_LEVELS + 1)
@ -137,7 +137,7 @@
#define LAG_MIN_LEVEL (OFFLOADS_MIN_LEVEL + KERNEL_RX_MACSEC_MIN_LEVEL + 1)
#define KERNEL_TX_IPSEC_NUM_PRIOS 1
#define KERNEL_TX_IPSEC_NUM_LEVELS 3
#define KERNEL_TX_IPSEC_NUM_LEVELS 4
#define KERNEL_TX_IPSEC_MIN_LEVEL (KERNEL_TX_IPSEC_NUM_LEVELS)
#define KERNEL_TX_MACSEC_NUM_PRIOS 1
@ -231,7 +231,7 @@ enum {
};
#define RDMA_RX_IPSEC_NUM_PRIOS 1
#define RDMA_RX_IPSEC_NUM_LEVELS 2
#define RDMA_RX_IPSEC_NUM_LEVELS 4
#define RDMA_RX_IPSEC_MIN_LEVEL (RDMA_RX_IPSEC_NUM_LEVELS)
#define RDMA_RX_BYPASS_MIN_LEVEL MLX5_BY_PASS_NUM_REGULAR_PRIOS
@ -288,7 +288,7 @@ enum {
#define RDMA_TX_BYPASS_MIN_LEVEL MLX5_BY_PASS_NUM_PRIOS
#define RDMA_TX_COUNTERS_MIN_LEVEL (RDMA_TX_BYPASS_MIN_LEVEL + 1)
#define RDMA_TX_IPSEC_NUM_PRIOS 1
#define RDMA_TX_IPSEC_NUM_PRIOS 2
#define RDMA_TX_IPSEC_PRIO_NUM_LEVELS 1
#define RDMA_TX_IPSEC_MIN_LEVEL (RDMA_TX_COUNTERS_MIN_LEVEL + RDMA_TX_IPSEC_NUM_PRIOS)

View File

@ -8,6 +8,7 @@
enum mlx5_devcom_component {
MLX5_DEVCOM_ESW_OFFLOADS,
MLX5_DEVCOM_MPV,
MLX5_DEVCOM_NUM_COMPONENTS,
};

View File

@ -2,8 +2,11 @@
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#include "fs_core.h"
#include "fs_cmd.h"
#include "en.h"
#include "lib/ipsec_fs_roce.h"
#include "mlx5_core.h"
#include <linux/random.h>
struct mlx5_ipsec_miss {
struct mlx5_flow_group *group;
@ -15,6 +18,12 @@ struct mlx5_ipsec_rx_roce {
struct mlx5_flow_table *ft;
struct mlx5_flow_handle *rule;
struct mlx5_ipsec_miss roce_miss;
struct mlx5_flow_table *nic_master_ft;
struct mlx5_flow_group *nic_master_group;
struct mlx5_flow_handle *nic_master_rule;
struct mlx5_flow_table *goto_alias_ft;
u32 alias_id;
char key[ACCESS_KEY_LEN];
struct mlx5_flow_table *ft_rdma;
struct mlx5_flow_namespace *ns_rdma;
@ -24,6 +33,9 @@ struct mlx5_ipsec_tx_roce {
struct mlx5_flow_group *g;
struct mlx5_flow_table *ft;
struct mlx5_flow_handle *rule;
struct mlx5_flow_table *goto_alias_ft;
u32 alias_id;
char key[ACCESS_KEY_LEN];
struct mlx5_flow_namespace *ns;
};
@ -31,6 +43,7 @@ struct mlx5_ipsec_fs {
struct mlx5_ipsec_rx_roce ipv4_rx;
struct mlx5_ipsec_rx_roce ipv6_rx;
struct mlx5_ipsec_tx_roce tx;
struct mlx5_devcom_comp_dev **devcom;
};
static void ipsec_fs_roce_setup_udp_dport(struct mlx5_flow_spec *spec,
@ -43,11 +56,83 @@ static void ipsec_fs_roce_setup_udp_dport(struct mlx5_flow_spec *spec,
MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, dport);
}
static bool ipsec_fs_create_alias_supported_one(struct mlx5_core_dev *mdev)
{
u64 obj_allowed = MLX5_CAP_GEN_2_64(mdev, allowed_object_for_other_vhca_access);
u32 obj_supp = MLX5_CAP_GEN_2(mdev, cross_vhca_object_to_object_supported);
if (!(obj_supp &
MLX5_CROSS_VHCA_OBJ_TO_OBJ_SUPPORTED_LOCAL_FLOW_TABLE_TO_REMOTE_FLOW_TABLE_MISS))
return false;
if (!(obj_allowed & MLX5_ALLOWED_OBJ_FOR_OTHER_VHCA_ACCESS_FLOW_TABLE))
return false;
return true;
}
static bool ipsec_fs_create_alias_supported(struct mlx5_core_dev *mdev,
struct mlx5_core_dev *master_mdev)
{
if (ipsec_fs_create_alias_supported_one(mdev) &&
ipsec_fs_create_alias_supported_one(master_mdev))
return true;
return false;
}
static int ipsec_fs_create_aliased_ft(struct mlx5_core_dev *ibv_owner,
struct mlx5_core_dev *ibv_allowed,
struct mlx5_flow_table *ft,
u32 *obj_id, char *alias_key, bool from_event)
{
u32 aliased_object_id = (ft->type << FT_ID_FT_TYPE_OFFSET) | ft->id;
u16 vhca_id_to_be_accessed = MLX5_CAP_GEN(ibv_owner, vhca_id);
struct mlx5_cmd_allow_other_vhca_access_attr allow_attr = {};
struct mlx5_cmd_alias_obj_create_attr alias_attr = {};
int ret;
int i;
if (!ipsec_fs_create_alias_supported(ibv_owner, ibv_allowed))
return -EOPNOTSUPP;
for (i = 0; i < ACCESS_KEY_LEN; i++)
if (!from_event)
alias_key[i] = get_random_u64() & 0xFF;
memcpy(allow_attr.access_key, alias_key, ACCESS_KEY_LEN);
allow_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
allow_attr.obj_id = aliased_object_id;
if (!from_event) {
ret = mlx5_cmd_allow_other_vhca_access(ibv_owner, &allow_attr);
if (ret) {
mlx5_core_err(ibv_owner, "Failed to allow other vhca access err=%d\n",
ret);
return ret;
}
}
memcpy(alias_attr.access_key, alias_key, ACCESS_KEY_LEN);
alias_attr.obj_id = aliased_object_id;
alias_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
alias_attr.vhca_id = vhca_id_to_be_accessed;
ret = mlx5_cmd_alias_obj_create(ibv_allowed, &alias_attr, obj_id);
if (ret) {
mlx5_core_err(ibv_allowed, "Failed to create alias object err=%d\n",
ret);
return ret;
}
return 0;
}
static int
ipsec_fs_roce_rx_rule_setup(struct mlx5_core_dev *mdev,
struct mlx5_flow_destination *default_dst,
struct mlx5_ipsec_rx_roce *roce)
{
bool is_mpv_slave = mlx5_core_is_mp_slave(mdev);
struct mlx5_flow_destination dst = {};
MLX5_DECLARE_FLOW_ACT(flow_act);
struct mlx5_flow_handle *rule;
@ -61,14 +146,19 @@ ipsec_fs_roce_rx_rule_setup(struct mlx5_core_dev *mdev,
ipsec_fs_roce_setup_udp_dport(spec, ROCE_V2_UDP_DPORT);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
dst.ft = roce->ft_rdma;
if (is_mpv_slave) {
dst.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dst.ft = roce->goto_alias_ft;
} else {
dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
dst.ft = roce->ft_rdma;
}
rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, &dst, 1);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
mlx5_core_err(mdev, "Fail to add RX RoCE IPsec rule err=%d\n",
err);
goto fail_add_rule;
goto out;
}
roce->rule = rule;
@ -84,12 +174,30 @@ ipsec_fs_roce_rx_rule_setup(struct mlx5_core_dev *mdev,
roce->roce_miss.rule = rule;
if (!is_mpv_slave)
goto out;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
dst.ft = roce->ft_rdma;
rule = mlx5_add_flow_rules(roce->nic_master_ft, NULL, &flow_act, &dst,
1);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
mlx5_core_err(mdev, "Fail to add RX RoCE IPsec rule for alias err=%d\n",
err);
goto fail_add_nic_master_rule;
}
roce->nic_master_rule = rule;
kvfree(spec);
return 0;
fail_add_nic_master_rule:
mlx5_del_flow_rules(roce->roce_miss.rule);
fail_add_default_rule:
mlx5_del_flow_rules(roce->rule);
fail_add_rule:
out:
kvfree(spec);
return err;
}
@ -120,25 +228,373 @@ out:
return err;
}
void mlx5_ipsec_fs_roce_tx_destroy(struct mlx5_ipsec_fs *ipsec_roce)
static int ipsec_fs_roce_tx_mpv_rule_setup(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_tx_roce *roce,
struct mlx5_flow_table *pol_ft)
{
struct mlx5_flow_destination dst = {};
MLX5_DECLARE_FLOW_ACT(flow_act);
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
int err = 0;
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters.source_vhca_port);
MLX5_SET(fte_match_param, spec->match_value, misc_parameters.source_vhca_port,
MLX5_CAP_GEN(mdev, native_port_num));
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
dst.ft = roce->goto_alias_ft;
rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, &dst, 1);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
mlx5_core_err(mdev, "Fail to add TX RoCE IPsec rule err=%d\n",
err);
goto out;
}
roce->rule = rule;
/* No need for miss rule, since on miss we go to next PRIO, in which
* if master is configured, he will catch the traffic to go to his
* encryption table.
*/
out:
kvfree(spec);
return err;
}
#define MLX5_TX_ROCE_GROUP_SIZE BIT(0)
#define MLX5_IPSEC_RDMA_TX_FT_LEVEL 0
#define MLX5_IPSEC_NIC_GOTO_ALIAS_FT_LEVEL 3 /* Since last used level in NIC ipsec is 2 */
static int ipsec_fs_roce_tx_mpv_create_ft(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_tx_roce *roce,
struct mlx5_flow_table *pol_ft,
struct mlx5e_priv *peer_priv,
bool from_event)
{
struct mlx5_flow_namespace *roce_ns, *nic_ns;
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_flow_table next_ft;
struct mlx5_flow_table *ft;
int err;
roce_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_RDMA_TX_IPSEC);
if (!roce_ns)
return -EOPNOTSUPP;
nic_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC);
if (!nic_ns)
return -EOPNOTSUPP;
err = ipsec_fs_create_aliased_ft(mdev, peer_priv->mdev, pol_ft, &roce->alias_id, roce->key,
from_event);
if (err)
return err;
next_ft.id = roce->alias_id;
ft_attr.max_fte = 1;
ft_attr.next_ft = &next_ft;
ft_attr.level = MLX5_IPSEC_NIC_GOTO_ALIAS_FT_LEVEL;
ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
ft = mlx5_create_flow_table(nic_ns, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec goto alias ft err=%d\n", err);
goto destroy_alias;
}
roce->goto_alias_ft = ft;
memset(&ft_attr, 0, sizeof(ft_attr));
ft_attr.max_fte = 1;
ft_attr.level = MLX5_IPSEC_RDMA_TX_FT_LEVEL;
ft = mlx5_create_flow_table(roce_ns, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx ft err=%d\n", err);
goto destroy_alias_ft;
}
roce->ft = ft;
return 0;
destroy_alias_ft:
mlx5_destroy_flow_table(roce->goto_alias_ft);
destroy_alias:
mlx5_cmd_alias_obj_destroy(peer_priv->mdev, roce->alias_id,
MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
return err;
}
static int ipsec_fs_roce_tx_mpv_create_group_rules(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_tx_roce *roce,
struct mlx5_flow_table *pol_ft,
u32 *in)
{
struct mlx5_flow_group *g;
int ix = 0;
int err;
u8 *mc;
mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters.source_vhca_port);
MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS);
MLX5_SET_CFG(in, start_flow_index, ix);
ix += MLX5_TX_ROCE_GROUP_SIZE;
MLX5_SET_CFG(in, end_flow_index, ix - 1);
g = mlx5_create_flow_group(roce->ft, in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx group err=%d\n", err);
return err;
}
roce->g = g;
err = ipsec_fs_roce_tx_mpv_rule_setup(mdev, roce, pol_ft);
if (err) {
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx rules err=%d\n", err);
goto destroy_group;
}
return 0;
destroy_group:
mlx5_destroy_flow_group(roce->g);
return err;
}
static int ipsec_fs_roce_tx_mpv_create(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_flow_table *pol_ft,
u32 *in, bool from_event)
{
struct mlx5_devcom_comp_dev *tmp = NULL;
struct mlx5_ipsec_tx_roce *roce;
struct mlx5e_priv *peer_priv;
int err;
if (!mlx5_devcom_for_each_peer_begin(*ipsec_roce->devcom))
return -EOPNOTSUPP;
peer_priv = mlx5_devcom_get_next_peer_data(*ipsec_roce->devcom, &tmp);
if (!peer_priv) {
err = -EOPNOTSUPP;
goto release_peer;
}
roce = &ipsec_roce->tx;
err = ipsec_fs_roce_tx_mpv_create_ft(mdev, roce, pol_ft, peer_priv, from_event);
if (err) {
mlx5_core_err(mdev, "Fail to create RoCE IPsec tables err=%d\n", err);
goto release_peer;
}
err = ipsec_fs_roce_tx_mpv_create_group_rules(mdev, roce, pol_ft, in);
if (err) {
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx group/rule err=%d\n", err);
goto destroy_tables;
}
mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
return 0;
destroy_tables:
mlx5_destroy_flow_table(roce->ft);
mlx5_destroy_flow_table(roce->goto_alias_ft);
mlx5_cmd_alias_obj_destroy(peer_priv->mdev, roce->alias_id,
MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
release_peer:
mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
return err;
}
static void roce_rx_mpv_destroy_tables(struct mlx5_core_dev *mdev, struct mlx5_ipsec_rx_roce *roce)
{
mlx5_destroy_flow_table(roce->goto_alias_ft);
mlx5_cmd_alias_obj_destroy(mdev, roce->alias_id,
MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
mlx5_destroy_flow_group(roce->nic_master_group);
mlx5_destroy_flow_table(roce->nic_master_ft);
}
#define MLX5_RX_ROCE_GROUP_SIZE BIT(0)
#define MLX5_IPSEC_RX_IPV4_FT_LEVEL 3
#define MLX5_IPSEC_RX_IPV6_FT_LEVEL 2
static int ipsec_fs_roce_rx_mpv_create(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_flow_namespace *ns,
u32 family, u32 level, u32 prio)
{
struct mlx5_flow_namespace *roce_ns, *nic_ns;
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_devcom_comp_dev *tmp = NULL;
struct mlx5_ipsec_rx_roce *roce;
struct mlx5_flow_table next_ft;
struct mlx5_flow_table *ft;
struct mlx5_flow_group *g;
struct mlx5e_priv *peer_priv;
int ix = 0;
u32 *in;
int err;
roce = (family == AF_INET) ? &ipsec_roce->ipv4_rx :
&ipsec_roce->ipv6_rx;
if (!mlx5_devcom_for_each_peer_begin(*ipsec_roce->devcom))
return -EOPNOTSUPP;
peer_priv = mlx5_devcom_get_next_peer_data(*ipsec_roce->devcom, &tmp);
if (!peer_priv) {
err = -EOPNOTSUPP;
goto release_peer;
}
roce_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_RDMA_RX_IPSEC);
if (!roce_ns) {
err = -EOPNOTSUPP;
goto release_peer;
}
nic_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_KERNEL);
if (!nic_ns) {
err = -EOPNOTSUPP;
goto release_peer;
}
in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
if (!in) {
err = -ENOMEM;
goto release_peer;
}
ft_attr.level = (family == AF_INET) ? MLX5_IPSEC_RX_IPV4_FT_LEVEL :
MLX5_IPSEC_RX_IPV6_FT_LEVEL;
ft_attr.max_fte = 1;
ft = mlx5_create_flow_table(roce_ns, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at rdma master err=%d\n", err);
goto free_in;
}
roce->ft_rdma = ft;
ft_attr.max_fte = 1;
ft_attr.prio = prio;
ft_attr.level = level + 2;
ft = mlx5_create_flow_table(nic_ns, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at NIC master err=%d\n", err);
goto destroy_ft_rdma;
}
roce->nic_master_ft = ft;
MLX5_SET_CFG(in, start_flow_index, ix);
ix += 1;
MLX5_SET_CFG(in, end_flow_index, ix - 1);
g = mlx5_create_flow_group(roce->nic_master_ft, in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx group aliased err=%d\n", err);
goto destroy_nic_master_ft;
}
roce->nic_master_group = g;
err = ipsec_fs_create_aliased_ft(peer_priv->mdev, mdev, roce->nic_master_ft,
&roce->alias_id, roce->key, false);
if (err) {
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx alias FT err=%d\n", err);
goto destroy_group;
}
next_ft.id = roce->alias_id;
ft_attr.max_fte = 1;
ft_attr.prio = prio;
ft_attr.level = roce->ft->level + 1;
ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
ft_attr.next_ft = &next_ft;
ft = mlx5_create_flow_table(ns, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at NIC slave err=%d\n", err);
goto destroy_alias;
}
roce->goto_alias_ft = ft;
kvfree(in);
mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
return 0;
destroy_alias:
mlx5_cmd_alias_obj_destroy(mdev, roce->alias_id,
MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
destroy_group:
mlx5_destroy_flow_group(roce->nic_master_group);
destroy_nic_master_ft:
mlx5_destroy_flow_table(roce->nic_master_ft);
destroy_ft_rdma:
mlx5_destroy_flow_table(roce->ft_rdma);
free_in:
kvfree(in);
release_peer:
mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
return err;
}
void mlx5_ipsec_fs_roce_tx_destroy(struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_core_dev *mdev)
{
struct mlx5_devcom_comp_dev *tmp = NULL;
struct mlx5_ipsec_tx_roce *tx_roce;
struct mlx5e_priv *peer_priv;
if (!ipsec_roce)
return;
tx_roce = &ipsec_roce->tx;
if (!tx_roce->ft)
return; /* Incase RoCE was cleaned from MPV event flow */
mlx5_del_flow_rules(tx_roce->rule);
mlx5_destroy_flow_group(tx_roce->g);
mlx5_destroy_flow_table(tx_roce->ft);
}
#define MLX5_TX_ROCE_GROUP_SIZE BIT(0)
if (!mlx5_core_is_mp_slave(mdev))
return;
if (!mlx5_devcom_for_each_peer_begin(*ipsec_roce->devcom))
return;
peer_priv = mlx5_devcom_get_next_peer_data(*ipsec_roce->devcom, &tmp);
if (!peer_priv) {
mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
return;
}
mlx5_destroy_flow_table(tx_roce->goto_alias_ft);
mlx5_cmd_alias_obj_destroy(peer_priv->mdev, tx_roce->alias_id,
MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
tx_roce->ft = NULL;
}
int mlx5_ipsec_fs_roce_tx_create(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_flow_table *pol_ft)
struct mlx5_flow_table *pol_ft,
bool from_event)
{
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_ipsec_tx_roce *roce;
@ -157,7 +613,14 @@ int mlx5_ipsec_fs_roce_tx_create(struct mlx5_core_dev *mdev,
if (!in)
return -ENOMEM;
if (mlx5_core_is_mp_slave(mdev)) {
err = ipsec_fs_roce_tx_mpv_create(mdev, ipsec_roce, pol_ft, in, from_event);
goto free_in;
}
ft_attr.max_fte = 1;
ft_attr.prio = 1;
ft_attr.level = MLX5_IPSEC_RDMA_TX_FT_LEVEL;
ft = mlx5_create_flow_table(roce->ns, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
@ -209,8 +672,10 @@ struct mlx5_flow_table *mlx5_ipsec_fs_roce_ft_get(struct mlx5_ipsec_fs *ipsec_ro
return rx_roce->ft;
}
void mlx5_ipsec_fs_roce_rx_destroy(struct mlx5_ipsec_fs *ipsec_roce, u32 family)
void mlx5_ipsec_fs_roce_rx_destroy(struct mlx5_ipsec_fs *ipsec_roce, u32 family,
struct mlx5_core_dev *mdev)
{
bool is_mpv_slave = mlx5_core_is_mp_slave(mdev);
struct mlx5_ipsec_rx_roce *rx_roce;
if (!ipsec_roce)
@ -218,23 +683,29 @@ void mlx5_ipsec_fs_roce_rx_destroy(struct mlx5_ipsec_fs *ipsec_roce, u32 family)
rx_roce = (family == AF_INET) ? &ipsec_roce->ipv4_rx :
&ipsec_roce->ipv6_rx;
if (!rx_roce->ft)
return; /* Incase RoCE was cleaned from MPV event flow */
if (is_mpv_slave)
mlx5_del_flow_rules(rx_roce->nic_master_rule);
mlx5_del_flow_rules(rx_roce->roce_miss.rule);
mlx5_del_flow_rules(rx_roce->rule);
if (is_mpv_slave)
roce_rx_mpv_destroy_tables(mdev, rx_roce);
mlx5_destroy_flow_table(rx_roce->ft_rdma);
mlx5_destroy_flow_group(rx_roce->roce_miss.group);
mlx5_destroy_flow_group(rx_roce->g);
mlx5_destroy_flow_table(rx_roce->ft);
rx_roce->ft = NULL;
}
#define MLX5_RX_ROCE_GROUP_SIZE BIT(0)
int mlx5_ipsec_fs_roce_rx_create(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_flow_namespace *ns,
struct mlx5_flow_destination *default_dst,
u32 family, u32 level, u32 prio)
{
bool is_mpv_slave = mlx5_core_is_mp_slave(mdev);
struct mlx5_flow_table_attr ft_attr = {};
struct mlx5_ipsec_rx_roce *roce;
struct mlx5_flow_table *ft;
@ -298,17 +769,27 @@ int mlx5_ipsec_fs_roce_rx_create(struct mlx5_core_dev *mdev,
}
roce->roce_miss.group = g;
memset(&ft_attr, 0, sizeof(ft_attr));
if (family == AF_INET)
ft_attr.level = 1;
ft = mlx5_create_flow_table(roce->ns_rdma, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at rdma err=%d\n", err);
goto fail_rdma_table;
}
if (is_mpv_slave) {
err = ipsec_fs_roce_rx_mpv_create(mdev, ipsec_roce, ns, family, level, prio);
if (err) {
mlx5_core_err(mdev, "Fail to create RoCE IPsec rx alias err=%d\n", err);
goto fail_mpv_create;
}
} else {
memset(&ft_attr, 0, sizeof(ft_attr));
if (family == AF_INET)
ft_attr.level = 1;
ft_attr.max_fte = 1;
ft = mlx5_create_flow_table(roce->ns_rdma, &ft_attr);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev,
"Fail to create RoCE IPsec rx ft at rdma err=%d\n", err);
goto fail_rdma_table;
}
roce->ft_rdma = ft;
roce->ft_rdma = ft;
}
err = ipsec_fs_roce_rx_rule_setup(mdev, default_dst, roce);
if (err) {
@ -320,7 +801,10 @@ int mlx5_ipsec_fs_roce_rx_create(struct mlx5_core_dev *mdev,
return 0;
fail_setup_rule:
if (is_mpv_slave)
roce_rx_mpv_destroy_tables(mdev, roce);
mlx5_destroy_flow_table(roce->ft_rdma);
fail_mpv_create:
fail_rdma_table:
mlx5_destroy_flow_group(roce->roce_miss.group);
fail_mgroup:
@ -332,12 +816,24 @@ fail_nomem:
return err;
}
bool mlx5_ipsec_fs_is_mpv_roce_supported(struct mlx5_core_dev *mdev)
{
if (!mlx5_core_mp_enabled(mdev))
return true;
if (ipsec_fs_create_alias_supported_one(mdev))
return true;
return false;
}
void mlx5_ipsec_fs_roce_cleanup(struct mlx5_ipsec_fs *ipsec_roce)
{
kfree(ipsec_roce);
}
struct mlx5_ipsec_fs *mlx5_ipsec_fs_roce_init(struct mlx5_core_dev *mdev)
struct mlx5_ipsec_fs *mlx5_ipsec_fs_roce_init(struct mlx5_core_dev *mdev,
struct mlx5_devcom_comp_dev **devcom)
{
struct mlx5_ipsec_fs *roce_ipsec;
struct mlx5_flow_namespace *ns;
@ -363,6 +859,8 @@ struct mlx5_ipsec_fs *mlx5_ipsec_fs_roce_init(struct mlx5_core_dev *mdev)
roce_ipsec->tx.ns = ns;
roce_ipsec->devcom = devcom;
return roce_ipsec;
err_tx:

View File

@ -4,22 +4,28 @@
#ifndef __MLX5_LIB_IPSEC_H__
#define __MLX5_LIB_IPSEC_H__
#include "lib/devcom.h"
struct mlx5_ipsec_fs;
struct mlx5_flow_table *
mlx5_ipsec_fs_roce_ft_get(struct mlx5_ipsec_fs *ipsec_roce, u32 family);
void mlx5_ipsec_fs_roce_rx_destroy(struct mlx5_ipsec_fs *ipsec_roce,
u32 family);
u32 family, struct mlx5_core_dev *mdev);
int mlx5_ipsec_fs_roce_rx_create(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_flow_namespace *ns,
struct mlx5_flow_destination *default_dst,
u32 family, u32 level, u32 prio);
void mlx5_ipsec_fs_roce_tx_destroy(struct mlx5_ipsec_fs *ipsec_roce);
void mlx5_ipsec_fs_roce_tx_destroy(struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_core_dev *mdev);
int mlx5_ipsec_fs_roce_tx_create(struct mlx5_core_dev *mdev,
struct mlx5_ipsec_fs *ipsec_roce,
struct mlx5_flow_table *pol_ft);
struct mlx5_flow_table *pol_ft,
bool from_event);
void mlx5_ipsec_fs_roce_cleanup(struct mlx5_ipsec_fs *ipsec_roce);
struct mlx5_ipsec_fs *mlx5_ipsec_fs_roce_init(struct mlx5_core_dev *mdev);
struct mlx5_ipsec_fs *mlx5_ipsec_fs_roce_init(struct mlx5_core_dev *mdev,
struct mlx5_devcom_comp_dev **devcom);
bool mlx5_ipsec_fs_is_mpv_roce_supported(struct mlx5_core_dev *mdev);
#endif /* __MLX5_LIB_IPSEC_H__ */

View File

@ -361,6 +361,12 @@ void mlx5_core_uplink_netdev_event_replay(struct mlx5_core_dev *dev)
}
EXPORT_SYMBOL(mlx5_core_uplink_netdev_event_replay);
void mlx5_core_mp_event_replay(struct mlx5_core_dev *dev, u32 event, void *data)
{
mlx5_blocking_notifier_call_chain(dev, event, data);
}
EXPORT_SYMBOL(mlx5_core_mp_event_replay);
int mlx5_core_get_caps_mode(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type,
enum mlx5_cap_mode cap_mode)
{

View File

@ -97,6 +97,22 @@ do { \
__func__, __LINE__, current->pid, \
##__VA_ARGS__)
#define ACCESS_KEY_LEN 32
#define FT_ID_FT_TYPE_OFFSET 24
struct mlx5_cmd_allow_other_vhca_access_attr {
u16 obj_type;
u32 obj_id;
u8 access_key[ACCESS_KEY_LEN];
};
struct mlx5_cmd_alias_obj_create_attr {
u32 obj_id;
u16 vhca_id;
u16 obj_type;
u8 access_key[ACCESS_KEY_LEN];
};
static inline void mlx5_printk(struct mlx5_core_dev *dev, int level, const char *format, ...)
{
struct device *device = dev->device;
@ -343,6 +359,12 @@ bool mlx5_eth_supported(struct mlx5_core_dev *dev);
bool mlx5_rdma_supported(struct mlx5_core_dev *dev);
bool mlx5_vnet_supported(struct mlx5_core_dev *dev);
bool mlx5_same_hw_devs(struct mlx5_core_dev *dev, struct mlx5_core_dev *peer_dev);
int mlx5_cmd_allow_other_vhca_access(struct mlx5_core_dev *dev,
struct mlx5_cmd_allow_other_vhca_access_attr *attr);
int mlx5_cmd_alias_obj_create(struct mlx5_core_dev *dev,
struct mlx5_cmd_alias_obj_create_attr *alias_attr,
u32 *obj_id);
int mlx5_cmd_alias_obj_destroy(struct mlx5_core_dev *dev, u32 obj_id, u16 obj_type);
static inline u16 mlx5_core_ec_vf_vport_base(const struct mlx5_core_dev *dev)
{

View File

@ -367,6 +367,8 @@ enum mlx5_driver_event {
MLX5_DRIVER_EVENT_MACSEC_SA_ADDED,
MLX5_DRIVER_EVENT_MACSEC_SA_DELETED,
MLX5_DRIVER_EVENT_SF_PEER_DEVLINK,
MLX5_DRIVER_EVENT_AFFILIATION_DONE,
MLX5_DRIVER_EVENT_AFFILIATION_REMOVED,
};
enum {

View File

@ -1029,6 +1029,8 @@ bool mlx5_cmd_is_down(struct mlx5_core_dev *dev);
void mlx5_core_uplink_netdev_set(struct mlx5_core_dev *mdev, struct net_device *netdev);
void mlx5_core_uplink_netdev_event_replay(struct mlx5_core_dev *mdev);
void mlx5_core_mp_event_replay(struct mlx5_core_dev *dev, u32 event, void *data);
void mlx5_health_cleanup(struct mlx5_core_dev *dev);
int mlx5_health_init(struct mlx5_core_dev *dev);
void mlx5_start_health_poll(struct mlx5_core_dev *dev);

View File

@ -312,6 +312,7 @@ enum {
MLX5_CMD_OP_QUERY_VHCA_STATE = 0xb0d,
MLX5_CMD_OP_MODIFY_VHCA_STATE = 0xb0e,
MLX5_CMD_OP_SYNC_CRYPTO = 0xb12,
MLX5_CMD_OP_ALLOW_OTHER_VHCA_ACCESS = 0xb16,
MLX5_CMD_OP_MAX
};
@ -1934,6 +1935,14 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 match_definer_format_supported[0x40];
};
enum {
MLX5_CROSS_VHCA_OBJ_TO_OBJ_SUPPORTED_LOCAL_FLOW_TABLE_TO_REMOTE_FLOW_TABLE_MISS = 0x80000,
};
enum {
MLX5_ALLOWED_OBJ_FOR_OTHER_VHCA_ACCESS_FLOW_TABLE = 0x200,
};
struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 reserved_at_0[0x80];
@ -1948,9 +1957,15 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 reserved_at_c0[0x8];
u8 migration_multi_load[0x1];
u8 migration_tracking_state[0x1];
u8 reserved_at_ca[0x16];
u8 reserved_at_ca[0x6];
u8 migration_in_chunks[0x1];
u8 reserved_at_d1[0xf];
u8 reserved_at_e0[0xc0];
u8 cross_vhca_object_to_object_supported[0x20];
u8 allowed_object_for_other_vhca_access[0x40];
u8 reserved_at_140[0x60];
u8 flow_table_type_2_type[0x8];
u8 reserved_at_1a8[0x3];
@ -6369,6 +6384,28 @@ struct mlx5_ifc_general_obj_out_cmd_hdr_bits {
u8 reserved_at_60[0x20];
};
struct mlx5_ifc_allow_other_vhca_access_in_bits {
u8 opcode[0x10];
u8 uid[0x10];
u8 reserved_at_20[0x10];
u8 op_mod[0x10];
u8 reserved_at_40[0x50];
u8 object_type_to_be_accessed[0x10];
u8 object_id_to_be_accessed[0x20];
u8 reserved_at_c0[0x40];
union {
u8 access_key_raw[0x100];
u8 access_key[8][0x20];
};
};
struct mlx5_ifc_allow_other_vhca_access_out_bits {
u8 status[0x8];
u8 reserved_at_8[0x18];
u8 syndrome[0x20];
u8 reserved_at_40[0x40];
};
struct mlx5_ifc_modify_header_arg_bits {
u8 reserved_at_0[0x80];
@ -6391,6 +6428,24 @@ struct mlx5_ifc_create_match_definer_out_bits {
struct mlx5_ifc_general_obj_out_cmd_hdr_bits general_obj_out_cmd_hdr;
};
struct mlx5_ifc_alias_context_bits {
u8 vhca_id_to_be_accessed[0x10];
u8 reserved_at_10[0xd];
u8 status[0x3];
u8 object_id_to_be_accessed[0x20];
u8 reserved_at_40[0x40];
union {
u8 access_key_raw[0x100];
u8 access_key[8][0x20];
};
u8 metadata[0x80];
};
struct mlx5_ifc_create_alias_obj_in_bits {
struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
struct mlx5_ifc_alias_context_bits alias_ctx;
};
enum {
MLX5_QUERY_FLOW_GROUP_OUT_MATCH_CRITERIA_ENABLE_OUTER_HEADERS = 0x0,
MLX5_QUERY_FLOW_GROUP_OUT_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS = 0x1,
@ -11920,6 +11975,7 @@ enum {
MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = 0x24,
MLX5_GENERAL_OBJECT_TYPES_MACSEC = 0x27,
MLX5_GENERAL_OBJECT_TYPES_INT_KEK = 0x47,
MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS = 0xff15,
};
enum {
@ -12395,7 +12451,8 @@ struct mlx5_ifc_query_vhca_migration_state_in_bits {
u8 op_mod[0x10];
u8 incremental[0x1];
u8 reserved_at_41[0xf];
u8 chunk[0x1];
u8 reserved_at_42[0xe];
u8 vhca_id[0x10];
u8 reserved_at_60[0x20];
@ -12411,7 +12468,11 @@ struct mlx5_ifc_query_vhca_migration_state_out_bits {
u8 required_umem_size[0x20];
u8 reserved_at_a0[0x160];
u8 reserved_at_a0[0x20];
u8 remaining_total_size[0x40];
u8 reserved_at_100[0x100];
};
struct mlx5_ifc_save_vhca_state_in_bits {
@ -12443,7 +12504,7 @@ struct mlx5_ifc_save_vhca_state_out_bits {
u8 actual_image_size[0x20];
u8 reserved_at_60[0x20];
u8 next_required_umem_size[0x20];
};
struct mlx5_ifc_load_vhca_state_in_bits {