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 9 struct mod_hdr_key { 10 int num_actions; 11 void *actions; 12 }; 13 14 struct 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 27 static 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 33 static 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 42 void mlx5e_mod_hdr_tbl_init(struct mod_hdr_tbl *tbl) 43 { 44 mutex_init(&tbl->lock); 45 hash_init(tbl->hlist); 46 } 47 48 void mlx5e_mod_hdr_tbl_destroy(struct mod_hdr_tbl *tbl) 49 { 50 mutex_destroy(&tbl->lock); 51 } 52 53 static 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 70 struct mlx5e_mod_hdr_handle * 71 mlx5e_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 128 attach_header: 129 return mh; 130 131 alloc_header_err: 132 complete_all(&mh->res_ready); 133 attach_header_err: 134 mlx5e_mod_hdr_detach(mdev, tbl, mh); 135 return ERR_PTR(err); 136 } 137 138 void 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 153 struct mlx5_modify_hdr *mlx5e_mod_hdr_get(struct mlx5e_mod_hdr_handle *mh) 154 { 155 return mh->modify_hdr; 156 } 157 158 char * 159 mlx5e_mod_hdr_alloc(struct mlx5_core_dev *mdev, int namespace, 160 struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts) 161 { 162 int new_num_actions, max_hw_actions; 163 size_t new_sz, old_sz; 164 void *ret; 165 166 if (mod_hdr_acts->num_actions < mod_hdr_acts->max_actions) 167 goto out; 168 169 max_hw_actions = mlx5e_mod_hdr_max_actions(mdev, namespace); 170 new_num_actions = min(max_hw_actions, 171 mod_hdr_acts->actions ? 172 mod_hdr_acts->max_actions * 2 : 1); 173 if (mod_hdr_acts->max_actions == new_num_actions) 174 return ERR_PTR(-ENOSPC); 175 176 new_sz = MLX5_MH_ACT_SZ * new_num_actions; 177 old_sz = mod_hdr_acts->max_actions * MLX5_MH_ACT_SZ; 178 179 if (mod_hdr_acts->is_static) { 180 ret = kzalloc(new_sz, GFP_KERNEL); 181 if (ret) { 182 memcpy(ret, mod_hdr_acts->actions, old_sz); 183 mod_hdr_acts->is_static = false; 184 } 185 } else { 186 ret = krealloc(mod_hdr_acts->actions, new_sz, GFP_KERNEL); 187 if (ret) 188 memset(ret + old_sz, 0, new_sz - old_sz); 189 } 190 if (!ret) 191 return ERR_PTR(-ENOMEM); 192 193 mod_hdr_acts->actions = ret; 194 mod_hdr_acts->max_actions = new_num_actions; 195 196 out: 197 return mod_hdr_acts->actions + (mod_hdr_acts->num_actions * MLX5_MH_ACT_SZ); 198 } 199 200 void 201 mlx5e_mod_hdr_dealloc(struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts) 202 { 203 if (!mod_hdr_acts->is_static) 204 kfree(mod_hdr_acts->actions); 205 206 mod_hdr_acts->actions = NULL; 207 mod_hdr_acts->num_actions = 0; 208 mod_hdr_acts->max_actions = 0; 209 } 210 211 char * 212 mlx5e_mod_hdr_get_item(struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts, int pos) 213 { 214 return mod_hdr_acts->actions + (pos * MLX5_MH_ACT_SZ); 215 } 216