1c9da1ac1SSteen Hegelund // SPDX-License-Identifier: GPL-2.0+
2c9da1ac1SSteen Hegelund /* Microchip VCAP API
3c9da1ac1SSteen Hegelund  *
4c9da1ac1SSteen Hegelund  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5c9da1ac1SSteen Hegelund  */
6c9da1ac1SSteen Hegelund 
7c9da1ac1SSteen Hegelund #include <linux/types.h>
8c9da1ac1SSteen Hegelund 
9d4134d41SSteen Hegelund #include "vcap_api_private.h"
10c9da1ac1SSteen Hegelund 
11*4f141e36SHoratiu Vultur static int keyfield_size_table[] = {
12*4f141e36SHoratiu Vultur 	[VCAP_FIELD_BIT]  = sizeof(struct vcap_u1_key),
13*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U32]  = sizeof(struct vcap_u32_key),
14*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U48]  = sizeof(struct vcap_u48_key),
15*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U56]  = sizeof(struct vcap_u56_key),
16*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U64]  = sizeof(struct vcap_u64_key),
17*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U72]  = sizeof(struct vcap_u72_key),
18*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U112] = sizeof(struct vcap_u112_key),
19*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U128] = sizeof(struct vcap_u128_key),
20*4f141e36SHoratiu Vultur };
21*4f141e36SHoratiu Vultur 
22*4f141e36SHoratiu Vultur static int actionfield_size_table[] = {
23*4f141e36SHoratiu Vultur 	[VCAP_FIELD_BIT]  = sizeof(struct vcap_u1_action),
24*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U32]  = sizeof(struct vcap_u32_action),
25*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U48]  = sizeof(struct vcap_u48_action),
26*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U56]  = sizeof(struct vcap_u56_action),
27*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U64]  = sizeof(struct vcap_u64_action),
28*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U72]  = sizeof(struct vcap_u72_action),
29*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U112] = sizeof(struct vcap_u112_action),
30*4f141e36SHoratiu Vultur 	[VCAP_FIELD_U128] = sizeof(struct vcap_u128_action),
31*4f141e36SHoratiu Vultur };
32*4f141e36SHoratiu Vultur 
338e10490bSSteen Hegelund /* Moving a rule in the VCAP address space */
348e10490bSSteen Hegelund struct vcap_rule_move {
358e10490bSSteen Hegelund 	int addr; /* address to move */
368e10490bSSteen Hegelund 	int offset; /* change in address */
378e10490bSSteen Hegelund 	int count; /* blocksize of addresses to move */
388e10490bSSteen Hegelund };
398e10490bSSteen Hegelund 
4067456717SSteen Hegelund /* Stores the filter cookie that enabled the port */
4167456717SSteen Hegelund struct vcap_enabled_port {
4267456717SSteen Hegelund 	struct list_head list; /* for insertion in enabled ports list */
4367456717SSteen Hegelund 	struct net_device *ndev;  /* the enabled port */
4467456717SSteen Hegelund 	unsigned long cookie; /* filter that enabled the port */
4567456717SSteen Hegelund };
4667456717SSteen Hegelund 
47d4134d41SSteen Hegelund void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
48683e05c0SSteen Hegelund 		   const struct vcap_typegroup *tg, u32 offset)
49683e05c0SSteen Hegelund {
50683e05c0SSteen Hegelund 	memset(itr, 0, sizeof(*itr));
51683e05c0SSteen Hegelund 	itr->offset = offset;
52683e05c0SSteen Hegelund 	itr->sw_width = sw_width;
53683e05c0SSteen Hegelund 	itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32);
54683e05c0SSteen Hegelund 	itr->tg = tg;
55683e05c0SSteen Hegelund }
56683e05c0SSteen Hegelund 
57683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr)
58683e05c0SSteen Hegelund {
59683e05c0SSteen Hegelund 	/* Compensate the field offset for preceding typegroups.
60683e05c0SSteen Hegelund 	 * A typegroup table ends with an all-zero terminator.
61683e05c0SSteen Hegelund 	 */
62683e05c0SSteen Hegelund 	while (itr->tg->width && itr->offset >= itr->tg->offset) {
63683e05c0SSteen Hegelund 		itr->offset += itr->tg->width;
64683e05c0SSteen Hegelund 		itr->tg++; /* next typegroup */
65683e05c0SSteen Hegelund 	}
66683e05c0SSteen Hegelund }
67683e05c0SSteen Hegelund 
68d4134d41SSteen Hegelund void vcap_iter_update(struct vcap_stream_iter *itr)
69683e05c0SSteen Hegelund {
70683e05c0SSteen Hegelund 	int sw_idx, sw_bitpos;
71683e05c0SSteen Hegelund 
72683e05c0SSteen Hegelund 	/* Calculate the subword index and bitposition for current bit */
73683e05c0SSteen Hegelund 	sw_idx = itr->offset / itr->sw_width;
74683e05c0SSteen Hegelund 	sw_bitpos = itr->offset % itr->sw_width;
75683e05c0SSteen Hegelund 	/* Calculate the register index and bitposition for current bit */
76683e05c0SSteen Hegelund 	itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32);
77683e05c0SSteen Hegelund 	itr->reg_bitpos = sw_bitpos % 32;
78683e05c0SSteen Hegelund }
79683e05c0SSteen Hegelund 
80d4134d41SSteen Hegelund void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
81683e05c0SSteen Hegelund 		    const struct vcap_typegroup *tg, u32 offset)
82683e05c0SSteen Hegelund {
83683e05c0SSteen Hegelund 	vcap_iter_set(itr, sw_width, tg, offset);
84683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
85683e05c0SSteen Hegelund 	vcap_iter_update(itr);
86683e05c0SSteen Hegelund }
87683e05c0SSteen Hegelund 
88d4134d41SSteen Hegelund void vcap_iter_next(struct vcap_stream_iter *itr)
89683e05c0SSteen Hegelund {
90683e05c0SSteen Hegelund 	itr->offset++;
91683e05c0SSteen Hegelund 	vcap_iter_skip_tg(itr);
92683e05c0SSteen Hegelund 	vcap_iter_update(itr);
93683e05c0SSteen Hegelund }
94683e05c0SSteen Hegelund 
95683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value)
96683e05c0SSteen Hegelund {
97683e05c0SSteen Hegelund 	u32 mask = BIT(itr->reg_bitpos);
98683e05c0SSteen Hegelund 	u32 *p = &stream[itr->reg_idx];
99683e05c0SSteen Hegelund 
100683e05c0SSteen Hegelund 	if (value)
101683e05c0SSteen Hegelund 		*p |= mask;
102683e05c0SSteen Hegelund 	else
103683e05c0SSteen Hegelund 		*p &= ~mask;
104683e05c0SSteen Hegelund }
105683e05c0SSteen Hegelund 
106683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val)
107683e05c0SSteen Hegelund {
108683e05c0SSteen Hegelund 	/* When intersected by a type group field, stream the type group bits
109683e05c0SSteen Hegelund 	 * before continuing with the value bit
110683e05c0SSteen Hegelund 	 */
111683e05c0SSteen Hegelund 	while (itr->tg->width &&
112683e05c0SSteen Hegelund 	       itr->offset >= itr->tg->offset &&
113683e05c0SSteen Hegelund 	       itr->offset < itr->tg->offset + itr->tg->width) {
114683e05c0SSteen Hegelund 		int tg_bitpos = itr->tg->offset - itr->offset;
115683e05c0SSteen Hegelund 
116683e05c0SSteen Hegelund 		vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1);
117683e05c0SSteen Hegelund 		itr->offset++;
118683e05c0SSteen Hegelund 		vcap_iter_update(itr);
119683e05c0SSteen Hegelund 	}
120683e05c0SSteen Hegelund 	vcap_set_bit(stream, itr, val);
121683e05c0SSteen Hegelund }
122683e05c0SSteen Hegelund 
123683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr,
124683e05c0SSteen Hegelund 			      int width, const u8 *value)
125683e05c0SSteen Hegelund {
126683e05c0SSteen Hegelund 	int idx;
127683e05c0SSteen Hegelund 
128683e05c0SSteen Hegelund 	/* Loop over the field value bits and add the value bits one by one to
129683e05c0SSteen Hegelund 	 * the output stream.
130683e05c0SSteen Hegelund 	 */
131683e05c0SSteen Hegelund 	for (idx = 0; idx < width; idx++) {
132683e05c0SSteen Hegelund 		u8 bidx = idx & GENMASK(2, 0);
133683e05c0SSteen Hegelund 
134683e05c0SSteen Hegelund 		/* Encode one field value bit */
135683e05c0SSteen Hegelund 		vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1);
136683e05c0SSteen Hegelund 		vcap_iter_next(itr);
137683e05c0SSteen Hegelund 	}
138683e05c0SSteen Hegelund }
139683e05c0SSteen Hegelund 
140683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width,
141683e05c0SSteen Hegelund 				   const struct vcap_typegroup *tg,
142683e05c0SSteen Hegelund 				   bool mask)
143683e05c0SSteen Hegelund {
144683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
145683e05c0SSteen Hegelund 	int idx;
146683e05c0SSteen Hegelund 
147683e05c0SSteen Hegelund 	/* Mask bits must be set to zeros (inverted later when writing to the
148683e05c0SSteen Hegelund 	 * mask cache register), so that the mask typegroup bits consist of
149683e05c0SSteen Hegelund 	 * match-1 or match-0, or both
150683e05c0SSteen Hegelund 	 */
151683e05c0SSteen Hegelund 	vcap_iter_set(&iter, sw_width, tg, 0);
152683e05c0SSteen Hegelund 	while (iter.tg->width) {
153683e05c0SSteen Hegelund 		/* Set position to current typegroup bit */
154683e05c0SSteen Hegelund 		iter.offset = iter.tg->offset;
155683e05c0SSteen Hegelund 		vcap_iter_update(&iter);
156683e05c0SSteen Hegelund 		for (idx = 0; idx < iter.tg->width; idx++) {
157683e05c0SSteen Hegelund 			/* Iterate over current typegroup bits. Mask typegroup
158683e05c0SSteen Hegelund 			 * bits are always set
159683e05c0SSteen Hegelund 			 */
160683e05c0SSteen Hegelund 			if (mask)
161683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter, 0x1);
162683e05c0SSteen Hegelund 			else
163683e05c0SSteen Hegelund 				vcap_set_bit(stream, &iter,
164683e05c0SSteen Hegelund 					     (iter.tg->value >> idx) & 0x1);
165683e05c0SSteen Hegelund 			iter.offset++;
166683e05c0SSteen Hegelund 			vcap_iter_update(&iter);
167683e05c0SSteen Hegelund 		}
168683e05c0SSteen Hegelund 		iter.tg++; /* next typegroup */
169683e05c0SSteen Hegelund 	}
170683e05c0SSteen Hegelund }
171683e05c0SSteen Hegelund 
17246be056eSSteen Hegelund /* Return the list of keyfields for the keyset */
173d4134d41SSteen Hegelund const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
17446be056eSSteen Hegelund 					enum vcap_type vt,
17546be056eSSteen Hegelund 					enum vcap_keyfield_set keyset)
17646be056eSSteen Hegelund {
17746be056eSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
17846be056eSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
17946be056eSSteen Hegelund 		return NULL;
18046be056eSSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map[keyset];
18146be056eSSteen Hegelund }
18246be056eSSteen Hegelund 
1838e10490bSSteen Hegelund /* Return the keyset information for the keyset */
184d4134d41SSteen Hegelund const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
1858e10490bSSteen Hegelund 					enum vcap_type vt,
1868e10490bSSteen Hegelund 					enum vcap_keyfield_set keyset)
1878e10490bSSteen Hegelund {
1888e10490bSSteen Hegelund 	const struct vcap_set *kset;
1898e10490bSSteen Hegelund 
1908e10490bSSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
1918e10490bSSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
1928e10490bSSteen Hegelund 		return NULL;
1938e10490bSSteen Hegelund 	kset = &vctrl->vcaps[vt].keyfield_set[keyset];
1948e10490bSSteen Hegelund 	if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count)
1958e10490bSSteen Hegelund 		return NULL;
1968e10490bSSteen Hegelund 	return kset;
1978e10490bSSteen Hegelund }
198465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfieldset);
1998e10490bSSteen Hegelund 
200683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */
201d4134d41SSteen Hegelund const struct vcap_typegroup *
202683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl,
203683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
204683e05c0SSteen Hegelund {
205683e05c0SSteen Hegelund 	const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset);
206683e05c0SSteen Hegelund 
207683e05c0SSteen Hegelund 	/* Check that the keyset is valid */
208683e05c0SSteen Hegelund 	if (!kset)
209683e05c0SSteen Hegelund 		return NULL;
210683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item];
211683e05c0SSteen Hegelund }
212683e05c0SSteen Hegelund 
213683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */
214d4134d41SSteen Hegelund int vcap_keyfield_count(struct vcap_control *vctrl,
215683e05c0SSteen Hegelund 			enum vcap_type vt, enum vcap_keyfield_set keyset)
216683e05c0SSteen Hegelund {
217683e05c0SSteen Hegelund 	/* Check that the keyset exists in the vcap keyset list */
218683e05c0SSteen Hegelund 	if (keyset >= vctrl->vcaps[vt].keyfield_set_size)
219683e05c0SSteen Hegelund 		return 0;
220683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].keyfield_set_map_size[keyset];
221683e05c0SSteen Hegelund }
222683e05c0SSteen Hegelund 
223683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri,
224683e05c0SSteen Hegelund 				 const struct vcap_client_keyfield *kf,
225683e05c0SSteen Hegelund 				 const struct vcap_field *rf,
226683e05c0SSteen Hegelund 				 const struct vcap_typegroup *tgt)
227683e05c0SSteen Hegelund {
228683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
229683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
230683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
231683e05c0SSteen Hegelund 	const u8 *value, *mask;
232683e05c0SSteen Hegelund 
233683e05c0SSteen Hegelund 	/* Encode the fields for the key and the mask in their respective
234683e05c0SSteen Hegelund 	 * streams, respecting the subword width.
235683e05c0SSteen Hegelund 	 */
236683e05c0SSteen Hegelund 	switch (kf->ctrl.type) {
237683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
238683e05c0SSteen Hegelund 		value = &kf->data.u1.value;
239683e05c0SSteen Hegelund 		mask = &kf->data.u1.mask;
240683e05c0SSteen Hegelund 		break;
241683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
242683e05c0SSteen Hegelund 		value = (const u8 *)&kf->data.u32.value;
243683e05c0SSteen Hegelund 		mask = (const u8 *)&kf->data.u32.mask;
244683e05c0SSteen Hegelund 		break;
245683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
246683e05c0SSteen Hegelund 		value = kf->data.u48.value;
247683e05c0SSteen Hegelund 		mask = kf->data.u48.mask;
248683e05c0SSteen Hegelund 		break;
249683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
250683e05c0SSteen Hegelund 		value = kf->data.u56.value;
251683e05c0SSteen Hegelund 		mask = kf->data.u56.mask;
252683e05c0SSteen Hegelund 		break;
253683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
254683e05c0SSteen Hegelund 		value = kf->data.u64.value;
255683e05c0SSteen Hegelund 		mask = kf->data.u64.mask;
256683e05c0SSteen Hegelund 		break;
257683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
258683e05c0SSteen Hegelund 		value = kf->data.u72.value;
259683e05c0SSteen Hegelund 		mask = kf->data.u72.mask;
260683e05c0SSteen Hegelund 		break;
261683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
262683e05c0SSteen Hegelund 		value = kf->data.u112.value;
263683e05c0SSteen Hegelund 		mask = kf->data.u112.mask;
264683e05c0SSteen Hegelund 		break;
265683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
266683e05c0SSteen Hegelund 		value = kf->data.u128.value;
267683e05c0SSteen Hegelund 		mask = kf->data.u128.mask;
268683e05c0SSteen Hegelund 		break;
269683e05c0SSteen Hegelund 	}
270683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
271683e05c0SSteen Hegelund 	vcap_encode_field(cache->keystream, &iter, rf->width, value);
272683e05c0SSteen Hegelund 	vcap_iter_init(&iter, sw_width, tgt, rf->offset);
273683e05c0SSteen Hegelund 	vcap_encode_field(cache->maskstream, &iter, rf->width, mask);
274683e05c0SSteen Hegelund }
275683e05c0SSteen Hegelund 
276683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl,
277683e05c0SSteen Hegelund 					    struct vcap_rule_internal *ri,
278683e05c0SSteen Hegelund 					    const struct vcap_typegroup *tgt)
279683e05c0SSteen Hegelund {
280683e05c0SSteen Hegelund 	int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width;
281683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
282683e05c0SSteen Hegelund 
283683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the key and the mask in their streams,
284683e05c0SSteen Hegelund 	 * respecting the subword width.
285683e05c0SSteen Hegelund 	 */
286683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->keystream, sw_width, tgt, false);
287683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true);
288683e05c0SSteen Hegelund }
289683e05c0SSteen Hegelund 
290683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri)
291683e05c0SSteen Hegelund {
292683e05c0SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
293683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
294683e05c0SSteen Hegelund 	const struct vcap_field *kf_table;
295683e05c0SSteen Hegelund 	int keyset_size;
296683e05c0SSteen Hegelund 
297683e05c0SSteen Hegelund 	/* Get a valid set of fields for the specific keyset */
298683e05c0SSteen Hegelund 	kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset);
299683e05c0SSteen Hegelund 	if (!kf_table) {
300683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this keyset: %d\n",
301683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
302683e05c0SSteen Hegelund 		return -EINVAL;
303683e05c0SSteen Hegelund 	}
304683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific keyset */
305683e05c0SSteen Hegelund 	tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype,
306683e05c0SSteen Hegelund 					   ri->data.keyset);
307683e05c0SSteen Hegelund 	if (!tg_table) {
308683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this keyset: %d\n",
309683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
310683e05c0SSteen Hegelund 		return -EINVAL;
311683e05c0SSteen Hegelund 	}
312683e05c0SSteen Hegelund 	/* Get a valid size for the specific keyset */
313683e05c0SSteen Hegelund 	keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype,
314683e05c0SSteen Hegelund 					  ri->data.keyset);
315683e05c0SSteen Hegelund 	if (keyset_size == 0) {
316683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this keyset: %d\n",
317683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.keyset);
318683e05c0SSteen Hegelund 		return -EINVAL;
319683e05c0SSteen Hegelund 	}
320683e05c0SSteen Hegelund 	/* Iterate over the keyfields (key, mask) in the rule
321683e05c0SSteen Hegelund 	 * and encode these bits
322683e05c0SSteen Hegelund 	 */
323683e05c0SSteen Hegelund 	if (list_empty(&ri->data.keyfields)) {
324683e05c0SSteen Hegelund 		pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__);
325683e05c0SSteen Hegelund 		return -EINVAL;
326683e05c0SSteen Hegelund 	}
327683e05c0SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
328683e05c0SSteen Hegelund 		/* Check that the client entry exists in the keyset */
329683e05c0SSteen Hegelund 		if (ckf->ctrl.key >= keyset_size) {
330683e05c0SSteen Hegelund 			pr_err("%s:%d: key %d is not in vcap\n",
331683e05c0SSteen Hegelund 			       __func__, __LINE__, ckf->ctrl.key);
332683e05c0SSteen Hegelund 			return -EINVAL;
333683e05c0SSteen Hegelund 		}
334683e05c0SSteen Hegelund 		vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table);
335683e05c0SSteen Hegelund 	}
336683e05c0SSteen Hegelund 	/* Add typegroup bits to the key/mask bitstreams */
337683e05c0SSteen Hegelund 	vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table);
338683e05c0SSteen Hegelund 	return 0;
339683e05c0SSteen Hegelund }
340683e05c0SSteen Hegelund 
341683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */
34272d84dd6SSteen Hegelund const struct vcap_field *
343683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl,
344683e05c0SSteen Hegelund 		  enum vcap_type vt, enum vcap_actionfield_set actionset)
345683e05c0SSteen Hegelund {
346683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
347683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
348683e05c0SSteen Hegelund 		return NULL;
349683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map[actionset];
350683e05c0SSteen Hegelund }
351683e05c0SSteen Hegelund 
35272d84dd6SSteen Hegelund const struct vcap_set *
3538e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl,
3548e10490bSSteen Hegelund 		    enum vcap_type vt, enum vcap_actionfield_set actionset)
3558e10490bSSteen Hegelund {
3568e10490bSSteen Hegelund 	const struct vcap_set *aset;
3578e10490bSSteen Hegelund 
3588e10490bSSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
3598e10490bSSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
3608e10490bSSteen Hegelund 		return NULL;
3618e10490bSSteen Hegelund 	aset = &vctrl->vcaps[vt].actionfield_set[actionset];
3628e10490bSSteen Hegelund 	if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count)
3638e10490bSSteen Hegelund 		return NULL;
3648e10490bSSteen Hegelund 	return aset;
3658e10490bSSteen Hegelund }
3668e10490bSSteen Hegelund 
367683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */
36872d84dd6SSteen Hegelund const struct vcap_typegroup *
369683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl,
370683e05c0SSteen Hegelund 			   enum vcap_type vt, enum vcap_actionfield_set actionset)
371683e05c0SSteen Hegelund {
372683e05c0SSteen Hegelund 	const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset);
373683e05c0SSteen Hegelund 
374683e05c0SSteen Hegelund 	/* Check that the actionset is valid */
375683e05c0SSteen Hegelund 	if (!aset)
376683e05c0SSteen Hegelund 		return NULL;
377683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item];
378683e05c0SSteen Hegelund }
379683e05c0SSteen Hegelund 
380683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */
38172d84dd6SSteen Hegelund int vcap_actionfield_count(struct vcap_control *vctrl,
382683e05c0SSteen Hegelund 			   enum vcap_type vt,
383683e05c0SSteen Hegelund 			   enum vcap_actionfield_set actionset)
384683e05c0SSteen Hegelund {
385683e05c0SSteen Hegelund 	/* Check that the actionset exists in the vcap actionset list */
386683e05c0SSteen Hegelund 	if (actionset >= vctrl->vcaps[vt].actionfield_set_size)
387683e05c0SSteen Hegelund 		return 0;
388683e05c0SSteen Hegelund 	return vctrl->vcaps[vt].actionfield_set_map_size[actionset];
389683e05c0SSteen Hegelund }
390683e05c0SSteen Hegelund 
391683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri,
392683e05c0SSteen Hegelund 				    const struct vcap_client_actionfield *af,
393683e05c0SSteen Hegelund 				    const struct vcap_field *rf,
394683e05c0SSteen Hegelund 				    const struct vcap_typegroup *tgt)
395683e05c0SSteen Hegelund {
396683e05c0SSteen Hegelund 	int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
397683e05c0SSteen Hegelund 
398683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
399683e05c0SSteen Hegelund 	struct vcap_stream_iter iter;
400683e05c0SSteen Hegelund 	const u8 *value;
401683e05c0SSteen Hegelund 
402683e05c0SSteen Hegelund 	/* Encode the action field in the stream, respecting the subword width */
403683e05c0SSteen Hegelund 	switch (af->ctrl.type) {
404683e05c0SSteen Hegelund 	case VCAP_FIELD_BIT:
405683e05c0SSteen Hegelund 		value = &af->data.u1.value;
406683e05c0SSteen Hegelund 		break;
407683e05c0SSteen Hegelund 	case VCAP_FIELD_U32:
408683e05c0SSteen Hegelund 		value = (const u8 *)&af->data.u32.value;
409683e05c0SSteen Hegelund 		break;
410683e05c0SSteen Hegelund 	case VCAP_FIELD_U48:
411683e05c0SSteen Hegelund 		value = af->data.u48.value;
412683e05c0SSteen Hegelund 		break;
413683e05c0SSteen Hegelund 	case VCAP_FIELD_U56:
414683e05c0SSteen Hegelund 		value = af->data.u56.value;
415683e05c0SSteen Hegelund 		break;
416683e05c0SSteen Hegelund 	case VCAP_FIELD_U64:
417683e05c0SSteen Hegelund 		value = af->data.u64.value;
418683e05c0SSteen Hegelund 		break;
419683e05c0SSteen Hegelund 	case VCAP_FIELD_U72:
420683e05c0SSteen Hegelund 		value = af->data.u72.value;
421683e05c0SSteen Hegelund 		break;
422683e05c0SSteen Hegelund 	case VCAP_FIELD_U112:
423683e05c0SSteen Hegelund 		value = af->data.u112.value;
424683e05c0SSteen Hegelund 		break;
425683e05c0SSteen Hegelund 	case VCAP_FIELD_U128:
426683e05c0SSteen Hegelund 		value = af->data.u128.value;
427683e05c0SSteen Hegelund 		break;
428683e05c0SSteen Hegelund 	}
429683e05c0SSteen Hegelund 	vcap_iter_init(&iter, act_width, tgt, rf->offset);
430683e05c0SSteen Hegelund 	vcap_encode_field(cache->actionstream, &iter, rf->width, value);
431683e05c0SSteen Hegelund }
432683e05c0SSteen Hegelund 
433683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri,
434683e05c0SSteen Hegelund 					       const struct vcap_typegroup *tgt)
435683e05c0SSteen Hegelund {
436683e05c0SSteen Hegelund 	int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
437683e05c0SSteen Hegelund 	struct vcap_cache_data *cache = &ri->admin->cache;
438683e05c0SSteen Hegelund 
439683e05c0SSteen Hegelund 	/* Encode the typegroup bits for the actionstream respecting the subword
440683e05c0SSteen Hegelund 	 * width.
441683e05c0SSteen Hegelund 	 */
442683e05c0SSteen Hegelund 	vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false);
443683e05c0SSteen Hegelund }
444683e05c0SSteen Hegelund 
445683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri)
446683e05c0SSteen Hegelund {
447683e05c0SSteen Hegelund 	const struct vcap_client_actionfield *caf;
448683e05c0SSteen Hegelund 	const struct vcap_typegroup *tg_table;
449683e05c0SSteen Hegelund 	const struct vcap_field *af_table;
450683e05c0SSteen Hegelund 	int actionset_size;
451683e05c0SSteen Hegelund 
452683e05c0SSteen Hegelund 	/* Get a valid set of actionset fields for the specific actionset */
453683e05c0SSteen Hegelund 	af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype,
454683e05c0SSteen Hegelund 				     ri->data.actionset);
455683e05c0SSteen Hegelund 	if (!af_table) {
456683e05c0SSteen Hegelund 		pr_err("%s:%d: no fields available for this actionset: %d\n",
457683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
458683e05c0SSteen Hegelund 		return -EINVAL;
459683e05c0SSteen Hegelund 	}
460683e05c0SSteen Hegelund 	/* Get a valid typegroup for the specific actionset */
461683e05c0SSteen Hegelund 	tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype,
462683e05c0SSteen Hegelund 					      ri->data.actionset);
463683e05c0SSteen Hegelund 	if (!tg_table) {
464683e05c0SSteen Hegelund 		pr_err("%s:%d: no typegroups available for this actionset: %d\n",
465683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
466683e05c0SSteen Hegelund 		return -EINVAL;
467683e05c0SSteen Hegelund 	}
468683e05c0SSteen Hegelund 	/* Get a valid actionset size for the specific actionset */
469683e05c0SSteen Hegelund 	actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype,
470683e05c0SSteen Hegelund 						ri->data.actionset);
471683e05c0SSteen Hegelund 	if (actionset_size == 0) {
472683e05c0SSteen Hegelund 		pr_err("%s:%d: zero field count for this actionset: %d\n",
473683e05c0SSteen Hegelund 		       __func__, __LINE__, ri->data.actionset);
474683e05c0SSteen Hegelund 		return -EINVAL;
475683e05c0SSteen Hegelund 	}
476683e05c0SSteen Hegelund 	/* Iterate over the actionfields in the rule
477683e05c0SSteen Hegelund 	 * and encode these bits
478683e05c0SSteen Hegelund 	 */
479683e05c0SSteen Hegelund 	if (list_empty(&ri->data.actionfields))
480683e05c0SSteen Hegelund 		pr_warn("%s:%d: no actionfields in the rule\n",
481683e05c0SSteen Hegelund 			__func__, __LINE__);
482683e05c0SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
483683e05c0SSteen Hegelund 		/* Check that the client action exists in the actionset */
484683e05c0SSteen Hegelund 		if (caf->ctrl.action >= actionset_size) {
485683e05c0SSteen Hegelund 			pr_err("%s:%d: action %d is not in vcap\n",
486683e05c0SSteen Hegelund 			       __func__, __LINE__, caf->ctrl.action);
487683e05c0SSteen Hegelund 			return -EINVAL;
488683e05c0SSteen Hegelund 		}
489683e05c0SSteen Hegelund 		vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action],
490683e05c0SSteen Hegelund 					tg_table);
491683e05c0SSteen Hegelund 	}
492683e05c0SSteen Hegelund 	/* Add typegroup bits to the entry bitstreams */
493683e05c0SSteen Hegelund 	vcap_encode_actionfield_typegroups(ri, tg_table);
494683e05c0SSteen Hegelund 	return 0;
495683e05c0SSteen Hegelund }
496683e05c0SSteen Hegelund 
4978e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri)
4988e10490bSSteen Hegelund {
499683e05c0SSteen Hegelund 	int err;
500683e05c0SSteen Hegelund 
501683e05c0SSteen Hegelund 	err = vcap_encode_rule_keyset(ri);
502683e05c0SSteen Hegelund 	if (err)
503683e05c0SSteen Hegelund 		return err;
504683e05c0SSteen Hegelund 	err = vcap_encode_rule_actionset(ri);
505683e05c0SSteen Hegelund 	if (err)
506683e05c0SSteen Hegelund 		return err;
5078e10490bSSteen Hegelund 	return 0;
5088e10490bSSteen Hegelund }
5098e10490bSSteen Hegelund 
510d4134d41SSteen Hegelund int vcap_api_check(struct vcap_control *ctrl)
5118e10490bSSteen Hegelund {
5128e10490bSSteen Hegelund 	if (!ctrl) {
5138e10490bSSteen Hegelund 		pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__);
5148e10490bSSteen Hegelund 		return -EINVAL;
5158e10490bSSteen Hegelund 	}
5168e10490bSSteen Hegelund 	if (!ctrl->ops || !ctrl->ops->validate_keyset ||
5178e10490bSSteen Hegelund 	    !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase ||
5188e10490bSSteen Hegelund 	    !ctrl->ops->cache_write || !ctrl->ops->cache_read ||
5198e10490bSSteen Hegelund 	    !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move ||
52067456717SSteen Hegelund 	    !ctrl->ops->port_info || !ctrl->ops->enable) {
5218e10490bSSteen Hegelund 		pr_err("%s:%d: client operations are missing\n",
5228e10490bSSteen Hegelund 		       __func__, __LINE__);
5238e10490bSSteen Hegelund 		return -ENOENT;
5248e10490bSSteen Hegelund 	}
5258e10490bSSteen Hegelund 	return 0;
5268e10490bSSteen Hegelund }
5278e10490bSSteen Hegelund 
5283a792156SSteen Hegelund void vcap_erase_cache(struct vcap_rule_internal *ri)
5298e10490bSSteen Hegelund {
5308e10490bSSteen Hegelund 	ri->vctrl->ops->cache_erase(ri->admin);
5318e10490bSSteen Hegelund }
5328e10490bSSteen Hegelund 
533c9da1ac1SSteen Hegelund /* Update the keyset for the rule */
534c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule,
535c9da1ac1SSteen Hegelund 			     enum vcap_keyfield_set keyset)
536c9da1ac1SSteen Hegelund {
5378e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
5388e10490bSSteen Hegelund 	const struct vcap_set *kset;
5398e10490bSSteen Hegelund 	int sw_width;
5408e10490bSSteen Hegelund 
5418e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset);
5428e10490bSSteen Hegelund 	/* Check that the keyset is valid */
5438e10490bSSteen Hegelund 	if (!kset)
5448e10490bSSteen Hegelund 		return -EINVAL;
5458e10490bSSteen Hegelund 	ri->keyset_sw = kset->sw_per_item;
5468e10490bSSteen Hegelund 	sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width;
5478e10490bSSteen Hegelund 	ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32);
5488e10490bSSteen Hegelund 	ri->data.keyset = keyset;
549c9da1ac1SSteen Hegelund 	return 0;
550c9da1ac1SSteen Hegelund }
551c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset);
552c9da1ac1SSteen Hegelund 
553c9da1ac1SSteen Hegelund /* Update the actionset for the rule */
554c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule,
555c9da1ac1SSteen Hegelund 				enum vcap_actionfield_set actionset)
556c9da1ac1SSteen Hegelund {
5578e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
5588e10490bSSteen Hegelund 	const struct vcap_set *aset;
5598e10490bSSteen Hegelund 	int act_width;
5608e10490bSSteen Hegelund 
5618e10490bSSteen Hegelund 	aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset);
5628e10490bSSteen Hegelund 	/* Check that the actionset is valid */
5638e10490bSSteen Hegelund 	if (!aset)
5648e10490bSSteen Hegelund 		return -EINVAL;
5658e10490bSSteen Hegelund 	ri->actionset_sw = aset->sw_per_item;
5668e10490bSSteen Hegelund 	act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width;
5678e10490bSSteen Hegelund 	ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32);
5688e10490bSSteen Hegelund 	ri->data.actionset = actionset;
569c9da1ac1SSteen Hegelund 	return 0;
570c9da1ac1SSteen Hegelund }
571c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset);
572c9da1ac1SSteen Hegelund 
573c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */
574c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl,
575c9da1ac1SSteen Hegelund 						   u32 id)
576c9da1ac1SSteen Hegelund {
577c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
578c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
579c9da1ac1SSteen Hegelund 
580c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
581c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
582c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
583c9da1ac1SSteen Hegelund 			if (ri->data.id == id)
584c9da1ac1SSteen Hegelund 				return ri;
585c9da1ac1SSteen Hegelund 	return NULL;
586c9da1ac1SSteen Hegelund }
587c9da1ac1SSteen Hegelund 
588c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */
589c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie)
590c9da1ac1SSteen Hegelund {
591c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
592c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
593c9da1ac1SSteen Hegelund 
594c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
595c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
596c9da1ac1SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list)
597c9da1ac1SSteen Hegelund 			if (ri->data.cookie == cookie)
598c9da1ac1SSteen Hegelund 				return ri->data.id;
599c9da1ac1SSteen Hegelund 	return -ENOENT;
600c9da1ac1SSteen Hegelund }
601c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie);
602c9da1ac1SSteen Hegelund 
6038e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */
6043a792156SSteen Hegelund struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
6058e10490bSSteen Hegelund {
6068e10490bSSteen Hegelund 	struct vcap_rule_internal *duprule;
6078e10490bSSteen Hegelund 
6088e10490bSSteen Hegelund 	/* Allocate the client part */
6098e10490bSSteen Hegelund 	duprule = kzalloc(sizeof(*duprule), GFP_KERNEL);
6108e10490bSSteen Hegelund 	if (!duprule)
6118e10490bSSteen Hegelund 		return ERR_PTR(-ENOMEM);
6128e10490bSSteen Hegelund 	*duprule = *ri;
6138e10490bSSteen Hegelund 	/* Not inserted in the VCAP */
6148e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->list);
6158e10490bSSteen Hegelund 	/* No elements in these lists */
6168e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.keyfields);
6178e10490bSSteen Hegelund 	INIT_LIST_HEAD(&duprule->data.actionfields);
6188e10490bSSteen Hegelund 	return duprule;
6198e10490bSSteen Hegelund }
6208e10490bSSteen Hegelund 
6218e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */
6228e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri)
6238e10490bSSteen Hegelund {
6248e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
6258e10490bSSteen Hegelund 	int sw_idx, ent_idx = 0, act_idx = 0;
6268e10490bSSteen Hegelund 	u32 addr = ri->addr;
6278e10490bSSteen Hegelund 
6288e10490bSSteen Hegelund 	if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
6298e10490bSSteen Hegelund 		pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
6308e10490bSSteen Hegelund 		return -EINVAL;
6318e10490bSSteen Hegelund 	}
6328e10490bSSteen Hegelund 	/* Use the values in the streams to write the VCAP cache */
6338e10490bSSteen Hegelund 	for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
6348e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
6358e10490bSSteen Hegelund 					    VCAP_SEL_ENTRY, ent_idx,
6368e10490bSSteen Hegelund 					    ri->keyset_sw_regs);
6378e10490bSSteen Hegelund 		ri->vctrl->ops->cache_write(ri->ndev, admin,
6388e10490bSSteen Hegelund 					    VCAP_SEL_ACTION, act_idx,
6398e10490bSSteen Hegelund 					    ri->actionset_sw_regs);
6408e10490bSSteen Hegelund 		ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
6418e10490bSSteen Hegelund 				       VCAP_SEL_ALL, addr);
6428e10490bSSteen Hegelund 		ent_idx += ri->keyset_sw_regs;
6438e10490bSSteen Hegelund 		act_idx += ri->actionset_sw_regs;
6448e10490bSSteen Hegelund 	}
6458e10490bSSteen Hegelund 	return 0;
6468e10490bSSteen Hegelund }
6478e10490bSSteen Hegelund 
648f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri,
649f13230a4SSteen Hegelund 			      struct vcap_counter *ctr)
650f13230a4SSteen Hegelund {
651f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
652f13230a4SSteen Hegelund 
653f13230a4SSteen Hegelund 	admin->cache.counter = ctr->value;
654f13230a4SSteen Hegelund 	admin->cache.sticky = ctr->sticky;
655f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
656f13230a4SSteen Hegelund 				    ri->counter_id, 0);
657f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
658f13230a4SSteen Hegelund 			       VCAP_SEL_COUNTER, ri->addr);
659f13230a4SSteen Hegelund 	return 0;
660f13230a4SSteen Hegelund }
661f13230a4SSteen Hegelund 
6627de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */
6637de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
6647de1dcadSSteen Hegelund {
6657de1dcadSSteen Hegelund 	int lookup_first = admin->vinst * admin->lookups_per_instance;
6667de1dcadSSteen Hegelund 	int lookup_last = lookup_first + admin->lookups_per_instance;
6677de1dcadSSteen Hegelund 	int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE;
6687de1dcadSSteen Hegelund 	int cid = admin->first_cid;
6697de1dcadSSteen Hegelund 	int lookup;
6707de1dcadSSteen Hegelund 
6717de1dcadSSteen Hegelund 	for (lookup = lookup_first; lookup < lookup_last; ++lookup,
6727de1dcadSSteen Hegelund 	     cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE)
6737de1dcadSSteen Hegelund 		if (cur_cid >= cid && cur_cid < cid_next)
6747de1dcadSSteen Hegelund 			return lookup;
6757de1dcadSSteen Hegelund 	return 0;
6767de1dcadSSteen Hegelund }
6777de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup);
6787de1dcadSSteen Hegelund 
679c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */
680c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
681c9da1ac1SSteen Hegelund {
682c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
683c9da1ac1SSteen Hegelund 
6848e10490bSSteen Hegelund 	if (vcap_api_check(vctrl))
6858e10490bSSteen Hegelund 		return NULL;
6868e10490bSSteen Hegelund 
687c9da1ac1SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
688c9da1ac1SSteen Hegelund 		if (cid >= admin->first_cid && cid <= admin->last_cid)
689c9da1ac1SSteen Hegelund 			return admin;
690c9da1ac1SSteen Hegelund 	}
691c9da1ac1SSteen Hegelund 	return NULL;
692c9da1ac1SSteen Hegelund }
693c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin);
694c9da1ac1SSteen Hegelund 
695392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */
696392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid)
697392d0ab0SSteen Hegelund {
698392d0ab0SSteen Hegelund 	struct vcap_admin *admin, *next_admin;
699392d0ab0SSteen Hegelund 	int lookup, next_lookup;
700392d0ab0SSteen Hegelund 
701392d0ab0SSteen Hegelund 	/* The offset must be at least one lookup */
702392d0ab0SSteen Hegelund 	if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE)
703392d0ab0SSteen Hegelund 		return false;
704392d0ab0SSteen Hegelund 
705392d0ab0SSteen Hegelund 	if (vcap_api_check(vctrl))
706392d0ab0SSteen Hegelund 		return false;
707392d0ab0SSteen Hegelund 
708392d0ab0SSteen Hegelund 	admin = vcap_find_admin(vctrl, cur_cid);
709392d0ab0SSteen Hegelund 	if (!admin)
710392d0ab0SSteen Hegelund 		return false;
711392d0ab0SSteen Hegelund 
712392d0ab0SSteen Hegelund 	/* If no VCAP contains the next chain, the next chain must be beyond
713392d0ab0SSteen Hegelund 	 * the last chain in the current VCAP
714392d0ab0SSteen Hegelund 	 */
715392d0ab0SSteen Hegelund 	next_admin = vcap_find_admin(vctrl, next_cid);
716392d0ab0SSteen Hegelund 	if (!next_admin)
717392d0ab0SSteen Hegelund 		return next_cid > admin->last_cid;
718392d0ab0SSteen Hegelund 
719392d0ab0SSteen Hegelund 	lookup = vcap_chain_id_to_lookup(admin, cur_cid);
720392d0ab0SSteen Hegelund 	next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid);
721392d0ab0SSteen Hegelund 
722392d0ab0SSteen Hegelund 	/* Next lookup must be the following lookup */
723392d0ab0SSteen Hegelund 	if (admin == next_admin || admin->vtype == next_admin->vtype)
724392d0ab0SSteen Hegelund 		return next_lookup == lookup + 1;
725392d0ab0SSteen Hegelund 
726392d0ab0SSteen Hegelund 	/* Must be the first lookup in the next VCAP instance */
727392d0ab0SSteen Hegelund 	return next_lookup == 0;
728392d0ab0SSteen Hegelund }
729392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup);
730392d0ab0SSteen Hegelund 
7318e10490bSSteen Hegelund /* Check if there is room for a new rule */
7328e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size)
7338e10490bSSteen Hegelund {
7348e10490bSSteen Hegelund 	if (admin->last_used_addr - size < admin->first_valid_addr) {
7358e10490bSSteen Hegelund 		pr_err("%s:%d: No room for rule size: %u, %u\n",
7368e10490bSSteen Hegelund 		       __func__, __LINE__, size, admin->first_valid_addr);
7378e10490bSSteen Hegelund 		return -ENOSPC;
7388e10490bSSteen Hegelund 	}
7398e10490bSSteen Hegelund 	return 0;
7408e10490bSSteen Hegelund }
7418e10490bSSteen Hegelund 
7428e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */
7438e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule)
7448e10490bSSteen Hegelund {
7458e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
7468e10490bSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
7478e10490bSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
7488e10490bSSteen Hegelund 	const struct vcap_field *fields;
7498e10490bSSteen Hegelund 	const struct vcap_set *kset;
7508e10490bSSteen Hegelund 	int ret = -EINVAL;
7518e10490bSSteen Hegelund 
7528e10490bSSteen Hegelund 	kset = vcap_keyfieldset(ri->vctrl, vt, keyset);
7538e10490bSSteen Hegelund 	if (!kset)
7548e10490bSSteen Hegelund 		return ret;
7558e10490bSSteen Hegelund 	if (kset->type_id == (u8)-1)  /* No type field is needed */
7568e10490bSSteen Hegelund 		return 0;
7578e10490bSSteen Hegelund 
7588e10490bSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
7598e10490bSSteen Hegelund 	if (!fields)
7608e10490bSSteen Hegelund 		return -EINVAL;
7618e10490bSSteen Hegelund 	if (fields[VCAP_KF_TYPE].width > 1) {
7628e10490bSSteen Hegelund 		ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE,
7638e10490bSSteen Hegelund 					    kset->type_id, 0xff);
7648e10490bSSteen Hegelund 	} else {
7658e10490bSSteen Hegelund 		if (kset->type_id)
7668e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
7678e10490bSSteen Hegelund 						    VCAP_BIT_1);
7688e10490bSSteen Hegelund 		else
7698e10490bSSteen Hegelund 			ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE,
7708e10490bSSteen Hegelund 						    VCAP_BIT_0);
7718e10490bSSteen Hegelund 	}
7728e10490bSSteen Hegelund 	return 0;
7738e10490bSSteen Hegelund }
7748e10490bSSteen Hegelund 
775abc4010dSSteen Hegelund /* Add a keyset to a keyset list */
776abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
777abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset)
778abc4010dSSteen Hegelund {
779abc4010dSSteen Hegelund 	int idx;
780abc4010dSSteen Hegelund 
781abc4010dSSteen Hegelund 	if (keysetlist->cnt < keysetlist->max) {
782abc4010dSSteen Hegelund 		/* Avoid duplicates */
783abc4010dSSteen Hegelund 		for (idx = 0; idx < keysetlist->cnt; ++idx)
784abc4010dSSteen Hegelund 			if (keysetlist->keysets[idx] == keyset)
785abc4010dSSteen Hegelund 				return keysetlist->cnt < keysetlist->max;
786abc4010dSSteen Hegelund 		keysetlist->keysets[keysetlist->cnt++] = keyset;
787abc4010dSSteen Hegelund 	}
788abc4010dSSteen Hegelund 	return keysetlist->cnt < keysetlist->max;
789abc4010dSSteen Hegelund }
790abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add);
791abc4010dSSteen Hegelund 
792abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */
793abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl,
794abc4010dSSteen Hegelund 			     enum vcap_keyfield_set keyset)
795abc4010dSSteen Hegelund {
796abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_set_names[keyset];
797abc4010dSSteen Hegelund }
798abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name);
799abc4010dSSteen Hegelund 
800abc4010dSSteen Hegelund /* map key field id to a string with the key name */
801abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl,
802abc4010dSSteen Hegelund 			       enum vcap_key_field key)
803abc4010dSSteen Hegelund {
804abc4010dSSteen Hegelund 	return vctrl->stats->keyfield_names[key];
805abc4010dSSteen Hegelund }
806abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name);
807abc4010dSSteen Hegelund 
8083a792156SSteen Hegelund /* map actionset id to a string with the actionset name */
8093a792156SSteen Hegelund const char *vcap_actionset_name(struct vcap_control *vctrl,
8103a792156SSteen Hegelund 				enum vcap_actionfield_set actionset)
8113a792156SSteen Hegelund {
8123a792156SSteen Hegelund 	return vctrl->stats->actionfield_set_names[actionset];
8133a792156SSteen Hegelund }
8143a792156SSteen Hegelund 
815242df4f7SSteen Hegelund /* map action field id to a string with the action name */
8163a792156SSteen Hegelund const char *vcap_actionfield_name(struct vcap_control *vctrl,
817242df4f7SSteen Hegelund 				  enum vcap_action_field action)
818242df4f7SSteen Hegelund {
819242df4f7SSteen Hegelund 	return vctrl->stats->actionfield_names[action];
820242df4f7SSteen Hegelund }
821242df4f7SSteen Hegelund 
822abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */
823abc4010dSSteen Hegelund static const struct vcap_field *
824abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl,
825abc4010dSSteen Hegelund 			  enum vcap_type vtype,
826abc4010dSSteen Hegelund 			  enum vcap_keyfield_set keyset,
827abc4010dSSteen Hegelund 			  enum vcap_key_field key)
828abc4010dSSteen Hegelund {
829abc4010dSSteen Hegelund 	const struct vcap_field *fields;
830abc4010dSSteen Hegelund 	int idx, count;
831abc4010dSSteen Hegelund 
832abc4010dSSteen Hegelund 	fields = vcap_keyfields(vctrl, vtype, keyset);
833abc4010dSSteen Hegelund 	if (!fields)
834abc4010dSSteen Hegelund 		return NULL;
835abc4010dSSteen Hegelund 
836abc4010dSSteen Hegelund 	/* Iterate the keyfields of the keyset */
837abc4010dSSteen Hegelund 	count = vcap_keyfield_count(vctrl, vtype, keyset);
838abc4010dSSteen Hegelund 	for (idx = 0; idx < count; ++idx) {
839abc4010dSSteen Hegelund 		if (fields[idx].width == 0)
840abc4010dSSteen Hegelund 			continue;
841abc4010dSSteen Hegelund 
842abc4010dSSteen Hegelund 		if (key == idx)
843abc4010dSSteen Hegelund 			return &fields[idx];
844abc4010dSSteen Hegelund 	}
845abc4010dSSteen Hegelund 
846abc4010dSSteen Hegelund 	return NULL;
847abc4010dSSteen Hegelund }
848abc4010dSSteen Hegelund 
849abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
850465a38a2SSteen Hegelund static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri,
851abc4010dSSteen Hegelund 				    struct vcap_keyset_list *matches)
852abc4010dSSteen Hegelund {
853abc4010dSSteen Hegelund 	const struct vcap_client_keyfield *ckf;
854abc4010dSSteen Hegelund 	int keyset, found, keycount, map_size;
855abc4010dSSteen Hegelund 	const struct vcap_field **map;
856abc4010dSSteen Hegelund 	enum vcap_type vtype;
857abc4010dSSteen Hegelund 
858abc4010dSSteen Hegelund 	vtype = ri->admin->vtype;
859abc4010dSSteen Hegelund 	map = ri->vctrl->vcaps[vtype].keyfield_set_map;
860abc4010dSSteen Hegelund 	map_size = ri->vctrl->vcaps[vtype].keyfield_set_size;
861abc4010dSSteen Hegelund 
862abc4010dSSteen Hegelund 	/* Get a count of the keyfields we want to match */
863abc4010dSSteen Hegelund 	keycount = 0;
864abc4010dSSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
865abc4010dSSteen Hegelund 		++keycount;
866abc4010dSSteen Hegelund 
867abc4010dSSteen Hegelund 	matches->cnt = 0;
868abc4010dSSteen Hegelund 	/* Iterate the keysets of the VCAP */
869abc4010dSSteen Hegelund 	for (keyset = 0; keyset < map_size; ++keyset) {
870abc4010dSSteen Hegelund 		if (!map[keyset])
871abc4010dSSteen Hegelund 			continue;
872abc4010dSSteen Hegelund 
873abc4010dSSteen Hegelund 		/* Iterate the keys in the rule */
874abc4010dSSteen Hegelund 		found = 0;
875abc4010dSSteen Hegelund 		list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
876abc4010dSSteen Hegelund 			if (vcap_find_keyset_keyfield(ri->vctrl, vtype,
877abc4010dSSteen Hegelund 						      keyset, ckf->ctrl.key))
878abc4010dSSteen Hegelund 				++found;
879abc4010dSSteen Hegelund 
880abc4010dSSteen Hegelund 		/* Save the keyset if all keyfields were found */
881abc4010dSSteen Hegelund 		if (found == keycount)
882abc4010dSSteen Hegelund 			if (!vcap_keyset_list_add(matches, keyset))
883abc4010dSSteen Hegelund 				/* bail out when the quota is filled */
884abc4010dSSteen Hegelund 				break;
885abc4010dSSteen Hegelund 	}
886abc4010dSSteen Hegelund 
887abc4010dSSteen Hegelund 	return matches->cnt > 0;
888abc4010dSSteen Hegelund }
889abc4010dSSteen Hegelund 
890465a38a2SSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */
891465a38a2SSteen Hegelund bool vcap_rule_find_keysets(struct vcap_rule *rule,
892465a38a2SSteen Hegelund 			    struct vcap_keyset_list *matches)
893465a38a2SSteen Hegelund {
894465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
895465a38a2SSteen Hegelund 
896465a38a2SSteen Hegelund 	return _vcap_rule_find_keysets(ri, matches);
897465a38a2SSteen Hegelund }
898465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_find_keysets);
899465a38a2SSteen Hegelund 
900c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */
901c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
902c9da1ac1SSteen Hegelund {
903c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
904abc4010dSSteen Hegelund 	struct vcap_keyset_list matches = {};
9058e10490bSSteen Hegelund 	enum vcap_keyfield_set keysets[10];
9068e10490bSSteen Hegelund 	int ret;
907c9da1ac1SSteen Hegelund 
9088e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
9098e10490bSSteen Hegelund 	if (ret)
9108e10490bSSteen Hegelund 		return ret;
911c9da1ac1SSteen Hegelund 	if (!ri->admin) {
912c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ADMIN;
913c9da1ac1SSteen Hegelund 		return -EINVAL;
914c9da1ac1SSteen Hegelund 	}
915c9da1ac1SSteen Hegelund 	if (!ri->ndev) {
916c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_NETDEV;
917c9da1ac1SSteen Hegelund 		return -EINVAL;
918c9da1ac1SSteen Hegelund 	}
919abc4010dSSteen Hegelund 
920abc4010dSSteen Hegelund 	matches.keysets = keysets;
921abc4010dSSteen Hegelund 	matches.max = ARRAY_SIZE(keysets);
922c9da1ac1SSteen Hegelund 	if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
923abc4010dSSteen Hegelund 		/* Iterate over rule keyfields and select keysets that fits */
924465a38a2SSteen Hegelund 		if (!_vcap_rule_find_keysets(ri, &matches)) {
925c9da1ac1SSteen Hegelund 			ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
926c9da1ac1SSteen Hegelund 			return -EINVAL;
927c9da1ac1SSteen Hegelund 		}
928abc4010dSSteen Hegelund 	} else {
9298e10490bSSteen Hegelund 		/* prepare for keyset validation */
9308e10490bSSteen Hegelund 		keysets[0] = ri->data.keyset;
931abc4010dSSteen Hegelund 		matches.cnt = 1;
932abc4010dSSteen Hegelund 	}
933abc4010dSSteen Hegelund 
9348e10490bSSteen Hegelund 	/* Pick a keyset that is supported in the port lookups */
935abc4010dSSteen Hegelund 	ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule,
936abc4010dSSteen Hegelund 					      &matches, l3_proto);
9378e10490bSSteen Hegelund 	if (ret < 0) {
9388e10490bSSteen Hegelund 		pr_err("%s:%d: keyset validation failed: %d\n",
9398e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
9408e10490bSSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH;
9418e10490bSSteen Hegelund 		return ret;
9428e10490bSSteen Hegelund 	}
943abc4010dSSteen Hegelund 	/* use the keyset that is supported in the port lookups */
944abc4010dSSteen Hegelund 	ret = vcap_set_rule_set_keyset(rule, ret);
945abc4010dSSteen Hegelund 	if (ret < 0) {
946abc4010dSSteen Hegelund 		pr_err("%s:%d: keyset was not updated: %d\n",
947abc4010dSSteen Hegelund 		       __func__, __LINE__, ret);
948abc4010dSSteen Hegelund 		return ret;
949abc4010dSSteen Hegelund 	}
950c9da1ac1SSteen Hegelund 	if (ri->data.actionset == VCAP_AFS_NO_VALUE) {
951abc4010dSSteen Hegelund 		/* Later also actionsets will be matched against actions in
952abc4010dSSteen Hegelund 		 * the rule, and the type will be set accordingly
953abc4010dSSteen Hegelund 		 */
954c9da1ac1SSteen Hegelund 		ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH;
955c9da1ac1SSteen Hegelund 		return -EINVAL;
956c9da1ac1SSteen Hegelund 	}
9578e10490bSSteen Hegelund 	vcap_add_type_keyfield(rule);
9588e10490bSSteen Hegelund 	/* Add default fields to this rule */
9598e10490bSSteen Hegelund 	ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule);
9608e10490bSSteen Hegelund 
9618e10490bSSteen Hegelund 	/* Rule size is the maximum of the entry and action subword count */
9628e10490bSSteen Hegelund 	ri->size = max(ri->keyset_sw, ri->actionset_sw);
9638e10490bSSteen Hegelund 
9648e10490bSSteen Hegelund 	/* Finally check if there is room for the rule in the VCAP */
9658e10490bSSteen Hegelund 	return vcap_rule_space(ri->admin, ri->size);
966c9da1ac1SSteen Hegelund }
967c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule);
968c9da1ac1SSteen Hegelund 
969990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key.
970990e4839SSteen Hegelund  * I.e. Lowest numerical sort_key is first in list.
971990e4839SSteen Hegelund  * In order to locate largest keys first in list we negate the key size with
972990e4839SSteen Hegelund  * (max_size - size).
973990e4839SSteen Hegelund  */
974990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
975990e4839SSteen Hegelund {
976990e4839SSteen Hegelund 	return ((max_size - size) << 24) | (user << 16) | prio;
977990e4839SSteen Hegelund }
978990e4839SSteen Hegelund 
9798e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */
9808e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
9818e10490bSSteen Hegelund {
9828e10490bSSteen Hegelund 	return ((addr - ri->size) /  ri->size) * ri->size;
9838e10490bSSteen Hegelund }
9848e10490bSSteen Hegelund 
985c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */
986c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
987c9da1ac1SSteen Hegelund {
988c9da1ac1SSteen Hegelund 	u32 next_id;
989c9da1ac1SSteen Hegelund 
990c9da1ac1SSteen Hegelund 	if (ri->data.id != 0)
991c9da1ac1SSteen Hegelund 		return ri->data.id;
992c9da1ac1SSteen Hegelund 
993c9da1ac1SSteen Hegelund 	next_id = ri->vctrl->rule_id + 1;
994c9da1ac1SSteen Hegelund 
995c9da1ac1SSteen Hegelund 	for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) {
996c9da1ac1SSteen Hegelund 		if (!vcap_lookup_rule(ri->vctrl, next_id)) {
997c9da1ac1SSteen Hegelund 			ri->data.id = next_id;
998c9da1ac1SSteen Hegelund 			ri->vctrl->rule_id = next_id;
999c9da1ac1SSteen Hegelund 			break;
1000c9da1ac1SSteen Hegelund 		}
1001c9da1ac1SSteen Hegelund 	}
1002c9da1ac1SSteen Hegelund 	return ri->data.id;
1003c9da1ac1SSteen Hegelund }
1004c9da1ac1SSteen Hegelund 
10058e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri,
10068e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
10078e10490bSSteen Hegelund {
1008990e4839SSteen Hegelund 	int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
1009990e4839SSteen Hegelund 	struct vcap_rule_internal *duprule, *iter, *elem = NULL;
10108e10490bSSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1011990e4839SSteen Hegelund 	u32 addr;
10128e10490bSSteen Hegelund 
1013990e4839SSteen Hegelund 	ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
1014990e4839SSteen Hegelund 				     ri->data.priority);
1015990e4839SSteen Hegelund 
1016990e4839SSteen Hegelund 	/* Insert the new rule in the list of rule based on the sort key
1017990e4839SSteen Hegelund 	 * If the rule needs to be  inserted between existing rules then move
1018990e4839SSteen Hegelund 	 * these rules to make room for the new rule and update their start
1019990e4839SSteen Hegelund 	 * address.
1020990e4839SSteen Hegelund 	 */
1021990e4839SSteen Hegelund 	list_for_each_entry(iter, &admin->rules, list) {
1022990e4839SSteen Hegelund 		if (ri->sort_key < iter->sort_key) {
1023990e4839SSteen Hegelund 			elem = iter;
1024990e4839SSteen Hegelund 			break;
1025990e4839SSteen Hegelund 		}
1026990e4839SSteen Hegelund 	}
1027990e4839SSteen Hegelund 
1028990e4839SSteen Hegelund 	if (!elem) {
10298e10490bSSteen Hegelund 		ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
10308e10490bSSteen Hegelund 		admin->last_used_addr = ri->addr;
1031990e4839SSteen Hegelund 
10328e10490bSSteen Hegelund 		/* Add a shallow copy of the rule to the VCAP list */
10338e10490bSSteen Hegelund 		duprule = vcap_dup_rule(ri);
10348e10490bSSteen Hegelund 		if (IS_ERR(duprule))
10358e10490bSSteen Hegelund 			return PTR_ERR(duprule);
1036990e4839SSteen Hegelund 
10378e10490bSSteen Hegelund 		list_add_tail(&duprule->list, &admin->rules);
10388e10490bSSteen Hegelund 		return 0;
10398e10490bSSteen Hegelund 	}
10408e10490bSSteen Hegelund 
1041990e4839SSteen Hegelund 	/* Reuse the space of the current rule */
1042990e4839SSteen Hegelund 	addr = elem->addr + elem->size;
1043990e4839SSteen Hegelund 	ri->addr = vcap_next_rule_addr(addr, ri);
1044990e4839SSteen Hegelund 	addr = ri->addr;
1045990e4839SSteen Hegelund 
1046990e4839SSteen Hegelund 	/* Add a shallow copy of the rule to the VCAP list */
1047990e4839SSteen Hegelund 	duprule = vcap_dup_rule(ri);
1048990e4839SSteen Hegelund 	if (IS_ERR(duprule))
1049990e4839SSteen Hegelund 		return PTR_ERR(duprule);
1050990e4839SSteen Hegelund 
1051990e4839SSteen Hegelund 	/* Add before the current entry */
1052990e4839SSteen Hegelund 	list_add_tail(&duprule->list, &elem->list);
1053990e4839SSteen Hegelund 
1054990e4839SSteen Hegelund 	/* Update the current rule */
1055990e4839SSteen Hegelund 	elem->addr = vcap_next_rule_addr(addr, elem);
1056990e4839SSteen Hegelund 	addr = elem->addr;
1057990e4839SSteen Hegelund 
1058990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1059990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list) {
1060990e4839SSteen Hegelund 		elem->addr = vcap_next_rule_addr(addr, elem);
1061990e4839SSteen Hegelund 		addr = elem->addr;
1062990e4839SSteen Hegelund 	}
1063990e4839SSteen Hegelund 
1064990e4839SSteen Hegelund 	/* Update the move info */
1065990e4839SSteen Hegelund 	move->addr = admin->last_used_addr;
1066990e4839SSteen Hegelund 	move->count = ri->addr - addr;
1067990e4839SSteen Hegelund 	move->offset = admin->last_used_addr - addr;
1068990e4839SSteen Hegelund 	admin->last_used_addr = addr;
1069990e4839SSteen Hegelund 	return 0;
1070990e4839SSteen Hegelund }
1071990e4839SSteen Hegelund 
10728e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri,
10738e10490bSSteen Hegelund 			    struct vcap_rule_move *move)
10748e10490bSSteen Hegelund {
10758e10490bSSteen Hegelund 	ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr,
10768e10490bSSteen Hegelund 			 move->offset, move->count);
10778e10490bSSteen Hegelund }
10788e10490bSSteen Hegelund 
1079c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */
1080c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule)
1081c9da1ac1SSteen Hegelund {
10828e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
10838e10490bSSteen Hegelund 	struct vcap_rule_move move = {0};
10848e10490bSSteen Hegelund 	int ret;
10858e10490bSSteen Hegelund 
10868e10490bSSteen Hegelund 	ret = vcap_api_check(ri->vctrl);
10878e10490bSSteen Hegelund 	if (ret)
10888e10490bSSteen Hegelund 		return ret;
10898e10490bSSteen Hegelund 	/* Insert the new rule in the list of vcap rules */
109071c9de99SSteen Hegelund 	mutex_lock(&ri->admin->lock);
10918e10490bSSteen Hegelund 	ret = vcap_insert_rule(ri, &move);
10928e10490bSSteen Hegelund 	if (ret < 0) {
10938e10490bSSteen Hegelund 		pr_err("%s:%d: could not insert rule in vcap list: %d\n",
10948e10490bSSteen Hegelund 		       __func__, __LINE__, ret);
10958e10490bSSteen Hegelund 		goto out;
10968e10490bSSteen Hegelund 	}
10978e10490bSSteen Hegelund 	if (move.count > 0)
10988e10490bSSteen Hegelund 		vcap_move_rules(ri, &move);
10998e10490bSSteen Hegelund 	ret = vcap_encode_rule(ri);
11008e10490bSSteen Hegelund 	if (ret) {
11018e10490bSSteen Hegelund 		pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret);
11028e10490bSSteen Hegelund 		goto out;
11038e10490bSSteen Hegelund 	}
11048e10490bSSteen Hegelund 
11058e10490bSSteen Hegelund 	ret = vcap_write_rule(ri);
11068e10490bSSteen Hegelund 	if (ret)
11078e10490bSSteen Hegelund 		pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
11088e10490bSSteen Hegelund out:
110971c9de99SSteen Hegelund 	mutex_unlock(&ri->admin->lock);
11108e10490bSSteen Hegelund 	return ret;
1111c9da1ac1SSteen Hegelund }
1112c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule);
1113c9da1ac1SSteen Hegelund 
1114c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */
1115c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
1116c9da1ac1SSteen Hegelund 				  struct net_device *ndev, int vcap_chain_id,
1117c9da1ac1SSteen Hegelund 				  enum vcap_user user, u16 priority,
1118c9da1ac1SSteen Hegelund 				  u32 id)
1119c9da1ac1SSteen Hegelund {
1120c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri;
1121c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1122990e4839SSteen Hegelund 	int err, maxsize;
1123c9da1ac1SSteen Hegelund 
1124990e4839SSteen Hegelund 	err = vcap_api_check(vctrl);
1125990e4839SSteen Hegelund 	if (err)
1126990e4839SSteen Hegelund 		return ERR_PTR(err);
1127c9da1ac1SSteen Hegelund 	if (!ndev)
1128c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENODEV);
1129c9da1ac1SSteen Hegelund 	/* Get the VCAP instance */
1130c9da1ac1SSteen Hegelund 	admin = vcap_find_admin(vctrl, vcap_chain_id);
1131c9da1ac1SSteen Hegelund 	if (!admin)
1132c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOENT);
11338e10490bSSteen Hegelund 	/* Sanity check that this VCAP is supported on this platform */
11348e10490bSSteen Hegelund 	if (vctrl->vcaps[admin->vtype].rows == 0)
11358e10490bSSteen Hegelund 		return ERR_PTR(-EINVAL);
11368e10490bSSteen Hegelund 	/* Check if a rule with this id already exists */
11378e10490bSSteen Hegelund 	if (vcap_lookup_rule(vctrl, id))
11388e10490bSSteen Hegelund 		return ERR_PTR(-EEXIST);
11398e10490bSSteen Hegelund 	/* Check if there is room for the rule in the block(s) of the VCAP */
11408e10490bSSteen Hegelund 	maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */
11418e10490bSSteen Hegelund 	if (vcap_rule_space(admin, maxsize))
11428e10490bSSteen Hegelund 		return ERR_PTR(-ENOSPC);
1143c9da1ac1SSteen Hegelund 	/* Create a container for the rule and return it */
1144c9da1ac1SSteen Hegelund 	ri = kzalloc(sizeof(*ri), GFP_KERNEL);
1145c9da1ac1SSteen Hegelund 	if (!ri)
1146c9da1ac1SSteen Hegelund 		return ERR_PTR(-ENOMEM);
1147c9da1ac1SSteen Hegelund 	ri->data.vcap_chain_id = vcap_chain_id;
1148c9da1ac1SSteen Hegelund 	ri->data.user = user;
1149c9da1ac1SSteen Hegelund 	ri->data.priority = priority;
1150c9da1ac1SSteen Hegelund 	ri->data.id = id;
1151c9da1ac1SSteen Hegelund 	ri->data.keyset = VCAP_KFS_NO_VALUE;
1152c9da1ac1SSteen Hegelund 	ri->data.actionset = VCAP_AFS_NO_VALUE;
1153c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->list);
1154c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.keyfields);
1155c9da1ac1SSteen Hegelund 	INIT_LIST_HEAD(&ri->data.actionfields);
1156c9da1ac1SSteen Hegelund 	ri->ndev = ndev;
1157c9da1ac1SSteen Hegelund 	ri->admin = admin; /* refer to the vcap instance */
1158c9da1ac1SSteen Hegelund 	ri->vctrl = vctrl; /* refer to the client */
1159c9da1ac1SSteen Hegelund 	if (vcap_set_rule_id(ri) == 0)
1160c9da1ac1SSteen Hegelund 		goto out_free;
11618e10490bSSteen Hegelund 	vcap_erase_cache(ri);
1162c9da1ac1SSteen Hegelund 	return (struct vcap_rule *)ri;
1163c9da1ac1SSteen Hegelund 
1164c9da1ac1SSteen Hegelund out_free:
1165c9da1ac1SSteen Hegelund 	kfree(ri);
1166c9da1ac1SSteen Hegelund 	return ERR_PTR(-EINVAL);
1167c9da1ac1SSteen Hegelund }
1168c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule);
1169c9da1ac1SSteen Hegelund 
1170c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */
1171c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule)
1172c9da1ac1SSteen Hegelund {
1173c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1174c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *caf, *next_caf;
1175c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
1176c9da1ac1SSteen Hegelund 
1177c9da1ac1SSteen Hegelund 	/* Deallocate the list of keys and actions */
1178c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) {
1179c9da1ac1SSteen Hegelund 		list_del(&ckf->ctrl.list);
1180c9da1ac1SSteen Hegelund 		kfree(ckf);
1181c9da1ac1SSteen Hegelund 	}
1182c9da1ac1SSteen Hegelund 	list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) {
1183c9da1ac1SSteen Hegelund 		list_del(&caf->ctrl.list);
1184c9da1ac1SSteen Hegelund 		kfree(caf);
1185c9da1ac1SSteen Hegelund 	}
1186c9da1ac1SSteen Hegelund 	/* Deallocate the rule */
1187c9da1ac1SSteen Hegelund 	kfree(rule);
1188c9da1ac1SSteen Hegelund }
1189c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule);
1190c9da1ac1SSteen Hegelund 
1191990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */
1192990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
1193990e4839SSteen Hegelund {
1194990e4839SSteen Hegelund 	return (el->addr + offset) % el->size;
1195990e4839SSteen Hegelund }
1196990e4839SSteen Hegelund 
1197990e4839SSteen Hegelund /* Update the rule address with an offset */
1198990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
1199990e4839SSteen Hegelund {
1200990e4839SSteen Hegelund 	el->addr += offset;
1201990e4839SSteen Hegelund }
1202990e4839SSteen Hegelund 
1203990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */
1204990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
1205990e4839SSteen Hegelund {
1206990e4839SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1207990e4839SSteen Hegelund 	struct vcap_rule_internal *elem;
1208990e4839SSteen Hegelund 	struct vcap_rule_move move;
1209990e4839SSteen Hegelund 	int gap = 0, offset = 0;
1210990e4839SSteen Hegelund 
1211990e4839SSteen Hegelund 	/* If the first rule is deleted: Move other rules to the top */
1212990e4839SSteen Hegelund 	if (list_is_first(&ri->list, &admin->rules))
1213990e4839SSteen Hegelund 		offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
1214990e4839SSteen Hegelund 
1215990e4839SSteen Hegelund 	/* Locate gaps between odd size rules and adjust the move */
1216990e4839SSteen Hegelund 	elem = ri;
1217990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
1218990e4839SSteen Hegelund 		gap += vcap_valid_rule_move(elem, ri->size);
1219990e4839SSteen Hegelund 
1220990e4839SSteen Hegelund 	/* Update the address in the remaining rules in the list */
1221990e4839SSteen Hegelund 	elem = ri;
1222990e4839SSteen Hegelund 	list_for_each_entry_continue(elem, &admin->rules, list)
1223990e4839SSteen Hegelund 		vcap_adjust_rule_addr(elem, ri->size + gap + offset);
1224990e4839SSteen Hegelund 
1225990e4839SSteen Hegelund 	/* Update the move info */
1226990e4839SSteen Hegelund 	move.addr = admin->last_used_addr;
1227990e4839SSteen Hegelund 	move.count = ri->addr - admin->last_used_addr - gap;
1228990e4839SSteen Hegelund 	move.offset = -(ri->size + gap + offset);
1229990e4839SSteen Hegelund 
1230990e4839SSteen Hegelund 	/* Do the actual move operation */
1231990e4839SSteen Hegelund 	vcap_move_rules(ri, &move);
1232990e4839SSteen Hegelund 
1233990e4839SSteen Hegelund 	return gap + offset;
1234990e4839SSteen Hegelund }
1235990e4839SSteen Hegelund 
1236c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */
1237c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
1238c9da1ac1SSteen Hegelund {
1239c9da1ac1SSteen Hegelund 	struct vcap_rule_internal *ri, *elem;
1240c9da1ac1SSteen Hegelund 	struct vcap_admin *admin;
1241990e4839SSteen Hegelund 	int gap = 0, err;
1242c9da1ac1SSteen Hegelund 
1243c9da1ac1SSteen Hegelund 	/* This will later also handle rule moving */
1244c9da1ac1SSteen Hegelund 	if (!ndev)
1245c9da1ac1SSteen Hegelund 		return -ENODEV;
12468e10490bSSteen Hegelund 	err = vcap_api_check(vctrl);
12478e10490bSSteen Hegelund 	if (err)
12488e10490bSSteen Hegelund 		return err;
1249c9da1ac1SSteen Hegelund 	/* Look for the rule id in all vcaps */
1250c9da1ac1SSteen Hegelund 	ri = vcap_lookup_rule(vctrl, id);
1251c9da1ac1SSteen Hegelund 	if (!ri)
1252c9da1ac1SSteen Hegelund 		return -EINVAL;
1253c9da1ac1SSteen Hegelund 	admin = ri->admin;
12548e10490bSSteen Hegelund 
1255990e4839SSteen Hegelund 	if (ri->addr > admin->last_used_addr)
1256990e4839SSteen Hegelund 		gap = vcap_fill_rule_gap(ri);
1257990e4839SSteen Hegelund 
1258990e4839SSteen Hegelund 	/* Delete the rule from the list of rules and the cache */
125971c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
1260990e4839SSteen Hegelund 	list_del(&ri->list);
1261990e4839SSteen Hegelund 	vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
1262990e4839SSteen Hegelund 	kfree(ri);
126371c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
1264990e4839SSteen Hegelund 
1265277e9179SSteen Hegelund 	/* Update the last used address, set to default when no rules */
1266c9da1ac1SSteen Hegelund 	if (list_empty(&admin->rules)) {
1267277e9179SSteen Hegelund 		admin->last_used_addr = admin->last_valid_addr + 1;
1268c9da1ac1SSteen Hegelund 	} else {
1269990e4839SSteen Hegelund 		elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
1270990e4839SSteen Hegelund 				       list);
1271c9da1ac1SSteen Hegelund 		admin->last_used_addr = elem->addr;
1272c9da1ac1SSteen Hegelund 	}
1273c9da1ac1SSteen Hegelund 	return 0;
1274c9da1ac1SSteen Hegelund }
1275c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule);
1276c9da1ac1SSteen Hegelund 
12778e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */
12788e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
12798e10490bSSteen Hegelund {
128067456717SSteen Hegelund 	struct vcap_enabled_port *eport, *next_eport;
12818e10490bSSteen Hegelund 	struct vcap_rule_internal *ri, *next_ri;
12828e10490bSSteen Hegelund 	int ret = vcap_api_check(vctrl);
12838e10490bSSteen Hegelund 
12848e10490bSSteen Hegelund 	if (ret)
12858e10490bSSteen Hegelund 		return ret;
128671c9de99SSteen Hegelund 
128771c9de99SSteen Hegelund 	mutex_lock(&admin->lock);
12888e10490bSSteen Hegelund 	list_for_each_entry_safe(ri, next_ri, &admin->rules, list) {
12898e10490bSSteen Hegelund 		vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size);
12908e10490bSSteen Hegelund 		list_del(&ri->list);
12918e10490bSSteen Hegelund 		kfree(ri);
12928e10490bSSteen Hegelund 	}
12938e10490bSSteen Hegelund 	admin->last_used_addr = admin->last_valid_addr;
129467456717SSteen Hegelund 
129567456717SSteen Hegelund 	/* Remove list of enabled ports */
129667456717SSteen Hegelund 	list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) {
129767456717SSteen Hegelund 		list_del(&eport->list);
129867456717SSteen Hegelund 		kfree(eport);
129967456717SSteen Hegelund 	}
130071c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
130167456717SSteen Hegelund 
13028e10490bSSteen Hegelund 	return 0;
13038e10490bSSteen Hegelund }
13048e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules);
13058e10490bSSteen Hegelund 
1306465a38a2SSteen Hegelund /* Find a client key field in a rule */
1307465a38a2SSteen Hegelund static struct vcap_client_keyfield *
1308465a38a2SSteen Hegelund vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key)
1309465a38a2SSteen Hegelund {
1310465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1311465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
1312465a38a2SSteen Hegelund 
1313465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1314465a38a2SSteen Hegelund 		if (ckf->ctrl.key == key)
1315465a38a2SSteen Hegelund 			return ckf;
1316465a38a2SSteen Hegelund 	return NULL;
1317465a38a2SSteen Hegelund }
1318465a38a2SSteen Hegelund 
131946be056eSSteen Hegelund /* Find information on a key field in a rule */
132046be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
132146be056eSSteen Hegelund 					      enum vcap_key_field key)
132246be056eSSteen Hegelund {
13238e10490bSSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
132446be056eSSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
132546be056eSSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
132646be056eSSteen Hegelund 	const struct vcap_field *fields;
132746be056eSSteen Hegelund 
132846be056eSSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
132946be056eSSteen Hegelund 		return NULL;
133046be056eSSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
133146be056eSSteen Hegelund 	if (!fields)
133246be056eSSteen Hegelund 		return NULL;
133346be056eSSteen Hegelund 	return &fields[key];
133446be056eSSteen Hegelund }
133546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield);
133646be056eSSteen Hegelund 
1337*4f141e36SHoratiu Vultur /* Copy data from src to dst but reverse the data in chunks of 32bits.
1338*4f141e36SHoratiu Vultur  * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will
1339*4f141e36SHoratiu Vultur  * have the value 22:33:44:55:00:11.
1340*4f141e36SHoratiu Vultur  */
1341*4f141e36SHoratiu Vultur static void vcap_copy_to_w32be(u8 *dst, u8 *src, int size)
1342*4f141e36SHoratiu Vultur {
1343*4f141e36SHoratiu Vultur 	for (int idx = 0; idx < size; ++idx) {
1344*4f141e36SHoratiu Vultur 		int first_byte_index = 0;
1345*4f141e36SHoratiu Vultur 		int nidx;
1346*4f141e36SHoratiu Vultur 
1347*4f141e36SHoratiu Vultur 		first_byte_index = size - (((idx >> 2) + 1) << 2);
1348*4f141e36SHoratiu Vultur 		if (first_byte_index < 0)
1349*4f141e36SHoratiu Vultur 			first_byte_index = 0;
1350*4f141e36SHoratiu Vultur 		nidx = idx + first_byte_index - (idx & ~0x3);
1351*4f141e36SHoratiu Vultur 		dst[nidx] = src[idx];
1352*4f141e36SHoratiu Vultur 	}
1353*4f141e36SHoratiu Vultur }
1354*4f141e36SHoratiu Vultur 
1355c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule,
1356c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield *field,
1357c9da1ac1SSteen Hegelund 					   struct vcap_client_keyfield_data *data)
1358c9da1ac1SSteen Hegelund {
1359*4f141e36SHoratiu Vultur 	struct vcap_rule_internal *ri = to_intrule(rule);
1360*4f141e36SHoratiu Vultur 	int size;
1361*4f141e36SHoratiu Vultur 
1362*4f141e36SHoratiu Vultur 	if (!ri->admin->w32be) {
1363c9da1ac1SSteen Hegelund 		memcpy(&field->data, data, sizeof(field->data));
1364*4f141e36SHoratiu Vultur 		return;
1365*4f141e36SHoratiu Vultur 	}
1366*4f141e36SHoratiu Vultur 
1367*4f141e36SHoratiu Vultur 	size = keyfield_size_table[field->ctrl.type] / 2;
1368*4f141e36SHoratiu Vultur 	switch (field->ctrl.type) {
1369*4f141e36SHoratiu Vultur 	case VCAP_FIELD_BIT:
1370*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U32:
1371*4f141e36SHoratiu Vultur 		memcpy(&field->data, data, sizeof(field->data));
1372*4f141e36SHoratiu Vultur 		break;
1373*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U48:
1374*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size);
1375*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u48.mask,  data->u48.mask, size);
1376*4f141e36SHoratiu Vultur 		break;
1377*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U56:
1378*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size);
1379*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u56.mask,  data->u56.mask, size);
1380*4f141e36SHoratiu Vultur 		break;
1381*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U64:
1382*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size);
1383*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u64.mask,  data->u64.mask, size);
1384*4f141e36SHoratiu Vultur 		break;
1385*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U72:
1386*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size);
1387*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u72.mask,  data->u72.mask, size);
1388*4f141e36SHoratiu Vultur 		break;
1389*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U112:
1390*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size);
1391*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u112.mask,  data->u112.mask, size);
1392*4f141e36SHoratiu Vultur 		break;
1393*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U128:
1394*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size);
1395*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u128.mask,  data->u128.mask, size);
1396*4f141e36SHoratiu Vultur 		break;
1397*4f141e36SHoratiu Vultur 	};
1398c9da1ac1SSteen Hegelund }
1399c9da1ac1SSteen Hegelund 
1400242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */
1401242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule,
1402242df4f7SSteen Hegelund 				 enum vcap_key_field key)
1403242df4f7SSteen Hegelund {
1404242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1405242df4f7SSteen Hegelund 	const struct vcap_client_keyfield *ckf;
1406242df4f7SSteen Hegelund 
1407242df4f7SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
1408242df4f7SSteen Hegelund 		if (ckf->ctrl.key == key)
1409242df4f7SSteen Hegelund 			return false;
1410242df4f7SSteen Hegelund 	return true;
1411242df4f7SSteen Hegelund }
1412242df4f7SSteen Hegelund 
1413242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */
1414242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule,
1415242df4f7SSteen Hegelund 				       enum vcap_key_field key)
1416242df4f7SSteen Hegelund {
1417242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1418242df4f7SSteen Hegelund 	enum vcap_keyfield_set keyset = rule->keyset;
1419242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
1420242df4f7SSteen Hegelund 	const struct vcap_field *fields;
1421242df4f7SSteen Hegelund 
1422242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no keyset yet */
1423242df4f7SSteen Hegelund 	if (keyset == VCAP_KFS_NO_VALUE)
1424242df4f7SSteen Hegelund 		return true;
1425242df4f7SSteen Hegelund 	fields = vcap_keyfields(ri->vctrl, vt, keyset);
1426242df4f7SSteen Hegelund 	if (!fields)
1427242df4f7SSteen Hegelund 		return false;
1428242df4f7SSteen Hegelund 	/* if there is a width there is a way */
1429242df4f7SSteen Hegelund 	return fields[key].width > 0;
1430242df4f7SSteen Hegelund }
1431242df4f7SSteen Hegelund 
1432c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule,
1433c9da1ac1SSteen Hegelund 			     enum vcap_key_field key,
1434c9da1ac1SSteen Hegelund 			     enum vcap_field_type ftype,
1435c9da1ac1SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
1436c9da1ac1SSteen Hegelund {
1437242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1438c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield *field;
1439c9da1ac1SSteen Hegelund 
1440242df4f7SSteen Hegelund 	if (!vcap_keyfield_unique(rule, key)) {
1441242df4f7SSteen Hegelund 		pr_warn("%s:%d: keyfield %s is already in the rule\n",
1442242df4f7SSteen Hegelund 			__func__, __LINE__,
1443242df4f7SSteen Hegelund 			vcap_keyfield_name(ri->vctrl, key));
1444242df4f7SSteen Hegelund 		return -EINVAL;
1445242df4f7SSteen Hegelund 	}
1446242df4f7SSteen Hegelund 
1447242df4f7SSteen Hegelund 	if (!vcap_keyfield_match_keyset(rule, key)) {
1448242df4f7SSteen Hegelund 		pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n",
1449242df4f7SSteen Hegelund 		       __func__, __LINE__,
1450242df4f7SSteen Hegelund 		       vcap_keyfield_name(ri->vctrl, key));
1451242df4f7SSteen Hegelund 		return -EINVAL;
1452242df4f7SSteen Hegelund 	}
1453242df4f7SSteen Hegelund 
1454c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1455c9da1ac1SSteen Hegelund 	if (!field)
1456c9da1ac1SSteen Hegelund 		return -ENOMEM;
1457c9da1ac1SSteen Hegelund 	field->ctrl.key = key;
1458c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
1459c9da1ac1SSteen Hegelund 	vcap_copy_from_client_keyfield(rule, field, data);
1460c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->keyfields);
1461c9da1ac1SSteen Hegelund 	return 0;
1462c9da1ac1SSteen Hegelund }
1463c9da1ac1SSteen Hegelund 
146446be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val)
146546be056eSSteen Hegelund {
146646be056eSSteen Hegelund 	switch (val) {
146746be056eSSteen Hegelund 	case VCAP_BIT_0:
146846be056eSSteen Hegelund 		u1->value = 0;
146946be056eSSteen Hegelund 		u1->mask = 1;
147046be056eSSteen Hegelund 		break;
147146be056eSSteen Hegelund 	case VCAP_BIT_1:
147246be056eSSteen Hegelund 		u1->value = 1;
147346be056eSSteen Hegelund 		u1->mask = 1;
147446be056eSSteen Hegelund 		break;
147546be056eSSteen Hegelund 	case VCAP_BIT_ANY:
147646be056eSSteen Hegelund 		u1->value = 0;
147746be056eSSteen Hegelund 		u1->mask = 0;
147846be056eSSteen Hegelund 		break;
147946be056eSSteen Hegelund 	}
148046be056eSSteen Hegelund }
148146be056eSSteen Hegelund 
148246be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */
148346be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
148446be056eSSteen Hegelund 			  enum vcap_bit val)
148546be056eSSteen Hegelund {
148646be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
148746be056eSSteen Hegelund 
148846be056eSSteen Hegelund 	vcap_rule_set_key_bitsize(&data.u1, val);
148946be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data);
149046be056eSSteen Hegelund }
149146be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit);
149246be056eSSteen Hegelund 
149346be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */
149446be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
149546be056eSSteen Hegelund 			  u32 value, u32 mask)
149646be056eSSteen Hegelund {
149746be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
149846be056eSSteen Hegelund 
149946be056eSSteen Hegelund 	data.u32.value = value;
150046be056eSSteen Hegelund 	data.u32.mask = mask;
150146be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data);
150246be056eSSteen Hegelund }
150346be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32);
150446be056eSSteen Hegelund 
1505c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */
1506c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
1507c9da1ac1SSteen Hegelund 			  struct vcap_u48_key *fieldval)
1508c9da1ac1SSteen Hegelund {
1509c9da1ac1SSteen Hegelund 	struct vcap_client_keyfield_data data;
1510c9da1ac1SSteen Hegelund 
1511c9da1ac1SSteen Hegelund 	memcpy(&data.u48, fieldval, sizeof(data.u48));
1512c9da1ac1SSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data);
1513c9da1ac1SSteen Hegelund }
1514c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48);
1515c9da1ac1SSteen Hegelund 
151646be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */
151746be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
151846be056eSSteen Hegelund 			  struct vcap_u72_key *fieldval)
151946be056eSSteen Hegelund {
152046be056eSSteen Hegelund 	struct vcap_client_keyfield_data data;
152146be056eSSteen Hegelund 
152246be056eSSteen Hegelund 	memcpy(&data.u72, fieldval, sizeof(data.u72));
152346be056eSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data);
152446be056eSSteen Hegelund }
152546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72);
152646be056eSSteen Hegelund 
1527d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */
1528d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
1529d6c2964dSSteen Hegelund 			   struct vcap_u128_key *fieldval)
1530d6c2964dSSteen Hegelund {
1531d6c2964dSSteen Hegelund 	struct vcap_client_keyfield_data data;
1532d6c2964dSSteen Hegelund 
1533d6c2964dSSteen Hegelund 	memcpy(&data.u128, fieldval, sizeof(data.u128));
1534d6c2964dSSteen Hegelund 	return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data);
1535d6c2964dSSteen Hegelund }
1536d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
1537d6c2964dSSteen Hegelund 
1538465a38a2SSteen Hegelund /* Find a client action field in a rule */
1539465a38a2SSteen Hegelund static struct vcap_client_actionfield *
1540465a38a2SSteen Hegelund vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act)
1541465a38a2SSteen Hegelund {
1542465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule;
1543465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
1544465a38a2SSteen Hegelund 
1545465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
1546465a38a2SSteen Hegelund 		if (caf->ctrl.action == act)
1547465a38a2SSteen Hegelund 			return caf;
1548465a38a2SSteen Hegelund 	return NULL;
1549465a38a2SSteen Hegelund }
1550465a38a2SSteen Hegelund 
1551c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule,
1552c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield *field,
1553c9da1ac1SSteen Hegelund 					      struct vcap_client_actionfield_data *data)
1554c9da1ac1SSteen Hegelund {
1555*4f141e36SHoratiu Vultur 	struct vcap_rule_internal *ri = to_intrule(rule);
1556*4f141e36SHoratiu Vultur 	int size;
1557*4f141e36SHoratiu Vultur 
1558*4f141e36SHoratiu Vultur 	if (!ri->admin->w32be) {
1559c9da1ac1SSteen Hegelund 		memcpy(&field->data, data, sizeof(field->data));
1560*4f141e36SHoratiu Vultur 		return;
1561*4f141e36SHoratiu Vultur 	}
1562*4f141e36SHoratiu Vultur 
1563*4f141e36SHoratiu Vultur 	size = actionfield_size_table[field->ctrl.type];
1564*4f141e36SHoratiu Vultur 	switch (field->ctrl.type) {
1565*4f141e36SHoratiu Vultur 	case VCAP_FIELD_BIT:
1566*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U32:
1567*4f141e36SHoratiu Vultur 		memcpy(&field->data, data, sizeof(field->data));
1568*4f141e36SHoratiu Vultur 		break;
1569*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U48:
1570*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size);
1571*4f141e36SHoratiu Vultur 		break;
1572*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U56:
1573*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size);
1574*4f141e36SHoratiu Vultur 		break;
1575*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U64:
1576*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size);
1577*4f141e36SHoratiu Vultur 		break;
1578*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U72:
1579*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size);
1580*4f141e36SHoratiu Vultur 		break;
1581*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U112:
1582*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size);
1583*4f141e36SHoratiu Vultur 		break;
1584*4f141e36SHoratiu Vultur 	case VCAP_FIELD_U128:
1585*4f141e36SHoratiu Vultur 		vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size);
1586*4f141e36SHoratiu Vultur 		break;
1587*4f141e36SHoratiu Vultur 	};
1588c9da1ac1SSteen Hegelund }
1589c9da1ac1SSteen Hegelund 
1590242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */
1591242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule,
1592242df4f7SSteen Hegelund 				    enum vcap_action_field act)
1593242df4f7SSteen Hegelund {
1594242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1595242df4f7SSteen Hegelund 	const struct vcap_client_actionfield *caf;
1596242df4f7SSteen Hegelund 
1597242df4f7SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
1598242df4f7SSteen Hegelund 		if (caf->ctrl.action == act)
1599242df4f7SSteen Hegelund 			return false;
1600242df4f7SSteen Hegelund 	return true;
1601242df4f7SSteen Hegelund }
1602242df4f7SSteen Hegelund 
1603242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */
1604242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule,
1605242df4f7SSteen Hegelund 					     enum vcap_action_field action)
1606242df4f7SSteen Hegelund {
1607242df4f7SSteen Hegelund 	enum vcap_actionfield_set actionset = rule->actionset;
1608242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1609242df4f7SSteen Hegelund 	enum vcap_type vt = ri->admin->vtype;
1610242df4f7SSteen Hegelund 	const struct vcap_field *fields;
1611242df4f7SSteen Hegelund 
1612242df4f7SSteen Hegelund 	/* the field is accepted if the rule has no actionset yet */
1613242df4f7SSteen Hegelund 	if (actionset == VCAP_AFS_NO_VALUE)
1614242df4f7SSteen Hegelund 		return true;
1615242df4f7SSteen Hegelund 	fields = vcap_actionfields(ri->vctrl, vt, actionset);
1616242df4f7SSteen Hegelund 	if (!fields)
1617242df4f7SSteen Hegelund 		return false;
1618242df4f7SSteen Hegelund 	/* if there is a width there is a way */
1619242df4f7SSteen Hegelund 	return fields[action].width > 0;
1620242df4f7SSteen Hegelund }
1621242df4f7SSteen Hegelund 
1622c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule,
1623c9da1ac1SSteen Hegelund 				enum vcap_action_field action,
1624c9da1ac1SSteen Hegelund 				enum vcap_field_type ftype,
1625c9da1ac1SSteen Hegelund 				struct vcap_client_actionfield_data *data)
1626c9da1ac1SSteen Hegelund {
1627242df4f7SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1628c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield *field;
1629c9da1ac1SSteen Hegelund 
1630242df4f7SSteen Hegelund 	if (!vcap_actionfield_unique(rule, action)) {
1631242df4f7SSteen Hegelund 		pr_warn("%s:%d: actionfield %s is already in the rule\n",
1632242df4f7SSteen Hegelund 			__func__, __LINE__,
1633242df4f7SSteen Hegelund 			vcap_actionfield_name(ri->vctrl, action));
1634242df4f7SSteen Hegelund 		return -EINVAL;
1635242df4f7SSteen Hegelund 	}
1636242df4f7SSteen Hegelund 
1637242df4f7SSteen Hegelund 	if (!vcap_actionfield_match_actionset(rule, action)) {
1638242df4f7SSteen Hegelund 		pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n",
1639242df4f7SSteen Hegelund 		       __func__, __LINE__,
1640242df4f7SSteen Hegelund 		       vcap_actionfield_name(ri->vctrl, action));
1641242df4f7SSteen Hegelund 		return -EINVAL;
1642242df4f7SSteen Hegelund 	}
1643242df4f7SSteen Hegelund 
1644c9da1ac1SSteen Hegelund 	field = kzalloc(sizeof(*field), GFP_KERNEL);
1645c9da1ac1SSteen Hegelund 	if (!field)
1646c9da1ac1SSteen Hegelund 		return -ENOMEM;
1647c9da1ac1SSteen Hegelund 	field->ctrl.action = action;
1648c9da1ac1SSteen Hegelund 	field->ctrl.type = ftype;
1649c9da1ac1SSteen Hegelund 	vcap_copy_from_client_actionfield(rule, field, data);
1650c9da1ac1SSteen Hegelund 	list_add_tail(&field->ctrl.list, &rule->actionfields);
1651c9da1ac1SSteen Hegelund 	return 0;
1652c9da1ac1SSteen Hegelund }
1653c9da1ac1SSteen Hegelund 
1654c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1,
1655c9da1ac1SSteen Hegelund 					 enum vcap_bit val)
1656c9da1ac1SSteen Hegelund {
1657c9da1ac1SSteen Hegelund 	switch (val) {
1658c9da1ac1SSteen Hegelund 	case VCAP_BIT_0:
1659c9da1ac1SSteen Hegelund 		u1->value = 0;
1660c9da1ac1SSteen Hegelund 		break;
1661c9da1ac1SSteen Hegelund 	case VCAP_BIT_1:
1662c9da1ac1SSteen Hegelund 		u1->value = 1;
1663c9da1ac1SSteen Hegelund 		break;
1664c9da1ac1SSteen Hegelund 	case VCAP_BIT_ANY:
1665c9da1ac1SSteen Hegelund 		u1->value = 0;
1666c9da1ac1SSteen Hegelund 		break;
1667c9da1ac1SSteen Hegelund 	}
1668c9da1ac1SSteen Hegelund }
1669c9da1ac1SSteen Hegelund 
1670c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */
1671c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule,
1672c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
1673c9da1ac1SSteen Hegelund 			     enum vcap_bit val)
1674c9da1ac1SSteen Hegelund {
1675c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
1676c9da1ac1SSteen Hegelund 
1677c9da1ac1SSteen Hegelund 	vcap_rule_set_action_bitsize(&data.u1, val);
1678c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data);
1679c9da1ac1SSteen Hegelund }
1680c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit);
1681c9da1ac1SSteen Hegelund 
1682c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */
1683c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule,
1684c9da1ac1SSteen Hegelund 			     enum vcap_action_field action,
1685c9da1ac1SSteen Hegelund 			     u32 value)
1686c9da1ac1SSteen Hegelund {
1687c9da1ac1SSteen Hegelund 	struct vcap_client_actionfield_data data;
1688c9da1ac1SSteen Hegelund 
1689c9da1ac1SSteen Hegelund 	data.u32.value = value;
1690c9da1ac1SSteen Hegelund 	return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data);
1691c9da1ac1SSteen Hegelund }
1692c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
1693c9da1ac1SSteen Hegelund 
1694f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri,
1695f13230a4SSteen Hegelund 			     struct vcap_counter *ctr)
1696f13230a4SSteen Hegelund {
1697f13230a4SSteen Hegelund 	struct vcap_admin *admin = ri->admin;
1698f13230a4SSteen Hegelund 
1699f13230a4SSteen Hegelund 	ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
1700f13230a4SSteen Hegelund 			       ri->addr);
1701f13230a4SSteen Hegelund 	ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
1702f13230a4SSteen Hegelund 				   ri->counter_id, 0);
1703f13230a4SSteen Hegelund 	ctr->value = admin->cache.counter;
1704f13230a4SSteen Hegelund 	ctr->sticky = admin->cache.sticky;
1705f13230a4SSteen Hegelund 	return 0;
1706f13230a4SSteen Hegelund }
1707f13230a4SSteen Hegelund 
1708c9da1ac1SSteen Hegelund /* Copy to host byte order */
1709c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
1710c9da1ac1SSteen Hegelund {
1711c9da1ac1SSteen Hegelund 	int idx;
1712c9da1ac1SSteen Hegelund 
1713c9da1ac1SSteen Hegelund 	for (idx = 0; idx < count; ++idx, ++dst)
1714c9da1ac1SSteen Hegelund 		*dst = src[count - idx - 1];
1715c9da1ac1SSteen Hegelund }
1716c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy);
1717c9da1ac1SSteen Hegelund 
1718c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */
1719c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule)
1720c9da1ac1SSteen Hegelund {
1721c9da1ac1SSteen Hegelund 	switch (vrule->exterr) {
1722c9da1ac1SSteen Hegelund 	case VCAP_ERR_NONE:
1723c9da1ac1SSteen Hegelund 		break;
1724c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ADMIN:
1725c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1726c9da1ac1SSteen Hegelund 				   "Missing VCAP instance");
1727c9da1ac1SSteen Hegelund 		break;
1728c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_NETDEV:
1729c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1730c9da1ac1SSteen Hegelund 				   "Missing network interface");
1731c9da1ac1SSteen Hegelund 		break;
1732c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_KEYSET_MATCH:
1733c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1734c9da1ac1SSteen Hegelund 				   "No keyset matched the filter keys");
1735c9da1ac1SSteen Hegelund 		break;
1736c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_ACTIONSET_MATCH:
1737c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1738c9da1ac1SSteen Hegelund 				   "No actionset matched the filter actions");
1739c9da1ac1SSteen Hegelund 		break;
1740c9da1ac1SSteen Hegelund 	case VCAP_ERR_NO_PORT_KEYSET_MATCH:
1741c9da1ac1SSteen Hegelund 		NL_SET_ERR_MSG_MOD(fco->common.extack,
1742c9da1ac1SSteen Hegelund 				   "No port keyset matched the filter keys");
1743c9da1ac1SSteen Hegelund 		break;
1744c9da1ac1SSteen Hegelund 	}
1745c9da1ac1SSteen Hegelund }
1746c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr);
174767d63751SSteen Hegelund 
174867456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */
174967456717SSteen Hegelund static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev,
175067456717SSteen Hegelund 			    unsigned long cookie)
175167456717SSteen Hegelund {
175267456717SSteen Hegelund 	struct vcap_enabled_port *eport;
175367456717SSteen Hegelund 
175467456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list)
175567456717SSteen Hegelund 		if (eport->cookie == cookie || eport->ndev == ndev)
175667456717SSteen Hegelund 			return true;
175767456717SSteen Hegelund 
175867456717SSteen Hegelund 	return false;
175967456717SSteen Hegelund }
176067456717SSteen Hegelund 
176167456717SSteen Hegelund /* Enable this port for this VCAP instance */
176267456717SSteen Hegelund static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev,
176367456717SSteen Hegelund 		       unsigned long cookie)
176467456717SSteen Hegelund {
176567456717SSteen Hegelund 	struct vcap_enabled_port *eport;
176667456717SSteen Hegelund 
176767456717SSteen Hegelund 	eport = kzalloc(sizeof(*eport), GFP_KERNEL);
176867456717SSteen Hegelund 	if (!eport)
176967456717SSteen Hegelund 		return -ENOMEM;
177067456717SSteen Hegelund 
177167456717SSteen Hegelund 	eport->ndev = ndev;
177267456717SSteen Hegelund 	eport->cookie = cookie;
177367456717SSteen Hegelund 	list_add_tail(&eport->list, &admin->enabled);
177467456717SSteen Hegelund 
177567456717SSteen Hegelund 	return 0;
177667456717SSteen Hegelund }
177767456717SSteen Hegelund 
177867456717SSteen Hegelund /* Disable this port for this VCAP instance */
177967456717SSteen Hegelund static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev,
178067456717SSteen Hegelund 			unsigned long cookie)
178167456717SSteen Hegelund {
178267456717SSteen Hegelund 	struct vcap_enabled_port *eport;
178367456717SSteen Hegelund 
178467456717SSteen Hegelund 	list_for_each_entry(eport, &admin->enabled, list) {
178567456717SSteen Hegelund 		if (eport->cookie == cookie && eport->ndev == ndev) {
178667456717SSteen Hegelund 			list_del(&eport->list);
178767456717SSteen Hegelund 			kfree(eport);
178867456717SSteen Hegelund 			return 0;
178967456717SSteen Hegelund 		}
179067456717SSteen Hegelund 	}
179167456717SSteen Hegelund 
179267456717SSteen Hegelund 	return -ENOENT;
179367456717SSteen Hegelund }
179467456717SSteen Hegelund 
179567456717SSteen Hegelund /* Find the VCAP instance that enabled the port using a specific filter */
179667456717SSteen Hegelund static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl,
179767456717SSteen Hegelund 						    unsigned long cookie)
179867456717SSteen Hegelund {
179967456717SSteen Hegelund 	struct vcap_enabled_port *eport;
180067456717SSteen Hegelund 	struct vcap_admin *admin;
180167456717SSteen Hegelund 
180267456717SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list)
180367456717SSteen Hegelund 		list_for_each_entry(eport, &admin->enabled, list)
180467456717SSteen Hegelund 			if (eport->cookie == cookie)
180567456717SSteen Hegelund 				return admin;
180667456717SSteen Hegelund 
180767456717SSteen Hegelund 	return NULL;
180867456717SSteen Hegelund }
180967456717SSteen Hegelund 
181067456717SSteen Hegelund /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
181167456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
181267456717SSteen Hegelund 			int chain_id, unsigned long cookie, bool enable)
181367456717SSteen Hegelund {
181467456717SSteen Hegelund 	struct vcap_admin *admin;
181567456717SSteen Hegelund 	int err;
181667456717SSteen Hegelund 
181767456717SSteen Hegelund 	err = vcap_api_check(vctrl);
181867456717SSteen Hegelund 	if (err)
181967456717SSteen Hegelund 		return err;
182067456717SSteen Hegelund 
182167456717SSteen Hegelund 	if (!ndev)
182267456717SSteen Hegelund 		return -ENODEV;
182367456717SSteen Hegelund 
182467456717SSteen Hegelund 	if (chain_id)
182567456717SSteen Hegelund 		admin = vcap_find_admin(vctrl, chain_id);
182667456717SSteen Hegelund 	else
182767456717SSteen Hegelund 		admin = vcap_find_admin_by_cookie(vctrl, cookie);
182867456717SSteen Hegelund 	if (!admin)
182967456717SSteen Hegelund 		return -ENOENT;
183067456717SSteen Hegelund 
183167456717SSteen Hegelund 	/* first instance and first chain */
183267456717SSteen Hegelund 	if (admin->vinst || chain_id > admin->first_cid)
183367456717SSteen Hegelund 		return -EFAULT;
183467456717SSteen Hegelund 
183567456717SSteen Hegelund 	err = vctrl->ops->enable(ndev, admin, enable);
183667456717SSteen Hegelund 	if (err)
183767456717SSteen Hegelund 		return err;
183867456717SSteen Hegelund 
183967456717SSteen Hegelund 	if (chain_id) {
184067456717SSteen Hegelund 		if (vcap_is_enabled(admin, ndev, cookie))
184167456717SSteen Hegelund 			return -EADDRINUSE;
184271c9de99SSteen Hegelund 		mutex_lock(&admin->lock);
184367456717SSteen Hegelund 		vcap_enable(admin, ndev, cookie);
184467456717SSteen Hegelund 	} else {
184571c9de99SSteen Hegelund 		mutex_lock(&admin->lock);
184667456717SSteen Hegelund 		vcap_disable(admin, ndev, cookie);
184767456717SSteen Hegelund 	}
184871c9de99SSteen Hegelund 	mutex_unlock(&admin->lock);
184967456717SSteen Hegelund 
185067456717SSteen Hegelund 	return 0;
185167456717SSteen Hegelund }
185267456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups);
185367456717SSteen Hegelund 
1854f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */
1855f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
1856f13230a4SSteen Hegelund {
1857f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1858f13230a4SSteen Hegelund 
1859f13230a4SSteen Hegelund 	ri->counter_id = counter_id;
1860f13230a4SSteen Hegelund }
1861f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
1862f13230a4SSteen Hegelund 
186340e7fe18SSteen Hegelund /* Provide all rules via a callback interface */
186440e7fe18SSteen Hegelund int vcap_rule_iter(struct vcap_control *vctrl,
186540e7fe18SSteen Hegelund 		   int (*callback)(void *, struct vcap_rule *), void *arg)
186640e7fe18SSteen Hegelund {
186740e7fe18SSteen Hegelund 	struct vcap_rule_internal *ri;
186840e7fe18SSteen Hegelund 	struct vcap_admin *admin;
186940e7fe18SSteen Hegelund 	int ret;
187040e7fe18SSteen Hegelund 
187140e7fe18SSteen Hegelund 	ret = vcap_api_check(vctrl);
187240e7fe18SSteen Hegelund 	if (ret)
187340e7fe18SSteen Hegelund 		return ret;
187440e7fe18SSteen Hegelund 
187540e7fe18SSteen Hegelund 	/* Iterate all rules in each VCAP instance */
187640e7fe18SSteen Hegelund 	list_for_each_entry(admin, &vctrl->list, list) {
187740e7fe18SSteen Hegelund 		list_for_each_entry(ri, &admin->rules, list) {
187840e7fe18SSteen Hegelund 			ret = callback(arg, &ri->data);
187940e7fe18SSteen Hegelund 			if (ret)
188040e7fe18SSteen Hegelund 				return ret;
188140e7fe18SSteen Hegelund 		}
188240e7fe18SSteen Hegelund 	}
188340e7fe18SSteen Hegelund 
188440e7fe18SSteen Hegelund 	return 0;
188540e7fe18SSteen Hegelund }
188640e7fe18SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_iter);
188740e7fe18SSteen Hegelund 
1888f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
1889f13230a4SSteen Hegelund {
1890f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1891f13230a4SSteen Hegelund 	int err;
1892f13230a4SSteen Hegelund 
1893f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
1894f13230a4SSteen Hegelund 	if (err)
1895f13230a4SSteen Hegelund 		return err;
1896f13230a4SSteen Hegelund 	if (!ctr) {
1897f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
1898f13230a4SSteen Hegelund 		return -EINVAL;
1899f13230a4SSteen Hegelund 	}
1900f13230a4SSteen Hegelund 	return vcap_write_counter(ri, ctr);
1901f13230a4SSteen Hegelund }
1902f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
1903f13230a4SSteen Hegelund 
1904f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
1905f13230a4SSteen Hegelund {
1906f13230a4SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1907f13230a4SSteen Hegelund 	int err;
1908f13230a4SSteen Hegelund 
1909f13230a4SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
1910f13230a4SSteen Hegelund 	if (err)
1911f13230a4SSteen Hegelund 		return err;
1912f13230a4SSteen Hegelund 	if (!ctr) {
1913f13230a4SSteen Hegelund 		pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
1914f13230a4SSteen Hegelund 		return -EINVAL;
1915f13230a4SSteen Hegelund 	}
1916f13230a4SSteen Hegelund 	return vcap_read_counter(ri, ctr);
1917f13230a4SSteen Hegelund }
1918f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
1919f13230a4SSteen Hegelund 
1920465a38a2SSteen Hegelund static int vcap_rule_mod_key(struct vcap_rule *rule,
1921465a38a2SSteen Hegelund 			     enum vcap_key_field key,
1922465a38a2SSteen Hegelund 			     enum vcap_field_type ftype,
1923465a38a2SSteen Hegelund 			     struct vcap_client_keyfield_data *data)
1924465a38a2SSteen Hegelund {
1925465a38a2SSteen Hegelund 	struct vcap_client_keyfield *field;
1926465a38a2SSteen Hegelund 
1927465a38a2SSteen Hegelund 	field = vcap_find_keyfield(rule, key);
1928465a38a2SSteen Hegelund 	if (!field)
1929465a38a2SSteen Hegelund 		return vcap_rule_add_key(rule, key, ftype, data);
1930465a38a2SSteen Hegelund 	vcap_copy_from_client_keyfield(rule, field, data);
1931465a38a2SSteen Hegelund 	return 0;
1932465a38a2SSteen Hegelund }
1933465a38a2SSteen Hegelund 
1934465a38a2SSteen Hegelund /* Modify a 32 bit key field with value and mask in the rule */
1935465a38a2SSteen Hegelund int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
1936465a38a2SSteen Hegelund 			  u32 value, u32 mask)
1937465a38a2SSteen Hegelund {
1938465a38a2SSteen Hegelund 	struct vcap_client_keyfield_data data;
1939465a38a2SSteen Hegelund 
1940465a38a2SSteen Hegelund 	data.u32.value = value;
1941465a38a2SSteen Hegelund 	data.u32.mask = mask;
1942465a38a2SSteen Hegelund 	return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data);
1943465a38a2SSteen Hegelund }
1944465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32);
1945465a38a2SSteen Hegelund 
1946465a38a2SSteen Hegelund static int vcap_rule_mod_action(struct vcap_rule *rule,
1947465a38a2SSteen Hegelund 				enum vcap_action_field action,
1948465a38a2SSteen Hegelund 				enum vcap_field_type ftype,
1949465a38a2SSteen Hegelund 				struct vcap_client_actionfield_data *data)
1950465a38a2SSteen Hegelund {
1951465a38a2SSteen Hegelund 	struct vcap_client_actionfield *field;
1952465a38a2SSteen Hegelund 
1953465a38a2SSteen Hegelund 	field = vcap_find_actionfield(rule, action);
1954465a38a2SSteen Hegelund 	if (!field)
1955465a38a2SSteen Hegelund 		return vcap_rule_add_action(rule, action, ftype, data);
1956465a38a2SSteen Hegelund 	vcap_copy_from_client_actionfield(rule, field, data);
1957465a38a2SSteen Hegelund 	return 0;
1958465a38a2SSteen Hegelund }
1959465a38a2SSteen Hegelund 
1960465a38a2SSteen Hegelund /* Modify a 32 bit action field with value in the rule */
1961465a38a2SSteen Hegelund int vcap_rule_mod_action_u32(struct vcap_rule *rule,
1962465a38a2SSteen Hegelund 			     enum vcap_action_field action,
1963465a38a2SSteen Hegelund 			     u32 value)
1964465a38a2SSteen Hegelund {
1965465a38a2SSteen Hegelund 	struct vcap_client_actionfield_data data;
1966465a38a2SSteen Hegelund 
1967465a38a2SSteen Hegelund 	data.u32.value = value;
1968465a38a2SSteen Hegelund 	return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data);
1969465a38a2SSteen Hegelund }
1970465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32);
1971465a38a2SSteen Hegelund 
1972465a38a2SSteen Hegelund /* Drop keys in a keylist and any keys that are not supported by the keyset */
1973465a38a2SSteen Hegelund int vcap_filter_rule_keys(struct vcap_rule *rule,
1974465a38a2SSteen Hegelund 			  enum vcap_key_field keylist[], int length,
1975465a38a2SSteen Hegelund 			  bool drop_unsupported)
1976465a38a2SSteen Hegelund {
1977465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(rule);
1978465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf, *next_ckf;
1979465a38a2SSteen Hegelund 	const struct vcap_field *fields;
1980465a38a2SSteen Hegelund 	enum vcap_key_field key;
1981465a38a2SSteen Hegelund 	int err = 0;
1982465a38a2SSteen Hegelund 	int idx;
1983465a38a2SSteen Hegelund 
1984465a38a2SSteen Hegelund 	if (length > 0) {
1985465a38a2SSteen Hegelund 		err = -EEXIST;
1986465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
1987465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
1988465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
1989465a38a2SSteen Hegelund 			for (idx = 0; idx < length; ++idx)
1990465a38a2SSteen Hegelund 				if (key == keylist[idx]) {
1991465a38a2SSteen Hegelund 					list_del(&ckf->ctrl.list);
1992465a38a2SSteen Hegelund 					kfree(ckf);
1993465a38a2SSteen Hegelund 					idx++;
1994465a38a2SSteen Hegelund 					err = 0;
1995465a38a2SSteen Hegelund 				}
1996465a38a2SSteen Hegelund 		}
1997465a38a2SSteen Hegelund 	}
1998465a38a2SSteen Hegelund 	if (drop_unsupported) {
1999465a38a2SSteen Hegelund 		err = -EEXIST;
2000465a38a2SSteen Hegelund 		fields = vcap_keyfields(ri->vctrl, ri->admin->vtype,
2001465a38a2SSteen Hegelund 					rule->keyset);
2002465a38a2SSteen Hegelund 		if (!fields)
2003465a38a2SSteen Hegelund 			return err;
2004465a38a2SSteen Hegelund 		list_for_each_entry_safe(ckf, next_ckf,
2005465a38a2SSteen Hegelund 					 &ri->data.keyfields, ctrl.list) {
2006465a38a2SSteen Hegelund 			key = ckf->ctrl.key;
2007465a38a2SSteen Hegelund 			if (fields[key].width == 0) {
2008465a38a2SSteen Hegelund 				list_del(&ckf->ctrl.list);
2009465a38a2SSteen Hegelund 				kfree(ckf);
2010465a38a2SSteen Hegelund 				err = 0;
2011465a38a2SSteen Hegelund 			}
2012465a38a2SSteen Hegelund 		}
2013465a38a2SSteen Hegelund 	}
2014465a38a2SSteen Hegelund 	return err;
2015465a38a2SSteen Hegelund }
2016465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_filter_rule_keys);
2017465a38a2SSteen Hegelund 
2018465a38a2SSteen Hegelund /* Make a full copy of an existing rule with a new rule id */
2019465a38a2SSteen Hegelund struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
2020465a38a2SSteen Hegelund {
2021465a38a2SSteen Hegelund 	struct vcap_rule_internal *ri = to_intrule(erule);
2022465a38a2SSteen Hegelund 	struct vcap_client_actionfield *caf;
2023465a38a2SSteen Hegelund 	struct vcap_client_keyfield *ckf;
2024465a38a2SSteen Hegelund 	struct vcap_rule *rule;
2025465a38a2SSteen Hegelund 	int err;
2026465a38a2SSteen Hegelund 
2027465a38a2SSteen Hegelund 	err = vcap_api_check(ri->vctrl);
2028465a38a2SSteen Hegelund 	if (err)
2029465a38a2SSteen Hegelund 		return ERR_PTR(err);
2030465a38a2SSteen Hegelund 
2031465a38a2SSteen Hegelund 	rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id,
2032465a38a2SSteen Hegelund 			       ri->data.user, ri->data.priority, 0);
2033465a38a2SSteen Hegelund 	if (IS_ERR(rule))
2034465a38a2SSteen Hegelund 		return rule;
2035465a38a2SSteen Hegelund 
2036465a38a2SSteen Hegelund 	list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
2037465a38a2SSteen Hegelund 		/* Add a key duplicate in the new rule */
2038465a38a2SSteen Hegelund 		err = vcap_rule_add_key(rule,
2039465a38a2SSteen Hegelund 					ckf->ctrl.key,
2040465a38a2SSteen Hegelund 					ckf->ctrl.type,
2041465a38a2SSteen Hegelund 					&ckf->data);
2042465a38a2SSteen Hegelund 		if (err)
2043465a38a2SSteen Hegelund 			goto err;
2044465a38a2SSteen Hegelund 	}
2045465a38a2SSteen Hegelund 
2046465a38a2SSteen Hegelund 	list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
2047465a38a2SSteen Hegelund 		/* Add a action duplicate in the new rule */
2048465a38a2SSteen Hegelund 		err = vcap_rule_add_action(rule,
2049465a38a2SSteen Hegelund 					   caf->ctrl.action,
2050465a38a2SSteen Hegelund 					   caf->ctrl.type,
2051465a38a2SSteen Hegelund 					   &caf->data);
2052465a38a2SSteen Hegelund 		if (err)
2053465a38a2SSteen Hegelund 			goto err;
2054465a38a2SSteen Hegelund 	}
2055465a38a2SSteen Hegelund 	return rule;
2056465a38a2SSteen Hegelund err:
2057465a38a2SSteen Hegelund 	vcap_free_rule(rule);
2058465a38a2SSteen Hegelund 	return ERR_PTR(err);
2059465a38a2SSteen Hegelund }
2060465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_copy_rule);
2061465a38a2SSteen Hegelund 
206267d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST
206367d63751SSteen Hegelund #include "vcap_api_kunit.c"
206467d63751SSteen Hegelund #endif
2065