File Index
Files and directories
Sign in
FILE

mod_hdr.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en/mod_hdr.c C
  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	WARN_ON(!hash_empty(tbl->hlist));
 51	mutex_destroy(&tbl->lock);
 52}
 53
 54static struct mlx5e_mod_hdr_handle *mod_hdr_get(struct mod_hdr_tbl *tbl,
 55						struct mod_hdr_key *key,
 56						u32 hash_key)
 57{
 58	struct mlx5e_mod_hdr_handle *mh, *found = NULL;
 59
 60	hash_for_each_possible(tbl->hlist, mh, mod_hdr_hlist, hash_key) {
 61		if (!cmp_mod_hdr_info(&mh->key, key)) {
 62			refcount_inc(&mh->refcnt);
 63			found = mh;
 64			break;
 65		}
 66	}
 67
 68	return found;
 69}
 70
 71struct mlx5e_mod_hdr_handle *
 72mlx5e_mod_hdr_attach(struct mlx5_core_dev *mdev,
 73		     struct mod_hdr_tbl *tbl,
 74		     enum mlx5_flow_namespace_type namespace,
 75		     struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts)
 76{
 77	int num_actions, actions_size, err;
 78	struct mlx5e_mod_hdr_handle *mh;
 79	struct mod_hdr_key key;
 80	u32 hash_key;
 81
 82	num_actions  = mod_hdr_acts->num_actions;
 83	actions_size = MLX5_MH_ACT_SZ * num_actions;
 84
 85	key.actions = mod_hdr_acts->actions;
 86	key.num_actions = num_actions;
 87
 88	hash_key = hash_mod_hdr_info(&key);
 89
 90	mutex_lock(&tbl->lock);
 91	mh = mod_hdr_get(tbl, &key, hash_key);
 92	if (mh) {
 93		mutex_unlock(&tbl->lock);
 94		wait_for_completion(&mh->res_ready);
 95
 96		if (mh->compl_result < 0) {
 97			err = -EREMOTEIO;
 98			goto attach_header_err;
 99		}
100		goto attach_header;
101	}
102
103	mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL);
104	if (!mh) {
105		mutex_unlock(&tbl->lock);
106		return ERR_PTR(-ENOMEM);
107	}
108
109	mh->key.actions = (void *)mh + sizeof(*mh);
110	memcpy(mh->key.actions, key.actions, actions_size);
111	mh->key.num_actions = num_actions;
112	refcount_set(&mh->refcnt, 1);
113	init_completion(&mh->res_ready);
114
115	hash_add(tbl->hlist, &mh->mod_hdr_hlist, hash_key);
116	mutex_unlock(&tbl->lock);
117
118	mh->modify_hdr = mlx5_modify_header_alloc(mdev, namespace,
119						  mh->key.num_actions,
120						  mh->key.actions);
121	if (IS_ERR(mh->modify_hdr)) {
122		err = PTR_ERR(mh->modify_hdr);
123		mh->compl_result = err;
124		goto alloc_header_err;
125	}
126	mh->compl_result = 1;
127	complete_all(&mh->res_ready);
128
129attach_header:
130	return mh;
131
132alloc_header_err:
133	complete_all(&mh->res_ready);
134attach_header_err:
135	mlx5e_mod_hdr_detach(mdev, tbl, mh);
136	return ERR_PTR(err);
137}
138
139void mlx5e_mod_hdr_detach(struct mlx5_core_dev *mdev,
140			  struct mod_hdr_tbl *tbl,
141			  struct mlx5e_mod_hdr_handle *mh)
142{
143	if (!refcount_dec_and_mutex_lock(&mh->refcnt, &tbl->lock))
144		return;
145	hash_del(&mh->mod_hdr_hlist);
146	mutex_unlock(&tbl->lock);
147
148	if (mh->compl_result > 0)
149		mlx5_modify_header_dealloc(mdev, mh->modify_hdr);
150
151	kfree(mh);
152}
153
154struct mlx5_modify_hdr *mlx5e_mod_hdr_get(struct mlx5e_mod_hdr_handle *mh)
155{
156	return mh->modify_hdr;
157}
158
159char *
160mlx5e_mod_hdr_alloc(struct mlx5_core_dev *mdev, int namespace,
161		    struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts)
162{
163	int new_num_actions, max_hw_actions;
164	size_t new_sz, old_sz;
165	void *ret;
166
167	if (mod_hdr_acts->num_actions < mod_hdr_acts->max_actions)
168		goto out;
169
170	max_hw_actions = mlx5e_mod_hdr_max_actions(mdev, namespace);
171	new_num_actions = min(max_hw_actions,
172			      mod_hdr_acts->actions ?
173			      mod_hdr_acts->max_actions * 2 : 1);
174	if (mod_hdr_acts->max_actions == new_num_actions)
175		return ERR_PTR(-ENOSPC);
176
177	new_sz = MLX5_MH_ACT_SZ * new_num_actions;
178	old_sz = mod_hdr_acts->max_actions * MLX5_MH_ACT_SZ;
179
180	if (mod_hdr_acts->is_static) {
181		ret = kzalloc(new_sz, GFP_KERNEL);
182		if (ret) {
183			memcpy(ret, mod_hdr_acts->actions, old_sz);
184			mod_hdr_acts->is_static = false;
185		}
186	} else {
187		ret = krealloc(mod_hdr_acts->actions, new_sz, GFP_KERNEL);
188		if (ret)
189			memset(ret + old_sz, 0, new_sz - old_sz);
190	}
191	if (!ret)
192		return ERR_PTR(-ENOMEM);
193
194	mod_hdr_acts->actions = ret;
195	mod_hdr_acts->max_actions = new_num_actions;
196
197out:
198	return mod_hdr_acts->actions + (mod_hdr_acts->num_actions * MLX5_MH_ACT_SZ);
199}
200
201void
202mlx5e_mod_hdr_dealloc(struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts)
203{
204	if (!mod_hdr_acts->is_static)
205		kfree(mod_hdr_acts->actions);
206
207	mod_hdr_acts->actions = NULL;
208	mod_hdr_acts->num_actions = 0;
209	mod_hdr_acts->max_actions = 0;
210}
211
212char *
213mlx5e_mod_hdr_get_item(struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts, int pos)
214{
215	return mod_hdr_acts->actions + (pos * MLX5_MH_ACT_SZ);
216}
~/ Read-only file preview.