// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB // Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include "fs_core.h" #include "eswitch.h" #include "en_accel/ipsec.h" #include "esw/ipsec_fs.h" #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) #include "en/tc_priv.h" #endif enum { MLX5_ESW_IPSEC_RX_POL_FT_LEVEL, MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL, MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL, }; enum { MLX5_ESW_IPSEC_TX_POL_FT_LEVEL, MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL, MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL, }; void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx_create_attr *attr) { attr->prio = FDB_CRYPTO_INGRESS; attr->pol_level = MLX5_ESW_IPSEC_RX_POL_FT_LEVEL; attr->sa_level = MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL; attr->status_level = MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL; attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB; } int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec, struct mlx5_flow_destination *dest) { dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; dest->ft = mlx5_chains_get_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0); return 0; } int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry, struct mlx5_flow_act *flow_act) { u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {}; struct mlx5e_ipsec *ipsec = sa_entry->ipsec; struct mlx5_core_dev *mdev = ipsec->mdev; struct mlx5_modify_hdr *modify_hdr; u32 mapped_id; int err; err = xa_alloc_bh(&ipsec->ipsec_obj_id_map, &mapped_id, xa_mk_value(sa_entry->ipsec_obj_id), XA_LIMIT(1, ESW_IPSEC_RX_MAPPED_ID_MASK), 0); if (err) return err; /* reuse tunnel bits for ipsec, * tun_id is always 0 and tun_opts is mapped to ipsec_obj_id. */ MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET); MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_C_1); MLX5_SET(set_action_in, action, offset, ESW_ZONE_ID_BITS); MLX5_SET(set_action_in, action, length, ESW_TUN_ID_BITS + ESW_TUN_OPTS_BITS); MLX5_SET(set_action_in, action, data, mapped_id); modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_FDB, 1, action); if (IS_ERR(modify_hdr)) { err = PTR_ERR(modify_hdr); goto err_header_alloc; } sa_entry->rx_mapped_id = mapped_id; flow_act->modify_hdr = modify_hdr; flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; return 0; err_header_alloc: xa_erase_bh(&ipsec->ipsec_obj_id_map, mapped_id); return err; } void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry) { struct mlx5e_ipsec *ipsec = sa_entry->ipsec; if (sa_entry->rx_mapped_id) xa_erase_bh(&ipsec->ipsec_obj_id_map, sa_entry->rx_mapped_id); } int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id, u32 *ipsec_obj_id) { struct mlx5e_ipsec *ipsec = priv->ipsec; void *val; val = xa_load(&ipsec->ipsec_obj_id_map, id); if (!val) return -ENOENT; *ipsec_obj_id = xa_to_value(val); return 0; } void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx_create_attr *attr) { attr->prio = FDB_CRYPTO_EGRESS; attr->pol_level = MLX5_ESW_IPSEC_TX_POL_FT_LEVEL; attr->sa_level = MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL; attr->cnt_level = MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL; attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB; } #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw, struct mlx5e_tc_flow *flow) { struct mlx5_esw_flow_attr *esw_attr; struct mlx5_flow_attr *attr; int err; attr = flow->attr; esw_attr = attr->esw_attr; if (esw_attr->out_count - esw_attr->split_count > 1) return 0; err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr, esw_attr->out_count - 1); return err; } #endif void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev) { #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) struct mlx5_eswitch *esw = mdev->priv.eswitch; struct mlx5_eswitch_rep *rep; struct mlx5e_rep_priv *rpriv; struct rhashtable_iter iter; struct mlx5e_tc_flow *flow; unsigned long i; int err; xa_for_each(&esw->offloads.vport_reps, i, rep) { rpriv = rep->rep_data[REP_ETH].priv; if (!rpriv || !rpriv->netdev) continue; rhashtable_walk_enter(&rpriv->tc_ht, &iter); rhashtable_walk_start(&iter); while ((flow = rhashtable_walk_next(&iter)) != NULL) { if (IS_ERR(flow)) continue; err = mlx5_esw_ipsec_modify_flow_dests(esw, flow); if (err) mlx5_core_warn_once(mdev, "Failed to modify flow dests for IPsec"); } rhashtable_walk_stop(&iter); rhashtable_walk_exit(&iter); } #endif }