1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */ 3 4 #include "mlx5_core.h" 5 #include "ipsec.h" 6 #include "lib/mlx5.h" 7 8 u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev) 9 { 10 u32 caps = 0; 11 12 if (!MLX5_CAP_GEN(mdev, ipsec_offload)) 13 return 0; 14 15 if (!MLX5_CAP_GEN(mdev, log_max_dek)) 16 return 0; 17 18 if (!(MLX5_CAP_GEN_64(mdev, general_obj_types) & 19 MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC)) 20 return 0; 21 22 if (!MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ipsec_encrypt) || 23 !MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ipsec_decrypt)) 24 return 0; 25 26 if (!MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_encrypt) || 27 !MLX5_CAP_IPSEC(mdev, ipsec_crypto_esp_aes_gcm_128_decrypt)) 28 return 0; 29 30 if (MLX5_CAP_IPSEC(mdev, ipsec_crypto_offload) && 31 MLX5_CAP_ETH(mdev, insert_trailer) && MLX5_CAP_ETH(mdev, swp)) 32 caps |= MLX5_IPSEC_CAP_CRYPTO; 33 34 if (!caps) 35 return 0; 36 37 if (MLX5_CAP_IPSEC(mdev, ipsec_esn)) 38 caps |= MLX5_IPSEC_CAP_ESN; 39 40 /* We can accommodate up to 2^24 different IPsec objects 41 * because we use up to 24 bit in flow table metadata 42 * to hold the IPsec Object unique handle. 43 */ 44 WARN_ON_ONCE(MLX5_CAP_IPSEC(mdev, log_max_ipsec_offload) > 24); 45 return caps; 46 } 47 EXPORT_SYMBOL_GPL(mlx5_ipsec_device_caps); 48 49 static int mlx5_create_ipsec_obj(struct mlx5e_ipsec_sa_entry *sa_entry) 50 { 51 struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs; 52 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 53 struct aes_gcm_keymat *aes_gcm = &attrs->aes_gcm; 54 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; 55 u32 in[MLX5_ST_SZ_DW(create_ipsec_obj_in)] = {}; 56 void *obj, *salt_p, *salt_iv_p; 57 int err; 58 59 obj = MLX5_ADDR_OF(create_ipsec_obj_in, in, ipsec_object); 60 61 /* salt and seq_iv */ 62 salt_p = MLX5_ADDR_OF(ipsec_obj, obj, salt); 63 memcpy(salt_p, &aes_gcm->salt, sizeof(aes_gcm->salt)); 64 65 MLX5_SET(ipsec_obj, obj, icv_length, MLX5_IPSEC_OBJECT_ICV_LEN_16B); 66 salt_iv_p = MLX5_ADDR_OF(ipsec_obj, obj, implicit_iv); 67 memcpy(salt_iv_p, &aes_gcm->seq_iv, sizeof(aes_gcm->seq_iv)); 68 /* esn */ 69 if (attrs->flags & MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED) { 70 MLX5_SET(ipsec_obj, obj, esn_en, 1); 71 MLX5_SET(ipsec_obj, obj, esn_msb, attrs->esn); 72 if (attrs->flags & MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP) 73 MLX5_SET(ipsec_obj, obj, esn_overlap, 1); 74 } 75 76 MLX5_SET(ipsec_obj, obj, dekn, sa_entry->enc_key_id); 77 78 /* general object fields set */ 79 MLX5_SET(general_obj_in_cmd_hdr, in, opcode, 80 MLX5_CMD_OP_CREATE_GENERAL_OBJECT); 81 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, 82 MLX5_GENERAL_OBJECT_TYPES_IPSEC); 83 84 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 85 if (!err) 86 sa_entry->ipsec_obj_id = 87 MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); 88 89 return err; 90 } 91 92 static void mlx5_destroy_ipsec_obj(struct mlx5e_ipsec_sa_entry *sa_entry) 93 { 94 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 95 u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; 96 u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; 97 98 MLX5_SET(general_obj_in_cmd_hdr, in, opcode, 99 MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); 100 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, 101 MLX5_GENERAL_OBJECT_TYPES_IPSEC); 102 MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sa_entry->ipsec_obj_id); 103 104 mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 105 } 106 107 int mlx5_ipsec_create_sa_ctx(struct mlx5e_ipsec_sa_entry *sa_entry) 108 { 109 struct aes_gcm_keymat *aes_gcm = &sa_entry->attrs.aes_gcm; 110 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 111 int err; 112 113 /* key */ 114 err = mlx5_create_encryption_key(mdev, aes_gcm->aes_key, 115 aes_gcm->key_len / BITS_PER_BYTE, 116 MLX5_ACCEL_OBJ_IPSEC_KEY, 117 &sa_entry->enc_key_id); 118 if (err) { 119 mlx5_core_dbg(mdev, "Failed to create encryption key (err = %d)\n", err); 120 return err; 121 } 122 123 err = mlx5_create_ipsec_obj(sa_entry); 124 if (err) { 125 mlx5_core_dbg(mdev, "Failed to create IPsec object (err = %d)\n", err); 126 goto err_enc_key; 127 } 128 129 return 0; 130 131 err_enc_key: 132 mlx5_destroy_encryption_key(mdev, sa_entry->enc_key_id); 133 return err; 134 } 135 136 void mlx5_ipsec_free_sa_ctx(struct mlx5e_ipsec_sa_entry *sa_entry) 137 { 138 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 139 140 mlx5_destroy_ipsec_obj(sa_entry); 141 mlx5_destroy_encryption_key(mdev, sa_entry->enc_key_id); 142 } 143 144 static int mlx5_modify_ipsec_obj(struct mlx5e_ipsec_sa_entry *sa_entry, 145 const struct mlx5_accel_esp_xfrm_attrs *attrs) 146 { 147 struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry); 148 u32 in[MLX5_ST_SZ_DW(modify_ipsec_obj_in)] = {}; 149 u32 out[MLX5_ST_SZ_DW(query_ipsec_obj_out)]; 150 u64 modify_field_select = 0; 151 u64 general_obj_types; 152 void *obj; 153 int err; 154 155 if (!(attrs->flags & MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED)) 156 return 0; 157 158 general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types); 159 if (!(general_obj_types & MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC)) 160 return -EINVAL; 161 162 /* general object fields set */ 163 MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_QUERY_GENERAL_OBJECT); 164 MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_GENERAL_OBJECT_TYPES_IPSEC); 165 MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sa_entry->ipsec_obj_id); 166 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 167 if (err) { 168 mlx5_core_err(mdev, "Query IPsec object failed (Object id %d), err = %d\n", 169 sa_entry->ipsec_obj_id, err); 170 return err; 171 } 172 173 obj = MLX5_ADDR_OF(query_ipsec_obj_out, out, ipsec_object); 174 modify_field_select = MLX5_GET64(ipsec_obj, obj, modify_field_select); 175 176 /* esn */ 177 if (!(modify_field_select & MLX5_MODIFY_IPSEC_BITMASK_ESN_OVERLAP) || 178 !(modify_field_select & MLX5_MODIFY_IPSEC_BITMASK_ESN_MSB)) 179 return -EOPNOTSUPP; 180 181 obj = MLX5_ADDR_OF(modify_ipsec_obj_in, in, ipsec_object); 182 MLX5_SET64(ipsec_obj, obj, modify_field_select, 183 MLX5_MODIFY_IPSEC_BITMASK_ESN_OVERLAP | 184 MLX5_MODIFY_IPSEC_BITMASK_ESN_MSB); 185 MLX5_SET(ipsec_obj, obj, esn_msb, attrs->esn); 186 if (attrs->flags & MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP) 187 MLX5_SET(ipsec_obj, obj, esn_overlap, 1); 188 189 /* general object fields set */ 190 MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); 191 192 return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); 193 } 194 195 void mlx5_accel_esp_modify_xfrm(struct mlx5e_ipsec_sa_entry *sa_entry, 196 const struct mlx5_accel_esp_xfrm_attrs *attrs) 197 { 198 int err; 199 200 err = mlx5_modify_ipsec_obj(sa_entry, attrs); 201 if (err) 202 return; 203 204 memcpy(&sa_entry->attrs, attrs, sizeof(sa_entry->attrs)); 205 } 206