linux/drivers/net/ethernet/mellanox/mlx5/core/en/mod_hdr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2// Copyright (c) 2020 Mellanox Technologies
   3
   4#include <linux/jhash.h>
   5#include "mod_hdr.h"
   6
   7#define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)
   8
   9struct mod_hdr_key {
  10        int num_actions;
  11        void *actions;
  12};
  13
  14struct mlx5e_mod_hdr_handle {
  15        /* a node of a hash table which keeps all the mod_hdr entries */
  16        struct hlist_node mod_hdr_hlist;
  17
  18        struct mod_hdr_key key;
  19
  20        struct mlx5_modify_hdr *modify_hdr;
  21
  22        refcount_t refcnt;
  23        struct completion res_ready;
  24        int compl_result;
  25};
  26
  27static u32 hash_mod_hdr_info(struct mod_hdr_key *key)
  28{
  29        return jhash(key->actions,
  30                     key->num_actions * MLX5_MH_ACT_SZ, 0);
  31}
  32
  33static int cmp_mod_hdr_info(struct mod_hdr_key *a, struct mod_hdr_key *b)
  34{
  35        if (a->num_actions != b->num_actions)
  36                return 1;
  37
  38        return memcmp(a->actions, b->actions,
  39                      a->num_actions * MLX5_MH_ACT_SZ);
  40}
  41
  42void mlx5e_mod_hdr_tbl_init(struct mod_hdr_tbl *tbl)
  43{
  44        mutex_init(&tbl->lock);
  45        hash_init(tbl->hlist);
  46}
  47
  48void mlx5e_mod_hdr_tbl_destroy(struct mod_hdr_tbl *tbl)
  49{
  50        mutex_destroy(&tbl->lock);
  51}
  52
  53static struct mlx5e_mod_hdr_handle *mod_hdr_get(struct mod_hdr_tbl *tbl,
  54                                                struct mod_hdr_key *key,
  55                                                u32 hash_key)
  56{
  57        struct mlx5e_mod_hdr_handle *mh, *found = NULL;
  58
  59        hash_for_each_possible(tbl->hlist, mh, mod_hdr_hlist, hash_key) {
  60                if (!cmp_mod_hdr_info(&mh->key, key)) {
  61                        refcount_inc(&mh->refcnt);
  62                        found = mh;
  63                        break;
  64                }
  65        }
  66
  67        return found;
  68}
  69
  70struct mlx5e_mod_hdr_handle *
  71mlx5e_mod_hdr_attach(struct mlx5_core_dev *mdev,
  72                     struct mod_hdr_tbl *tbl,
  73                     enum mlx5_flow_namespace_type namespace,
  74                     struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts)
  75{
  76        int num_actions, actions_size, err;
  77        struct mlx5e_mod_hdr_handle *mh;
  78        struct mod_hdr_key key;
  79        u32 hash_key;
  80
  81        num_actions  = mod_hdr_acts->num_actions;
  82        actions_size = MLX5_MH_ACT_SZ * num_actions;
  83
  84        key.actions = mod_hdr_acts->actions;
  85        key.num_actions = num_actions;
  86
  87        hash_key = hash_mod_hdr_info(&key);
  88
  89        mutex_lock(&tbl->lock);
  90        mh = mod_hdr_get(tbl, &key, hash_key);
  91        if (mh) {
  92                mutex_unlock(&tbl->lock);
  93                wait_for_completion(&mh->res_ready);
  94
  95                if (mh->compl_result < 0) {
  96                        err = -EREMOTEIO;
  97                        goto attach_header_err;
  98                }
  99                goto attach_header;
 100        }
 101
 102        mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL);
 103        if (!mh) {
 104                mutex_unlock(&tbl->lock);
 105                return ERR_PTR(-ENOMEM);
 106        }
 107
 108        mh->key.actions = (void *)mh + sizeof(*mh);
 109        memcpy(mh->key.actions, key.actions, actions_size);
 110        mh->key.num_actions = num_actions;
 111        refcount_set(&mh->refcnt, 1);
 112        init_completion(&mh->res_ready);
 113
 114        hash_add(tbl->hlist, &mh->mod_hdr_hlist, hash_key);
 115        mutex_unlock(&tbl->lock);
 116
 117        mh->modify_hdr = mlx5_modify_header_alloc(mdev, namespace,
 118                                                  mh->key.num_actions,
 119                                                  mh->key.actions);
 120        if (IS_ERR(mh->modify_hdr)) {
 121                err = PTR_ERR(mh->modify_hdr);
 122                mh->compl_result = err;
 123                goto alloc_header_err;
 124        }
 125        mh->compl_result = 1;
 126        complete_all(&mh->res_ready);
 127
 128attach_header:
 129        return mh;
 130
 131alloc_header_err:
 132        complete_all(&mh->res_ready);
 133attach_header_err:
 134        mlx5e_mod_hdr_detach(mdev, tbl, mh);
 135        return ERR_PTR(err);
 136}
 137
 138void mlx5e_mod_hdr_detach(struct mlx5_core_dev *mdev,
 139                          struct mod_hdr_tbl *tbl,
 140                          struct mlx5e_mod_hdr_handle *mh)
 141{
 142        if (!refcount_dec_and_mutex_lock(&mh->refcnt, &tbl->lock))
 143                return;
 144        hash_del(&mh->mod_hdr_hlist);
 145        mutex_unlock(&tbl->lock);
 146
 147        if (mh->compl_result > 0)
 148                mlx5_modify_header_dealloc(mdev, mh->modify_hdr);
 149
 150        kfree(mh);
 151}
 152
 153struct mlx5_modify_hdr *mlx5e_mod_hdr_get(struct mlx5e_mod_hdr_handle *mh)
 154{
 155        return mh->modify_hdr;
 156}
 157
 158