linux/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 *
  32 */
  33
  34#include <linux/rhashtable.h>
  35#include <linux/mlx5/driver.h>
  36#include <linux/mlx5/fs_helpers.h>
  37#include <linux/mlx5/fs.h>
  38#include <linux/rbtree.h>
  39
  40#include "mlx5_core.h"
  41#include "fs_cmd.h"
  42#include "fpga/ipsec.h"
  43#include "fpga/sdk.h"
  44#include "fpga/core.h"
  45
  46enum mlx5_fpga_ipsec_cmd_status {
  47        MLX5_FPGA_IPSEC_CMD_PENDING,
  48        MLX5_FPGA_IPSEC_CMD_SEND_FAIL,
  49        MLX5_FPGA_IPSEC_CMD_COMPLETE,
  50};
  51
  52struct mlx5_fpga_ipsec_cmd_context {
  53        struct mlx5_fpga_dma_buf buf;
  54        enum mlx5_fpga_ipsec_cmd_status status;
  55        struct mlx5_ifc_fpga_ipsec_cmd_resp resp;
  56        int status_code;
  57        struct completion complete;
  58        struct mlx5_fpga_device *dev;
  59        struct list_head list; /* Item in pending_cmds */
  60        u8 command[0];
  61};
  62
  63struct mlx5_fpga_esp_xfrm;
  64
  65struct mlx5_fpga_ipsec_sa_ctx {
  66        struct rhash_head               hash;
  67        struct mlx5_ifc_fpga_ipsec_sa   hw_sa;
  68        struct mlx5_core_dev            *dev;
  69        struct mlx5_fpga_esp_xfrm       *fpga_xfrm;
  70};
  71
  72struct mlx5_fpga_esp_xfrm {
  73        unsigned int                    num_rules;
  74        struct mlx5_fpga_ipsec_sa_ctx   *sa_ctx;
  75        struct mutex                    lock; /* xfrm lock */
  76        struct mlx5_accel_esp_xfrm      accel_xfrm;
  77};
  78
  79struct mlx5_fpga_ipsec_rule {
  80        struct rb_node                  node;
  81        struct fs_fte                   *fte;
  82        struct mlx5_fpga_ipsec_sa_ctx   *ctx;
  83};
  84
  85static const struct rhashtable_params rhash_sa = {
  86        /* Keep out "cmd" field from the key as it's
  87         * value is not constant during the lifetime
  88         * of the key object.
  89         */
  90        .key_len = FIELD_SIZEOF(struct mlx5_fpga_ipsec_sa_ctx, hw_sa) -
  91                   FIELD_SIZEOF(struct mlx5_ifc_fpga_ipsec_sa_v1, cmd),
  92        .key_offset = offsetof(struct mlx5_fpga_ipsec_sa_ctx, hw_sa) +
  93                      FIELD_SIZEOF(struct mlx5_ifc_fpga_ipsec_sa_v1, cmd),
  94        .head_offset = offsetof(struct mlx5_fpga_ipsec_sa_ctx, hash),
  95        .automatic_shrinking = true,
  96        .min_size = 1,
  97};
  98
  99struct mlx5_fpga_ipsec {
 100        struct mlx5_fpga_device *fdev;
 101        struct list_head pending_cmds;
 102        spinlock_t pending_cmds_lock; /* Protects pending_cmds */
 103        u32 caps[MLX5_ST_SZ_DW(ipsec_extended_cap)];
 104        struct mlx5_fpga_conn *conn;
 105
 106        struct notifier_block   fs_notifier_ingress_bypass;
 107        struct notifier_block   fs_notifier_egress;
 108
 109        /* Map hardware SA           -->  SA context
 110         *     (mlx5_fpga_ipsec_sa)       (mlx5_fpga_ipsec_sa_ctx)
 111         * We will use this hash to avoid SAs duplication in fpga which
 112         * aren't allowed
 113         */
 114        struct rhashtable sa_hash;      /* hw_sa -> mlx5_fpga_ipsec_sa_ctx */
 115        struct mutex sa_hash_lock;
 116
 117        /* Tree holding all rules for this fpga device
 118         * Key for searching a rule (mlx5_fpga_ipsec_rule) is (ft, id)
 119         */
 120        struct rb_root rules_rb;
 121        struct mutex rules_rb_lock; /* rules lock */
 122};
 123
 124static bool mlx5_fpga_is_ipsec_device(struct mlx5_core_dev *mdev)
 125{
 126        if (!mdev->fpga || !MLX5_CAP_GEN(mdev, fpga))
 127                return false;
 128
 129        if (MLX5_CAP_FPGA(mdev, ieee_vendor_id) !=
 130            MLX5_FPGA_CAP_SANDBOX_VENDOR_ID_MLNX)
 131                return false;
 132
 133        if (MLX5_CAP_FPGA(mdev, sandbox_product_id) !=
 134            MLX5_FPGA_CAP_SANDBOX_PRODUCT_ID_IPSEC)
 135                return false;
 136
 137        return true;
 138}
 139
 140static void mlx5_fpga_ipsec_send_complete(struct mlx5_fpga_conn *conn,
 141                                          struct mlx5_fpga_device *fdev,
 142                                          struct mlx5_fpga_dma_buf *buf,
 143                                          u8 status)
 144{
 145        struct mlx5_fpga_ipsec_cmd_context *context;
 146
 147        if (status) {
 148                context = container_of(buf, struct mlx5_fpga_ipsec_cmd_context,
 149                                       buf);
 150                mlx5_fpga_warn(fdev, "IPSec command send failed with status %u\n",
 151                               status);
 152                context->status = MLX5_FPGA_IPSEC_CMD_SEND_FAIL;
 153                complete(&context->complete);
 154        }
 155}
 156
 157static inline
 158int syndrome_to_errno(enum mlx5_ifc_fpga_ipsec_response_syndrome syndrome)
 159{
 160        switch (syndrome) {
 161        case MLX5_FPGA_IPSEC_RESPONSE_SUCCESS:
 162                return 0;
 163        case MLX5_FPGA_IPSEC_RESPONSE_SADB_ISSUE:
 164                return -EEXIST;
 165        case MLX5_FPGA_IPSEC_RESPONSE_ILLEGAL_REQUEST:
 166                return -EINVAL;
 167        case MLX5_FPGA_IPSEC_RESPONSE_WRITE_RESPONSE_ISSUE:
 168                return -EIO;
 169        }
 170        return -EIO;
 171}
 172
 173static void mlx5_fpga_ipsec_recv(void *cb_arg, struct mlx5_fpga_dma_buf *buf)
 174{
 175        struct mlx5_ifc_fpga_ipsec_cmd_resp *resp = buf->sg[0].data;
 176        struct mlx5_fpga_ipsec_cmd_context *context;
 177        enum mlx5_ifc_fpga_ipsec_response_syndrome syndrome;
 178        struct mlx5_fpga_device *fdev = cb_arg;
 179        unsigned long flags;
 180
 181        if (buf->sg[0].size < sizeof(*resp)) {
 182                mlx5_fpga_warn(fdev, "Short receive from FPGA IPSec: %u < %zu bytes\n",
 183                               buf->sg[0].size, sizeof(*resp));
 184                return;
 185        }
 186
 187        mlx5_fpga_dbg(fdev, "mlx5_ipsec recv_cb syndrome %08x\n",
 188                      ntohl(resp->syndrome));
 189
 190        spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags);
 191        context = list_first_entry_or_null(&fdev->ipsec->pending_cmds,
 192                                           struct mlx5_fpga_ipsec_cmd_context,
 193                                           list);
 194        if (context)
 195                list_del(&context->list);
 196        spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags);
 197
 198        if (!context) {
 199                mlx5_fpga_warn(fdev, "Received IPSec offload response without pending command request\n");
 200                return;
 201        }
 202        mlx5_fpga_dbg(fdev, "Handling response for %p\n", context);
 203
 204        syndrome = ntohl(resp->syndrome);
 205        context->status_code = syndrome_to_errno(syndrome);
 206        context->status = MLX5_FPGA_IPSEC_CMD_COMPLETE;
 207        memcpy(&context->resp, resp, sizeof(*resp));
 208
 209        if (context->status_code)
 210                mlx5_fpga_warn(fdev, "IPSec command failed with syndrome %08x\n",
 211                               syndrome);
 212
 213        complete(&context->complete);
 214}
 215
 216static void *mlx5_fpga_ipsec_cmd_exec(struct mlx5_core_dev *mdev,
 217                                      const void *cmd, int cmd_size)
 218{
 219        struct mlx5_fpga_ipsec_cmd_context *context;
 220        struct mlx5_fpga_device *fdev = mdev->fpga;
 221        unsigned long flags;
 222        int res;
 223
 224        if (!fdev || !fdev->ipsec)
 225                return ERR_PTR(-EOPNOTSUPP);
 226
 227        if (cmd_size & 3)
 228                return ERR_PTR(-EINVAL);
 229
 230        context = kzalloc(sizeof(*context) + cmd_size, GFP_ATOMIC);
 231        if (!context)
 232                return ERR_PTR(-ENOMEM);
 233
 234        context->status = MLX5_FPGA_IPSEC_CMD_PENDING;
 235        context->dev = fdev;
 236        context->buf.complete = mlx5_fpga_ipsec_send_complete;
 237        init_completion(&context->complete);
 238        memcpy(&context->command, cmd, cmd_size);
 239        context->buf.sg[0].size = cmd_size;
 240        context->buf.sg[0].data = &context->command;
 241
 242        spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags);
 243        res = mlx5_fpga_sbu_conn_sendmsg(fdev->ipsec->conn, &context->buf);
 244        if (!res)
 245                list_add_tail(&context->list, &fdev->ipsec->pending_cmds);
 246        spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags);
 247
 248        if (res) {
 249                mlx5_fpga_warn(fdev, "Failed to send IPSec command: %d\n", res);
 250                kfree(context);
 251                return ERR_PTR(res);
 252        }
 253
 254        /* Context should be freed by the caller after completion. */
 255        return context;
 256}
 257
 258static int mlx5_fpga_ipsec_cmd_wait(void *ctx)
 259{
 260        struct mlx5_fpga_ipsec_cmd_context *context = ctx;
 261        unsigned long timeout =
 262                msecs_to_jiffies(MLX5_FPGA_CMD_TIMEOUT_MSEC);
 263        int res;
 264
 265        res = wait_for_completion_timeout(&context->complete, timeout);
 266        if (!res) {
 267                mlx5_fpga_warn(context->dev, "Failure waiting for IPSec command response\n");
 268                return -ETIMEDOUT;
 269        }
 270
 271        if (context->status == MLX5_FPGA_IPSEC_CMD_COMPLETE)
 272                res = context->status_code;
 273        else
 274                res = -EIO;
 275
 276        return res;
 277}
 278
 279static inline bool is_v2_sadb_supported(struct mlx5_fpga_ipsec *fipsec)
 280{
 281        if (MLX5_GET(ipsec_extended_cap, fipsec->caps, v2_command))
 282                return true;
 283        return false;
 284}
 285
 286static int mlx5_fpga_ipsec_update_hw_sa(struct mlx5_fpga_device *fdev,
 287                                        struct mlx5_ifc_fpga_ipsec_sa *hw_sa,
 288                                        int opcode)
 289{
 290        struct mlx5_core_dev *dev = fdev->mdev;
 291        struct mlx5_ifc_fpga_ipsec_sa *sa;
 292        struct mlx5_fpga_ipsec_cmd_context *cmd_context;
 293        size_t sa_cmd_size;
 294        int err;
 295
 296        hw_sa->ipsec_sa_v1.cmd = htonl(opcode);
 297        if (is_v2_sadb_supported(fdev->ipsec))
 298                sa_cmd_size = sizeof(*hw_sa);
 299        else
 300                sa_cmd_size = sizeof(hw_sa->ipsec_sa_v1);
 301
 302        cmd_context = (struct mlx5_fpga_ipsec_cmd_context *)
 303                        mlx5_fpga_ipsec_cmd_exec(dev, hw_sa, sa_cmd_size);
 304        if (IS_ERR(cmd_context))
 305                return PTR_ERR(cmd_context);
 306
 307        err = mlx5_fpga_ipsec_cmd_wait(cmd_context);
 308        if (err)
 309                goto out;
 310
 311        sa = (struct mlx5_ifc_fpga_ipsec_sa *)&cmd_context->command;
 312        if (sa->ipsec_sa_v1.sw_sa_handle != cmd_context->resp.sw_sa_handle) {
 313                mlx5_fpga_err(fdev, "mismatch SA handle. cmd 0x%08x vs resp 0x%08x\n",
 314                              ntohl(sa->ipsec_sa_v1.sw_sa_handle),
 315                              ntohl(cmd_context->resp.sw_sa_handle));
 316                err = -EIO;
 317        }
 318
 319out:
 320        kfree(cmd_context);
 321        return err;
 322}
 323
 324u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev)
 325{
 326        struct mlx5_fpga_device *fdev = mdev->fpga;
 327        u32 ret = 0;
 328
 329        if (mlx5_fpga_is_ipsec_device(mdev)) {
 330                ret |= MLX5_ACCEL_IPSEC_CAP_DEVICE;
 331                ret |= MLX5_ACCEL_IPSEC_CAP_REQUIRED_METADATA;
 332        } else {
 333                return ret;
 334        }
 335
 336        if (!fdev->ipsec)
 337                return ret;
 338
 339        if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, esp))
 340                ret |= MLX5_ACCEL_IPSEC_CAP_ESP;
 341
 342        if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, ipv6))
 343                ret |= MLX5_ACCEL_IPSEC_CAP_IPV6;
 344
 345        if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, lso))
 346                ret |= MLX5_ACCEL_IPSEC_CAP_LSO;
 347
 348        if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, rx_no_trailer))
 349                ret |= MLX5_ACCEL_IPSEC_CAP_RX_NO_TRAILER;
 350
 351        if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, esn)) {
 352                ret |= MLX5_ACCEL_IPSEC_CAP_ESN;
 353                ret |= MLX5_ACCEL_IPSEC_CAP_TX_IV_IS_ESN;
 354        }
 355
 356        return ret;
 357}
 358
 359unsigned int mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev)
 360{
 361        struct mlx5_fpga_device *fdev = mdev->fpga;
 362
 363        if (!fdev || !fdev->ipsec)
 364                return 0;
 365
 366        return MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps,
 367                        number_of_ipsec_counters);
 368}
 369
 370int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters,
 371                                  unsigned int counters_count)
 372{
 373        struct mlx5_fpga_device *fdev = mdev->fpga;
 374        unsigned int i;
 375        __be32 *data;
 376        u32 count;
 377        u64 addr;
 378        int ret;
 379
 380        if (!fdev || !fdev->ipsec)
 381                return 0;
 382
 383        addr = (u64)MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps,
 384                             ipsec_counters_addr_low) +
 385               ((u64)MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps,
 386                             ipsec_counters_addr_high) << 32);
 387
 388        count = mlx5_fpga_ipsec_counters_count(mdev);
 389
 390        data = kzalloc(array3_size(sizeof(*data), count, 2), GFP_KERNEL);
 391        if (!data) {
 392                ret = -ENOMEM;
 393                goto out;
 394        }
 395
 396        ret = mlx5_fpga_mem_read(fdev, count * sizeof(u64), addr, data,
 397                                 MLX5_FPGA_ACCESS_TYPE_DONTCARE);
 398        if (ret < 0) {
 399                mlx5_fpga_err(fdev, "Failed to read IPSec counters from HW: %d\n",
 400                              ret);
 401                goto out;
 402        }
 403        ret = 0;
 404
 405        if (count > counters_count)
 406                count = counters_count;
 407
 408        /* Each counter is low word, then high. But each word is big-endian */
 409        for (i = 0; i < count; i++)
 410                counters[i] = (u64)ntohl(data[i * 2]) |
 411                              ((u64)ntohl(data[i * 2 + 1]) << 32);
 412
 413out:
 414        kfree(data);
 415        return ret;
 416}
 417
 418static int mlx5_fpga_ipsec_set_caps(struct mlx5_core_dev *mdev, u32 flags)
 419{
 420        struct mlx5_fpga_ipsec_cmd_context *context;
 421        struct mlx5_ifc_fpga_ipsec_cmd_cap cmd = {0};
 422        int err;
 423
 424        cmd.cmd = htonl(MLX5_FPGA_IPSEC_CMD_OP_SET_CAP);
 425        cmd.flags = htonl(flags);
 426        context = mlx5_fpga_ipsec_cmd_exec(mdev, &cmd, sizeof(cmd));
 427        if (IS_ERR(context))
 428                return PTR_ERR(context);
 429
 430        err = mlx5_fpga_ipsec_cmd_wait(context);
 431        if (err)
 432                goto out;
 433
 434        if ((context->resp.flags & cmd.flags) != cmd.flags) {
 435                mlx5_fpga_err(context->dev, "Failed to set capabilities. cmd 0x%08x vs resp 0x%08x\n",
 436                              cmd.flags,
 437                              context->resp.flags);
 438                err = -EIO;
 439        }
 440
 441out:
 442        kfree(context);
 443        return err;
 444}
 445
 446static int mlx5_fpga_ipsec_enable_supported_caps(struct mlx5_core_dev *mdev)
 447{
 448        u32 dev_caps = mlx5_fpga_ipsec_device_caps(mdev);
 449        u32 flags = 0;
 450
 451        if (dev_caps & MLX5_ACCEL_IPSEC_CAP_RX_NO_TRAILER)
 452                flags |= MLX5_FPGA_IPSEC_CAP_NO_TRAILER;
 453
 454        return mlx5_fpga_ipsec_set_caps(mdev, flags);
 455}
 456
 457static void
 458mlx5_fpga_ipsec_build_hw_xfrm(struct mlx5_core_dev *mdev,
 459                              const struct mlx5_accel_esp_xfrm_attrs *xfrm_attrs,
 460                              struct mlx5_ifc_fpga_ipsec_sa *hw_sa)
 461{
 462        const struct aes_gcm_keymat *aes_gcm = &xfrm_attrs->keymat.aes_gcm;
 463
 464        /* key */
 465        memcpy(&hw_sa->ipsec_sa_v1.key_enc, aes_gcm->aes_key,
 466               aes_gcm->key_len / 8);
 467        /* Duplicate 128 bit key twice according to HW layout */
 468        if (aes_gcm->key_len == 128)
 469                memcpy(&hw_sa->ipsec_sa_v1.key_enc[16],
 470                       aes_gcm->aes_key, aes_gcm->key_len / 8);
 471
 472        /* salt and seq_iv */
 473        memcpy(&hw_sa->ipsec_sa_v1.gcm.salt_iv, &aes_gcm->seq_iv,
 474               sizeof(aes_gcm->seq_iv));
 475        memcpy(&hw_sa->ipsec_sa_v1.gcm.salt, &aes_gcm->salt,
 476               sizeof(aes_gcm->salt));
 477
 478        /* esn */
 479        if (xfrm_attrs->flags & MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED) {
 480                hw_sa->ipsec_sa_v1.flags |= MLX5_FPGA_IPSEC_SA_ESN_EN;
 481                hw_sa->ipsec_sa_v1.flags |=
 482                                (xfrm_attrs->flags &
 483                                 MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP) ?
 484                                        MLX5_FPGA_IPSEC_SA_ESN_OVERLAP : 0;
 485                hw_sa->esn = htonl(xfrm_attrs->esn);
 486        } else {
 487                hw_sa->ipsec_sa_v1.flags &= ~MLX5_FPGA_IPSEC_SA_ESN_EN;
 488                hw_sa->ipsec_sa_v1.flags &=
 489                                ~(xfrm_attrs->flags &
 490                                  MLX5_ACCEL_ESP_FLAGS_ESN_STATE_OVERLAP) ?
 491                                        MLX5_FPGA_IPSEC_SA_ESN_OVERLAP : 0;
 492                hw_sa->esn = 0;
 493        }
 494
 495        /* rx handle */
 496        hw_sa->ipsec_sa_v1.sw_sa_handle = htonl(xfrm_attrs->sa_handle);
 497
 498        /* enc mode */
 499        switch (aes_gcm->key_len) {
 500        case 128:
 501                hw_sa->ipsec_sa_v1.enc_mode =
 502                        MLX5_FPGA_IPSEC_SA_ENC_MODE_AES_GCM_128_AUTH_128;
 503                break;
 504        case 256:
 505                hw_sa->ipsec_sa_v1.enc_mode =
 506                        MLX5_FPGA_IPSEC_SA_ENC_MODE_AES_GCM_256_AUTH_128;
 507                break;
 508        }
 509
 510        /* flags */
 511        hw_sa->ipsec_sa_v1.flags |= MLX5_FPGA_IPSEC_SA_SA_VALID |
 512                        MLX5_FPGA_IPSEC_SA_SPI_EN |
 513                        MLX5_FPGA_IPSEC_SA_IP_ESP;
 514
 515        if (xfrm_attrs->action & MLX5_ACCEL_ESP_ACTION_ENCRYPT)
 516                hw_sa->ipsec_sa_v1.flags |= MLX5_FPGA_IPSEC_SA_DIR_SX;
 517        else
 518                hw_sa->ipsec_sa_v1.flags &= ~MLX5_FPGA_IPSEC_SA_DIR_SX;
 519}
 520
 521static void
 522mlx5_fpga_ipsec_build_hw_sa(struct mlx5_core_dev *mdev,
 523                            struct mlx5_accel_esp_xfrm_attrs *xfrm_attrs,
 524                            const __be32 saddr[4],
 525                            const __be32 daddr[4],
 526                            const __be32 spi, bool is_ipv6,
 527                            struct mlx5_ifc_fpga_ipsec_sa *hw_sa)
 528{
 529        mlx5_fpga_ipsec_build_hw_xfrm(mdev, xfrm_attrs, hw_sa);
 530
 531        /* IPs */
 532        memcpy(hw_sa->ipsec_sa_v1.sip, saddr, sizeof(hw_sa->ipsec_sa_v1.sip));
 533        memcpy(hw_sa->ipsec_sa_v1.dip, daddr, sizeof(hw_sa->ipsec_sa_v1.dip));
 534
 535        /* SPI */
 536        hw_sa->ipsec_sa_v1.spi = spi;
 537
 538        /* flags */
 539        if (is_ipv6)
 540                hw_sa->ipsec_sa_v1.flags |= MLX5_FPGA_IPSEC_SA_IPV6;
 541}
 542
 543static bool is_full_mask(const void *p, size_t len)
 544{
 545        WARN_ON(len % 4);
 546
 547        return !memchr_inv(p, 0xff, len);
 548}
 549
 550static bool validate_fpga_full_mask(struct mlx5_core_dev *dev,
 551                                    const u32 *match_c,
 552                                    const u32 *match_v)
 553{
 554        const void *misc_params_c = MLX5_ADDR_OF(fte_match_param,
 555                                                 match_c,
 556                                                 misc_parameters);
 557        const void *headers_c = MLX5_ADDR_OF(fte_match_param,
 558                                             match_c,
 559                                             outer_headers);
 560        const void *headers_v = MLX5_ADDR_OF(fte_match_param,
 561                                             match_v,
 562                                             outer_headers);
 563
 564        if (mlx5_fs_is_outer_ipv4_flow(dev, headers_c, headers_v)) {
 565                const void *s_ipv4_c = MLX5_ADDR_OF(fte_match_set_lyr_2_4,
 566                                                    headers_c,
 567                                                    src_ipv4_src_ipv6.ipv4_layout.ipv4);
 568                const void *d_ipv4_c = MLX5_ADDR_OF(fte_match_set_lyr_2_4,
 569                                                    headers_c,
 570                                                    dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
 571
 572                if (!is_full_mask(s_ipv4_c, MLX5_FLD_SZ_BYTES(ipv4_layout,
 573                                                              ipv4)) ||
 574                    !is_full_mask(d_ipv4_c, MLX5_FLD_SZ_BYTES(ipv4_layout,
 575                                                              ipv4)))
 576                        return false;
 577        } else {
 578                const void *s_ipv6_c = MLX5_ADDR_OF(fte_match_set_lyr_2_4,
 579                                                    headers_c,
 580                                                    src_ipv4_src_ipv6.ipv6_layout.ipv6);
 581                const void *d_ipv6_c = MLX5_ADDR_OF(fte_match_set_lyr_2_4,
 582                                                    headers_c,
 583                                                    dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
 584
 585                if (!is_full_mask(s_ipv6_c, MLX5_FLD_SZ_BYTES(ipv6_layout,
 586                                                              ipv6)) ||
 587                    !is_full_mask(d_ipv6_c, MLX5_FLD_SZ_BYTES(ipv6_layout,
 588                                                              ipv6)))
 589                        return false;
 590        }
 591
 592        if (!is_full_mask(MLX5_ADDR_OF(fte_match_set_misc, misc_params_c,
 593                                       outer_esp_spi),
 594                          MLX5_FLD_SZ_BYTES(fte_match_set_misc, outer_esp_spi)))
 595                return false;
 596
 597        return true;
 598}
 599
 600static bool mlx5_is_fpga_ipsec_rule(struct mlx5_core_dev *dev,
 601                                    u8 match_criteria_enable,
 602                                    const u32 *match_c,
 603                                    const u32 *match_v)
 604{
 605        u32 ipsec_dev_caps = mlx5_accel_ipsec_device_caps(dev);
 606        bool ipv6_flow;
 607
 608        ipv6_flow = mlx5_fs_is_outer_ipv6_flow(dev, match_c, match_v);
 609
 610        if (!(match_criteria_enable & MLX5_MATCH_OUTER_HEADERS) ||
 611            mlx5_fs_is_outer_udp_flow(match_c, match_v) ||
 612            mlx5_fs_is_outer_tcp_flow(match_c, match_v) ||
 613            mlx5_fs_is_vxlan_flow(match_c) ||
 614            !(mlx5_fs_is_outer_ipv4_flow(dev, match_c, match_v) ||
 615              ipv6_flow))
 616                return false;
 617
 618        if (!(ipsec_dev_caps & MLX5_ACCEL_IPSEC_CAP_DEVICE))
 619                return false;
 620
 621        if (!(ipsec_dev_caps & MLX5_ACCEL_IPSEC_CAP_ESP) &&
 622            mlx5_fs_is_outer_ipsec_flow(match_c))
 623                return false;
 624
 625        if (!(ipsec_dev_caps & MLX5_ACCEL_IPSEC_CAP_IPV6) &&
 626            ipv6_flow)
 627                return false;
 628
 629        if (!validate_fpga_full_mask(dev, match_c, match_v))
 630                return false;
 631
 632        return true;
 633}
 634
 635static bool mlx5_is_fpga_egress_ipsec_rule(struct mlx5_core_dev *dev,
 636                                           u8 match_criteria_enable,
 637                                           const u32 *match_c,
 638                                           const u32 *match_v,
 639                                           struct mlx5_flow_act *flow_act,
 640                                           struct mlx5_flow_context *flow_context)
 641{
 642        const void *outer_c = MLX5_ADDR_OF(fte_match_param, match_c,
 643                                           outer_headers);
 644        bool is_dmac = MLX5_GET(fte_match_set_lyr_2_4, outer_c, dmac_47_16) ||
 645                        MLX5_GET(fte_match_set_lyr_2_4, outer_c, dmac_15_0);
 646        bool is_smac = MLX5_GET(fte_match_set_lyr_2_4, outer_c, smac_47_16) ||
 647                        MLX5_GET(fte_match_set_lyr_2_4, outer_c, smac_15_0);
 648        int ret;
 649
 650        ret = mlx5_is_fpga_ipsec_rule(dev, match_criteria_enable, match_c,
 651                                      match_v);
 652        if (!ret)
 653                return ret;
 654
 655        if (is_dmac || is_smac ||
 656            (match_criteria_enable &
 657             ~(MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS)) ||
 658            (flow_act->action & ~(MLX5_FLOW_CONTEXT_ACTION_ENCRYPT | MLX5_FLOW_CONTEXT_ACTION_ALLOW)) ||
 659             (flow_context->flags & FLOW_CONTEXT_HAS_TAG))
 660                return false;
 661
 662        return true;
 663}
 664
 665void *mlx5_fpga_ipsec_create_sa_ctx(struct mlx5_core_dev *mdev,
 666                                    struct mlx5_accel_esp_xfrm *accel_xfrm,
 667                                    const __be32 saddr[4],
 668                                    const __be32 daddr[4],
 669                                    const __be32 spi, bool is_ipv6)
 670{
 671        struct mlx5_fpga_ipsec_sa_ctx *sa_ctx;
 672        struct mlx5_fpga_esp_xfrm *fpga_xfrm =
 673                        container_of(accel_xfrm, typeof(*fpga_xfrm),
 674                                     accel_xfrm);
 675        struct mlx5_fpga_device *fdev = mdev->fpga;
 676        struct mlx5_fpga_ipsec *fipsec = fdev->ipsec;
 677        int opcode, err;
 678        void *context;
 679
 680        /* alloc SA */
 681        sa_ctx = kzalloc(sizeof(*sa_ctx), GFP_KERNEL);
 682        if (!sa_ctx)
 683                return ERR_PTR(-ENOMEM);
 684
 685        sa_ctx->dev = mdev;
 686
 687        /* build candidate SA */
 688        mlx5_fpga_ipsec_build_hw_sa(mdev, &accel_xfrm->attrs,
 689                                    saddr, daddr, spi, is_ipv6,
 690                                    &sa_ctx->hw_sa);
 691
 692        mutex_lock(&fpga_xfrm->lock);
 693
 694        if (fpga_xfrm->sa_ctx) {        /* multiple rules for same accel_xfrm */
 695                /* all rules must be with same IPs and SPI */
 696                if (memcmp(&sa_ctx->hw_sa, &fpga_xfrm->sa_ctx->hw_sa,
 697                           sizeof(sa_ctx->hw_sa))) {
 698                        context = ERR_PTR(-EINVAL);
 699                        goto exists;
 700                }
 701
 702                ++fpga_xfrm->num_rules;
 703                context = fpga_xfrm->sa_ctx;
 704                goto exists;
 705        }
 706
 707        /* This is unbounded fpga_xfrm, try to add to hash */
 708        mutex_lock(&fipsec->sa_hash_lock);
 709
 710        err = rhashtable_lookup_insert_fast(&fipsec->sa_hash, &sa_ctx->hash,
 711                                            rhash_sa);
 712        if (err) {
 713                /* Can't bound different accel_xfrm to already existing sa_ctx.
 714                 * This is because we can't support multiple ketmats for
 715                 * same IPs and SPI
 716                 */
 717                context = ERR_PTR(-EEXIST);
 718                goto unlock_hash;
 719        }
 720
 721        /* Bound accel_xfrm to sa_ctx */
 722        opcode = is_v2_sadb_supported(fdev->ipsec) ?
 723                        MLX5_FPGA_IPSEC_CMD_OP_ADD_SA_V2 :
 724                        MLX5_FPGA_IPSEC_CMD_OP_ADD_SA;
 725        err = mlx5_fpga_ipsec_update_hw_sa(fdev, &sa_ctx->hw_sa, opcode);
 726        sa_ctx->hw_sa.ipsec_sa_v1.cmd = 0;
 727        if (err) {
 728                context = ERR_PTR(err);
 729                goto delete_hash;
 730        }
 731
 732        mutex_unlock(&fipsec->sa_hash_lock);
 733
 734        ++fpga_xfrm->num_rules;
 735        fpga_xfrm->sa_ctx = sa_ctx;
 736        sa_ctx->fpga_xfrm = fpga_xfrm;
 737
 738        mutex_unlock(&fpga_xfrm->lock);
 739
 740        return sa_ctx;
 741
 742delete_hash:
 743        WARN_ON(rhashtable_remove_fast(&fipsec->sa_hash, &sa_ctx->hash,
 744                                       rhash_sa));
 745unlock_hash:
 746        mutex_unlock(&fipsec->sa_hash_lock);
 747
 748exists:
 749        mutex_unlock(&fpga_xfrm->lock);
 750        kfree(sa_ctx);
 751        return context;
 752}
 753
 754static void *
 755mlx5_fpga_ipsec_fs_create_sa_ctx(struct mlx5_core_dev *mdev,
 756                                 struct fs_fte *fte,
 757                                 bool is_egress)
 758{
 759        struct mlx5_accel_esp_xfrm *accel_xfrm;
 760        __be32 saddr[4], daddr[4], spi;
 761        struct mlx5_flow_group *fg;
 762        bool is_ipv6 = false;
 763
 764        fs_get_obj(fg, fte->node.parent);
 765        /* validate */
 766        if (is_egress &&
 767            !mlx5_is_fpga_egress_ipsec_rule(mdev,
 768                                            fg->mask.match_criteria_enable,
 769                                            fg->mask.match_criteria,
 770                                            fte->val,
 771                                            &fte->action,
 772                                            &fte->flow_context))
 773                return ERR_PTR(-EINVAL);
 774        else if (!mlx5_is_fpga_ipsec_rule(mdev,
 775                                          fg->mask.match_criteria_enable,
 776                                          fg->mask.match_criteria,
 777                                          fte->val))
 778                return ERR_PTR(-EINVAL);
 779
 780        /* get xfrm context */
 781        accel_xfrm =
 782                (struct mlx5_accel_esp_xfrm *)fte->action.esp_id;
 783
 784        /* IPs */
 785        if (mlx5_fs_is_outer_ipv4_flow(mdev, fg->mask.match_criteria,
 786                                       fte->val)) {
 787                memcpy(&saddr[3],
 788                       MLX5_ADDR_OF(fte_match_set_lyr_2_4,
 789                                    fte->val,
 790                                    src_ipv4_src_ipv6.ipv4_layout.ipv4),
 791                                    sizeof(saddr[3]));
 792                memcpy(&daddr[3],
 793                       MLX5_ADDR_OF(fte_match_set_lyr_2_4,
 794                                    fte->val,
 795                                    dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
 796                                    sizeof(daddr[3]));
 797        } else {
 798                memcpy(saddr,
 799                       MLX5_ADDR_OF(fte_match_param,
 800                                    fte->val,
 801                                    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
 802                                    sizeof(saddr));
 803                memcpy(daddr,
 804                       MLX5_ADDR_OF(fte_match_param,
 805                                    fte->val,
 806                                    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
 807                                    sizeof(daddr));
 808                is_ipv6 = true;
 809        }
 810
 811        /* SPI */
 812        spi = MLX5_GET_BE(typeof(spi),
 813                          fte_match_param, fte->val,
 814                          misc_parameters.outer_esp_spi);
 815
 816        /* create */
 817        return mlx5_fpga_ipsec_create_sa_ctx(mdev, accel_xfrm,
 818                                             saddr, daddr,
 819                                             spi, is_ipv6);
 820}
 821
 822static void
 823mlx5_fpga_ipsec_release_sa_ctx(struct mlx5_fpga_ipsec_sa_ctx *sa_ctx)
 824{
 825        struct mlx5_fpga_device *fdev = sa_ctx->dev->fpga;
 826        struct mlx5_fpga_ipsec *fipsec = fdev->ipsec;
 827        int opcode = is_v2_sadb_supported(fdev->ipsec) ?
 828                        MLX5_FPGA_IPSEC_CMD_OP_DEL_SA_V2 :
 829                        MLX5_FPGA_IPSEC_CMD_OP_DEL_SA;
 830        int err;
 831
 832        err = mlx5_fpga_ipsec_update_hw_sa(fdev, &sa_ctx->hw_sa, opcode);
 833        sa_ctx->hw_sa.ipsec_sa_v1.cmd = 0;
 834        if (err) {
 835                WARN_ON(err);
 836                return;
 837        }
 838
 839        mutex_lock(&fipsec->sa_hash_lock);
 840        WARN_ON(rhashtable_remove_fast(&fipsec->sa_hash, &sa_ctx->hash,
 841                                       rhash_sa));
 842        mutex_unlock(&fipsec->sa_hash_lock);
 843}
 844
 845void mlx5_fpga_ipsec_delete_sa_ctx(void *context)
 846{
 847        struct mlx5_fpga_esp_xfrm *fpga_xfrm =
 848                        ((struct mlx5_fpga_ipsec_sa_ctx *)context)->fpga_xfrm;
 849
 850        mutex_lock(&fpga_xfrm->lock);
 851        if (!--fpga_xfrm->num_rules) {
 852                mlx5_fpga_ipsec_release_sa_ctx(fpga_xfrm->sa_ctx);
 853                fpga_xfrm->sa_ctx = NULL;
 854        }
 855        mutex_unlock(&fpga_xfrm->lock);
 856}
 857
 858static inline struct mlx5_fpga_ipsec_rule *
 859_rule_search(struct rb_root *root, struct fs_fte *fte)
 860{
 861        struct rb_node *node = root->rb_node;
 862
 863        while (node) {
 864                struct mlx5_fpga_ipsec_rule *rule =
 865                                container_of(node, struct mlx5_fpga_ipsec_rule,
 866                                             node);
 867
 868                if (rule->fte < fte)
 869                        node = node->rb_left;
 870                else if (rule->fte > fte)
 871                        node = node->rb_right;
 872                else
 873                        return rule;
 874        }
 875        return NULL;
 876}
 877
 878static struct mlx5_fpga_ipsec_rule *
 879rule_search(struct mlx5_fpga_ipsec *ipsec_dev, struct fs_fte *fte)
 880{
 881        struct mlx5_fpga_ipsec_rule *rule;
 882
 883        mutex_lock(&ipsec_dev->rules_rb_lock);
 884        rule = _rule_search(&ipsec_dev->rules_rb, fte);
 885        mutex_unlock(&ipsec_dev->rules_rb_lock);
 886
 887        return rule;
 888}
 889
 890static inline int _rule_insert(struct rb_root *root,
 891                               struct mlx5_fpga_ipsec_rule *rule)
 892{
 893        struct rb_node **new = &root->rb_node, *parent = NULL;
 894
 895        /* Figure out where to put new node */
 896        while (*new) {
 897                struct mlx5_fpga_ipsec_rule *this =
 898                                container_of(*new, struct mlx5_fpga_ipsec_rule,
 899                                             node);
 900
 901                parent = *new;
 902                if (rule->fte < this->fte)
 903                        new = &((*new)->rb_left);
 904                else if (rule->fte > this->fte)
 905                        new = &((*new)->rb_right);
 906                else
 907                        return -EEXIST;
 908        }
 909
 910        /* Add new node and rebalance tree. */
 911        rb_link_node(&rule->node, parent, new);
 912        rb_insert_color(&rule->node, root);
 913
 914        return 0;
 915}
 916
 917static int rule_insert(struct mlx5_fpga_ipsec *ipsec_dev,
 918                       struct mlx5_fpga_ipsec_rule *rule)
 919{
 920        int ret;
 921
 922        mutex_lock(&ipsec_dev->rules_rb_lock);
 923        ret = _rule_insert(&ipsec_dev->rules_rb, rule);
 924        mutex_unlock(&ipsec_dev->rules_rb_lock);
 925
 926        return ret;
 927}
 928
 929static inline void _rule_delete(struct mlx5_fpga_ipsec *ipsec_dev,
 930                                struct mlx5_fpga_ipsec_rule *rule)
 931{
 932        struct rb_root *root = &ipsec_dev->rules_rb;
 933
 934        mutex_lock(&ipsec_dev->rules_rb_lock);
 935        rb_erase(&rule->node, root);
 936        mutex_unlock(&ipsec_dev->rules_rb_lock);
 937}
 938
 939static void rule_delete(struct mlx5_fpga_ipsec *ipsec_dev,
 940                        struct mlx5_fpga_ipsec_rule *rule)
 941{
 942        _rule_delete(ipsec_dev, rule);
 943        kfree(rule);
 944}
 945
 946struct mailbox_mod {
 947        uintptr_t                       saved_esp_id;
 948        u32                             saved_action;
 949        u32                             saved_outer_esp_spi_value;
 950};
 951
 952static void restore_spec_mailbox(struct fs_fte *fte,
 953                                 struct mailbox_mod *mbox_mod)
 954{
 955        char *misc_params_v = MLX5_ADDR_OF(fte_match_param,
 956                                           fte->val,
 957                                           misc_parameters);
 958
 959        MLX5_SET(fte_match_set_misc, misc_params_v, outer_esp_spi,
 960                 mbox_mod->saved_outer_esp_spi_value);
 961        fte->action.action |= mbox_mod->saved_action;
 962        fte->action.esp_id = (uintptr_t)mbox_mod->saved_esp_id;
 963}
 964
 965static void modify_spec_mailbox(struct mlx5_core_dev *mdev,
 966                                struct fs_fte *fte,
 967                                struct mailbox_mod *mbox_mod)
 968{
 969        char *misc_params_v = MLX5_ADDR_OF(fte_match_param,
 970                                           fte->val,
 971                                           misc_parameters);
 972
 973        mbox_mod->saved_esp_id = fte->action.esp_id;
 974        mbox_mod->saved_action = fte->action.action &
 975                        (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
 976                         MLX5_FLOW_CONTEXT_ACTION_DECRYPT);
 977        mbox_mod->saved_outer_esp_spi_value =
 978                        MLX5_GET(fte_match_set_misc, misc_params_v,
 979                                 outer_esp_spi);
 980
 981        fte->action.esp_id = 0;
 982        fte->action.action &= ~(MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
 983                                MLX5_FLOW_CONTEXT_ACTION_DECRYPT);
 984        if (!MLX5_CAP_FLOWTABLE(mdev,
 985                                flow_table_properties_nic_receive.ft_field_support.outer_esp_spi))
 986                MLX5_SET(fte_match_set_misc, misc_params_v, outer_esp_spi, 0);
 987}
 988
 989static enum fs_flow_table_type egress_to_fs_ft(bool egress)
 990{
 991        return egress ? FS_FT_NIC_TX : FS_FT_NIC_RX;
 992}
 993
 994static int fpga_ipsec_fs_create_flow_group(struct mlx5_flow_root_namespace *ns,
 995                                           struct mlx5_flow_table *ft,
 996                                           u32 *in,
 997                                           struct mlx5_flow_group *fg,
 998                                           bool is_egress)
 999{
1000        int (*create_flow_group)(struct mlx5_flow_root_namespace *ns,
1001                                 struct mlx5_flow_table *ft, u32 *in,
1002                                 struct mlx5_flow_group *fg) =
1003                mlx5_fs_cmd_get_default(egress_to_fs_ft(is_egress))->create_flow_group;
1004        char *misc_params_c = MLX5_ADDR_OF(create_flow_group_in, in,
1005                                           match_criteria.misc_parameters);
1006        struct mlx5_core_dev *dev = ns->dev;
1007        u32 saved_outer_esp_spi_mask;
1008        u8 match_criteria_enable;
1009        int ret;
1010
1011        if (MLX5_CAP_FLOWTABLE(dev,
1012                               flow_table_properties_nic_receive.ft_field_support.outer_esp_spi))
1013                return create_flow_group(ns, ft, in, fg);
1014
1015        match_criteria_enable =
1016                MLX5_GET(create_flow_group_in, in, match_criteria_enable);
1017        saved_outer_esp_spi_mask =
1018                MLX5_GET(fte_match_set_misc, misc_params_c, outer_esp_spi);
1019        if (!match_criteria_enable || !saved_outer_esp_spi_mask)
1020                return create_flow_group(ns, ft, in, fg);
1021
1022        MLX5_SET(fte_match_set_misc, misc_params_c, outer_esp_spi, 0);
1023
1024        if (!(*misc_params_c) &&
1025            !memcmp(misc_params_c, misc_params_c + 1, MLX5_ST_SZ_BYTES(fte_match_set_misc) - 1))
1026                MLX5_SET(create_flow_group_in, in, match_criteria_enable,
1027                         match_criteria_enable & ~MLX5_MATCH_MISC_PARAMETERS);
1028
1029        ret = create_flow_group(ns, ft, in, fg);
1030
1031        MLX5_SET(fte_match_set_misc, misc_params_c, outer_esp_spi, saved_outer_esp_spi_mask);
1032        MLX5_SET(create_flow_group_in, in, match_criteria_enable, match_criteria_enable);
1033
1034        return ret;
1035}
1036
1037static int fpga_ipsec_fs_create_fte(struct mlx5_flow_root_namespace *ns,
1038                                    struct mlx5_flow_table *ft,
1039                                    struct mlx5_flow_group *fg,
1040                                    struct fs_fte *fte,
1041                                    bool is_egress)
1042{
1043        int (*create_fte)(struct mlx5_flow_root_namespace *ns,
1044                          struct mlx5_flow_table *ft,
1045                          struct mlx5_flow_group *fg,
1046                          struct fs_fte *fte) =
1047                mlx5_fs_cmd_get_default(egress_to_fs_ft(is_egress))->create_fte;
1048        struct mlx5_core_dev *dev = ns->dev;
1049        struct mlx5_fpga_device *fdev = dev->fpga;
1050        struct mlx5_fpga_ipsec *fipsec = fdev->ipsec;
1051        struct mlx5_fpga_ipsec_rule *rule;
1052        bool is_esp = fte->action.esp_id;
1053        struct mailbox_mod mbox_mod;
1054        int ret;
1055
1056        if (!is_esp ||
1057            !(fte->action.action &
1058              (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
1059               MLX5_FLOW_CONTEXT_ACTION_DECRYPT)))
1060                return create_fte(ns, ft, fg, fte);
1061
1062        rule = kzalloc(sizeof(*rule), GFP_KERNEL);
1063        if (!rule)
1064                return -ENOMEM;
1065
1066        rule->ctx = mlx5_fpga_ipsec_fs_create_sa_ctx(dev, fte, is_egress);
1067        if (IS_ERR(rule->ctx)) {
1068                int err = PTR_ERR(rule->ctx);
1069                kfree(rule);
1070                return err;
1071        }
1072
1073        rule->fte = fte;
1074        WARN_ON(rule_insert(fipsec, rule));
1075
1076        modify_spec_mailbox(dev, fte, &mbox_mod);
1077        ret = create_fte(ns, ft, fg, fte);
1078        restore_spec_mailbox(fte, &mbox_mod);
1079        if (ret) {
1080                _rule_delete(fipsec, rule);
1081                mlx5_fpga_ipsec_delete_sa_ctx(rule->ctx);
1082                kfree(rule);
1083        }
1084
1085        return ret;
1086}
1087
1088static int fpga_ipsec_fs_update_fte(struct mlx5_flow_root_namespace *ns,
1089                                    struct mlx5_flow_table *ft,
1090                                    struct mlx5_flow_group *fg,
1091                                    int modify_mask,
1092                                    struct fs_fte *fte,
1093                                    bool is_egress)
1094{
1095        int (*update_fte)(struct mlx5_flow_root_namespace *ns,
1096                          struct mlx5_flow_table *ft,
1097                          struct mlx5_flow_group *fg,
1098                          int modify_mask,
1099                          struct fs_fte *fte) =
1100                mlx5_fs_cmd_get_default(egress_to_fs_ft(is_egress))->update_fte;
1101        struct mlx5_core_dev *dev = ns->dev;
1102        bool is_esp = fte->action.esp_id;
1103        struct mailbox_mod mbox_mod;
1104        int ret;
1105
1106        if (!is_esp ||
1107            !(fte->action.action &
1108              (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
1109               MLX5_FLOW_CONTEXT_ACTION_DECRYPT)))
1110                return update_fte(ns, ft, fg, modify_mask, fte);
1111
1112        modify_spec_mailbox(dev, fte, &mbox_mod);
1113        ret = update_fte(ns, ft, fg, modify_mask, fte);
1114        restore_spec_mailbox(fte, &mbox_mod);
1115
1116        return ret;
1117}
1118
1119static int fpga_ipsec_fs_delete_fte(struct mlx5_flow_root_namespace *ns,
1120                                    struct mlx5_flow_table *ft,
1121                                    struct fs_fte *fte,
1122                                    bool is_egress)
1123{
1124        int (*delete_fte)(struct mlx5_flow_root_namespace *ns,
1125                          struct mlx5_flow_table *ft,
1126                          struct fs_fte *fte) =
1127                mlx5_fs_cmd_get_default(egress_to_fs_ft(is_egress))->delete_fte;
1128        struct mlx5_core_dev *dev = ns->dev;
1129        struct mlx5_fpga_device *fdev = dev->fpga;
1130        struct mlx5_fpga_ipsec *fipsec = fdev->ipsec;
1131        struct mlx5_fpga_ipsec_rule *rule;
1132        bool is_esp = fte->action.esp_id;
1133        struct mailbox_mod mbox_mod;
1134        int ret;
1135
1136        if (!is_esp ||
1137            !(fte->action.action &
1138              (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
1139               MLX5_FLOW_CONTEXT_ACTION_DECRYPT)))
1140                return delete_fte(ns, ft, fte);
1141
1142        rule = rule_search(fipsec, fte);
1143        if (!rule)
1144                return -ENOENT;
1145
1146        mlx5_fpga_ipsec_delete_sa_ctx(rule->ctx);
1147        rule_delete(fipsec, rule);
1148
1149        modify_spec_mailbox(dev, fte, &mbox_mod);
1150        ret = delete_fte(ns, ft, fte);
1151        restore_spec_mailbox(fte, &mbox_mod);
1152
1153        return ret;
1154}
1155
1156static int
1157mlx5_fpga_ipsec_fs_create_flow_group_egress(struct mlx5_flow_root_namespace *ns,
1158                                            struct mlx5_flow_table *ft,
1159                                            u32 *in,
1160                                            struct mlx5_flow_group *fg)
1161{
1162        return fpga_ipsec_fs_create_flow_group(ns, ft, in, fg, true);
1163}
1164
1165static int
1166mlx5_fpga_ipsec_fs_create_fte_egress(struct mlx5_flow_root_namespace *ns,
1167                                     struct mlx5_flow_table *ft,
1168                                     struct mlx5_flow_group *fg,
1169                                     struct fs_fte *fte)
1170{
1171        return fpga_ipsec_fs_create_fte(ns, ft, fg, fte, true);
1172}
1173
1174static int
1175mlx5_fpga_ipsec_fs_update_fte_egress(struct mlx5_flow_root_namespace *ns,
1176                                     struct mlx5_flow_table *ft,
1177                                     struct mlx5_flow_group *fg,
1178                                     int modify_mask,
1179                                     struct fs_fte *fte)
1180{
1181        return fpga_ipsec_fs_update_fte(ns, ft, fg, modify_mask, fte,
1182                                        true);
1183}
1184
1185static int
1186mlx5_fpga_ipsec_fs_delete_fte_egress(struct mlx5_flow_root_namespace *ns,
1187                                     struct mlx5_flow_table *ft,
1188                                     struct fs_fte *fte)
1189{
1190        return fpga_ipsec_fs_delete_fte(ns, ft, fte, true);
1191}
1192
1193static int
1194mlx5_fpga_ipsec_fs_create_flow_group_ingress(struct mlx5_flow_root_namespace *ns,
1195                                             struct mlx5_flow_table *ft,
1196                                             u32 *in,
1197                                             struct mlx5_flow_group *fg)
1198{
1199        return fpga_ipsec_fs_create_flow_group(ns, ft, in, fg, false);
1200}
1201
1202static int
1203mlx5_fpga_ipsec_fs_create_fte_ingress(struct mlx5_flow_root_namespace *ns,
1204                                      struct mlx5_flow_table *ft,
1205                                      struct mlx5_flow_group *fg,
1206                                      struct fs_fte *fte)
1207{
1208        return fpga_ipsec_fs_create_fte(ns, ft, fg, fte, false);
1209}
1210
1211static int
1212mlx5_fpga_ipsec_fs_update_fte_ingress(struct mlx5_flow_root_namespace *ns,
1213                                      struct mlx5_flow_table *ft,
1214                                      struct mlx5_flow_group *fg,
1215                                      int modify_mask,
1216                                      struct fs_fte *fte)
1217{
1218        return fpga_ipsec_fs_update_fte(ns, ft, fg, modify_mask, fte,
1219                                        false);
1220}
1221
1222static int
1223mlx5_fpga_ipsec_fs_delete_fte_ingress(struct mlx5_flow_root_namespace *ns,
1224                                      struct mlx5_flow_table *ft,
1225                                      struct fs_fte *fte)
1226{
1227        return fpga_ipsec_fs_delete_fte(ns, ft, fte, false);
1228}
1229
1230static struct mlx5_flow_cmds fpga_ipsec_ingress;
1231static struct mlx5_flow_cmds fpga_ipsec_egress;
1232
1233const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default_ipsec_fpga_cmds(enum fs_flow_table_type type)
1234{
1235        switch (type) {
1236        case FS_FT_NIC_RX:
1237                return &fpga_ipsec_ingress;
1238        case FS_FT_NIC_TX:
1239                return &fpga_ipsec_egress;
1240        default:
1241                WARN_ON(true);
1242                return NULL;
1243        }
1244}
1245
1246int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev)
1247{
1248        struct mlx5_fpga_conn_attr init_attr = {0};
1249        struct mlx5_fpga_device *fdev = mdev->fpga;
1250        struct mlx5_fpga_conn *conn;
1251        int err;
1252
1253        if (!mlx5_fpga_is_ipsec_device(mdev))
1254                return 0;
1255
1256        fdev->ipsec = kzalloc(sizeof(*fdev->ipsec), GFP_KERNEL);
1257        if (!fdev->ipsec)
1258                return -ENOMEM;
1259
1260        fdev->ipsec->fdev = fdev;
1261
1262        err = mlx5_fpga_get_sbu_caps(fdev, sizeof(fdev->ipsec->caps),
1263                                     fdev->ipsec->caps);
1264        if (err) {
1265                mlx5_fpga_err(fdev, "Failed to retrieve IPSec extended capabilities: %d\n",
1266                              err);
1267                goto error;
1268        }
1269
1270        INIT_LIST_HEAD(&fdev->ipsec->pending_cmds);
1271        spin_lock_init(&fdev->ipsec->pending_cmds_lock);
1272
1273        init_attr.rx_size = SBU_QP_QUEUE_SIZE;
1274        init_attr.tx_size = SBU_QP_QUEUE_SIZE;
1275        init_attr.recv_cb = mlx5_fpga_ipsec_recv;
1276        init_attr.cb_arg = fdev;
1277        conn = mlx5_fpga_sbu_conn_create(fdev, &init_attr);
1278        if (IS_ERR(conn)) {
1279                err = PTR_ERR(conn);
1280                mlx5_fpga_err(fdev, "Error creating IPSec command connection %d\n",
1281                              err);
1282                goto error;
1283        }
1284        fdev->ipsec->conn = conn;
1285
1286        err = rhashtable_init(&fdev->ipsec->sa_hash, &rhash_sa);
1287        if (err)
1288                goto err_destroy_conn;
1289        mutex_init(&fdev->ipsec->sa_hash_lock);
1290
1291        fdev->ipsec->rules_rb = RB_ROOT;
1292        mutex_init(&fdev->ipsec->rules_rb_lock);
1293
1294        err = mlx5_fpga_ipsec_enable_supported_caps(mdev);
1295        if (err) {
1296                mlx5_fpga_err(fdev, "Failed to enable IPSec extended capabilities: %d\n",
1297                              err);
1298                goto err_destroy_hash;
1299        }
1300
1301        return 0;
1302
1303err_destroy_hash:
1304        rhashtable_destroy(&fdev->ipsec->sa_hash);
1305
1306err_destroy_conn:
1307        mlx5_fpga_sbu_conn_destroy(conn);
1308
1309error:
1310        kfree(fdev->ipsec);
1311        fdev->ipsec = NULL;
1312        return err;
1313}
1314
1315static void destroy_rules_rb(struct rb_root *root)
1316{
1317        struct mlx5_fpga_ipsec_rule *r, *tmp;
1318
1319        rbtree_postorder_for_each_entry_safe(r, tmp, root, node) {
1320                rb_erase(&r->node, root);
1321                mlx5_fpga_ipsec_delete_sa_ctx(r->ctx);
1322                kfree(r);
1323        }
1324}
1325
1326void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev)
1327{
1328        struct mlx5_fpga_device *fdev = mdev->fpga;
1329
1330        if (!mlx5_fpga_is_ipsec_device(mdev))
1331                return;
1332
1333        destroy_rules_rb(&fdev->ipsec->rules_rb);
1334        rhashtable_destroy(&fdev->ipsec->sa_hash);
1335
1336        mlx5_fpga_sbu_conn_destroy(fdev->ipsec->conn);
1337        kfree(fdev->ipsec);
1338        fdev->ipsec = NULL;
1339}
1340
1341void mlx5_fpga_ipsec_build_fs_cmds(void)
1342{
1343        /* ingress */
1344        fpga_ipsec_ingress.create_flow_table =
1345                mlx5_fs_cmd_get_default(egress_to_fs_ft(false))->create_flow_table;
1346        fpga_ipsec_ingress.destroy_flow_table =
1347                mlx5_fs_cmd_get_default(egress_to_fs_ft(false))->destroy_flow_table;
1348        fpga_ipsec_ingress.modify_flow_table =
1349                mlx5_fs_cmd_get_default(egress_to_fs_ft(false))->modify_flow_table;
1350        fpga_ipsec_ingress.create_flow_group =
1351                mlx5_fpga_ipsec_fs_create_flow_group_ingress;
1352        fpga_ipsec_ingress.destroy_flow_group =
1353                 mlx5_fs_cmd_get_default(egress_to_fs_ft(false))->destroy_flow_group;
1354        fpga_ipsec_ingress.create_fte =
1355                mlx5_fpga_ipsec_fs_create_fte_ingress;
1356        fpga_ipsec_ingress.update_fte =
1357                mlx5_fpga_ipsec_fs_update_fte_ingress;
1358        fpga_ipsec_ingress.delete_fte =
1359                mlx5_fpga_ipsec_fs_delete_fte_ingress;
1360        fpga_ipsec_ingress.update_root_ft =
1361                mlx5_fs_cmd_get_default(egress_to_fs_ft(false))->update_root_ft;
1362
1363        /* egress */
1364        fpga_ipsec_egress.create_flow_table =
1365                mlx5_fs_cmd_get_default(egress_to_fs_ft(true))->create_flow_table;
1366        fpga_ipsec_egress.destroy_flow_table =
1367                mlx5_fs_cmd_get_default(egress_to_fs_ft(true))->destroy_flow_table;
1368        fpga_ipsec_egress.modify_flow_table =
1369                mlx5_fs_cmd_get_default(egress_to_fs_ft(true))->modify_flow_table;
1370        fpga_ipsec_egress.create_flow_group =
1371                mlx5_fpga_ipsec_fs_create_flow_group_egress;
1372        fpga_ipsec_egress.destroy_flow_group =
1373                mlx5_fs_cmd_get_default(egress_to_fs_ft(true))->destroy_flow_group;
1374        fpga_ipsec_egress.create_fte =
1375                mlx5_fpga_ipsec_fs_create_fte_egress;
1376        fpga_ipsec_egress.update_fte =
1377                mlx5_fpga_ipsec_fs_update_fte_egress;
1378        fpga_ipsec_egress.delete_fte =
1379                mlx5_fpga_ipsec_fs_delete_fte_egress;
1380        fpga_ipsec_egress.update_root_ft =
1381                mlx5_fs_cmd_get_default(egress_to_fs_ft(true))->update_root_ft;
1382}
1383
1384static int
1385mlx5_fpga_esp_validate_xfrm_attrs(struct mlx5_core_dev *mdev,
1386                                  const struct mlx5_accel_esp_xfrm_attrs *attrs)
1387{
1388        if (attrs->tfc_pad) {
1389                mlx5_core_err(mdev, "Cannot offload xfrm states with tfc padding\n");
1390                return -EOPNOTSUPP;
1391        }
1392
1393        if (attrs->replay_type != MLX5_ACCEL_ESP_REPLAY_NONE) {
1394                mlx5_core_err(mdev, "Cannot offload xfrm states with anti replay\n");
1395                return -EOPNOTSUPP;
1396        }
1397
1398        if (attrs->keymat_type != MLX5_ACCEL_ESP_KEYMAT_AES_GCM) {
1399                mlx5_core_err(mdev, "Only aes gcm keymat is supported\n");
1400                return -EOPNOTSUPP;
1401        }
1402
1403        if (attrs->keymat.aes_gcm.iv_algo !=
1404            MLX5_ACCEL_ESP_AES_GCM_IV_ALGO_SEQ) {
1405                mlx5_core_err(mdev, "Only iv sequence algo is supported\n");
1406                return -EOPNOTSUPP;
1407        }
1408
1409        if (attrs->keymat.aes_gcm.icv_len != 128) {
1410                mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD ICV length other than 128bit\n");
1411                return -EOPNOTSUPP;
1412        }
1413
1414        if (attrs->keymat.aes_gcm.key_len != 128 &&
1415            attrs->keymat.aes_gcm.key_len != 256) {
1416                mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bit\n");
1417                return -EOPNOTSUPP;
1418        }
1419
1420        if ((attrs->flags & MLX5_ACCEL_ESP_FLAGS_ESN_TRIGGERED) &&
1421            (!MLX5_GET(ipsec_extended_cap, mdev->fpga->ipsec->caps,
1422                       v2_command))) {
1423                mlx5_core_err(mdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bit\n");
1424                return -EOPNOTSUPP;
1425        }
1426
1427        return 0;
1428}
1429
1430struct mlx5_accel_esp_xfrm *
1431mlx5_fpga_esp_create_xfrm(struct mlx5_core_dev *mdev,
1432                          const struct mlx5_accel_esp_xfrm_attrs *attrs,
1433                          u32 flags)
1434{
1435        struct mlx5_fpga_esp_xfrm *fpga_xfrm;
1436
1437        if (!(flags & MLX5_ACCEL_XFRM_FLAG_REQUIRE_METADATA)) {
1438                mlx5_core_warn(mdev, "Tried to create an esp action without metadata\n");
1439                return ERR_PTR(-EINVAL);
1440        }
1441
1442        if (mlx5_fpga_esp_validate_xfrm_attrs(mdev, attrs)) {
1443                mlx5_core_warn(mdev, "Tried to create an esp with unsupported attrs\n");
1444                return ERR_PTR(-EOPNOTSUPP);
1445        }
1446
1447        fpga_xfrm = kzalloc(sizeof(*fpga_xfrm), GFP_KERNEL);
1448        if (!fpga_xfrm)
1449                return ERR_PTR(-ENOMEM);
1450
1451        mutex_init(&fpga_xfrm->lock);
1452        memcpy(&fpga_xfrm->accel_xfrm.attrs, attrs,
1453               sizeof(fpga_xfrm->accel_xfrm.attrs));
1454
1455        return &fpga_xfrm->accel_xfrm;
1456}
1457
1458void mlx5_fpga_esp_destroy_xfrm(struct mlx5_accel_esp_xfrm *xfrm)
1459{
1460        struct mlx5_fpga_esp_xfrm *fpga_xfrm =
1461                        container_of(xfrm, struct mlx5_fpga_esp_xfrm,
1462                                     accel_xfrm);
1463        /* assuming no sa_ctx are connected to this xfrm_ctx */
1464        kfree(fpga_xfrm);
1465}
1466
1467int mlx5_fpga_esp_modify_xfrm(struct mlx5_accel_esp_xfrm *xfrm,
1468                              const struct mlx5_accel_esp_xfrm_attrs *attrs)
1469{
1470        struct mlx5_core_dev *mdev = xfrm->mdev;
1471        struct mlx5_fpga_device *fdev = mdev->fpga;
1472        struct mlx5_fpga_ipsec *fipsec = fdev->ipsec;
1473        struct mlx5_fpga_esp_xfrm *fpga_xfrm;
1474        struct mlx5_ifc_fpga_ipsec_sa org_hw_sa;
1475
1476        int err = 0;
1477
1478        if (!memcmp(&xfrm->attrs, attrs, sizeof(xfrm->attrs)))
1479                return 0;
1480
1481        if (!mlx5_fpga_esp_validate_xfrm_attrs(mdev, attrs)) {
1482                mlx5_core_warn(mdev, "Tried to create an esp with unsupported attrs\n");
1483                return -EOPNOTSUPP;
1484        }
1485
1486        if (is_v2_sadb_supported(fipsec)) {
1487                mlx5_core_warn(mdev, "Modify esp is not supported\n");
1488                return -EOPNOTSUPP;
1489        }
1490
1491        fpga_xfrm = container_of(xfrm, struct mlx5_fpga_esp_xfrm, accel_xfrm);
1492
1493        mutex_lock(&fpga_xfrm->lock);
1494
1495        if (!fpga_xfrm->sa_ctx)
1496                /* Unbounded xfrm, chane only sw attrs */
1497                goto change_sw_xfrm_attrs;
1498
1499        /* copy original hw sa */
1500        memcpy(&org_hw_sa, &fpga_xfrm->sa_ctx->hw_sa, sizeof(org_hw_sa));
1501        mutex_lock(&fipsec->sa_hash_lock);
1502        /* remove original hw sa from hash */
1503        WARN_ON(rhashtable_remove_fast(&fipsec->sa_hash,
1504                                       &fpga_xfrm->sa_ctx->hash, rhash_sa));
1505        /* update hw_sa with new xfrm attrs*/
1506        mlx5_fpga_ipsec_build_hw_xfrm(xfrm->mdev, attrs,
1507                                      &fpga_xfrm->sa_ctx->hw_sa);
1508        /* try to insert new hw_sa to hash */
1509        err = rhashtable_insert_fast(&fipsec->sa_hash,
1510                                     &fpga_xfrm->sa_ctx->hash, rhash_sa);
1511        if (err)
1512                goto rollback_sa;
1513
1514        /* modify device with new hw_sa */
1515        err = mlx5_fpga_ipsec_update_hw_sa(fdev, &fpga_xfrm->sa_ctx->hw_sa,
1516                                           MLX5_FPGA_IPSEC_CMD_OP_MOD_SA_V2);
1517        fpga_xfrm->sa_ctx->hw_sa.ipsec_sa_v1.cmd = 0;
1518        if (err)
1519                WARN_ON(rhashtable_remove_fast(&fipsec->sa_hash,
1520                                               &fpga_xfrm->sa_ctx->hash,
1521                                               rhash_sa));
1522rollback_sa:
1523        if (err) {
1524                /* return original hw_sa to hash */
1525                memcpy(&fpga_xfrm->sa_ctx->hw_sa, &org_hw_sa,
1526                       sizeof(org_hw_sa));
1527                WARN_ON(rhashtable_insert_fast(&fipsec->sa_hash,
1528                                               &fpga_xfrm->sa_ctx->hash,
1529                                               rhash_sa));
1530        }
1531        mutex_unlock(&fipsec->sa_hash_lock);
1532
1533change_sw_xfrm_attrs:
1534        if (!err)
1535                memcpy(&xfrm->attrs, attrs, sizeof(xfrm->attrs));
1536        mutex_unlock(&fpga_xfrm->lock);
1537        return err;
1538}
1539